Repository navigation
feat(agent): add isolated signed update delivery - #1214
Merged
Merged
Conversation
Contributor
|
Maple development preview: https://038b3c34.maple-ca8.pages.dev Commit: Uses development API, billing, flags and PCR configuration. Cloudflare Access applies. |
Contributor
|
Maple Auth development preview: https://e675ea15.maple-auth-dev.pages.dev Commit: Uses development services. Cloudflare Access applies. Provider OAuth is not configured for PR URLs; use the stable Auth Dev host for OAuth rehearsal. |
Accept raw and commented public keys with the real minisign verifier. Reuse byte-identical immutable objects before attempting a conditional write, preserving create-only race handling and fail-closed storage errors. Add real-CLI pointer retry/repair regressions and offline R2 signing and transport coverage. Pin the publisher GitHub CLI, run preparation in its pinned shell, and follow profile/package-contract changes in delivery checks. Configured-bucket lock and pointer-race behavior remains an activation rehearsal gate. Validation: isolated delivery checks passed (94 publisher tests, 6 workflow tests, 10 Worker/workerd tests); selector tests and independent changed-workflow actionlint/ShellCheck passed. Full root flake check and normal hook were attempted but stalled in this host's actionlint/ShellCheck integration and unrelated iOS fixture. Commit hook skipped only after equivalent focused checks; hosted repository checks remain required.
AnthonyRonning
added a commit
that referenced
this pull request
Oct 27, 2026
…package build - opensecret_change_detection.py lists services/agent-updates/ as an independent root. Since #1214 every agent-updates change selected every OpenSecret check, including both EIF builds. Unknown roots still select every check. - os-flake-check runs only the component `nix flake check`. Nothing consumed the x86_64 `#default` package: the shipped EIF is aarch64, and os-rust, os-sdk-e2e and the EIF lanes compile and test the same code. - deps-opensecret follows its own Cargo.toml, Cargo.lock and deny.toml instead of the selector's `audit` output, which CI files also trigger. CI edits no longer select any deps lane, so new RustSec advisories surface in the nightly run instead of failing unrelated PRs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AnthonyRonning
added a commit
that referenced
this pull request
Oct 27, 2026
…package build - opensecret_change_detection.py lists services/agent-updates/ as an independent root. Since #1214 every agent-updates change selected every OpenSecret check, including both EIF builds. Unknown roots still select every check. - os-flake-check runs only the component `nix flake check`. Nothing consumed the x86_64 `#default` package: the shipped EIF is aarch64, and os-rust, os-sdk-e2e and the EIF lanes compile and test the same code. - deps-opensecret follows its own Cargo.toml, Cargo.lock and deny.toml instead of the selector's `audit` output, which CI files also trigger. CI edits no longer select any deps lane, so new RustSec advisories surface in the nightly run instead of failing unrelated PRs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AnthonyRonning
added a commit
that referenced
this pull request
Oct 27, 2026
…package build - opensecret_change_detection.py lists services/agent-updates/ as an independent root. Since #1214 every agent-updates change selected every OpenSecret check, including both EIF builds. Unknown roots still select every check. - os-flake-check runs only the component `nix flake check`. Nothing consumed the x86_64 `#default` package: the shipped EIF is aarch64, and os-rust, os-sdk-e2e and the EIF lanes compile and test the same code. - deps-opensecret follows its own Cargo.toml, Cargo.lock and deny.toml instead of the selector's `audit` output, which CI files also trigger. CI edits no longer select any deps lane, so new RustSec advisories surface in the nightly run instead of failing unrelated PRs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AnthonyRonning
added a commit
that referenced
this pull request
Oct 27, 2026
* ci: add ci.yml, the lane planner and the Agent PR gate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: replace workflow shape tests with policy and contract tests; activate the repo lane
The manual Windows signature probe's `actions: read` moves from the
workflow to its one job, as the read-only workflow-permissions policy
requires; the job's token is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: run Agent verification, packaging rehearsal and nightly checks from ci.yml
Activate the remaining Agent lanes (full Linux/macOS/Windows suites,
supply chain, provider, store bench, PR packaging rehearsals), add
nightly.yml with one ci-nightly issue, make agent-desktop-build.yml
master-only with exact-key release caches and a Blacksmith Windows
builder, and delete agent-ci.yml, the SQLCipher and store workflows
and the dependency archive, cache-scope, measurement and selector
scripts.
test_windows_updater_workflow.py reads the Windows Rust pin from
setup-agent-windows, which windows-build now uses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: move SDK, proxy, Research and service checks into ci.yml lanes
Activate the sdk-ts, sdk-rust, proxy, deps-{research,sdk,proxy},
proxy-container(-arm64), research-web, research-rust, research-ios,
research-android, research-desktop-{macos,linux,windows}, research-dev-macos,
auth, updates and agent-updates lanes. PR lanes restore only caches that
master writes and never save one. frontend-tests, web-build and rust-tests
become push-only evidence twins (rust-tests on Blacksmith, writing
ci-v1-research-rust); proxy-rust keeps only the release rehearsal. Delete the
twelve workflows these lanes replace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: run OpenSecret checks and the PR EIF candidate from ci.yml lanes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: finish the rebuild: signed-lane hygiene, hook on the planner, CI docs
Signed Research workflows get job timeouts and job-level OIDC and
attestation scopes; Maple Dev TestFlight builds only for Research web or
iOS inputs (dispatch always builds); CodeQL runs on every master push,
per SHA, never cancelled. The temporary policy and contract allowlists
are gone.
The pre-commit hook selects components with `plan.py hook --staged`
from the lane table, and the Agent hook runs the agent-lint and
agent-test recipes. docs/ci.md is new, docs/repository-workflows.md is
rewritten, AGENTS.md gains CI rules for agents, and the unused flake
apps.ci-* outputs are removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: address review findings
- os-sdk-e2e and os-helpers select on their own entry scripts; the
OpenSecret selector routes inert paths too, so its routing is verbatim
- widen the Agent packaging selector to the scripts packaging calls, the
Agent flake and (macOS) the Xcode pin; agent-windows runs the native
Windows tests; acp-only and proxy-only clippy move into ci-lint
- os-eif: PRs to master only, plus a ci:eif label; os-flake-check builds
the x86_64 package again; opensecret-eif.yml runs on every PR to master
- ci-ok calls `plan.py verdict`; lint checks special jobs' runners and
timeouts; setup-bun saves no PR cache; agent-test on 32 vCPU
- ci.yml's nightly run covers deps and supply chain; the reporter needs
today's scheduled run
- drop PR-only scripts from the signed-build selector; Auth push paths
rehearse publisher edits again; docs fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: fix validation
Keep services/opensecret/ byte-identical to master, as the OpenSecret port
requires: restore its README, nitro-deploy.md and hook comment. The C7 docs
contract skips that subtree; its docs move with OpenSecret PRs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: route agent-updates away from OpenSecret and drop the unused x86 package build
- opensecret_change_detection.py lists services/agent-updates/ as an
independent root. Since #1214 every agent-updates change selected every
OpenSecret check, including both EIF builds. Unknown roots still select
every check.
- os-flake-check runs only the component `nix flake check`. Nothing consumed
the x86_64 `#default` package: the shipped EIF is aarch64, and os-rust,
os-sdk-e2e and the EIF lanes compile and test the same code.
- deps-opensecret follows its own Cargo.toml, Cargo.lock and deny.toml
instead of the selector's `audit` output, which CI files also trigger. CI
edits no longer select any deps lane, so new RustSec advisories surface in
the nightly run instead of failing unrelated PRs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci(opensecret): report EIF approval mismatches on master as pending, not failed
check_opensecret_eif.sh exits 3 for a PCR mismatch and prints the built
pcr.json; usage, build and comparison failures keep their non-3 statuses
(a Nix build failure is now always 1, never 3).
opensecret-eif.yml's compare step, identical in eif and eif-trusted:
- master push or dispatch: a mismatch is a notice, with the built PCRs in
the step summary, and the job passes;
- pull_request: a mode must match only if the PR's own diff (merge base to
head, SHAs through env) edits that mode's pcr<Env>.json or
pcr<Env>History.json; otherwise its mismatch is a notice;
- dispatch outside master: a mismatch fails, as before;
- any other non-zero status fails.
Job conditions, runners, permissions, cache steps and the matrix are
unchanged; opensecret-eif-release.yml does not call the script.
services/opensecret/README.md and docs/nitro-deploy.md now name ci.yml
instead of the deleted workflows and describe the new verdicts, so C7 no
longer skips services/opensecret/. The eif-dev and eif-prod derivations are
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: address follow-up review findings
- opensecret-eif.yml: the EIF compare step accepts only full 40-hex PR
base and head SHAs before it diffs the approval files. Anything else
fails the job, so an option-like or abbreviated value cannot make an
edited mode's mismatch look neutral. Both approval jobs keep the same
step; test_contracts covers option-like and abbreviated SHAs.
- docs/ci.md: the advisory rule is scoped to the deps-* lanes, and names
the two gate lanes that still audit advisories (agent-supply-chain,
sdk-ts).
- services/opensecret/.githooks/pre-commit: the comment names ci.yml's
os-rust and os-flake-check lanes and drops the removed package build.
Comment lines only; the eif-dev, eif-prod and eif-preview drvPaths are
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(agent): allow two intentional Windows-only Clippy lints
The new Windows Clippy lane is the first CI job to lint the Agent's
cfg(windows) code. Both findings are intentional, so they get a scoped
allow with the reason; behaviour is unchanged:
- filesystem_kind joins "\" to the path prefix on purpose: joining a rooted
path keeps the prefix, so C: becomes C:\ for GetDriveTypeW.
- The Windows-only hard-link cleanup test clears the read-only attribute,
not Unix mode bits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: size Agent lane timeouts for cold runs and lint on 32 vCPU
The first ci.yml run timed out agent-lint and agent-supply-chain at 15
minutes on a cold cache, and a lane that times out never saves its cache.
Timeouts now cover a cold run (lint and test 40, supply chain 30). The
lint lane joins agent-test on the 32 vCPU runner, since it is on the Agent
PR path whenever a dependency bump misses the cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: faster PR packaging, cached Research git deps, no store benchmark
- Agent PR packaging rehearsals build with thin LTO and 16 codegen units. They
prove the packaging scripts, not the optimizer; master's signed builds keep
fat LTO. A profile change rebuilds every dependency, so the rehearsals keep
their own cache, which ci.yml's nightly master run saves.
- research-android restores the Research Rust cache rust-tests.yml writes.
Cargo fetches every git dependency in the lockfile for any target, so the
Android build was spending most of its time fetching Goose and PDFOxide.
- The store benchmark leaves CI: no ci:perf lane and no nightly job. The
crate and `just store-bench` remain for local runs.
- docs/ci.md, AGENTS.md and the Agent skill say when a label is worth adding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: align with #1316
#1316 (signed Windows Agent updates) landed while this branch moved the
Windows jobs. Carry its contracts over:
- agent-package-windows replaces the deleted PR-only windows-unsigned job,
so it now exports MAPLE_PACKAGE_BUILD_NUMBER, which windows-release.py
requires: the Actions run number, or 1 outside Actions (as
package-release.sh does), so `just lane agent-package-windows` still runs
locally.
- test_contracts C2 asks the publisher to trust a run with Windows too, and
pins MAPLE_PACKAGE_BUILD_NUMBER to github.run_number on every job that
packages or verifies Windows (the assertion #1316 added to the deleted
test_agent_workflows.py).
- The manual signature probe checks that each Windows Prod job ran on
windows-2025. The unsigned build now runs on Blacksmith, so the build job
may also report blacksmith-8vcpu-windows-2025 (signing and verification
still must be GitHub's). A new C2 contract runs the probe's producer check
against this workflow's jobs and runners.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: fold the Windows updater tests into ci.yml lanes
agent-windows-updater-tests.yml (from #1316) becomes the
agent-windows-updater lane, reported by ci-ok:
- Selected by the workflow's own paths on pull requests, the merge queue
and master pushes alike, by ci:windows and ci:full, by CI edits, and
nightly. Only the deleted workflow's own path is dropped.
- It runs scripts/ci/windows-app-typecheck.ps1, then
scripts/ci/windows-updater-tests.ps1, unchanged, with pwsh from the
repository root and the workflow's environment (RUSTFLAGS -D warnings,
CARGO_TERM_COLOR never, no incremental build, no debug info). Both
always run, as the two parallel jobs did, and either failure fails the
lane.
- A special ci.yml job keeps both receipts and Cargo logs as one artifact
even on failure. It uses setup-agent-windows, the pinned Rust, MSVC,
native Perl and linker the workflow set up by hand, and restores no
cache. The fxc selection is not carried over: GPUI compiles shaders only
in builds without debug assertions, so a dev-profile cargo check never
runs fxc.
- It runs on the Windows lane runner (Blacksmith, CI_WINDOWS_RUNNER to
fail over) instead of GitHub's windows-2025. The native reparse fixtures
need the symlink privilege, so this PR's own run is the first proof on
Blacksmith.
test_windows_updater_workflow.py now tests the lane, the job and the
scripts instead of the workflow's YAML: no authority, the pinned toolchain
and no cache, selection through the planner, both scripts running (with a
stub pwsh) and the retained evidence. The script assertions are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: address #1316 integration review
- agent-package-windows also runs on its own Windows inputs: the Windows
packaging scripts, build-release.sh (its Windows branch), release-info.py,
the release profile files and the Windows toolchain. #1316 put Windows on
the Agent feed, and on master every Agent PR built, installed and
smoke-tested an unsigned Windows package; label-only selection assumed
Windows was not published. ci:package and ci:full still add it.
- test_contracts C2 evaluates each agent-desktop-build.yml job's `if:` and
`needs` for a master push and a dispatch, so a condition that skips a
Prod job the publisher requires fails the contract. Bare true, false and
null evaluate as GitHub's literals.
- A new C2 contract runs every lane that calls windows-release.py package
or verify with stand-ins and checks they receive MAPLE_PACKAGE_BUILD_NUMBER:
the Actions run number, or 1 outside Actions.
- C7 also checks quoted or bold workflow display names in docs; updates.md
named the deleted Agent Windows Updater Tests workflow and now names the
agent-windows-updater lane.
- magic-nix-cache-action counts as a cache writer unless use-gha-cache is
disabled. opensecret-eif.yml's eif job (fork PRs that edit approvals,
manual runs outside master) is the one exempt pull-request writer: no
FlakeHub, no id-token, branch-scoped cache. The workflow is unchanged;
the cache docs now name the exception.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: run the Agent's native Windows test lanes on GitHub's windows-2025
The first Blacksmith run of agent-windows-updater failed one native test:
the updater's storage validation rejects the test image because Blacksmith's
workspace inherits a foreign write ACE, which GitHub's workspace does not.
The validation is right, and #1316 proved these tests on windows-2025, so
agent-windows-updater and agent-full-windows (which runs the same tests) use
GitHub's image again. The Windows Clippy lane and the unsigned builds stay on
Blacksmith.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(agent): satisfy Windows Clippy in the updater's Windows bundle code
The Windows Clippy lane is the first CI job to lint #1316's Windows-only
updater code. Five mechanical fixes, no behaviour change: three collapsible
ifs (two as let chains), a range check written with RangeInclusive::contains,
and PROCESSENTRY32W built with its size in the initializer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: run the Windows packaging rehearsal on GitHub's windows-2025
Run 5 built, packaged and verified the unsigned Dev installer on Blacksmith,
then the installer smoke test (setup.exe /S into a temporary directory)
failed there. Master's install smoke for the same installer runs on GitHub's
windows-2025 (agent-desktop-build.yml verify-windows), which also passes the
updater's native tests, so the PR rehearsal runs there too. It no longer
restores master's Blacksmith-written release cache, which a GitHub runner
cannot read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: cold-run timeouts for Research Rust and Android; fast Windows rehearsal
Run 6 cancelled research-rust at its 20-minute timeout: 14.7 minutes went to
Cargo fetching Goose's git history before master's Research cache exists.
research-rust and research-android get 45 minutes. The Windows packaging
rehearsal uses the same thin-LTO profile as the Linux and macOS ones; master's
signed Windows build keeps fat LTO.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add independent Agent update delivery: an Agent-only Worker serves signed metadata, enumerated immutable artifacts, download redirects and byte ranges from its own R2 binding. The protected manual publisher verifies exact trusted-master Prod package producers, final downloaded-package consumers, workflow/source attestations, package identity and hashes before reservation, signing and publication stages. Credentialed Agent jobs reuse the existing
updates-productionenvironment and existing BWS access credential, following the pinned PCR action pattern withset_env: false; only the consuming step maps fetched values. No new environments, machine accounts or tokens are required. Underlying BWS grants and the shared environment secret context remain trusted.Research's Worker, publisher, feed, clients, signing environment/policy and downloads remain unchanged. Agent publication creates no GitHub Releases or tags. Linux is omitted by default and requires its own packaged launch/update gates; this PR remains independent of #1212.
The publisher verifies current-pointer signatures with real minisign for either raw or commented public-key files. Identical retries compare immutable object bytes before writing locked keys; missing objects still use create-only writes and races require exact-byte equality. Different bytes, permission failures and storage errors fail closed. Pointer promotion remains conditional and monotonic. Private audit sidecars and exact-byte reservations make partial and already-promoted attempts retryable.
Validation at
c40d3364(bucket-binding follow-up to8b5181d4):ghandjqrun inside pinned Nix during preparation. Profile/release-info changes select delivery validation.8b5181d4, full local rootnix flake check --no-update-lock-filepassed for aarch64-darwin and the normal hook passed actionlint plus all 499 repository script tests. Signing-boundary, Agent-workflow, Nix-workflow and selector tests passed; standalone ShellCheck passed all 12 publisher run blocks.R2Storeandimmutable_putwith the bucket-scoped S3 pair: identical locked-object retries, missing-object creation, differing-byte refusal, streaming hash/HEAD/range, successful pointer CAS and stale-ETag 412 preservation all passed. Direct overwrite/delete of locked objects returned 409ObjectLockedByBucketPolicywith bytes preserved; an unrelated bucket denied access with 403. The real latest pointer was untouched. This proves bounded transport/lock/CAS interoperability, not full manifest publication or an installed update.Delivery remains inactive. The owner provisioned the private
maple-agent-updatesR2 bucket, disabled public bucket endpoints, configured the immutable-release lock and stored the bucket-scoped publisher credentials in existing BWS infrastructure with Agent-specific inputs in the existingupdates-productionenvironment. The checked-in binding now names that bucket; local checks still substitute a separate fixture. Routes stay owner-managed outside routine deploy configuration, and empty source pins still block publication. No Worker/route deployment, release, publication or PR merge was performed; Research configuration is unchanged. Full locked-prefix manifest/publication retry rehearsal, narrowly scoped Worker deployment with its R2 binding, routing independence in both directions, and the signed installed0.0.1→0.0.2rehearsal remain activation gates before invitations.