Seed ingest/export moves behind ports.SeedRepository (SeedRepo in the postgres adapter; knowledge ingest absorbed from internal/knowledge, package deleted). pct_create flow (defaults, template/VMID/gateway pre-flights, pct create, graph registration) moves from httpapi's approved-execution path into app.ProvisioningService + the ssh provisioner adapter; CLI seed/export/secret become adapters over the services. EntityCreateInput gains EnrolledAt. Plan status corrected: phases 0-7 shipped, 8 + 9 gates open. VERSION 0.34.1.
73 lines
2.5 KiB
Go
73 lines
2.5 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// TestFlexBoolUnmarshal covers the exact production failure: the LLM emitted
|
|
// `"privileged":0` / `"nesting":1` (numbers) and the strict bool field made the
|
|
// already-approved pct_create execution fail to parse, so the LXC was never
|
|
// created.
|
|
func TestFlexBoolUnmarshal(t *testing.T) {
|
|
type cfg struct {
|
|
Privileged flexBool `json:"privileged"`
|
|
Nesting flexBool `json:"nesting"`
|
|
}
|
|
cases := []struct {
|
|
in string
|
|
privileged bool
|
|
nesting bool
|
|
wantErr bool
|
|
}{
|
|
{`{"privileged":0,"nesting":1}`, false, true, false}, // the prod payload
|
|
{`{"privileged":false,"nesting":true}`, false, true, false}, // canonical
|
|
{`{"privileged":"1","nesting":"0"}`, true, false, false}, // stringified
|
|
{`{"privileged":"true","nesting":"no"}`, true, false, false},
|
|
{`{}`, false, false, false}, // absent → zero
|
|
{`{"privileged":"maybe"}`, false, false, true},
|
|
}
|
|
for _, c := range cases {
|
|
var out cfg
|
|
err := json.Unmarshal([]byte(c.in), &out)
|
|
if (err != nil) != c.wantErr {
|
|
t.Fatalf("%s: err=%v wantErr=%v", c.in, err, c.wantErr)
|
|
}
|
|
if c.wantErr {
|
|
continue
|
|
}
|
|
if bool(out.Privileged) != c.privileged || bool(out.Nesting) != c.nesting {
|
|
t.Errorf("%s: got priv=%v nest=%v want priv=%v nest=%v",
|
|
c.in, bool(out.Privileged), bool(out.Nesting), c.privileged, c.nesting)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestJSONErrValidForNastyOutput guards the bug where command output with
|
|
// quotes/backslashes/newlines produced invalid JSON, failing the ::jsonb cast
|
|
// and silently dropping the execution's final status update.
|
|
func TestJSONErrValidForNastyOutput(t *testing.T) {
|
|
nasty := "CT 132 already exists on node \"hubris\"\n\tpath C:\\x\r\n\x00 100%"
|
|
for _, payload := range [][]byte{
|
|
jsonErr("%s", nasty),
|
|
jsonErr("list templates on %s: %s", "host:strong", nasty),
|
|
} {
|
|
var m map[string]any
|
|
if err := json.Unmarshal(payload, &m); err != nil {
|
|
t.Fatalf("jsonErr produced invalid JSON: %v\npayload=%s", err, payload)
|
|
}
|
|
if _, ok := m["error"]; !ok {
|
|
t.Errorf("missing error key: %s", payload)
|
|
}
|
|
}
|
|
}
|
|
|
|
// resolveTemplate and gatewayPreflightPassed moved to the ssh provisioner
|
|
// adapter with the pct flow (Phase 7); their tests live in
|
|
// internal/adapters/ssh/provisioner_test.go.
|
|
//
|
|
// provisionScript and sanitizePkgs were removed when pct_create was made
|
|
// atomic (create + start + register only) — installing packages and running
|
|
// setup scripts is now the agent's own job via follow-up `run` calls, which
|
|
// already has its own classifier/sanitization tests in internal/policy.
|