Skip to content

ci(nightly): add nightly build channel tracking latest agent CLIs - #1519

Merged
thepagent merged 7 commits into
mainfrom
nightly-build
Sep 3, 2026
Merged

ci(nightly): add nightly build channel tracking latest agent CLIs#1519
thepagent merged 7 commits into
mainfrom
nightly-build

Conversation

@chaodu-agent

@chaodu-agent chaodu-agent commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

⚠️ This is a drop-in replacement channel with no compatibility guarantee. Nightly
images track each vendor's latest coding CLI, which can change or break at any time.
They are not releases and carry no stability or compatibility promise. Pin a real
v* release (or a pre-beta-* tag) when you need a stable, reproducible image.

Summary

Adds a scheduled nightly image channel for openabdev/openab, analogous to the nightly
channel in openab-pty. Each supported variant packages the current OpenAB binary with the
vendor's latest CLI.

The pinned release and pre-beta lanes cannot already provide this: their CLI versions and,
for binary downloads, SHA256 values are defaults inside Dockerfile.package, so rebuilding
those lanes intentionally republishes the same CLI. Nightly resolves fresh vendor metadata
and supplies build-argument overrides without changing those defaults.

Channel behavior

  • Schedule: daily at 06:23 UTC; manual dispatch may select a strict comma-separated subset.
  • Pipeline: select matrix → compile OpenAB once per architecture + resolve each vendor once per
    variant → build each variant/architecture by digest → create per-variant multi-arch manifests.
  • Canonical publication is restricted to main. A feature-branch dispatch may validate the
    selector, compilation, and resolvers but cannot push images.
  • Tags:
    • nightly-<variant> — moving tag.
    • nightly-YYYYMMDD-<run-id>.<attempt>-<variant> — immutable rollback point; the attempt
      suffix prevents a workflow re-run from moving an existing rollback tag.
  • Variants publish independently. A failed resolver/build for one variant does not withhold
    successful siblings; that variant keeps yesterday's moving tag.
  • native and agentcore are excluded because they contain no vendor CLI. pi is temporarily
    excluded because its existing package target does not ship its configured adapter (fix(docker): pi target sets OPENAB_AGENT_COMMAND=openab-agent but never ships that binary #1520).

Integrity model

  • Release and pre-beta retain their pinned SHA256 checks exactly as before.
  • Devin resolves and validates both vendor-published architecture SHA256 values.
  • Hermes resolves a release tag to an immutable commit and hashes the installer fetched through
    the authenticated GitHub Contents API.
  • Kiro exposes no version index. Nightly resolves a strong ETag for each latest object once,
    validates it, and the Dockerfile sends If-Match during each download (a changed object fails
    HTTP 412). Each native image then runs kiro-cli --version; the tag job requires amd64 and
    arm64 reports to match before creating a manifest.
  • Grok and Antigravity do not publish an ahead-of-time digest usable by this lane; their nightly
    downloads intentionally use empty SHA overrides and rely on TLS. This relaxation is confined
    to nightly-* builds.

Validation

  • Exact selector script: rejects leading/interior/trailing/whitespace-only empty entries and
    duplicates; accepts normalized valid subsets and all.
  • Exact Kiro resolver: emits validated 32-hex ETags for both architectures.
  • Live Kiro CDN: matching quoted If-Match → HTTP 206; incorrect ETag → HTTP 412.
  • Kiro manifest gate: matching installed versions pass; mismatched versions fail closed.
  • Exact authenticated Antigravity resolver returns the latest release and expected build args.
  • actionlint + shellcheck: clean.
  • Dockerfile.package Kiro target: BuildKit --check clean after skipping only the unrelated,
    pre-existing OPENAB_AGENT_AUTH_COMMAND secret-name heuristic.
  • Package-pin parity assertions and git diff --check: pass.

Review Contract

Goal

Provide a daily and manually dispatchable nightly channel that is a drop-in image replacement
for each supported agent variant, packages the vendor's latest CLI, allows healthy variants to
publish independently, and leaves pinned release/pre-beta behavior unchanged. Nightly explicitly
has no compatibility guarantee.

Non-goals

  • It is not a stable release, SemVer promise, or compatibility/support commitment.
  • It does not alter release or pre-beta-* tags, pinned versions, or pinned SHA defaults.
  • It does not cover native, agentcore, or the currently broken pi package target (fix(docker): pi target sets OPENAB_AGENT_COMMAND=openab-agent but never ships that binary #1520).
  • It does not provide a runtime smoke test for every vendor CLI; Kiro receives a targeted native
    version check because its vendor offers only a mutable latest URL.
  • It does not publish canonical tags from non-main workflow dispatches.

Accepted Residual Risks

  • Vendor-latest compatibility: a vendor may publish a behaviorally incompatible CLI. The
    affected variant fails its build or advances its moving tag; recovery is pinning the previous
    attempt-unique rollback tag.
  • Grok/Antigravity nightly integrity: those vendors do not expose a usable digest in the
    current resolution path. Nightly relies on TLS and empty SHA overrides for these two variants.
    This does not weaken release/pre-beta because their non-empty pinned SHAs remain the defaults.
  • Partial cohorts: independent publication intentionally permits some variants to advance
    while another remains on yesterday's tag. The failed variant's red resolver/build/tag is the
    alert; successful variants are not withheld.
  • No general runtime gate: successful packaging does not guarantee a vendor CLI remains ACP
    compatible. This is part of the channel's explicit no-guarantee contract.

Acceptance Criteria

  • A scheduled run from main can publish moving and attempt-unique multi-arch tags for every
    selected supported variant; a non-main dispatch cannot publish.
  • One failed vendor resolver does not skip other variants' build matrix children. Each child
    proceeds only when its exact resolve artifact exists, and each tag requires its own two valid
    architecture digests.
  • Kiro downloads are bound to the once-resolved per-architecture ETags with If-Match; both
    installed kiro-cli --version reports must match before its manifest is created.
  • Manual variant input rejects unknown, duplicate, and every empty-field shape, including
    ,kiro, kiro,,claude, and kiro,.
  • Antigravity and Hermes GitHub API lookups use the authenticated helper.
  • Empty SHA args skip verification only for the explicit nightly paths; non-empty release and
    pre-beta defaults still fail on checksum mismatch, and pin-parity validation remains green.
  • Workflow YAML/action expressions and embedded shell pass actionlint/shellcheck; Dockerfile
    syntax, package-pin parity, and whitespace validation pass.

Follow-ups

  • Fix the existing pi package target and re-add it to nightly (fix(docker): pi target sets OPENAB_AGENT_COMMAND=openab-agent but never ships that binary #1520).
  • Add broader per-variant runtime smoke tests if the nightly channel needs stronger operational
    guarantees than its current build gate.
  • Replace Grok/Antigravity TLS-only nightly downloads with vendor-published digests if suitable
    metadata becomes available.
  • Add user-facing image-channel documentation after the channel's first successful production run.

Add a scheduled nightly image build that publishes drop-in images per
agent variant carrying each vendor's latest CLI. Unlike the release and
pre-beta lanes — which pin every CLI version (and SHA256) as a build
ARG and therefore republish the same CLI on every rebuild — this lane
resolves each vendor's latest version each morning and passes it as a
build-arg override to Dockerfile.package.

Nightly is a drop-in channel with no compatibility guarantee. It favors
freshness over cohort atomicity: variants build independently
(fail-fast: false), so one vendor breaking their latest does not hold
back the rest. Tags: nightly-<variant> (moving) plus
nightly-YYYYMMDD-<run-id>-<variant> (immutable rollback). native and
agentcore are excluded — they carry no agent CLI to freshen.

To let SHA-pinned variants (kiro, grok, devin, antigravity) move to an
unknown-ahead-of-time version, Dockerfile.package now skips the
sha256sum check when the SHA build-arg is empty. This is inert for the
release/pre-beta path, which still passes its pinned SHAs and stays
verified; devin and hermes resolve their SHA from the vendor and keep
the check enabled. antigravity's AGY_VERSION becomes an ARG (re-exported
as ENV) so it is build-arg overridable.
@chaodu-obk

This comment has been minimized.

@chaodu-obk

This comment has been minimized.

@chaodu-obk chaodu-obk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

CHANGES REQUESTED ⚠️ - One Critical and seven Important findings block this nightly publication workflow.

Consolidated review: #1519 (comment)

Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml
Comment thread .github/workflows/nightly-build.yml
Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml
Comment thread Dockerfile.package Outdated
Address independent review findings:

- Resolve each vendor's latest version once per variant in a dedicated
  resolve job (matrix over variants only) instead of independently in
  each variant×arch build leg. amd64 and arm64 now consume the same
  resolved version via a per-variant artifact, so a vendor publishing
  mid-run can no longer produce a mixed multi-arch manifest. devin now
  resolves both per-arch sha256 digests up front.
- Surface the resolved CLI version in the tag job step summary.
- Hash the hermes installer via the authenticated GitHub Contents API
  (raw+json) for the resolved commit, matching the release fetch and
  dodging shared-runner 429s on raw.githubusercontent.com.
- Harden the dispatch variant allowlist check with grep -qF.
@chaodu-agent

This comment has been minimized.

- F1: drop pi from the nightly matrix. Its package/unified target sets
  OPENAB_AGENT_COMMAND=openab-agent but never ships that binary (a
  pre-existing bug in all lanes), so nightly-pi would publish a
  runtime-broken image. Excluded until the pi target is fixed.
- F2: let each variant publish independently after a peer failure. tag
  now runs with always() && !cancelled() and tags only when its own two
  digests are present; a failed build leg fails just that variant's tag.
- F3: restrict canonical publication to the default branch. build and
  tag gate on github.ref == refs/heads/main, so a workflow_dispatch from
  a feature branch validates (matrix/compile/resolve) without publishing.
- F5: append GITHUB_RUN_ATTEMPT to the immutable rollback tag so a re-run
  (which re-resolves mutable versions) cannot move a tag documented
  immutable.
- F7: parse the manual variant input once into a normalized, validated,
  de-duplicated list; reject empty elements and duplicates before the
  matrix JSON is produced.
- F8: surface the effective antigravity version as an image label
  (dev.openab.agy.version) so inspect reflects the installed version,
  while the parity-checked ENV AGY_VERSION stays pinned.

F4 (resolve once per variant) and F6 (devin digest format validation)
were already addressed in the prior commit.
@chaodu-agent

This comment has been minimized.

@chaodu-obk

This comment has been minimized.

@chaodu-obk chaodu-obk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

CHANGES REQUESTED ⚠️ - One Critical and three Important findings block independent, reproducible nightly publication.

Consolidated review: #1519 (comment)

Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml
Comment thread .github/workflows/nightly-build.yml Outdated
Comment thread .github/workflows/nightly-build.yml
- allow build matrix children to run after a peer resolver failure while
  still requiring the shared matrix and compile prerequisites
- resolve Kiro latest objects to strong per-arch ETags, enforce them with
  If-Match during download, and require both installed CLI versions to
  match before creating the multi-arch manifest
- use the authenticated GitHub API helper for Antigravity releases
- reject leading, interior, trailing, and whitespace-only variant fields
- replace digest word-splitting with a quoted array
@chaodu-agent

Copy link
Copy Markdown
Collaborator Author

Response to review on e6e192c

All four findings from the latest review, plus the stale canonical Review Contract identified during re-review, are addressed in 4b0f874.

Finding Resolution
F1 — one resolver failure suppresses every build build now overrides the default needs success gate with always() && !cancelled(), while still requiring successful shared matrix/compile jobs. Each matrix child downloads its exact nightly-resolve-<variant> artifact; only the failed resolver's two build children fail, while sibling variants continue. tag already runs status-aware and requires only its own two digests.
F2 — Kiro remains mutable per architecture The resolver now captures and validates each latest object's strong ETag once. Dockerfile.package sends quoted If-Match on the native download, so content drift fails HTTP 412. After push-by-digest, each native architecture runs kiro-cli --version and uploads a report; the Kiro tag job requires both reports to exist and match before manifest creation. Live verification: matching ETag → 206, wrong ETag → 412.
F3 — Antigravity bypasses authenticated helper Release lookup now uses github_api; the exact resolver was executed successfully and resolved 1.1.24.
F4 — trailing empty selector accepted Raw comma shapes are rejected before Bash field splitting, then trimmed elements are validated/deduplicated. The exact script rejects ,kiro, kiro,,claude, kiro,, kiro, , and duplicates; valid normalized subsets and all pass.
Canonical Review Contract stale PR description and all five contract sections now reflect the resolve job, main-only publication, pi exclusion, attempt-unique tag, Antigravity override/label, Kiro ETag+version gate, current accepted risks, and current acceptance criteria.

Additional validation: actionlint + shellcheck clean; BuildKit Kiro-target check clean (skipping only an unrelated pre-existing secret-name heuristic); exact Kiro and Antigravity resolvers pass; Kiro equal/mismatch comparison tests pass/fail as intended; package-pin parity and git diff --check pass.

@chaodu-agent

Copy link
Copy Markdown
Collaborator Author

/review

@chaodu-obk

This comment has been minimized.

@chaodu-obk chaodu-obk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

CHANGES REQUESTED ⚠️ - Two important findings remain at the shared checksum-policy boundary and in Antigravity runtime version metadata.

Consolidated review: #1519 (comment)

Comment thread Dockerfile.package Outdated
Comment thread Dockerfile.package Outdated
@chaodu-obk

chaodu-obk Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Note

LGTM ✅ - The exact-head fix closes both prior blockers with fail-closed checksum policy and one authoritative Antigravity version source; independent review and remote CI are green.

What This PR Does

This PR adds a scheduled and manually dispatchable nightly-* image channel for 13 vendor CLI variants. It compiles OpenAB once per architecture, resolves each vendor once, builds architecture-specific images by digest, and publishes moving plus attempt-unique rollback tags while preserving pinned release and pre-beta defaults.

How It Works

A strict selector creates the variant matrix. Shared binaries are compiled for amd64 and arm64, per-variant resolver artifacts feed the build matrix, and each tag job requires its own two valid image digests. Kiro binds mutable downloads to resolved strong ETags and requires matching installed versions across architectures. Grok and Antigravity may use the accepted TLS-only nightly path only through an explicit default-false opt-in.

Findings

# Severity Finding Location
F1 🟢 Praise Empty SHA values now fail closed by default: Kiro requires SHA256 or ETag, Devin always verifies SHA256, and only Grok/Antigravity expose the explicit nightly-only opt-in. Dockerfile.package:72-76, :240-244, :346, :383-387
F2 🟢 Praise One AGY_VERSION argument now drives the download URL, persisted runtime environment, image label, and pinned-default parity contract. Dockerfile.package:366-381
F3 🟢 Praise Regression assertions constrain opt-in declarations and uses, all review lanes reported no blockers, and the full remote check matrix is green. .github/workflows/docker-smoke-test.yml:161-195
Resolved Finding Details

🟢 F1: Shared checksum policy now fails closed

The shared package Dockerfile no longer interprets an empty SHA as implicit authorization. Kiro accepts an empty SHA only when its once-resolved ETag is present. Grok and Antigravity declare ALLOW_UNVERIFIED_NIGHTLY_DOWNLOADS=false and proceed without a SHA only when the nightly resolver explicitly passes true. Devin returned to unconditional sha256sum -c verification. Static regression assertions require exactly two declarations, two nightly opt-ins, the Kiro ETag guard, and the unconditional Devin check.

🟢 F2: Antigravity metadata has one source of truth

ARG AGY_VERSION=1.1.13 is the stable default and the only version input. It feeds ENV AGY_VERSION, dev.openab.agy.version, and the download URL. Nightly overrides that same argument with the resolved version, so runtime environment, label, and installed binary no longer split across separate values. Pin parity now checks the default argument while preserving legacy pinned-image behavior.

Baseline Check
  • PR opened: 2026-09-02
  • Reviewed head: de0a3ca1b12d9f3ecee388ea7de509dde17a067a
  • Declared base: main
  • Merge base: d4f376f670982b2c93d5f58fddc2422fb19dd924
  • Diff: 3 files, 644 insertions, 6 deletions
  • Main already has: pinned release and pre-beta package lanes using Dockerfile.package
  • Net-new value: a daily vendor-latest channel with per-variant failure isolation, explicit integrity modes, moving tags, and attempt-unique rollback tags

Addressing Inline and External Reviewer Feedback

Prior inline findings

Empty SHA values disable checksum verification for any caller of the shared package targets.

Addressed in de0a3ca1: empty SHA now fails unless Kiro has a resolved ETag or the Grok/Antigravity target receives the explicit default-false nightly opt-in. Devin is again unconditional. Independent exact-SHA verification and the new regression assertions confirm the requested behavior.

Nightly Antigravity installs an override while persisting the pinned AGY_VERSION=1.1.13.

Addressed in de0a3ca1: the override/effective split was removed. One AGY_VERSION argument now drives download, ENV, label, and parity validation. Independent exact-SHA verification found no residual references to the removed variables.

All earlier workflow findings remain resolved: pi is excluded pending #1520, publication is main-only, resolver/build failures are isolated per variant, resolution occurs before architecture fan-out, rollback tags include the run attempt, Devin digests are validated, selector edge cases are rejected, Kiro is ETag/version gated, and GitHub API resolver calls are authenticated.

Contributor and prior review feedback

The pinned lanes keep non-empty defaults, while nightly intentionally relaxes integrity for vendors without usable digests.

Accepted and hardened: the accepted Grok/Antigravity TLS-only risk remains, but the relaxation is now explicit and fail-closed for every other caller. Release and pre-beta defaults remain pinned and verified.

The fix should preserve release/pre-beta behavior while making nightly metadata truthful.

Verified: pin-parity validation is green, legacy images retain their pinned defaults, and the nightly Antigravity image now persists the resolved effective version through the same argument used for installation.

Validation

  • Verified exact head, declared base, merge base, and the complete local diff.
  • git diff --check passed on the fix commit and the full base-to-head range.
  • Local targeted checks passed for package pin parity, policy counts, Kiro SHA-or-ETag behavior, exact Grok/Antigravity opt-in behavior, unconditional Devin verification, and removed stale Antigravity variables.
  • Independent reviewers executed the committed regression assertions and boundary cases; all reported LGTM with no blocking findings.
  • All 23 reported check runs completed successfully or were intentionally skipped, including Review Contract validation, validate-packaged-pins, and every image smoke job.
  • Hermes smoke attempts 1 and 2 hit an unrelated raw.githubusercontent.com HTTP 429 in unchanged code; attempt 3 passed after cooldown with no source change.

Review Coverage

Review lane Outcome
Reviewer A - architecture LGTM; prior checksum and metadata blockers verified resolved
Reviewer B - readability LGTM; exact-whitespace assertion coupling retained only as a non-blocking observation
Reviewer C - independent fix verification LGTM; all policy, metadata, and regression boundaries passed
Reviewer D - simplicity LGTM; explicit fail-closed opt-in accepted without a separate Dockerfile
Coordinator - correctness and CI LGTM; local checks and full remote CI verified

Non-blocking Follow-ups

  • Replace the exact-whitespace workflow assertion with a formatting-independent occurrence check when the resolver block is next refactored.
  • Consider a declarative variant capability manifest if the nightly matrix continues to expand.
  • Add uniform installed-version/integrity metadata and user-facing nightly documentation as the channel matures.
  • Add needs.matrix.result == 'success' to the tag job for cleaner invalid-input failure UX.
What's Good (🟢)
  • Integrity relaxation is explicit, target-limited, and fail-closed by default.
  • Antigravity version metadata and installed content now share one source of truth.
  • Kiro's mutable URLs are bound by ETags and a cross-architecture installed-version gate.
  • Resolver/build failures do not withhold successful sibling variants.
  • Canonical publication is restricted to main, and rollback tags are attempt-unique.
  • Permissions remain least-privilege, and error messages are specific and actionable.

Three Reasons We Might Not Need This PR

  1. Reviewed pin-update PRs may be safer - Automated version-and-digest updates could reuse existing pinned lanes and preserve reviewable reproducibility.
  2. Demand and support value remain unproven - The channel adds daily multi-architecture cost while explicitly carrying no compatibility guarantee.
  3. The maintenance surface is broad - Thirteen vendor resolvers and duplicated orchestration can drift; a declarative registry or reusable workflow may be a better long-term design.

chaodu-obk[bot]
chaodu-obk Bot previously approved these changes Sep 3, 2026

@chaodu-obk chaodu-obk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

LGTM ✅ - The exact-head fix closes both prior blockers; independent verification and the full remote check matrix are green.

Consolidated review: #1519 (comment)

@thepagent
thepagent merged commit f46764a into main Sep 3, 2026
42 of 43 checks passed
chaodu-agent added a commit that referenced this pull request Sep 3, 2026
Follow-up to #1519 addressing review findings from Sol and Fable:

- F1: accept multipart S3 ETags (<md5>-<partcount>) in the Kiro
  latest-object validation. The ~586MB object sits at the multipart
  boundary; a future re-upload flipping its ETag to the suffixed form
  would otherwise hard-fail every nightly-kiro build with no SHA
  fallback. If-Match accepts multipart ETags, so both shapes are valid.
- #2: use `grep -m1` instead of `grep | head -1` in the cursor
  resolver to avoid the SIGPIPE (exit 141) that head-closing-the-pipe
  triggers under pipefail, which surfaced as a spurious red job.
- F5: correct the misleading no-cache comment — no-cache rebuilds every
  Dockerfile.package layer for the variant, not just the CLI layer; the
  openab binary is not recompiled (prebuilt via the bins= context).
thepagent pushed a commit that referenced this pull request Sep 3, 2026
Follow-up to #1519 addressing review findings from Sol and Fable:

- F1: accept multipart S3 ETags (<md5>-<partcount>) in the Kiro
  latest-object validation. The ~586MB object sits at the multipart
  boundary; a future re-upload flipping its ETag to the suffixed form
  would otherwise hard-fail every nightly-kiro build with no SHA
  fallback. If-Match accepts multipart ETags, so both shapes are valid.
- #2: use `grep -m1` instead of `grep | head -1` in the cursor
  resolver to avoid the SIGPIPE (exit 141) that head-closing-the-pipe
  triggers under pipefail, which surfaced as a spurious red job.
- F5: correct the misleading no-cache comment — no-cache rebuilds every
  Dockerfile.package layer for the variant, not just the CLI layer; the
  openab binary is not recompiled (prebuilt via the bins= context).

Co-authored-by: chaodu-agent <chaodu-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants