Skip to content

feat(generate): add --cli-install=binary for allowlist-free CLI install#653

Merged
joshua-temple merged 1 commit into
mainfrom
feat/cli-install-binary-mode
Jul 21, 2026
Merged

feat(generate): add --cli-install=binary for allowlist-free CLI install#653
joshua-temple merged 1 commit into
mainfrom
feat/cli-install-binary-mode

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Closes #651.

Problem

Generated workflows install the CLI via uses: stablekernel/cascade/.github/actions/setup-cli@<ref>, a third-party action. Organizations that run a GitHub Actions allowlist must approve it before any generated pipeline can run, which is an adoption barrier. A shell-based binary fetch is not a third-party action and does not hit the allowlist.

Fix

generate-workflow gains --cli-install=action|binary (default action), threaded as a generator option (mirrors --own-repo; not a manifest field).

  • action (default): unchanged, byte-identical output.
  • binary: emits a self-contained run: install with no third-party uses: at all. Token and version pass through env (never spliced into the script, so no parse-time ${{ }}). It resolves latest to a concrete tag, detects OS/arch, installs cosign by pinned checksum-verified direct download (not the installer action), then runs the action's install.sh verbatim (embedded via //go:embed, kept in sync by a byte-identity guard test). This preserves the exact verification the action performs: mandatory sha256 gate plus keyless cosign verify, with the same loud sha256-only fallback. First-party actions/* are untouched.

Same security posture as the action, without requiring an org action-allowlist entry. Verification steps are documented in security.md#verifying-cascade-releases, which the new docs link.

Verification

  • go build ./..., go test ./... (3665 pass), go test -race ./internal/generate/... ./internal/setupcli/... (944 pass), golangci-lint run ./... all clean.
  • generate-workflow --own-repo regeneration: zero drift (action mode unchanged).
  • Emitted binary-mode YAML is actionlint-clean; executed verify gates stay covered by internal/setupcli running the real install.sh (tied to the emitted copy by the byte-identity guard).
  • No e2e scenario: act+gitea cannot fetch real releases or run cosign, so a binary-mode install cannot execute hermetically; asserting it would prove nothing. Coverage is emitted-text + actionlint + the hermetic setupcli suite (documented in the test rationale).

Docs updated: CLI reference, getting-started, README.

…CLI install

generate-workflow gains a --cli-install flag (action|binary, default
action). In binary mode every generated setup-cli step is a self-contained
run: step that uses no third-party action: it resolves the release tag,
detects OS/arch, installs a checksum-verified cosign by direct download, and
runs the same mandatory sha256 gate and keyless cosign verification the
composite action performs. The verify logic lives in one install.sh, embedded
and emitted inline, so both modes share a single contract. This lets a repo
adopt cascade without an organization Actions allowlist entry.

Default action mode is byte-identical to before (zero drift).

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
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.

Offer an allowlist-free CLI install mode (binary fetch) as a generator flag

1 participant