package taskrun import ( "encoding/json" "testing" ) func TestRunManifest_FreezeStableSHA(t *testing.T) { a := &RunManifest{ RunID: "run_a", WorkspaceID: "ws1", StorageIdentity: "env:dev", Members: []ManifestMember{ {LogicalID: "doc_b", Digest: "bbb", Kind: MemberKindDocument}, {LogicalID: "doc_a", Digest: "aaa", Kind: MemberKindDocument}, }, Extensions: map[string]json.RawMessage{ "fav/policy": json.RawMessage(`{"v":1}`), "ext/other": json.RawMessage(`{"k":"v"}`), }, } b := &RunManifest{ RunID: "run_a", WorkspaceID: "ws1", StorageIdentity: "env:dev", Members: []ManifestMember{ {LogicalID: "doc_a", Digest: "AAA", Kind: MemberKindDocument}, {LogicalID: "doc_b", Digest: "bbb", Kind: MemberKindDocument}, }, Extensions: map[string]json.RawMessage{ "ext/other": json.RawMessage(`{"k":"v"}`), "fav/policy": json.RawMessage(`{"v":1}`), }, } if err := a.Freeze(); err != nil { t.Fatal(err) } if err := b.Freeze(); err != nil { t.Fatal(err) } if a.SHA256 != b.SHA256 { t.Fatalf("canonical sha diverged: %s vs %s\n%s\n%s", a.SHA256, b.SHA256, a.CanonicalBytes, b.CanonicalBytes) } if len(a.CanonicalBytes) == 0 || a.Members[0].LogicalID != "doc_a" { t.Fatalf("members not sorted: %+v", a.Members) } } func TestRunManifest_RejectsIncompleteMember(t *testing.T) { m := &RunManifest{RunID: "run_x", Members: []ManifestMember{{LogicalID: "x", Kind: MemberKindDocument}}} if err := m.Freeze(); err == nil { t.Fatal("expected incomplete member error") } } func TestResolveBackend_StripsUnauthorized(t *testing.T) { if _, err := ResolveBackend("evil-shell", "stub"); err == nil { t.Fatal("expected unauthorized") } got, err := ResolveBackend("", "pi-agent") if err != nil || got != "pi-agent" { t.Fatalf("got %q %v", got, err) } if _, err := ResolveBackend("cursor", "pi-agent"); err == nil { t.Fatal("cursor backend must stay unauthorized") } got, err = ResolveBackend("pi-native", "pi-agent") if err != nil || got != "pi-native" { t.Fatalf("pi-native %q %v", got, err) } } func TestResolveBackendInEnv_RejectsStubInMain(t *testing.T) { if _, err := ResolveBackendInEnv("stub", "pi-agent", "main"); err == nil { t.Fatal("expected stub rejected in main") } if _, err := ResolveBackendInEnv("", "stub", "main"); err == nil { t.Fatal("expected stub config rejected in main") } if _, err := ResolveBackendInEnv("", "", "main"); err == nil { t.Fatal("expected empty fallback rejected in main") } got, err := ResolveBackendInEnv("stub", "pi-agent", "dev") if err != nil || got != "stub" { t.Fatalf("dev should allow stub, got %q %v", got, err) } got, err = ResolveBackendInEnv("", "pi-agent", "main") if err != nil || got != "pi-agent" { t.Fatalf("main should allow pi-agent, got %q %v", got, err) } } func TestStripSecretsAndSensitive(t *testing.T) { meta := StripSecrets(map[string]any{"api_key": "secret", "run_id": "r1", "authorization": "Bearer x"}) if _, ok := meta["api_key"]; ok { t.Fatal("api_key leaked") } if meta["run_id"] != "r1" { t.Fatalf("run_id stripped: %#v", meta) } if err := rejectSensitiveText("hello api_key=abcd"); err == nil { t.Fatal("expected sensitive reject") } }