Skip to content

fix(ci): lease network scope and evidence context checked end to end (D-1331, D-1299) - #562

Merged
acamarata merged 3 commits into
mainfrom
fix/trust-agent-lease-d1331-d1299
Oct 29, 2026
Merged

acamarata merged 3 commits into
mainfrom
fix/trust-agent-lease-d1331-d1299

Conversation

@acamarata

Copy link
Copy Markdown
Contributor

Fixes two high TRUST debt rows that block P7-TRUST-99. Both change the lease the coordinator sends and what the agent does with it, so they share files and ship together.

D-1331: network scope checked at run time

Root cause: only the scheduler's admission rule refused lan/privileged to an untrusted job. Nothing called netscope.Effective at run time, and a lease carried its trust class only when it carried secret refs.

  • netscope.RunScope: Effective's refusal for a declared scope. An undeclared scope runs as none (what the executor and the local path already do), so the class default never widens a job.
  • The coordinator's transport adapter refuses delivery with E679, and every lease now carries trust.
  • The agent passes the lease class into the exec spec and fails the attempt with E679 before the executor runs.
  • TestInvariant_I07 now also runs against the agent's lease path (cmd/agent).

D-1299: signed remote evidence verifies

Root cause: the agent's evidence named its own run id, repo_id: unknown, source untrusted, no policy digest and job job. attest.RunnerVerifier compares each of these with the coordinator's record, so every signed result was refused (context_mismatch).

  • protocol.Lease.evidence (optional) carries run id, repo id, source trust, policy digest, selection mode and job name. The runner-protocol schema is regenerated.
  • The adapter fills it with store.AttestLedger.AttemptFacts, the same read the verifier compares against (run.LeaseEvidence).
  • The agent names those facts and keeps the coordinator's repo id after the builder completes the document, before it is signed.

Tests (run on mm4, darwin/arm64)

  • New: TestRunScope, TestDeliverRefusesALANScopeForAnUntrustedJobAndCarriesTheClass, TestInvariant_I07 (cmd/agent), TestDeliveredLeaseCarriesTheAttemptsEvidenceContext, TestSignedRemoteEvidenceVerifiesAgainstTheCoordinatorRecord (end to end: coordinator context, agent run on a real checkout, node-key signature over the frame bytes, attest.VerifyFrame with the real store ledger; it also checks that a lease without the context, and an altered context, are refused).
  • On origin/main code, the D-1331 tests fail: I07 shows 13238 violations ("an untrusted lease declaring lan reached the executor"), and Deliver returns nil where E679 is expected. The D-1299 tests do not compile on main because the field and function are new.
  • Two existing assertions changed: a lease without refs now carries its class (remote_await_test.go, dispatch/deliver_test.go).
  • go test ./... in free/ci: all new and touched packages pass. The failures left are the same tests that fail on pristine origin/main 3d7da3f on mm4: internal/attest TestProfile_* (IPv6), internal/gates/truth TestDrill*, internal/nodes/registry TestNodeReportCannotSetHostedOrProviderLabels, cloudvm TestCloudVMFullCycle (nil deref), internal/run TestInfraPostsError, and with -tags security test/security TestApproval*/TestCotenancy*/TestRecordedForkPR* (network.lan_for_untrusted) and redteam TestC37/TestC38. None is in a file this PR touches. architecture (layers, file sizes) passes.

Docs: the trust guide's network-scope limits and signing handoff are updated.

…ivery and on the node (D-1331)

The scheduler admission rule was the only thing refusing lan or privileged to an
untrusted job on a remote node: nothing called netscope.Effective at run time and
the lease carried its trust class only when it carried secret refs.

- netscope.RunScope: Effective's refusal for a declared scope; an undeclared
  scope runs as none (what the executor already did), never the class default.
- The coordinator refuses to deliver a lease that fails RunScope (E679) and
  every lease now carries the class the job was placed at.
- The agent passes the lease's class into the exec spec and fails the attempt
  with E679 before the executor runs when RunScope refuses it.
- TestInvariant_I07 now also runs against the agent's lease path.
…ote evidence verifies (D-1299)

The agent built its evidence with its own run id, repo_id "unknown", source
untrusted and no policy digest, and the job named "job". attest.RunnerVerifier
compares each of these with what the coordinator recorded for the attempt, so
every signed result was refused (context_mismatch): safe, but no signing node
could satisfy a gate.

- protocol.Lease gains an optional evidence context (run id, repo id, source
  trust, policy digest, selection mode, job name); schema regenerated.
- The run's transport adapter fills it from store.AttestLedger.AttemptFacts,
  the same read the verifier compares with (run.LeaseEvidence).
- The agent names those facts in its evidence and keeps the coordinator's
  repo id after the builder completes the document, before it is signed.
- End-to-end test: coordinator context, agent run on a real checkout, node key
  signature over the frame bytes, attest.VerifyFrame with the real store
  ledger. A lease without the context and an altered context are refused.
@acamarata
acamarata merged commit f9ff324 into main Oct 29, 2026
29 of 37 checks passed
@acamarata
acamarata deleted the fix/trust-agent-lease-d1331-d1299 branch October 29, 2026 23:06
acamarata added a commit that referenced this pull request Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant