diff --git a/contracts/external-trust-signal-provider.schema.json b/contracts/external-trust-signal-provider.schema.json index e2a7c71..a3d3793 100644 --- a/contracts/external-trust-signal-provider.schema.json +++ b/contracts/external-trust-signal-provider.schema.json @@ -35,6 +35,7 @@ ] }, "sha256Digest": { + "type": ["string", "null"], "type": [ "string", "null" @@ -131,6 +132,13 @@ "failureReason" ], "properties": { + "providerRef": { "type": "string" }, + "signalType": { "$ref": "#/$defs/signalType" }, + "signalRef": { "type": "string" }, + "signalDigest": { "$ref": "#/$defs/sha256Digest" }, + "verifiedAt": { "type": "string" }, + "freshness": { "$ref": "#/$defs/freshness" }, + "signature": { "$ref": "#/$defs/signature" }, "providerRef": { "type": "string" }, @@ -156,6 +164,8 @@ "type": "string", "const": "non-authoritative-verifier-input" }, + "failureReason": { "type": ["string", "null"] }, + "notes": { "type": "array", "items": { "type": "string" } } "failureReason": { "type": [ "string", @@ -210,6 +220,8 @@ "signatureRequired" ], "properties": { + "requestId": { "type": "string" }, + "providerRef": { "type": "string" }, "requestId": { "type": "string" }, @@ -306,6 +318,10 @@ "properties": { "status": { "type": "string", + "enum": ["available", "unavailable", "stale", "malformed", "unsigned", "denied", "error"] + }, + "usableForGrantResolution": { "type": "boolean" }, + "providerRef": { "type": "string" }, "enum": [ "available", "unavailable", @@ -326,6 +342,13 @@ "type": "string", "const": "non-authoritative-verifier-input" }, + "verifiedAt": { "type": ["string", "null"] }, + "freshness": { "$ref": "#/$defs/freshness" }, + "signals": { + "type": "array", + "items": { "$ref": "#/$defs/externalTrustSignal" } + }, + "failureReason": { "type": ["string", "null"] } "verifiedAt": { "type": [ "string", @@ -379,6 +402,19 @@ "rawUserDataIncluded" ], "properties": { + "includeRawContent": { "type": "boolean", "const": false }, + "rawPromptContentIncluded": { "type": "boolean", "const": false }, + "rawKvCacheContentIncluded": { "type": "boolean", "const": false }, + "secretValuesIncluded": { "type": "boolean", "const": false }, + "privateMemoryIncluded": { "type": "boolean", "const": false }, + "apiKeysIncluded": { "type": "boolean", "const": false }, + "walletPrivateKeysIncluded": { "type": "boolean", "const": false }, + "rawCredentialsIncluded": { "type": "boolean", "const": false }, + "rawUserDataIncluded": { "type": "boolean", "const": false } + } + }, + "observedAt": { "type": "string" }, + "labels": { "type": "object", "additionalProperties": { "type": "string" } } "includeRawContent": { "type": "boolean", "const": false diff --git a/docs/architecture/agent-registry-grants.md b/docs/architecture/agent-registry-grants.md index 9a7219f..c860a20 100644 --- a/docs/architecture/agent-registry-grants.md +++ b/docs/architecture/agent-registry-grants.md @@ -10,7 +10,7 @@ This grant is a local SourceOS control-plane artifact. It may consume external i AgentPod -> Policy Fabric admission -> Agent Registry grant request - -> optional external verifier inputs + -> optional ExternalTrustSignalProvider verifier inputs -> local grant resolution -> ActivationDecision -> runtime placement or fail-closed @@ -56,9 +56,11 @@ Allowed scope must be no broader than the requested scope. Denied scope is expli ## External trust signals -External systems can be useful for agent identity verification, reputation, counterparty checks, and certificate-tier claims. They are not the Agent Registry. +External systems can be useful for agent identity verification, reputation, counterparty checks, registry lookup, and certificate-tier claims. They are not the Agent Registry. -When used, external trust signals must be recorded under `grant.externalTrustSignals` with: +`ExternalTrustSignalProvider` artifacts represent those adapter results. A usable result can be considered by the local Agent Registry grant resolver only when it is fresh, signed when signatures are required, scoped to the requested provider and signal types, and marked with `authority: non-authoritative-verifier-input`. + +When used inside an `AgentRegistryGrant`, external trust signals must be recorded under `grant.externalTrustSignals` with: - the provider reference; - the signal type; @@ -67,7 +69,7 @@ When used, external trust signals must be recorded under `grant.externalTrustSig - verification time; - `authority: non-authoritative-verifier-input`. -This keeps PCH/ERC-8004-style identity, reputation, and certificate-tier checks pluggable without making any external gateway the SourceOS root of trust. +This keeps PCH/ERC-8004-style identity, reputation, registry lookup, and certificate-tier checks pluggable without making any external gateway the SourceOS root of trust. ## Fail-closed rules @@ -79,10 +81,11 @@ Activation fails closed when: - the requested provider is not present in allowed provider scope; - required activation tools are absent from allowed tool scope; - the grant is missing a revocation hook; -- the grant payload includes secrets, raw prompts, raw KV-cache contents, or private memory contents. +- required external trust signals are unavailable, stale, malformed, unsigned when signatures are required, or authority-elevated; +- the grant or external trust payload includes secrets, raw prompts, raw KV-cache contents, private memory contents, API keys, private wallet keys, raw credentials, or raw user data. ## Relation to receipts -`DeploymentReceipt` proves deterministic derivation. `PolicyAdmission` proves policy admission. `AgentRegistryGrant` proves identity/session/tool/provider/storage authorization. `ActivationDecision` combines those inputs and either permits scoped activation or records fail-closed reasons. +`DeploymentReceipt` proves deterministic derivation. `PolicyAdmission` proves policy admission. `ExternalTrustSignalProvider` proves optional verifier-input posture. `AgentRegistryGrant` proves identity/session/tool/provider/storage authorization. `ActivationDecision` combines those inputs and either permits scoped activation or records fail-closed reasons. None of these artifacts should include raw prompt content, KV-cache contents, secret values, private memory, or raw user data. diff --git a/scripts/validate-package.py b/scripts/validate-package.py index 33ab161..0e0ba08 100644 --- a/scripts/validate-package.py +++ b/scripts/validate-package.py @@ -61,6 +61,8 @@ def main() -> int: raise AssertionError("supply_chain.is_sha256_digest rejected valid digest") if agent_machine.release_bundle.DEFAULT_REPOSITORY != "SourceOS-Linux/agent-machine": raise AssertionError("unexpected release_bundle default repository") + if agent_machine.external_trust.AUTHORITY != "non-authoritative-verifier-input": + raise AssertionError("unexpected external trust authority") if agent_machine.policy_fabric.DEFAULT_DECIDED_AT != "1970-01-01T00:00:00Z": raise AssertionError("unexpected policy_fabric default decided_at") if agent_machine.agent_registry.DEFAULT_ISSUED_AT != "1970-01-01T00:00:00Z": diff --git a/src/agent_machine/external_trust.py b/src/agent_machine/external_trust.py index 4ac3fd5..32deeb8 100644 --- a/src/agent_machine/external_trust.py +++ b/src/agent_machine/external_trust.py @@ -223,5 +223,6 @@ def main() -> int: try: raise SystemExit(main()) except (AssertionError, RuntimeError) as exc: + print(str(exc), file=__import__("sys").stderr) print(str(exc), file=sys.stderr) raise SystemExit(1) from exc