From 4b1db4b3bdc0826565b03187be3070073383139a Mon Sep 17 00:00:00 2001 From: gambtho Date: Wed, 21 Oct 2026 16:47:58 -0400 Subject: [PATCH] chore: migrate to focused AgentSuite v0.7.0 imports --- cmd/canvas-harness/inventory.go | 14 ++--- cmd/canvas/runtime_mode.go | 4 +- docs/generic-canvas.md | 2 +- examples/northwind-released/README.md | 9 +-- go.mod | 2 +- go.sum | 4 +- internal/canvas/announcement_http.go | 4 +- internal/canvas/changes.go | 4 +- internal/canvas/definition.go | 8 +-- internal/canvas/flow_definition.go | 4 +- internal/canvas/flow_http.go | 4 +- internal/contract/evaluation.go | 37 ++++++------ internal/contract/released_selection_test.go | 56 +++++++++---------- internal/contract/released_suite.go | 43 +++++++------- .../contract/released_suite_security_test.go | 6 +- internal/contract/released_transport.go | 31 +++++----- internal/contract/suite.go | 43 +++++++------- internal/contract/suite_limits_test.go | 33 +++++------ 18 files changed, 157 insertions(+), 151 deletions(-) diff --git a/cmd/canvas-harness/inventory.go b/cmd/canvas-harness/inventory.go index eb048b2..6e891c0 100644 --- a/cmd/canvas-harness/inventory.go +++ b/cmd/canvas-harness/inventory.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) type inventory struct { @@ -25,7 +25,7 @@ func decodeInventory(data []byte) (inventory, error) { Version int `json:"version"` Entries []json.RawMessage `json:"entries"` } - if err := agentsuite.Unmarshal(data, &wire); err != nil { + if err := core.Unmarshal(data, &wire); err != nil { return inventory{}, fmt.Errorf("invalid inventory: %w", err) } if (wire.Version != 1 && wire.Version != 2) || len(wire.Entries) == 0 || len(wire.Entries) > 32 { @@ -40,24 +40,24 @@ func decodeInventory(data []byte) (inventory, error) { Bundle string `json:"bundle"` Address string `json:"address"` } - err = agentsuite.Unmarshal(raw, &legacy) + err = core.Unmarshal(raw, &legacy) e.Bundle, e.Address = legacy.Bundle, legacy.Address } else { var fields map[string]json.RawMessage - err = agentsuite.Unmarshal(raw, &fields) + err = core.Unmarshal(raw, &fields) if err == nil { - err = agentsuite.Unmarshal(fields["kind"], &e.Kind) + err = core.Unmarshal(fields["kind"], &e.Kind) } if err == nil { switch e.Kind { case "bundle": - err = agentsuite.Unmarshal(raw, &e) + err = core.Unmarshal(raw, &e) case "simulated-announcement": var fixed struct { Kind string `json:"kind"` Address string `json:"address"` } - err = agentsuite.Unmarshal(raw, &fixed) + err = core.Unmarshal(raw, &fixed) e.Address = fixed.Address default: err = errors.New("unknown entry kind") diff --git a/cmd/canvas/runtime_mode.go b/cmd/canvas/runtime_mode.go index 7d74464..07e435a 100644 --- a/cmd/canvas/runtime_mode.go +++ b/cmd/canvas/runtime_mode.go @@ -9,7 +9,7 @@ import ( "os" "syscall" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) var errRuntimeMode = errors.New("runtime mode binding is invalid or incompatible; use separate state without changing existing history") @@ -90,7 +90,7 @@ func readRuntimeMode(root *os.Root) (string, bool, error) { } raw, err := io.ReadAll(io.LimitReader(file, 513)) var record runtimeModeRecord - if err != nil || len(raw) > 512 || agentsuite.Unmarshal(raw, &record) != nil || record.SchemaVersion != "canvas.runtime-mode/v1" || record.Mode != "fixture" && record.Mode != "real" { + if err != nil || len(raw) > 512 || core.Unmarshal(raw, &record) != nil || record.SchemaVersion != "canvas.runtime-mode/v1" || record.Mode != "fixture" && record.Mode != "real" { return "", false, errRuntimeMode } return record.Mode, true, nil diff --git a/docs/generic-canvas.md b/docs/generic-canvas.md index 5cb0cb5..2967abe 100644 --- a/docs/generic-canvas.md +++ b/docs/generic-canvas.md @@ -151,7 +151,7 @@ intents only. ## Identity and evaluation boundaries -`github.com/agent-primitives/suite v0.4.0` validates the captured directory and +`github.com/agent-primitives/suite v0.7.0` validates the captured directory and matching local OCI layout. Both views must have equal full-inventory content identity; the layout must match the configured artifact pin. Canvas delegates graph validation and evaluation verification to the shared library. It bounds transport and decompression before validation and does not parse kmx private receipts. diff --git a/examples/northwind-released/README.md b/examples/northwind-released/README.md index daee769..ddfc1dc 100644 --- a/examples/northwind-released/README.md +++ b/examples/northwind-released/README.md @@ -39,7 +39,7 @@ isolation/rollback limitations, and mock disclosure. These are transport/proof/ export consistency fixtures, not model-quality or complete Northwind evaluations. The successful label is **evaluation consistent; unsigned**. It means that -`agentsuite.VerifyEvaluation` matched the retained layout, independently reviewed +`evidence.VerifyEvaluation` matched the retained layout, independently reviewed expectations, case/run coverage and passing claims. It does not establish who made those claims, whether observations were real, clock authenticity, freshness, Canvas runtime equivalence or deployment readiness. Replay is a different check. @@ -57,9 +57,10 @@ Both select `linux/amd64`, the unprofiled/native composition, and its Orka runtime or this Canvas harness**. No associated images ran. The newly authored model is `northwind-mock`; the original Northwind model was not overridden. -The library module is `github.com/agent-primitives/suite v0.4.0`; the authored -schema version remains `1.0.0-draft`. Neither version is an artifact, graph, -member, composition, build-profile, evidence or execution-archive digest. +Canvas verifies these retained fixtures with +`github.com/agent-primitives/suite v0.7.0`; the authored schema version remains +`1.0.0-draft`. Neither version is an artifact, graph, member, composition, +build-profile, evidence or execution-archive digest. Producer details: diff --git a/go.mod b/go.mod index fca444d..5feb4d3 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.27.3 require ( github.com/agent-primitives/sessions v0.2.1-0.20261019224537-f18a2cb1454d github.com/agent-primitives/sessions/integrations/substrate v0.0.0-20261019224537-f18a2cb1454d - github.com/agent-primitives/suite v0.6.0 + github.com/agent-primitives/suite v0.7.0 github.com/agent-substrate/substrate v0.4.1-0.20261013053953-96dffb287919 github.com/coreos/go-oidc/v3 v3.17.0 github.com/google/jsonschema-go v0.4.3 diff --git a/go.sum b/go.sum index f5ddd2d..86b76a4 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/agent-primitives/sessions v0.2.1-0.20261019224537-f18a2cb1454d h1:5R4 github.com/agent-primitives/sessions v0.2.1-0.20261019224537-f18a2cb1454d/go.mod h1:DZCwTLhJb6bltufqRqKK7IOEsx+s6isnMK7PMiaR7Ts= github.com/agent-primitives/sessions/integrations/substrate v0.0.0-20261019224537-f18a2cb1454d h1:jf7ic/0UjUu8Q+G9poQqeUUdLze/pW6ptT7zfQIxmd8= github.com/agent-primitives/sessions/integrations/substrate v0.0.0-20261019224537-f18a2cb1454d/go.mod h1:4RZd3LCiXwGVYAvPDvRS3F/zjgh5SbHWHIeHkrMPqkc= -github.com/agent-primitives/suite v0.6.0 h1:bRGzbZTq+6ApAPiMS3pmbJCLG0RLA+dqGOhWMinQq9M= -github.com/agent-primitives/suite v0.6.0/go.mod h1:61Z9uzfg7z/DdWSzHxY3kcDq1SAKcEXEOX6qNmD6MC0= +github.com/agent-primitives/suite v0.7.0 h1:4Ks7PXdsSo5BWfAgmb6PErl/Pcqbo9yswAr0lzdcnBo= +github.com/agent-primitives/suite v0.7.0/go.mod h1:61Z9uzfg7z/DdWSzHxY3kcDq1SAKcEXEOX6qNmD6MC0= github.com/agent-substrate/substrate v0.4.1-0.20261013053953-96dffb287919 h1:RP19jHZ/bv7AcknDgut2SW9btWbYnpOeT41M5bjOVAY= github.com/agent-substrate/substrate v0.4.1-0.20261013053953-96dffb287919/go.mod h1:XVQwhYEmOlb+ILs9BvSCHXYhgo2F6/N2qN4DmRwogQI= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= diff --git a/internal/canvas/announcement_http.go b/internal/canvas/announcement_http.go index f68769e..7e3f5ce 100644 --- a/internal/canvas/announcement_http.go +++ b/internal/canvas/announcement_http.go @@ -8,7 +8,7 @@ import ( "net/http" "github.com/agent-primitives/canvas/internal/sessionclient" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) type announcementRequest struct { @@ -35,7 +35,7 @@ func (c *Canvas) announcementRoutes(mux *http.ServeMux, send func(http.ResponseW mux.HandleFunc("POST /api/announcement/", func(w http.ResponseWriter, r *http.Request) { raw, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 16<<10)) var object map[string]json.RawMessage - if err != nil || agentsuite.Unmarshal(raw, &object) != nil || object == nil { + if err != nil || core.Unmarshal(raw, &object) != nil || object == nil { send(w, 400, map[string]string{"error": "Invalid local announcement action."}) return } diff --git a/internal/canvas/changes.go b/internal/canvas/changes.go index 1dc83e5..227bd31 100644 --- a/internal/canvas/changes.go +++ b/internal/canvas/changes.go @@ -4,7 +4,7 @@ import ( "errors" "unicode/utf8" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) const maxProposalChanges = 32 @@ -60,7 +60,7 @@ func (d *CompiledDefinition) Changes(agent, output string) (map[string]string, e Content *string `json:"content"` } `json:"changes"` } - if agentsuite.Unmarshal([]byte(output), &envelope) != nil || len(envelope.Changes) == 0 || len(envelope.Changes) > maxProposalChanges { + if core.Unmarshal([]byte(output), &envelope) != nil || len(envelope.Changes) == 0 || len(envelope.Changes) > maxProposalChanges { return nil, errors.New("invalid bounded change envelope") } result := map[string]string{} diff --git a/internal/canvas/definition.go b/internal/canvas/definition.go index 7722944..2e477ea 100644 --- a/internal/canvas/definition.go +++ b/internal/canvas/definition.go @@ -18,7 +18,7 @@ import ( "github.com/agent-primitives/canvas/internal/contract" "github.com/agent-primitives/canvas/internal/sharedspace" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" "github.com/google/jsonschema-go/jsonschema" "go.yaml.in/yaml/v3" ) @@ -433,7 +433,7 @@ func loadGenericDefinition(filename string, resolver *contract.ReleaseResolver, loadFlowSchema := func(source string) (*jsonschema.Resolved, error) { resolved, err := loadSchema(source) var value any - if err != nil || agentsuite.Unmarshal(schemas[source], &value) != nil || !preservesJSONNumbers(value) { + if err != nil || core.Unmarshal(schemas[source], &value) != nil || !preservesJSONNumbers(value) { return nil, errDefinition } return resolved, nil @@ -464,7 +464,7 @@ func loadGenericDefinition(filename string, resolver *contract.ReleaseResolver, } func compileDocumentSchema(raw []byte) (*jsonschema.Resolved, error) { var value any - if agentsuite.Unmarshal(raw, &value) != nil || !localSchemaRefs(value) { + if core.Unmarshal(raw, &value) != nil || !localSchemaRefs(value) { return nil, errDefinition } var schema jsonschema.Schema @@ -506,7 +506,7 @@ func validateDocument(doc compiledDocument, content string) error { // Public strict decoding uses json.Number, which jsonschema-go v0.4.3 // classifies as a string. After strict/lossless validation, decode into // standard JSON values so numeric types reach schema validation intact. - if agentsuite.Unmarshal([]byte(content), &instance) != nil || json.Unmarshal([]byte(content), &instance) != nil || doc.schema.Validate(instance) != nil { + if core.Unmarshal([]byte(content), &instance) != nil || json.Unmarshal([]byte(content), &instance) != nil || doc.schema.Validate(instance) != nil { return errors.New("document does not satisfy schema") } } diff --git a/internal/canvas/flow_definition.go b/internal/canvas/flow_definition.go index 81b8407..8a4e2b6 100644 --- a/internal/canvas/flow_definition.go +++ b/internal/canvas/flow_definition.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" "github.com/google/jsonschema-go/jsonschema" "go.yaml.in/yaml/v3" ) @@ -85,7 +85,7 @@ func (d *CompiledDefinition) ValidateFlowInputs(id string, raw []byte) error { } var value any // Preserve strict JSON checks, then give schema validation native numbers. - if agentsuite.Unmarshal(raw, &value) != nil || !preservesJSONNumbers(value) || json.Unmarshal(raw, &value) != nil { + if core.Unmarshal(raw, &value) != nil || !preservesJSONNumbers(value) || json.Unmarshal(raw, &value) != nil { return errDefinition } if _, ok := value.(map[string]any); !ok || flow.inputs.Validate(value) != nil { diff --git a/internal/canvas/flow_http.go b/internal/canvas/flow_http.go index d4fd125..132a74d 100644 --- a/internal/canvas/flow_http.go +++ b/internal/canvas/flow_http.go @@ -10,7 +10,7 @@ import ( "slices" "github.com/agent-primitives/canvas/internal/sharedspace" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) // Polling omits exact historical inputs and private command/reservation journals. @@ -192,7 +192,7 @@ func (c *Canvas) registerFlowRoutes(mux *http.ServeMux) { func decodeFlowAction(w http.ResponseWriter, r *http.Request, limit int64, q any) bool { raw, err := io.ReadAll(http.MaxBytesReader(w, r.Body, limit)) var object map[string]json.RawMessage - if err != nil || agentsuite.Unmarshal(raw, &object) != nil || object == nil { + if err != nil || core.Unmarshal(raw, &object) != nil || object == nil { sendJSON(w, 400, map[string]string{"error": "A bounded JSON flow request is required.", "code": "FLOW_INVALID"}) return false } diff --git a/internal/contract/evaluation.go b/internal/contract/evaluation.go index 7c511f6..a4a005b 100644 --- a/internal/contract/evaluation.go +++ b/internal/contract/evaluation.go @@ -10,23 +10,24 @@ import ( "os" "strings" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" + "github.com/agent-primitives/suite/evidence" ) // EvaluationInfo is a checked release claim, never proof of the current Canvas run. type EvaluationInfo struct { - Status string `json:"status"` - Reason string `json:"reason,omitempty"` - EvidenceDigest string `json:"evidenceDigest,omitempty"` - ExpectedDigest string `json:"expectedDigest,omitempty"` - Cases int `json:"cases,omitempty"` - Runs int `json:"runs,omitempty"` - CompletedAt string `json:"completedAt,omitempty"` - Unsigned bool `json:"unsigned"` - TestedExecution *agentsuite.EvidenceExecution `json:"testedExecution,omitempty"` + Status string `json:"status"` + Reason string `json:"reason,omitempty"` + EvidenceDigest string `json:"evidenceDigest,omitempty"` + ExpectedDigest string `json:"expectedDigest,omitempty"` + Cases int `json:"cases,omitempty"` + Runs int `json:"runs,omitempty"` + CompletedAt string `json:"completedAt,omitempty"` + Unsigned bool `json:"unsigned"` + TestedExecution *evidence.EvidenceExecution `json:"testedExecution,omitempty"` } -func verifyReleaseEvaluation(layout string, a releasedArchive, manifest releaseDescriptor, identity *SuiteIdentity, agent agentsuite.Agent) EvaluationInfo { +func verifyReleaseEvaluation(layout string, a releasedArchive, manifest releaseDescriptor, identity *SuiteIdentity, agent core.Agent) EvaluationInfo { result := EvaluationInfo{Status: "not verified", Reason: "missing"} digest := func(data []byte) string { sum := sha256.Sum256(data); return fmt.Sprintf("sha256:%x", sum) } if len(a.Expected) > 0 { @@ -42,13 +43,13 @@ func verifyReleaseEvaluation(layout string, a releasedArchive, manifest releaseD if len(a.Expected) == 0 || len(a.Evidence) == 0 { return result } - var expected agentsuite.ExpectedEvaluation - if !validExpectedShape(a.Expected) || agentsuite.Unmarshal(a.Expected, &expected) != nil || expected.Judges == nil { + var expected evidence.ExpectedEvaluation + if !validExpectedShape(a.Expected) || core.Unmarshal(a.Expected, &expected) != nil || expected.Judges == nil { result.Reason = "malformed" return result } parts := strings.Split(a.Platform, "/") - platform := agentsuite.EvidencePlatform{} + platform := evidence.EvidencePlatform{} if len(parts) >= 2 { platform.OS = parts[0] platform.Architecture = parts[1] @@ -56,14 +57,14 @@ func verifyReleaseEvaluation(layout string, a releasedArchive, manifest releaseD if len(parts) == 3 { platform.Variant = parts[2] } - selected := agentsuite.EvidenceSubject{Manifest: agentsuite.EvidenceDescriptor{MediaType: manifest.MediaType, Digest: a.Pin, Size: manifest.Size}, MemberID: a.Member, MemberDigest: identity.MemberDigest, CompositionDigest: identity.Release.CompositionDigest, BuildProfileDigest: identity.Release.BuildProfileDigest, Platform: platform} + selected := evidence.EvidenceSubject{Manifest: evidence.EvidenceDescriptor{MediaType: manifest.MediaType, Digest: a.Pin, Size: manifest.Size}, MemberID: a.Member, MemberDigest: identity.MemberDigest, CompositionDigest: identity.Release.CompositionDigest, BuildProfileDigest: identity.Release.BuildProfileDigest, Platform: platform} if expected.Subject != selected || expected.Execution.Model.ID != agent.Model.Model || expected.Execution.Model.Protocol != agent.Model.Protocol { result.Reason = "subject" return result } - verified, err := agentsuite.VerifyEvaluation(layout, expected, bytes.NewReader(a.Evidence)) + verified, err := evidence.VerifyEvaluation(layout, expected, bytes.NewReader(a.Evidence)) if err != nil { - var refused *agentsuite.EvidenceRefusal + var refused *evidence.EvidenceRefusal if errors.As(err, &refused) { result.Reason = refused.Code } else { @@ -135,7 +136,7 @@ func readEvaluationFile(filename string) ([]byte, error) { // Strictly decode an independent expectation's outer shape, including explicit judges[]. func validExpectedShape(data []byte) bool { var fields map[string]json.RawMessage - if agentsuite.Unmarshal(data, &fields) != nil || len(fields) != 4 { + if core.Unmarshal(data, &fields) != nil || len(fields) != 4 { return false } for _, name := range []string{"subject", "execution", "evaluator", "judges"} { diff --git a/internal/contract/released_selection_test.go b/internal/contract/released_selection_test.go index 91903e1..86e13c6 100644 --- a/internal/contract/released_selection_test.go +++ b/internal/contract/released_selection_test.go @@ -12,10 +12,10 @@ import ( "strings" "testing" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) -func repackedRelease(t *testing.T, mutate func(map[string]retainedFile, *agentsuite.Suite)) SuiteRef { +func repackedRelease(t *testing.T, mutate func(map[string]retainedFile, *core.Suite)) SuiteRef { t.Helper() ref := releasedNorthwind(t) files, err := capture(ref.Layout) @@ -26,12 +26,12 @@ func repackedRelease(t *testing.T, mutate func(map[string]retainedFile, *agentsu if err != nil { t.Fatal(err) } - var suite agentsuite.Suite - if agentsuite.Unmarshal(content["agentsuite.json"].Data, &suite) != nil { + var suite core.Suite + if core.Unmarshal(content["agentsuite.json"].Data, &suite) != nil { t.Fatal("suite") } mutate(content, &suite) - raw, err := agentsuite.Marshal(suite) + raw, err := core.Marshal(suite) if err != nil { t.Fatal(err) } @@ -62,8 +62,8 @@ func repackedRelease(t *testing.T, mutate func(map[string]retainedFile, *agentsu } config := []byte(`{}`) layer := buffer.Bytes() - cfgDesc, layerDesc := descriptor(config, agentsuite.MediaTypeEmptyConfig), descriptor(layer, agentsuite.MediaTypeContent) - manifest, _ := json.Marshal(releaseManifest{SchemaVersion: 2, MediaType: releaseManifestType, ArtifactType: agentsuite.MediaTypeArtifact, Config: cfgDesc, Layers: []releaseDescriptor{layerDesc}}) + cfgDesc, layerDesc := descriptor(config, core.MediaTypeEmptyConfig), descriptor(layer, core.MediaTypeContent) + manifest, _ := json.Marshal(releaseManifest{SchemaVersion: 2, MediaType: releaseManifestType, ArtifactType: core.MediaTypeArtifact, Config: cfgDesc, Layers: []releaseDescriptor{layerDesc}}) manifestDesc := descriptor(manifest, releaseManifestType) index, _ := json.Marshal(releaseIndex{SchemaVersion: 2, Manifests: []releaseDescriptor{manifestDesc}}) artifact := map[string]retainedFile{"oci-layout": {Data: []byte(`{"imageLayoutVersion":"1.0.0"}`), Mode: 0600}, "index.json": {Data: index, Mode: 0600}} @@ -78,7 +78,7 @@ func repackedRelease(t *testing.T, mutate func(map[string]retainedFile, *agentsu } func TestReleasedMultiMemberSelectionAndAmbiguityRefusal(t *testing.T) { - ref := repackedRelease(t, func(content map[string]retainedFile, suite *agentsuite.Suite) { + ref := repackedRelease(t, func(content map[string]retainedFile, suite *core.Suite) { other := northwindRef(t, "reviewer") files, err := capture(other.Artifact) if err != nil { @@ -88,8 +88,8 @@ func TestReleasedMultiMemberSelectionAndAmbiguityRefusal(t *testing.T) { if err != nil { t.Fatal(err) } - var rs agentsuite.Suite - agentsuite.Unmarshal(reviewer["agentsuite.json"].Data, &rs) + var rs core.Suite + core.Unmarshal(reviewer["agentsuite.json"].Data, &rs) for name, file := range reviewer { if name != "agentsuite.json" { content[name] = file @@ -107,7 +107,7 @@ func TestReleasedMultiMemberSelectionAndAmbiguityRefusal(t *testing.T) { if b.Suite.Member != "reviewer" || b.Suite.Release.Platform != "linux/arm64" || len(b.Suite.Compositions) != 1 { t.Fatal("selected wrong member or platform") } - ambiguous := repackedRelease(t, func(_ map[string]retainedFile, suite *agentsuite.Suite) { + ambiguous := repackedRelease(t, func(_ map[string]retainedFile, suite *core.Suite) { suite.Compositions = append(suite.Compositions, suite.Compositions[0]) }) if _, err := LoadReleasedSuite("alias", ambiguous, nil); err == nil { @@ -116,22 +116,22 @@ func TestReleasedMultiMemberSelectionAndAmbiguityRefusal(t *testing.T) { } func TestReleasedForeignProfileRefusesWithExportUnavailable(t *testing.T) { - ref := repackedRelease(t, func(content map[string]retainedFile, suite *agentsuite.Suite) { - implementation := agentsuite.EvidenceImplementation{ID: "foreign-runtime", Version: "1.0.0", Digest: "sha256:" + strings.Repeat("a", 64)} - profile := agentsuite.RuntimeProfile{SchemaVersion: agentsuite.SpecVersion, MediaType: agentsuite.MediaTypeRuntimeProfile, ID: "foreign", Runtime: implementation, Harness: implementation, Renderer: implementation, ConfigurationABI: "foreign-abi", ImageRequired: true} - raw, _ := agentsuite.Marshal(profile) - digest, _ := agentsuite.Digest(raw) + ref := repackedRelease(t, func(content map[string]retainedFile, suite *core.Suite) { + implementation := core.EvidenceImplementation{ID: "foreign-runtime", Version: "1.0.0", Digest: "sha256:" + strings.Repeat("a", 64)} + profile := core.RuntimeProfile{SchemaVersion: core.SpecVersion, MediaType: core.MediaTypeRuntimeProfile, ID: "foreign", Runtime: implementation, Harness: implementation, Renderer: implementation, ConfigurationABI: "foreign-abi", ImageRequired: true} + raw, _ := core.Marshal(profile) + digest, _ := core.Digest(raw) name := "runtime-profiles/foreign.json" content[name] = retainedFile{Data: raw, Mode: 0644} - suite.RuntimeProfiles = []agentsuite.ManifestRef{{ID: "foreign", Path: name, Descriptor: agentsuite.Descriptor{MediaType: agentsuite.MediaTypeRuntimeProfile, Digest: digest, Size: int64(len(raw))}}} + suite.RuntimeProfiles = []core.ManifestRef{{ID: "foreign", Path: name, Descriptor: core.Descriptor{MediaType: core.MediaTypeRuntimeProfile, Digest: digest, Size: int64(len(raw))}}} suite.Compositions = suite.Compositions[:1] r := &suite.Compositions[0] - var c agentsuite.Composition - agentsuite.Unmarshal(content[r.Path].Data, &c) + var c core.Composition + core.Unmarshal(content[r.Path].Data, &c) c.RuntimeProfile = "foreign" r.RuntimeProfile = "foreign" - raw, _ = agentsuite.Marshal(c) - digest, _ = agentsuite.Digest(raw) + raw, _ = core.Marshal(c) + digest, _ = core.Digest(raw) content[r.Path] = retainedFile{Data: raw, Mode: 0644} r.Descriptor.Digest = digest r.Descriptor.Size = int64(len(raw)) @@ -146,22 +146,22 @@ func TestReleasedForeignProfileRefusesWithExportUnavailable(t *testing.T) { func TestReleasedSelectedSecretAndMissingImageRefused(t *testing.T) { for _, kind := range []string{"secret", "image"} { t.Run(kind, func(t *testing.T) { - ref := repackedRelease(t, func(content map[string]retainedFile, suite *agentsuite.Suite) { + ref := repackedRelease(t, func(content map[string]retainedFile, suite *core.Suite) { if kind == "secret" { - var agent agentsuite.Agent - agentsuite.Unmarshal(content[suite.Agents[0].Path].Data, &agent) + var agent core.Agent + core.Unmarshal(content[suite.Agents[0].Path].Data, &agent) agent.Model.SecretRefs = []string{"unsupported-secret"} - raw, _ := agentsuite.Marshal(agent) + raw, _ := core.Marshal(agent) content[suite.Agents[0].Path] = retainedFile{Data: raw, Mode: 0644} sum := sha256.Sum256(raw) suite.Agents[0].Descriptor.Digest = fmt.Sprintf("sha256:%x", sum) suite.Agents[0].Descriptor.Size = int64(len(raw)) } else { - var build agentsuite.BuildProfile + var build core.BuildProfile ref := &suite.BuildProfiles[0] - agentsuite.Unmarshal(content[ref.Path].Data, &build) + core.Unmarshal(content[ref.Path].Data, &build) build.Harness = build.Harness[1:] - raw, _ := agentsuite.Marshal(build) + raw, _ := core.Marshal(build) content[ref.Path] = retainedFile{Data: raw, Mode: 0644} sum := sha256.Sum256(raw) ref.Descriptor.Digest = fmt.Sprintf("sha256:%x", sum) diff --git a/internal/contract/released_suite.go b/internal/contract/released_suite.go index c574c95..e8d43d0 100644 --- a/internal/contract/released_suite.go +++ b/internal/contract/released_suite.go @@ -15,7 +15,8 @@ import ( "strings" "unicode/utf8" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" + "github.com/agent-primitives/suite/oci" ) var ErrReleaseProfile = errors.New("unsupported released runtime profile; evaluation not verified (export unavailable for this profile)") @@ -102,7 +103,7 @@ func parseReleasedArchive(data []byte) (Bundle, error) { } func releasedBundle(a releasedArchive) (Bundle, error) { - if a.Version != "canvas.local/release-execution-v1" || a.Kind != "ReleasedSuiteExecution" || !namePattern.MatchString(a.ID) || !agentsuite.IsValidDigest(a.Pin) || len(a.Expected) > 1<<20 || len(a.Evidence) > 1<<20 { + if a.Version != "canvas.local/release-execution-v1" || a.Kind != "ReleasedSuiteExecution" || !namePattern.MatchString(a.ID) || !core.IsValidDigest(a.Pin) || len(a.Expected) > 1<<20 || len(a.Evidence) > 1<<20 { return Bundle{}, errSuite } content, manifest, err := releaseContent(a.Artifact, a.Pin) @@ -118,20 +119,20 @@ func releasedBundle(a releasedArchive) (Bundle, error) { if copiedView(layout, a.Artifact) != nil || copiedView(directory, content) != nil { return Bundle{}, errSuite } - report, err := agentsuite.ValidatePath(layout) + report, err := oci.ValidatePath(layout) if err != nil { return Bundle{}, errSuite } - diff, err := agentsuite.DiffPaths(directory, layout) + diff, err := oci.DiffPaths(directory, layout) if err != nil || diff.After.ArtifactDigest != a.Pin || diff.Before.ContentDigest != diff.After.ContentDigest { return Bundle{}, errSuite } - var suite agentsuite.Suite + var suite core.Suite raw := content["agentsuite.json"].Data - if agentsuite.Unmarshal(raw, &suite) != nil || len(suite.Extensions) != 0 || len(suite.Capabilities) != 0 { + if core.Unmarshal(raw, &suite) != nil || len(suite.Extensions) != 0 || len(suite.Capabilities) != 0 { return Bundle{}, errSuite } - var selected agentsuite.CompositionSelection + var selected core.CompositionSelection count := 0 for _, s := range report.CompositionSelections { if s.Agent == a.Member && s.Platform.String() == a.Platform && s.RuntimeProfile == a.RuntimeProfile { @@ -146,7 +147,7 @@ func releasedBundle(a releasedArchive) (Bundle, error) { if selected.RuntimeProfile != "" { return Bundle{}, ErrReleaseProfile } - var member agentsuite.ManifestRef + var member core.ManifestRef count = 0 for _, m := range suite.Agents { if m.ID == a.Member { @@ -154,14 +155,14 @@ func releasedBundle(a releasedArchive) (Bundle, error) { count++ } } - var agent agentsuite.Agent - if count != 1 || agentsuite.Unmarshal(content[member.Path].Data, &agent) != nil || !modelOnlyAgent(agent) || agent.Policy != nil { + var agent core.Agent + if count != 1 || core.Unmarshal(content[member.Path].Data, &agent) != nil || !modelOnlyAgent(agent) || agent.Policy != nil { return Bundle{}, errSuite } - var composition agentsuite.Composition + var composition core.Composition for _, c := range suite.Compositions { if c.Descriptor.Digest == selected.Digest { - if agentsuite.Unmarshal(content[c.Path].Data, &composition) != nil { + if core.Unmarshal(content[c.Path].Data, &composition) != nil { return Bundle{}, errSuite } } @@ -169,12 +170,12 @@ func releasedBundle(a releasedArchive) (Bundle, error) { if composition.Agent != a.Member || composition.Platform.String() != a.Platform || len(composition.ToolProviders) != 0 { return Bundle{}, errSuite } - var build agentsuite.BuildProfile + var build core.BuildProfile var buildDigest string for _, r := range suite.BuildProfiles { if r.ID == selected.BuildProfile { buildDigest = r.Descriptor.Digest - if agentsuite.Unmarshal(content[r.Path].Data, &build) != nil { + if core.Unmarshal(content[r.Path].Data, &build) != nil { return Bundle{}, errSuite } } @@ -182,7 +183,7 @@ func releasedBundle(a releasedArchive) (Bundle, error) { if buildDigest == "" || build.Execution != nil { return Bundle{}, errSuite } - image := func(images []agentsuite.PlatformImage) (string, error) { + image := func(images []core.PlatformImage) (string, error) { found := "" for _, im := range images { if im.Platform == selected.Platform { @@ -209,11 +210,11 @@ func releasedBundle(a releasedArchive) (Bundle, error) { if len(instruction) == 0 || len(instruction) > 65536 || !utf8.Valid(instruction) { return Bundle{}, errSuite } - graph, err := agentsuite.Digest(raw) + graph, err := core.Digest(raw) if err != nil { return Bundle{}, errSuite } - identity := &SuiteIdentity{Digest: a.Pin, ContentDigest: diff.After.ContentDigest, GraphDigest: graph, Member: member.ID, MemberDigest: member.Descriptor.Digest, Compositions: []agentsuite.CompositionSelection{selected}, Release: &ReleaseIdentity{AuthoredModel: agent.Model.Model, SchemaVersion: suite.SchemaVersion, Platform: a.Platform, RuntimeProfile: a.RuntimeProfile, CompositionDigest: selected.Digest, BuildProfile: selected.BuildProfile, BuildProfileDigest: buildDigest, RuntimeImage: runtimeImage, HarnessImage: harnessImage, CanvasRuntime: "canvas-local/bundle-v4; execution not qualified by release evaluation"}} + identity := &SuiteIdentity{Digest: a.Pin, ContentDigest: diff.After.ContentDigest, GraphDigest: graph, Member: member.ID, MemberDigest: member.Descriptor.Digest, Compositions: []core.CompositionSelection{selected}, Release: &ReleaseIdentity{AuthoredModel: agent.Model.Model, SchemaVersion: suite.SchemaVersion, Platform: a.Platform, RuntimeProfile: a.RuntimeProfile, CompositionDigest: selected.Digest, BuildProfile: selected.BuildProfile, BuildProfileDigest: buildDigest, RuntimeImage: runtimeImage, HarnessImage: harnessImage, CanvasRuntime: "canvas-local/bundle-v4; execution not qualified by release evaluation"}} identity.Release.Evaluation = verifyReleaseEvaluation(layout, a, manifest, identity, agent) data, err := json.Marshal(a) if err != nil || len(data) > maxArchive { @@ -237,7 +238,7 @@ func releaseContent(files map[string]retainedFile, pin string) (map[string]retai } } var index releaseIndex - if agentsuite.Unmarshal(files["index.json"].Data, &index) != nil || index.SchemaVersion != 2 || len(index.Manifests) != 1 { + if core.Unmarshal(files["index.json"].Data, &index) != nil || index.SchemaVersion != 2 || len(index.Manifests) != 1 { return nil, zero, errSuite } desc := index.Manifests[0] @@ -249,12 +250,12 @@ func releaseContent(files map[string]retainedFile, pin string) (map[string]retai return nil, zero, errSuite } var manifest releaseManifest - if agentsuite.Unmarshal(raw, &manifest) != nil { + if core.Unmarshal(raw, &manifest) != nil { return nil, zero, errSuite } var layer []byte for _, d := range manifest.Layers { - if d.MediaType == agentsuite.MediaTypeContent { + if d.MediaType == core.MediaTypeContent { if layer != nil { return nil, zero, errSuite } @@ -311,7 +312,7 @@ func releaseContent(files map[string]retainedFile, pin string) (map[string]retai } func releaseBlob(files map[string]retainedFile, d releaseDescriptor) ([]byte, error) { - if !agentsuite.IsValidDigest(d.Digest) || d.Size < 0 || d.Size > 1<<20 || len(d.URLs) != 0 || len(d.Data) != 0 { + if !core.IsValidDigest(d.Digest) || d.Size < 0 || d.Size > 1<<20 || len(d.URLs) != 0 || len(d.Data) != 0 { return nil, errSuite } raw, ok := files["blobs/sha256/"+strings.TrimPrefix(d.Digest, "sha256:")] diff --git a/internal/contract/released_suite_security_test.go b/internal/contract/released_suite_security_test.go index 04d7ac9..79acb13 100644 --- a/internal/contract/released_suite_security_test.go +++ b/internal/contract/released_suite_security_test.go @@ -5,7 +5,7 @@ import ( "path/filepath" "testing" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" ) func TestReleasedArchiveRefusesPathEscapeBeforeExtraction(t *testing.T) { @@ -15,13 +15,13 @@ func TestReleasedArchiveRefusesPathEscapeBeforeExtraction(t *testing.T) { if err := os.WriteFile(witness, []byte("outside content"), 0600); err != nil { t.Fatal(err) } - control := repackedRelease(t, func(map[string]retainedFile, *agentsuite.Suite) {}) + control := repackedRelease(t, func(map[string]retainedFile, *core.Suite) {}) if _, err := LoadReleasedSuite("control", control, nil); err != nil { t.Fatal("valid repacked release refused", err) } for _, name := range []string{"../../escape", "dir/../../../escape", witness, `..\..\escape`, ".hidden", "dir/../escape"} { t.Run(name, func(t *testing.T) { - ref := repackedRelease(t, func(content map[string]retainedFile, _ *agentsuite.Suite) { + ref := repackedRelease(t, func(content map[string]retainedFile, _ *core.Suite) { content[name] = retainedFile{Data: []byte("attack"), Mode: 0644} }) // The helper recomputes layer/manifest digests, so a bad digest diff --git a/internal/contract/released_transport.go b/internal/contract/released_transport.go index d663353..8398469 100644 --- a/internal/contract/released_transport.go +++ b/internal/contract/released_transport.go @@ -17,20 +17,21 @@ import ( "syscall" "time" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" + "github.com/agent-primitives/suite/oci" ) const releaseManifestType = "application/vnd.oci.image.manifest.v1+json" type releaseDescriptor struct { - MediaType string `json:"mediaType"` - Digest string `json:"digest"` - Size int64 `json:"size"` - ArtifactType string `json:"artifactType,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` - Platform *agentsuite.Platform `json:"platform,omitempty"` - URLs json.RawMessage `json:"urls,omitempty"` - Data json.RawMessage `json:"data,omitempty"` + MediaType string `json:"mediaType"` + Digest string `json:"digest"` + Size int64 `json:"size"` + ArtifactType string `json:"artifactType,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` + Platform *core.Platform `json:"platform,omitempty"` + URLs json.RawMessage `json:"urls,omitempty"` + Data json.RawMessage `json:"data,omitempty"` } type releaseIndex struct { SchemaVersion int `json:"schemaVersion"` @@ -65,7 +66,7 @@ func releaseReference(ref string) (string, string, error) { if len(ref) > 1024 { return "", "", errSuite } - if agentsuite.IsValidDigest(ref) { + if core.IsValidDigest(ref) { return ref, "", nil } if strings.Count(ref, "@") != 1 { @@ -73,7 +74,7 @@ func releaseReference(ref string) (string, string, error) { } location, pin, _ := strings.Cut(ref, "@") host, repository, ok := strings.Cut(location, "/") - if !ok || host == "" || !agentsuite.IsValidDigest(pin) { + if !ok || host == "" || !core.IsValidDigest(pin) { return "", "", errSuite } u, err := url.Parse("https://" + host) @@ -248,7 +249,7 @@ func readReleaseCache(root *os.Root, key, pin string) (map[string]retainedFile, // the existing archive format's base64 byte fields, which suite's typed codec omits. func decodeReleaseJSON(data []byte, out any) error { var value any - if agentsuite.Unmarshal(data, &value) != nil { + if core.Unmarshal(data, &value) != nil { return errSuite } dec := json.NewDecoder(bytes.NewReader(data)) @@ -276,7 +277,7 @@ func validateReleaseLayout(files map[string]retainedFile, pin string) error { if copiedView(layout, files) != nil { return errSuite } - if _, err := agentsuite.ValidatePath(layout); err != nil { + if _, err := oci.ValidatePath(layout); err != nil { return errSuite } return nil @@ -332,14 +333,14 @@ func (r *ReleaseResolver) fetch(ref string) (map[string]retainedFile, error) { return nil, errSuite } var manifest releaseManifest - if agentsuite.Unmarshal(raw, &manifest) != nil || manifest.SchemaVersion != 2 || manifest.ArtifactType != agentsuite.MediaTypeArtifact || manifest.Subject != nil || len(manifest.Layers) > 32 { + if core.Unmarshal(raw, &manifest) != nil || manifest.SchemaVersion != 2 || manifest.ArtifactType != core.MediaTypeArtifact || manifest.Subject != nil || len(manifest.Layers) > 32 { return nil, errSuite } descriptor := releaseDescriptor{MediaType: releaseManifestType, Digest: pin, Size: int64(len(raw))} index, _ := json.Marshal(releaseIndex{SchemaVersion: 2, Manifests: []releaseDescriptor{descriptor}}) files := map[string]retainedFile{"oci-layout": {Data: []byte(`{"imageLayoutVersion":"1.0.0"}`), Mode: 0600}, "index.json": {Data: index, Mode: 0600}, "blobs/sha256/" + strings.TrimPrefix(pin, "sha256:"): {Data: raw, Mode: 0600}} for _, d := range append([]releaseDescriptor{manifest.Config}, manifest.Layers...) { - if !agentsuite.IsValidDigest(d.Digest) || d.Size < 0 || len(d.URLs) != 0 || len(d.Data) != 0 { + if !core.IsValidDigest(d.Digest) || d.Size < 0 || len(d.URLs) != 0 || len(d.Data) != 0 { return nil, errSuite } key := "blobs/sha256/" + strings.TrimPrefix(d.Digest, "sha256:") diff --git a/internal/contract/suite.go b/internal/contract/suite.go index c9c032f..349df29 100644 --- a/internal/contract/suite.go +++ b/internal/contract/suite.go @@ -16,7 +16,8 @@ import ( "strings" "unicode/utf8" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" + "github.com/agent-primitives/suite/oci" ) const maxArchive = 8 << 20 @@ -34,13 +35,13 @@ type SuiteRef struct { Member string `yaml:"member" json:"member"` } type SuiteIdentity struct { - Release *ReleaseIdentity `json:"release,omitempty"` - Digest string `json:"digest"` - ContentDigest string `json:"contentDigest"` - GraphDigest string `json:"graphDigest"` - Member string `json:"member"` - MemberDigest string `json:"memberDigest"` - Compositions []agentsuite.CompositionSelection `json:"compositions"` + Release *ReleaseIdentity `json:"release,omitempty"` + Digest string `json:"digest"` + ContentDigest string `json:"contentDigest"` + GraphDigest string `json:"graphDigest"` + Member string `json:"member"` + MemberDigest string `json:"memberDigest"` + Compositions []core.CompositionSelection `json:"compositions"` } // Clone keeps presentation and historical metadata from sharing mutable selections. @@ -57,7 +58,7 @@ func (s *SuiteIdentity) Clone() *SuiteIdentity { } copy.Release = &release } - copy.Compositions = append([]agentsuite.CompositionSelection(nil), s.Compositions...) + copy.Compositions = append([]core.CompositionSelection(nil), s.Compositions...) return © } @@ -254,9 +255,9 @@ func copiedView(root string, files map[string]retainedFile) error { } return nil } -func validateRetained(a executionArchive) (*SuiteIdentity, agentsuite.Agent, string, error) { - var agent agentsuite.Agent - if !namePattern.MatchString(a.ID) || !agentsuite.IsValidDigest(a.Pin) || checkRetained(a) != nil { +func validateRetained(a executionArchive) (*SuiteIdentity, core.Agent, string, error) { + var agent core.Agent + if !namePattern.MatchString(a.ID) || !core.IsValidDigest(a.Pin) || checkRetained(a) != nil { return nil, agent, "", errSuite } temp, err := os.MkdirTemp("", "canvas-suite-") @@ -268,35 +269,35 @@ func validateRetained(a executionArchive) (*SuiteIdentity, agentsuite.Agent, str if copiedView(before, a.Directory) != nil || copiedView(after, a.Artifact) != nil { return nil, agent, "", errSuite } - report, err := agentsuite.ValidateDirectory(before) + report, err := oci.ValidateDirectory(before) if err != nil { return nil, agent, "", errSuite } - diff, err := agentsuite.DiffPaths(before, after) + diff, err := oci.DiffPaths(before, after) if err != nil || diff.Before.SourceType != "directory" || diff.Before.ArtifactDigest != "" || diff.After.SourceType != "oci-layout" || diff.After.ArtifactDigest != a.Pin || diff.Before.ContentDigest != diff.After.ContentDigest { return nil, agent, "", errSuite } - var suite agentsuite.Suite + var suite core.Suite raw := a.Directory["agentsuite.json"].Data - if agentsuite.Unmarshal(raw, &suite) != nil || len(suite.Agents) != 1 || len(suite.Extensions) != 0 || len(suite.Capabilities) != 0 || report.ToolProviders != 0 || report.ToolProviderCompositions != 0 { + if core.Unmarshal(raw, &suite) != nil || len(suite.Agents) != 1 || len(suite.Extensions) != 0 || len(suite.Capabilities) != 0 || report.ToolProviders != 0 || report.ToolProviderCompositions != 0 { return nil, agent, "", errSuite } member := suite.Agents[0] - if member.ID != a.Member || !agentsuite.MatchesCanonicalDescriptor(a.Directory[member.Path].Data, member.Descriptor) || agentsuite.Unmarshal(a.Directory[member.Path].Data, &agent) != nil { + if member.ID != a.Member || !core.MatchesCanonicalDescriptor(a.Directory[member.Path].Data, member.Descriptor) || core.Unmarshal(a.Directory[member.Path].Data, &agent) != nil { return nil, agent, "", errSuite } if agent.ID != member.ID || !modelOnlyAgent(agent) { return nil, agent, "", errSuite } instruction := a.Directory[agent.Instructions.Path].Data - if agent.Instructions.Descriptor.MediaType != agentsuite.MediaTypeInstructions || !agentsuite.DescriptorSizeAndDigestMatch(instruction, agent.Instructions.Descriptor) || len(instruction) == 0 || len(instruction) > 65536 || !utf8.Valid(instruction) { + if agent.Instructions.Descriptor.MediaType != core.MediaTypeInstructions || !core.DescriptorSizeAndDigestMatch(instruction, agent.Instructions.Descriptor) || len(instruction) == 0 || len(instruction) > 65536 || !utf8.Valid(instruction) { return nil, agent, "", errSuite } - graph, err := agentsuite.Digest(raw) + graph, err := core.Digest(raw) if err != nil { return nil, agent, "", errSuite } - selected := make([]agentsuite.CompositionSelection, 0, len(report.CompositionSelections)) + selected := make([]core.CompositionSelection, 0, len(report.CompositionSelections)) for _, s := range report.CompositionSelections { if s.Agent == member.ID { selected = append(selected, s) @@ -307,7 +308,7 @@ func validateRetained(a executionArchive) (*SuiteIdentity, agentsuite.Agent, str } return &SuiteIdentity{Digest: a.Pin, ContentDigest: diff.Before.ContentDigest, GraphDigest: graph, Member: member.ID, MemberDigest: member.Descriptor.Digest, Compositions: selected}, agent, string(instruction), nil } -func modelOnlyAgent(agent agentsuite.Agent) bool { +func modelOnlyAgent(agent core.Agent) bool { return agent.Model.Protocol == "openai-compatible" && boundedModel(agent.Model.Model) && len(agent.Model.SecretRefs) == 0 && agent.Model.EndpointEnv == "" && len(agent.ToolProviders) == 0 && len(agent.Invokes) == 0 && len(agent.Extensions) == 0 } func boundedModel(model string) bool { diff --git a/internal/contract/suite_limits_test.go b/internal/contract/suite_limits_test.go index 9009f72..99614af 100644 --- a/internal/contract/suite_limits_test.go +++ b/internal/contract/suite_limits_test.go @@ -12,7 +12,8 @@ import ( "syscall" "testing" - agentsuite "github.com/agent-primitives/suite" + "github.com/agent-primitives/suite/core" + "github.com/agent-primitives/suite/oci" ) func suiteArchive(t *testing.T) (Bundle, executionArchive) { @@ -33,7 +34,7 @@ func TestSuiteArchiveTamperingNeverTrusted(t *testing.T) { t.Run(field, func(t *testing.T) { candidate := b identity := *b.Suite - identity.Compositions = append([]agentsuite.CompositionSelection{}, identity.Compositions...) + identity.Compositions = append([]core.CompositionSelection{}, identity.Compositions...) candidate.Suite = &identity switch field { case "digest": @@ -179,7 +180,7 @@ func TestDirectorySupplementAndSpecialFileRefusals(t *testing.T) { if err := os.WriteFile(filepath.Join(root, "extra.json"), []byte(`{"fictional":true}`), 0600); err != nil { t.Fatal(err) } - if _, err := agentsuite.ValidateDirectory(root); err != nil { + if _, err := oci.ValidateDirectory(root); err != nil { t.Fatal("supplement must be otherwise conformant", err) } if _, err := LoadSuite("writer", ref); err == nil { @@ -196,23 +197,23 @@ func TestDirectorySupplementAndSpecialFileRefusals(t *testing.T) { func TestSuiteModelOnlyPolicyRefusesUnsupportedFeatures(t *testing.T) { _, archive := suiteArchive(t) - var agent agentsuite.Agent - if err := agentsuite.Unmarshal(archive.Directory["agents/writer.json"].Data, &agent); err != nil { + var agent core.Agent + if err := core.Unmarshal(archive.Directory["agents/writer.json"].Data, &agent); err != nil { t.Fatal(err) } if !modelOnlyAgent(agent) { t.Fatal("fixture is not model-only") } - for _, mutate := range []func(*agentsuite.Agent){ - func(a *agentsuite.Agent) { a.Model.Protocol = "other" }, - func(a *agentsuite.Agent) { a.Model.Model = "" }, - func(a *agentsuite.Agent) { a.Model.Model = strings.Repeat("x", 161) }, - func(a *agentsuite.Agent) { a.Model.Model = "model\ncredential-canary" }, - func(a *agentsuite.Agent) { a.Model.EndpointEnv = "CREDENTIAL_CANARY" }, - func(a *agentsuite.Agent) { a.Model.SecretRefs = []string{"credential-canary"} }, - func(a *agentsuite.Agent) { a.ToolProviders = []agentsuite.ToolProviderRequirement{{ID: "tool"}} }, - func(a *agentsuite.Agent) { a.Invokes = []agentsuite.AgentInvoke{{Agent: "other"}} }, - func(a *agentsuite.Agent) { a.Extensions = []agentsuite.Extension{{Name: "extra"}} }, + for _, mutate := range []func(*core.Agent){ + func(a *core.Agent) { a.Model.Protocol = "other" }, + func(a *core.Agent) { a.Model.Model = "" }, + func(a *core.Agent) { a.Model.Model = strings.Repeat("x", 161) }, + func(a *core.Agent) { a.Model.Model = "model\ncredential-canary" }, + func(a *core.Agent) { a.Model.EndpointEnv = "CREDENTIAL_CANARY" }, + func(a *core.Agent) { a.Model.SecretRefs = []string{"credential-canary"} }, + func(a *core.Agent) { a.ToolProviders = []core.ToolProviderRequirement{{ID: "tool"}} }, + func(a *core.Agent) { a.Invokes = []core.AgentInvoke{{Agent: "other"}} }, + func(a *core.Agent) { a.Extensions = []core.Extension{{Name: "extra"}} }, } { a := agent mutate(&a) @@ -221,7 +222,7 @@ func TestSuiteModelOnlyPolicyRefusesUnsupportedFeatures(t *testing.T) { } } raw := bytes.Replace(archive.Directory["agents/writer.json"].Data, []byte(`"id":"writer"`), []byte(`"id":"writer","environment":{"SECRET":"credential-canary"}`), 1) - if agentsuite.Unmarshal(raw, &agent) == nil { + if core.Unmarshal(raw, &agent) == nil { t.Fatal("unknown executable fields accepted") } }