package workspaceops import ( "bytes" "encoding/base64" "encoding/json" "errors" "fmt" "os" "path/filepath" "reflect" "strings" "testing" "context" "github.com/aritmolab/thothii/tools/thothctl/internal/compose" "github.com/aritmolab/thothii/tools/thothctl/internal/config" "github.com/aritmolab/thothii/tools/thothctl/internal/safeio" ) func TestMakeInputUsesPlatformBasename(t *testing.T) { if filepath.Separator == '\\' { t.Skip("Unix basename behavior") } root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } path := filepath.Join(root, "schema\\v2.sql") if err := os.WriteFile(path, []byte("select 1"), 0o600); err != nil { t.Fatal(err) } _, payload, err := makeInput(SuggestFksRequest{WorkspaceID: "psd", FromSQL: []string{path}}) if err != nil { t.Fatal(err) } var envelope inputEnvelope if err := json.Unmarshal([]byte(payload), &envelope); err != nil { t.Fatal(err) } if len(envelope.SQL) != 1 || envelope.SQL[0].Basename != "schema\\v2.sql" { t.Fatalf("basename=%q", envelope.SQL[0].Basename) } } func TestPublishCandidateRejectsTrailingYAMLDocument(t *testing.T) { candidate := []byte("candidates: []\n---\n[\n") digest := DigestBytes(candidate) x := hostExport{MediaType: "application/yaml", SHA256: digest, ContentBase64: base64.StdEncoding.EncodeToString(candidate)} result := Result{RunID: strings.Repeat("b", 32)} if err := publishCandidate(&x, result, ""); err == nil { t.Fatal("accepted malformed trailing YAML document") } } func TestParseWorkspaceCommands(t *testing.T) { cases := []struct { name string argv []string want any }{ {"inspect", []string{"workspace", "inspect", "--workspace", "psd", "--json"}, InspectCommand{WorkspaceID: "psd", JSON: true}}, {"dwh", []string{"workspace", "preprocess", "dwh", "--workspace", "psd", "--resume", "0123456789abcdef0123456789abcdef"}, DwhRequest{WorkspaceID: "psd", Resume: "0123456789abcdef0123456789abcdef"}}, {"suggest", []string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", "a=b"}, SuggestFksRequest{WorkspaceID: "psd", Assume: []string{"a=b"}}}, {"check", []string{"workspace", "schema", "check", "--workspace", "psd", "--resume", "0123456789abcdef0123456789abcdef"}, CheckSchemaRequest{WorkspaceID: "psd", Resume: "0123456789abcdef0123456789abcdef"}}, {"index", []string{"workspace", "index-schema", "--workspace", "psd"}, IndexSchemaRequest{WorkspaceID: "psd"}}, {"evidence", []string{"workspace", "preprocess", "evidence", "--workspace", "psd", "--dry-run"}, EvidenceRequest{WorkspaceID: "psd", DryRun: true}}, {"run", []string{"workspace", "preprocess", "run", "--workspace", "psd"}, RunRequest{WorkspaceID: "psd"}}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, err := ParseWorkspaceCommand(tc.argv) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(got, tc.want) { t.Errorf("got %#v want %#v", got, tc.want) } }) } } func TestParseWorkspaceRejectsUnsafeOrAmbiguousOptions(t *testing.T) { bad := [][]string{ {"workspace", "inspect", "--workspace", "psd", "--resume", "0123456789abcdef0123456789abcdef"}, {"workspace", "inspect", "--workspace", "psd", "--bootstrap-run-id", "0123456789abcdef0123456789abcdef"}, {"workspace", "inspect", "--workspace", "psd", "--passthrough"}, {"workspace", "preprocess", "run", "--workspace", "PSd"}, {"workspace", "preprocess", "run", "--workspace", "psd", "--resume", "bad"}, {"workspace", "schema", "check", "--workspace", "psd"}, {"workspace", "schema", "check", "--workspace", "psd", "--resume", "0123456789abcdef0123456789abcdef", "--annotations", "a"}, } for _, argv := range bad { if _, err := ParseWorkspaceCommand(argv); err == nil { t.Errorf("accepted unsafe argv %v", argv) } } } func TestParseWorkspaceRejectsNonContractHierarchyAndAssumeShell(t *testing.T) { for _, argv := range [][]string{ {"workspace", "schema", "dwh", "--workspace", "psd"}, {"workspace", "preprocess", "check", "--workspace", "psd"}, {"workspace", "suggest-fks", "--workspace", "psd"}, {"workspace", "inspect", "--workspace", "psd", "--bootstrap-run-id", strings.Repeat("a", 32)}, {"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", "a"}, {"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", "a=$(id)"}, } { if _, err := ParseWorkspaceCommand(argv); err == nil { t.Errorf("accepted non-contract argv %v", argv) } } } func TestRunUsesBase64BasenameIngressAndNoTTY(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } sqlPath := filepath.Join(root, "schema.sql") if err := os.WriteFile(sqlPath, []byte("select 1"), 0o600); err != nil { t.Fatal(err) } stdinCapture := filepath.Join(root, "stdin.json") argsCapture := filepath.Join(root, "args.txt") resultJSON := `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"0123456789012345678901234567890123456789","descriptorBlob":"abcdefabcdefabcdefabcdefabcdefabcdefabcd","operation":"suggest-fks","runId":"0123456789abcdef0123456789abcdef","completedStages":[]}` script := "#!/bin/sh\nprintf '%s\n' \"$@\" > '" + argsCapture + "'\ncat > '" + stdinCapture + "'\nprintf '%s' '" + resultJSON + "'\n" fake := filepath.Join(root, "docker") if err := os.WriteFile(fake, []byte(script), 0o700); err != nil { t.Fatal(err) } cmd, err := ParseWorkspaceCommand([]string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--from-sql", sqlPath}) if err != nil { t.Fatal(err) } got, err := Run(context.Background(), config.Installation{ProjectDirectory: root, EnvFile: filepath.Join(root, "env")}, compose.NewRunner(fake), cmd, nil) if err != nil { t.Fatal(err) } if got.Code != "ok" { t.Fatalf("result = %#v", got) } stdinBytes, err := os.ReadFile(stdinCapture) if err != nil { t.Fatal(err) } if strings.Contains(string(stdinBytes), sqlPath) || !strings.Contains(string(stdinBytes), "contentBase64") || !strings.Contains(string(stdinBytes), "schema.sql") { t.Fatalf("stdin envelope = %q; want basename/base64 without host path", stdinBytes) } argsBytes, err := os.ReadFile(argsCapture) if err != nil { t.Fatal(err) } if strings.Contains(string(argsBytes), sqlPath) || !strings.Contains(string(argsBytes), "--operation\nsuggest-fks") || !strings.Contains(string(argsBytes), "--workspace\npsd") { t.Fatalf("child args = %q; want closed operation/workspace args", argsBytes) } } func TestRunPublishesOnlyVerifiedCandidateExport(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } candidate := []byte("candidates: []\n") digest := DigestBytes(candidate) encoded := base64.StdEncoding.EncodeToString(candidate) resultJSON := `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"0123456789012345678901234567890123456789","descriptorBlob":"abcdefabcdefabcdefabcdefabcdefabcdefabcd","operation":"suggest-fks","runId":"0123456789abcdef0123456789abcdef","completedStages":[],"artifactIdentities":[{"kind":"fk-candidates","digest":"` + digest + `"}],"hostExport":{"mediaType":"application/yaml","sha256":"` + digest + `","contentBase64":"` + encoded + `"}}` fake := filepath.Join(root, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ncat >/dev/null\nprintf '%s' '"+resultJSON+"'\n"), 0o700); err != nil { t.Fatal(err) } path := filepath.Join(root, "out.yaml") cmd, err := ParseWorkspaceCommand([]string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--output", path}) if err != nil { t.Fatal(err) } got, err := Run(context.Background(), config.Installation{ProjectDirectory: root, EnvFile: filepath.Join(root, "env")}, compose.NewRunner(fake), cmd, nil) if err != nil { t.Fatal(err) } if got.RunID == "" { t.Fatal("missing run identity") } b, err := os.ReadFile(path) if err != nil || string(b) != string(candidate) { t.Fatalf("candidate = %q, %v", b, err) } } func validWorkspaceResult(status, code string) Result { return Result{SchemaVersion: 1, Status: status, Code: code, WorkspaceID: "psd", WorkspaceRevision: strings.Repeat("0", 40), DescriptorBlob: strings.Repeat("a", 40), Operation: "evidence", CompletedStages: []string{}} } func TestValidateIngressRejectsExplicitOmittedEvidenceZeroFields(t *testing.T) { command := EvidenceRequest{WorkspaceID: "psd"} expected, _, err := makeInput(command) if err != nil { t.Fatal(err) } for _, payload := range []string{ `{"schemaVersion":1,"operation":"evidence","workspaceId":"psd","resume":""}`, `{"schemaVersion":1,"operation":"evidence","workspaceId":"psd","workspaceId":"psd"}`, `{"schemaVersion":1,"operation":"evidence","workspaceId":"psd","dryRun":false}`, `{"schemaVersion":1,"operation":"evidence","workspaceId":"psd","resume":null}`, } { if err := validateIngress([]byte(payload), expected); err == nil { t.Errorf("accepted non-derived envelope %s", payload) } } } func TestValidateIngressRequiresExactDerivedFieldSetForOptionalInputs(t *testing.T) { command := SuggestFksRequest{WorkspaceID: "psd"} expected, _, err := makeInput(command) if err != nil { t.Fatal(err) } payload := `{"schemaVersion":1,"operation":"suggest-fks","workspaceId":"psd","sql":null,"assume":[]}` if err := validateIngress([]byte(payload), expected); err == nil { t.Fatal("accepted explicit null/empty optional fields omitted by command") } } func TestPublishCandidateValidatesInternalExportWithoutOutput(t *testing.T) { candidate := []byte("candidates: []\n") digest := DigestBytes(candidate) result := validWorkspaceResult("succeeded", "ok") result.Operation = "suggest-fks" result.RunID = strings.Repeat("b", 32) result.ArtifactIdentities = []ArtifactIdentity{{Kind: "fk-candidates", Digest: digest}} for _, export := range []hostExport{ {MediaType: "application/json", SHA256: digest, ContentBase64: base64.StdEncoding.EncodeToString(candidate)}, {MediaType: "application/yaml", SHA256: digest, ContentBase64: base64.StdEncoding.EncodeToString(candidate)}, } { if export.MediaType == "application/json" { if err := publishCandidate(&export, result, ""); err == nil { t.Fatal("accepted invalid media type without output") } } else if err := publishCandidate(&export, result, ""); err != nil { t.Fatal(err) } } } func TestValidateResultBindsStatusCodeAndExit(t *testing.T) { cases := []struct { status, code string exit int valid bool }{ {"succeeded", "ok", 0, true}, {"unchanged", "ok", 0, true}, {"dry_run", "ok", 0, true}, {"blocked", "manual_review_required", 3, true}, {"failed", "workspace_not_found", 1, true}, {"blocked", "manual_review_required", 0, false}, {"failed", "workspace_not_found", 0, false}, {"succeeded", "workspace_not_found", 0, false}, {"failed", "ok", 1, false}, } for _, tc := range cases { r := validWorkspaceResult(tc.status, tc.code) err := validateResult(r, "psd", "evidence") got := err == nil && resultExitMatches(tc.status, tc.exit) if got != tc.valid { t.Errorf("%s/%s exit %d valid=%v err=%v", tc.status, tc.code, tc.exit, tc.valid, err) } } } func TestRunRejectsUnknownHostExportFieldWithoutOutput(t *testing.T) { d := t.TempDir() candidate := []byte("candidates: []\n") digest := DigestBytes(candidate) response := `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"` + strings.Repeat("0", 40) + `","descriptorBlob":"` + strings.Repeat("a", 40) + `","operation":"suggest-fks","runId":"` + strings.Repeat("b", 32) + `","completedStages":[],"artifactIdentities":[{"kind":"fk-candidates","digest":"` + digest + `"}],"hostExport":{"mediaType":"application/yaml","sha256":"` + digest + `","contentBase64":"` + base64.StdEncoding.EncodeToString(candidate) + `","extra":1}}` fake := filepath.Join(d, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ncat >/dev/null\nprintf '%s' '"+response+"'\n"), 0o700); err != nil { t.Fatal(err) } cmd := SuggestFksRequest{WorkspaceID: "psd"} if _, err := Run(context.Background(), config.Installation{ProjectDirectory: d}, compose.NewRunner(fake), cmd, nil); err == nil { t.Fatal("accepted unknown hostExport field") } } func TestPublishCandidateRejectsOversizedExportWithoutOutput(t *testing.T) { candidate := bytes.Repeat([]byte("y"), maxCandidate+1) digest := DigestBytes(candidate) x := hostExport{MediaType: "application/yaml", SHA256: digest, ContentBase64: base64.StdEncoding.EncodeToString(candidate)} r := validWorkspaceResult("succeeded", "ok") r.Operation, r.RunID = "suggest-fks", strings.Repeat("b", 32) if err := publishCandidate(&x, r, ""); err == nil { t.Fatal("accepted oversized export without output") } } func TestRunAcceptsOnlyMatchingChildExitForStatus(t *testing.T) { for _, tc := range []struct { name, status, code string exit int wantErr bool }{ {"blocked-exit3", "blocked", "manual_review_required", 3, false}, {"blocked-exit0", "blocked", "manual_review_required", 0, true}, {"failed-exit1", "failed", "workspace_not_found", 1, false}, {"failed-exit0", "failed", "workspace_not_found", 0, true}, } { t.Run(tc.name, func(t *testing.T) { d := t.TempDir() response := fmt.Sprintf(`{"schemaVersion":1,"status":"%s","code":"%s","workspaceId":"psd","workspaceRevision":"%s","descriptorBlob":"%s","operation":"evidence","completedStages":[]}`, tc.status, tc.code, strings.Repeat("0", 40), strings.Repeat("a", 40)) fake := filepath.Join(d, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ncat >/dev/null\nprintf '%s' '"+response+"'\nexit "+fmt.Sprint(tc.exit)+"\n"), 0o700); err != nil { t.Fatal(err) } _, err := Run(context.Background(), config.Installation{ProjectDirectory: d}, compose.NewRunner(fake), EvidenceRequest{WorkspaceID: "psd"}, nil) if (err != nil) != tc.wantErr { t.Fatalf("error=%v wantErr=%v", err, tc.wantErr) } }) } } func TestParseWorkspaceRejectsDuplicateMissingAndUnknownOptions(t *testing.T) { validResume := strings.Repeat("0", 32) for _, argv := range [][]string{ {"workspace", "inspect", "--json", "--json", "--workspace", "psd"}, {"workspace", "inspect", "--workspace", "psd", "--workspace", "psd"}, {"workspace", "preprocess", "dwh", "--workspace", "psd", "--resume", validResume, "--resume", validResume}, {"workspace", "schema", "suggest-fks", "--workspace", "psd", "--output", "a", "--output", "b"}, {"workspace", "inspect", "--json", "--unknown", "x", "--workspace", "psd"}, {"workspace", "inspect", "--json"}, } { if _, err := ParseWorkspaceCommand(argv); err == nil { t.Errorf("accepted invalid argv %v", argv) } } } func TestParseWorkspaceAcceptsAssumptionAndEnforcesLimits(t *testing.T) { if _, err := ParseWorkspaceCommand([]string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", "orders.id=customers.id"}); err != nil { t.Fatal(err) } exactAssumption := strings.Repeat("a", 127) + "=" + strings.Repeat("b", 128) if len(exactAssumption) != maxAssumptionBytes { t.Fatalf("test assumption length = %d, want %d", len(exactAssumption), maxAssumptionBytes) } if _, err := ParseWorkspaceCommand([]string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", exactAssumption}); err != nil { t.Fatalf("rejected exact assumption bound: %v", err) } if _, err := ParseWorkspaceCommand([]string{"workspace", "schema", "suggest-fks", "--workspace", "psd", "--assume", exactAssumption + "a"}); err == nil { t.Fatal("accepted oversized assumption") } args := []string{"workspace", "schema", "suggest-fks", "--workspace", "psd"} for i := 0; i < maxAssumptions; i++ { args = append(args, "--assume", fmt.Sprintf("a%d=b%d", i, i)) } if _, err := ParseWorkspaceCommand(args); err != nil { t.Fatalf("rejected exact assumption count: %v", err) } args = append(args, "--assume", "overflow=overflow") if _, err := ParseWorkspaceCommand(args); err == nil { t.Fatalf("accepted %d assumptions", maxAssumptions+1) } args = []string{"workspace", "schema", "suggest-fks", "--workspace", "psd"} for i := 0; i < 33; i++ { args = append(args, "--from-sql", fmt.Sprintf("schema-%d.sql", i)) } if _, err := ParseWorkspaceCommand(args); err == nil { t.Fatal("accepted 33 SQL files") } } func TestMakeInputAcceptsMaximumSingleSQLFile(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } path := filepath.Join(root, "schema.sql") if err := os.WriteFile(path, bytes.Repeat([]byte("x"), maxSQLFile), 0o600); err != nil { t.Fatal(err) } command := SuggestFksRequest{WorkspaceID: "psd", FromSQL: []string{path}} if _, payload, err := makeInput(command); err != nil { t.Fatalf("makeInput() error = %v", err) } else if len(payload) <= maxResult { t.Fatalf("payload length = %d, want larger than result cap %d", len(payload), maxResult) } } func TestMakeInputAcceptsMaximumAnnotationWithReviewDigestPair(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } path := filepath.Join(root, "annotations.md") contents := bytes.Repeat([]byte("a"), maxAnnotations) if err := os.WriteFile(path, contents, 0o600); err != nil { t.Fatal(err) } command := CheckSchemaRequest{WorkspaceID: "psd", Resume: strings.Repeat("0", 32), Annotations: path, ReviewedCandidates: DigestBytes([]byte("reviewed"))} env, payload, err := makeInput(command) if err != nil { t.Fatal(err) } if env.Annotations == nil || env.ReviewedCandidates == "" || len(payload) <= maxResult { t.Fatalf("annotation envelope = %#v payload=%d; want pair and request larger than result cap", env, len(payload)) } if err := validateIngress([]byte(payload), env); err != nil { t.Fatalf("validateIngress() = %v", err) } } func TestWorkspaceIngressAcceptsExactCountsAndByteBounds(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } paths := make([]string, 0, 32) for i := 0; i < 32; i++ { path := filepath.Join(root, fmt.Sprintf("schema-%02d.sql", i)) if err := os.WriteFile(path, []byte("x"), 0o600); err != nil { t.Fatal(err) } paths = append(paths, path) } assumptions := make([]string, 0, maxAssumptions) for i := 0; i < maxAssumptions; i++ { assumptions = append(assumptions, fmt.Sprintf("column_%d=table_%d", i, i)) } argv := []string{"workspace", "schema", "suggest-fks", "--workspace", "psd"} for _, path := range paths { argv = append(argv, "--from-sql", path) } for _, assumption := range assumptions { argv = append(argv, "--assume", assumption) } parsed, err := ParseWorkspaceCommand(argv) if err != nil { t.Fatalf("parser rejected exact file/assumption counts: %v", err) } command, ok := parsed.(SuggestFksRequest) if !ok { t.Fatalf("parsed command = %T, want SuggestFksRequest", parsed) } for _, path := range paths { if b, e := safeio.ReadCanonicalUTF8(path, maxSQLFile); e != nil { t.Fatalf("direct read %s: %v", path, e) } else if len(b) != 1 { t.Fatalf("direct read length=%d", len(b)) } } env, payload, err := makeInput(command) if err != nil { t.Fatalf("exact file/assumption counts rejected: %v", err) } if len(env.SQL) != 32 || len(env.Assume) != maxAssumptions { t.Fatalf("derived envelope counts = sql %d assumptions %d", len(env.SQL), len(env.Assume)) } if err := validateIngress([]byte(payload), env); err != nil { t.Fatalf("exact-bound envelope rejected: %v", err) } } func TestWorkspaceIngressRejectsSQLAggregateOverLimit(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } paths := make([]string, 0, 17) for i := 0; i < 17; i++ { path := filepath.Join(root, fmt.Sprintf("schema-%02d.sql", i)) if err := os.WriteFile(path, bytes.Repeat([]byte("x"), maxSQLFile), 0o600); err != nil { t.Fatal(err) } paths = append(paths, path) } command := SuggestFksRequest{WorkspaceID: "psd", FromSQL: paths[:16]} if _, _, err := makeInput(command); err != nil { t.Fatalf("exact SQL aggregate rejected: %v", err) } command.FromSQL = paths if _, _, err := makeInput(command); err == nil { t.Fatal("accepted SQL aggregate over 16 MiB") } } func TestValidateIngressRejectsTrailingAndUnknownFields(t *testing.T) { command := EvidenceRequest{WorkspaceID: "psd", DryRun: true} expected, payload, err := makeInput(command) if err != nil { t.Fatal(err) } if err := validateIngress([]byte(payload), expected); err != nil { t.Fatalf("generated envelope rejected: %v", err) } for _, invalid := range []string{ payload + " {}", strings.TrimSuffix(payload, "}") + `,"unknown":1}`, } { if err := validateIngress([]byte(invalid), expected); err == nil { t.Errorf("accepted invalid ingress envelope %q", invalid) } } } func TestValidateResultRejectsIdentitySchemaAndUnknownValues(t *testing.T) { base := validWorkspaceResult("succeeded", "ok") cases := []Result{ base, func() Result { r := base; r.SchemaVersion = 2; return r }(), func() Result { r := base; r.WorkspaceID = "other"; return r }(), func() Result { r := base; r.Operation = "run"; return r }(), func() Result { r := base; r.WorkspaceRevision = "short"; return r }(), func() Result { r := base; r.DescriptorBlob = "short"; return r }(), func() Result { r := base; r.RunID = "not-a-run"; return r }(), func() Result { r := base; r.ChildRuns = map[string]string{"child": "not-a-run"}; return r }(), func() Result { r := base r.ArtifactIdentities = []ArtifactIdentity{{Kind: "fk", Digest: "not-a-digest"}} return r }(), func() Result { r := base; r.CompletedStages = nil; return r }(), } for i, result := range cases { err := validateResult(result, "psd", "evidence") if (i == 0 && err != nil) || (i > 0 && err == nil) { t.Errorf("case %d validateResult() = %v", i, err) } } } func TestPublishCandidateRejectsInvalidEncodingDigestUTF8AndYAML(t *testing.T) { result := validWorkspaceResult("succeeded", "ok") result.Operation = "suggest-fks" result.RunID = strings.Repeat("b", 32) valid := []byte("candidates: []\n") validDigest := DigestBytes(valid) result.ArtifactIdentities = []ArtifactIdentity{{Kind: "fk-candidates", Digest: validDigest}} cases := []hostExport{ {MediaType: "application/yaml", SHA256: validDigest, ContentBase64: "%%%"}, {MediaType: "application/yaml", SHA256: DigestBytes([]byte("other")), ContentBase64: base64.StdEncoding.EncodeToString(valid)}, {MediaType: "application/yaml", SHA256: validDigest, ContentBase64: base64.StdEncoding.EncodeToString([]byte{0xff})}, {MediaType: "application/yaml", SHA256: DigestBytes([]byte("not yaml")), ContentBase64: base64.StdEncoding.EncodeToString([]byte("["))}, } for i, candidate := range cases { if err := publishCandidate(&candidate, result, ""); err == nil { t.Errorf("case %d accepted invalid candidate export", i) } } } func TestRunRejectsUnsafeInputsBeforeComposeInvocation(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } realSQL := filepath.Join(root, "real.sql") if err := os.WriteFile(realSQL, []byte("select 1"), 0o600); err != nil { t.Fatal(err) } unsafeSQL := filepath.Join(root, "linked.sql") if err := os.Symlink(realSQL, unsafeSQL); err != nil { t.Fatal(err) } marker := filepath.Join(root, "invoked") fake := filepath.Join(root, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ntouch '"+marker+"'\n"), 0o700); err != nil { t.Fatal(err) } command := SuggestFksRequest{WorkspaceID: "psd", FromSQL: []string{unsafeSQL}} if _, err := Run(context.Background(), config.Installation{ProjectDirectory: root}, compose.NewRunner(fake), command, nil); err == nil { t.Fatal("accepted unsafe SQL input") } if _, err := os.Stat(marker); !os.IsNotExist(err) { t.Fatalf("Compose was invoked for unsafe input: stat err=%v", err) } } func TestMakeInputRejectsOversizedOrInvalidAnnotation(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } path := filepath.Join(root, "annotations.md") if err := os.WriteFile(path, bytes.Repeat([]byte("a"), maxAnnotations+1), 0o600); err != nil { t.Fatal(err) } command := CheckSchemaRequest{WorkspaceID: "psd", Resume: strings.Repeat("0", 32), Annotations: path, ReviewedCandidates: DigestBytes([]byte("reviewed"))} if _, _, err := makeInput(command); err == nil { t.Fatal("accepted annotation over 16 MiB") } if err := os.WriteFile(path, []byte{0xff}, 0o600); err != nil { t.Fatal(err) } if _, _, err := makeInput(command); err == nil { t.Fatal("accepted non-UTF-8 annotation") } } func TestRunRejectsTrailingOrUnknownResultEnvelope(t *testing.T) { for name, suffix := range map[string]string{ "trailing": "} {}", "unknown": `,"unknown":1`, } { t.Run(name, func(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } response := `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"` + strings.Repeat("0", 40) + `","descriptorBlob":"` + strings.Repeat("a", 40) + `","operation":"evidence","completedStages":[]` + suffix if name == "unknown" { response += "}" } fake := filepath.Join(root, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ncat >/dev/null\nprintf '%s' '"+response+"'\n"), 0o700); err != nil { t.Fatal(err) } if _, err := Run(context.Background(), config.Installation{ProjectDirectory: root}, compose.NewRunner(fake), EvidenceRequest{WorkspaceID: "psd"}, nil); err == nil { t.Fatal("accepted malformed result envelope") } }) } } func TestRunProjectsBeforePublishingCandidate(t *testing.T) { root, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } candidate := []byte("candidates: []\n") digest := DigestBytes(candidate) result := validWorkspaceResult("succeeded", "ok") result.Operation = "suggest-fks" result.RunID = strings.Repeat("b", 32) result.ArtifactIdentities = []ArtifactIdentity{{Kind: "fk-candidates", Digest: digest}} envelope := map[string]any{"schemaVersion": result.SchemaVersion, "status": result.Status, "code": result.Code, "workspaceId": result.WorkspaceID, "workspaceRevision": result.WorkspaceRevision, "descriptorBlob": result.DescriptorBlob, "operation": result.Operation, "runId": result.RunID, "completedStages": []string{"safe\nforged"}, "artifactIdentities": result.ArtifactIdentities, "hostExport": hostExport{MediaType: "application/yaml", SHA256: digest, ContentBase64: base64.StdEncoding.EncodeToString(candidate)}} payload, err := json.Marshal(envelope) if err != nil { t.Fatal(err) } fake := filepath.Join(root, "docker") if err := os.WriteFile(fake, []byte("#!/bin/sh\ncat >/dev/null\nprintf '%s' '"+string(payload)+"'\n"), 0o700); err != nil { t.Fatal(err) } output := filepath.Join(root, "candidate.yaml") _, err = RunWithProjector(context.Background(), config.Installation{ProjectDirectory: root}, compose.NewRunner(fake), SuggestFksRequest{WorkspaceID: "psd", Output: output}, nil, func(result Result) (Result, error) { return Result{}, errors.New("unsafe projected result") }) if err == nil { t.Fatal("accepted a rejected public projection") } if _, statErr := os.Stat(output); !os.IsNotExist(statErr) { t.Fatalf("candidate was published before projection rejection: %v", statErr) } }