Skip to content

[stack] feat(release): signed managed-release pipeline - #23

Merged
michaelshimeles merged 14 commits into
stack/infrafrom
stack/release
Aug 11, 2026
Merged

[stack] feat(release): signed managed-release pipeline#23
michaelshimeles merged 14 commits into
stack/infrafrom
stack/release

Conversation

@michaelshimeles

@michaelshimeles michaelshimeles commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Lands the signed managed-release pipeline slice, verbatim from the managed-cloud implementation: scripts/release/ — deterministic build + immutable checksum verification, signed guest-image and offline host-package builders with double-build reproducibility checks, tag-bound version resolution, fail-closed CI authorization, the Homebrew formula template, and the release policy tests — plus the release.yml workflow.
  • Reshapes ci.yml to the exact four-job matrix the release policy enforces (go, workspace, wire-contract, shell): the go job now runs the nehemiahd, guest-agent, and gateway test suites with govulncheck; the workspace job gains the npm audit --audit-level=high gate, the release policy checks, a root build, and the Postgres-backed control-plane migration replay + full 337-test suite; the new wire-contract job checks generated OpenAPI model drift (brings the 62-line scripts/openapi-models.mjs); shell also lints authorize-ci.sh.
  • Two workspace steps whose slices have not landed yet (live-harness syntax checks for tests/nehemiah/, staging/production promotion policy for scripts/deploy/) are deferred to those slices. Lockfile bumps via npm audit fix (5 high-severity advisories, all semver-compatible) satisfy the new audit gate. .gitignore gains apps/nehemiah/dist/ (present on the source branch, missed when that app landed).
  • With this slice present, the managed-provisioning harness's previously gated release assertions (ipset package policy, signed-archive local-unit exclusion, release-script shellcheck) now execute instead of skipping.

Test plan

  • node --test scripts/release/test/*.test.mjs — 17/17, including the live workflow-policy validation against the reshaped ci.yml
  • node scripts/release/check.mjs — "release checks passed for 0.2.0-beta.0"
  • bash infra/latitude/test/managed-provisioning.test.sh — passes with the release assertions active
  • go test -race + govulncheck — nehemiahd, guest-agent, gateway all clean
  • npm audit --audit-level=high — clean after the lockfile fixes
  • npm run check / lint / test / build — green
  • Postgres 17 (dockerized): migration applied twice (replay-safe) + full control-plane suite with --no-file-parallelism — 337/337
  • wire-contract steps: apps/nehemiah build, model drift check, generated TS type-check, Python compile, gofmt + go test
  • release.yml's guest-images/host-packages jobs are path-triggered and will run on this PR; they need ubuntu-24.04-arm runners — confirm they schedule and pass in CI

Made with Cursor


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
boringcomputers Ready Ready Preview Aug 11, 2026 10:21pm

Request Review

@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown

Greptile Summary

The release changes now build the guest agent from its standalone Go module, package the CLI with its required keyring dependency, and recover from truncated managed-host downloads. Executed checks disproved the earlier guest-agent build failure, CLI dependency assertion failure, and truncated-download retry failure.

Confidence Score: 5/5

No blocking failure remains.

The checked release construction, package metadata, download recovery, and CI trust paths behaved as intended.

T-Rex T-Rex Logs

What T-Rex did

  • The guest-agent Go build was executed in an isolated temporary directory and produced a statically linked x86-64 Linux executable at guest-image-input/bc-guest-agent.
  • A focused downloader retry harness was run against scripts/release/managed_host_packages.py::download; the test first encountered an incomplete read and then completed successfully, with two open calls and a cleanup before retry, ending in a final payload.
  • The release-build script trex-artifacts/release-guest-agent-build.sh and its captured output were reviewed, confirming no source changes and that the script isolates the workflow output to a temporary path.
  • The managed-host-download-retry-01-before.py harness run produced an after-log showing the retry sequence and the final complete payload with exit code 0.
  • Policy and validation checks compared a baseline exact-SHA CI run with a tampered-harness verifier; the tampered run produced a non-zero result, validating the fail-closed behavior.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (16): Last reviewed commit: "fix(release): drain the retention reaper..." | Re-trigger Greptile

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread scripts/release/build.mjs Outdated
Comment thread scripts/release/managed_host_packages.py Outdated
Comment thread scripts/release/managed_host_packages.py Outdated
Comment thread scripts/release/managed_host_packages.py
@michaelshimeles

Copy link
Copy Markdown
Collaborator Author

@greptile review

Comment thread scripts/release/managed_host_packages.py Outdated
michaelshimeles and others added 5 commits August 11, 2026 18:21
Lands the release slice of the managed-cloud implementation verbatim:
scripts/release/ (deterministic build/verify, signed guest-image and
offline host-package builders, tag-bound version resolution, fail-closed
CI authorization, and their tests) plus the release-artifacts workflow.

The release policy requires an exact CI job matrix, so ci.yml is reshaped
to it: the go job now tests nehemiahd, the guest agent, and the public
gateway (with govulncheck); the workspace job gains the npm audit gate,
the release policy checks, a root build, and the Postgres-backed
control-plane migration replay + full suite; the new wire-contract job
checks generated model drift (bringing scripts/openapi-models.mjs); shell
now also lints authorize-ci.sh. Two workspace steps whose slices have not
landed yet (live-harness syntax, deploy promotion policy) are deferred to
those slices. Lockfile bumps via npm audit fix satisfy the new
audit-level=high gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
…bootstrap

CI resolves Go from the go directive (1.25.0), whose standard library now
carries 30 known vulnerabilities fixed in later patches, so govulncheck
fails there while a locally newer toolchain passes. Pin toolchain go1.26.5
in nehemiahd, guest-agent, and gateway. Rewrite bootstrap.sh's KVM
permission warning as an explicit if: the release validate job runs the
provisioning harness, whose default-severity shellcheck flags the
"A && B || C" form (SC2015) on current shellcheck.

Co-authored-by: Cursor <cursoragent@cursor.com>
The CLI type-checks against nehemiah-sdk's published dist/ types, which
the validate job never built, so every run of the step failed with
TS2307/TS18046 cascades — including on the source branch, where this job
was red too. Build the SDK workspace between its own checks and the CLI's.

Co-authored-by: Cursor <cursoragent@cursor.com>
The step ran `go build ./guest-agent` from the repo root, but there is no
Go module at the root (each component is its own module), so every
guest-images run failed with "cannot find main module". Build with
-C guest-agent and emit the binary to an absolute path, matching how
build.mjs compiles components (cwd set to the module directory).

Co-authored-by: Cursor <cursoragent@cursor.com>
…pshot

The host-packages inspector extracted with tarfile, which stops at the tar
end-of-archive marker and never reads the gzip trailer, so the workflow's
truncated-archive negative test proved a one-byte-truncated archive
inspected cleanly. Decompress the full stream (bounded by the extraction
policy) before extracting so the CRC/length trailer is always checked;
verified against intact, trailer-truncated, and mid-stream-corrupted
archives.

Alpine republished the v3.23 indexes after the policy's snapshot was
captured, so every guest-image build failed its index digest check.
Refresh the four APKINDEX pins from the live repository and update the
reviewed capturedAt in both places that pin it (check.mjs and the release
test), per the security-refresh ritual.

Co-authored-by: Cursor <cursoragent@cursor.com>
michaelshimeles and others added 9 commits August 11, 2026 18:21
…ependency

esbuild cannot bundle @napi-rs/keyring's native .node binding, so the
deterministic-build job failed bundling the CLI. Mark it external and
declare it (exact-pinned from the CLI workspace) as the generated
package's single runtime dependency; npm resolves the platform binding at
install time, matching how the Homebrew formula installs the tarball.

Co-authored-by: Cursor <cursoragent@cursor.com>
The packed CLI must install with npm --offline against an empty cache, so
the keyring cannot be an ordinary registry dependency. Vendor the napi-rs
keyring and all twelve platform bindings into the package as a bundled
dependency, each fetched at build time and verified against an exact
pinned tarball digest, with the platform bindings nested under the keyring
package so its per-platform require resolves offline. The post-install
invariant now asserts exactly the bundled keyring dependency and that its
vendored tree landed (the offline install itself still proves nothing is
fetched), and check.mjs pins the new assertion plus the digest-pinned
download path.

Verified locally end to end: bundle, vendor, npm pack (11.9 MB), offline
global install with an empty cache, vendored tree present, and bc help.

Co-authored-by: Cursor <cursoragent@cursor.com>
The host-packages packager emits manifest.json with canonically sorted
keys, so parsed evidence carries operatingSystem as {codename, id,
version}. Cloning that into the release manifest broke the contract
validator's JSON.stringify deep-equality against the policy's reviewed
{id, version, codename} order. Rebuild the object in policy key order,
require the exact evidence key set, and key-sort the test fixture the
way the packager does so the suite reproduces the drift.

Co-authored-by: Cursor <cursoragent@cursor.com>
Both package-closure matrix jobs died 25 minutes in when
snapshot.ubuntu.com answered 500/502 during the repeat build. Retry
server and network failures up to three times with backoff, matching
the curl fetchers' --retry 3. Client errors still fail immediately,
policy violations are never retried, and every download remains
digest-verified, so retries cannot alter the closure.

Co-authored-by: Cursor <cursoragent@cursor.com>
The snapshot.ubuntu.com load balancer flapped for over ten minutes and
outlived the previous three-retry, fourteen-second budget. Retry up to
eight attempts with a capped backoff (about two minutes per file) so a
burst cannot sink a 25-minute matrix job; client errors still fail
immediately and every download stays digest-verified.

Co-authored-by: Cursor <cursoragent@cursor.com>
Trivy stamps DownloadedAt with nanosecond precision while the evidence
recorded observedAt in whole seconds, so when both landed in the same
second the truncated observation sorted "before" the download and the
evidence verifier rejected the ordering. Record observedAt at the same
precision so program order is preserved in the timestamps.

Co-authored-by: Cursor <cursoragent@cursor.com>
http.client.IncompleteRead is not an OSError, so a response cut off
after streaming began escaped the retry handler on the first attempt
and left the partial file behind. Treat http.client transport
exceptions as retryable alongside the existing failures, and pin the
downloader's whole retry contract — truncation retried without residue,
5xx bursts bridged, client errors immediate, exhaustion fail-closed —
with a stubbed-opener harness run from the release test suite.

Co-authored-by: Cursor <cursoragent@cursor.com>
Alpine republished both v3.23 main indexes this morning, so every
guest-image build failed its immutable index digest check. Refresh the
two changed APKINDEX pins from the live repository (both community
indexes are unchanged) and update the reviewed capturedAt in check.mjs
and the release test, per the security-refresh ritual.

Co-authored-by: Cursor <cursoragent@cursor.com>
The device-auth suite freezes its clock at a calendar date, and once its
revoked fixture families aged past the reaper's 24-hour window they sort
ahead of the retention test's chain and fill the whole default family
batch of 4, so a single reap pass no longer removed the chain and the
new policy-enforcing workspace job started failing mid-day. Run the job
to completion the way its schedule would — batched drains promise
eventual removal, not first-pass removal — and assert the accumulated
totals; verified against a fresh sequential Postgres run.

Co-authored-by: Cursor <cursoragent@cursor.com>
@michaelshimeles
michaelshimeles merged commit fea6f0a into main Aug 11, 2026
16 checks passed
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