From 36c7d8f9052ce09ba66fccf597ce8ed2368a8d1d Mon Sep 17 00:00:00 2001 From: Joshua Temple Date: Tue, 30 Jun 2026 21:45:32 -0400 Subject: [PATCH 1/2] docs(configuration): document action_pins, pin_mode, release_trigger, validate_check, merge_queue Signed-off-by: Joshua Temple --- docs/src/content/docs/configuration.md | 77 ++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/src/content/docs/configuration.md b/docs/src/content/docs/configuration.md index a67e7fa..1bbda2a 100644 --- a/docs/src/content/docs/configuration.md +++ b/docs/src/content/docs/configuration.md @@ -85,6 +85,9 @@ ci: | `cli_version` | string | No | latest | CLI version: `latest`, `beta`, or specific version (e.g., `v2.0.4`) | | `cli_version_sha` | string | No | - | 40-hex commit SHA that `cli_version` resolves to. With `pin_mode: sha`, the generated setup-cli ref is pinned to this commit. See [cli_version_sha](#cli_version_sha). | | `triggers` | list | No | - | Global path patterns that activate orchestration | +| `release_trigger` | string | No | `push` | How the orchestrate workflow fires. `push` keeps the push-on-trunk plus `workflow_dispatch` triggers; `dispatch` drops the `push:` trigger so releases run only on manual `workflow_dispatch`. See [Release trigger](#release-trigger). | +| `pin_mode` | string | No | `tag` | Third-party action pin policy. `tag` emits `@`; `sha` emits `@` with the version as a trailing comment. See [Action pinning](#action-pinning). | +| `action_pins` | map | No | - | Per-action ref overrides keyed by action path (e.g. `actions/checkout`), applied regardless of `pin_mode`. See [Action pinning](#action-pinning). | | `tag_prefix` | string | No | `v` | Version tag prefix | | `release_token` | string | No | `state_token` if set, else `${{ secrets.GITHUB_TOKEN }}` | Token expression for release API calls and the rc tag; inherits `state_token` when unset so the rc-to-release chain has a trigger-capable token | | `state_token` | string | No | `${{ secrets.GITHUB_TOKEN }}` | Token expression for writing manifest state to the trunk branch | @@ -124,6 +127,46 @@ The `with: version:` input the action reads to select the release asset stays th This closes the supply-chain gap where the cascade self-action was referenced by a mutable tag while third-party actions were already SHA-pinned. The field is optional and only takes effect under `pin_mode: sha`; leave it unset (or use the default `pin_mode: tag`) to keep the tag-based ref. Set `cli_version_sha` alongside `cli_version` whenever you bump the pinned version. Because cascade release tags are annotated, resolve the underlying commit (not the tag object) with `git ls-remote https://github.com/stablekernel/cascade 'refs/tags/^{}'`. +### Release trigger + +`release_trigger` selects how the generated orchestrate workflow fires. It is opt-in; repos that leave it unset keep the push triggers. + +| Value | Behavior | +|-------|----------| +| `push` | Default. Orchestrate fires on trunk pushes (filtered by `triggers:`) plus `workflow_dispatch`. | +| `dispatch` | Drops the `push:` trigger so orchestrate runs only on `workflow_dispatch`, letting a maintainer-owned gate decide when a release candidate is cut. | + +```yaml +ci: + config: + release_trigger: dispatch +``` + +### Action pinning + +cascade governs how the third-party actions it emits into your workflows (for example `actions/checkout` and `actions/github-script`) are referenced. Two fields control the policy. + +`pin_mode` sets the reference style for every third-party action cascade emits: + +| Value | Behavior | +|-------|----------| +| `tag` | Default. Emits `@` (for example `actions/checkout@v4`). Never `@latest`. | +| `sha` | Emits `@ # `, pinning each action to an immutable commit with the human-readable version as a trailing comment. Under `sha`, pair `cli_version` with [`cli_version_sha`](#cli_version_sha) so the cascade self-action ref is pinned too. | + +The default `sha` values come from a single committed pin table (`internal/generate/action_pins.yaml`); no per-repo configuration is needed to adopt SHA pinning beyond setting `pin_mode: sha`. + +`action_pins` overrides the built-in table for individual actions, keyed by action path. An override is applied regardless of `pin_mode`, so use it to point at a fork or an org-mirrored action: + +```yaml +ci: + config: + pin_mode: sha + action_pins: + actions/checkout: my-org/checkout@0123456789abcdef0123456789abcdef01234567 +``` + +An action that is neither in the built-in table nor overridden is emitted unchanged. + ### Token authentication Two seams call GitHub on cascade's behalf: `release_token` for release API calls and `state_token` for writing manifest state back to the trunk branch. Both default to `${{ secrets.GITHUB_TOKEN }}`, which is enough for a single-repo project whose trunk is unprotected. When the default token cannot do the job, supply your own token through one of two paths: a static secret (PAT) or a GitHub App. @@ -554,6 +597,40 @@ Behavior: - **Least-privilege scope.** The toggle adds `deployments: write` to the workflow's top-level permissions only when enabled; the OFF-state output is unchanged. - **Opt-in and additive.** Omit `deployments` and nothing is emitted. The field did not bump `schema_version`. +### Validate-check workflow (opt-in) + +Set `validate_check.enabled: true` and `generate-workflow` emits a lightweight `pull_request` workflow (`.github/workflows/cascade-validate.yaml`) that runs [`cascade parse-config`](/cli-reference/#parse-config) against the manifest and fails the check when the configuration is invalid, so a malformed manifest cannot merge to trunk. + +```yaml +ci: + config: + validate_check: + enabled: true +``` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | bool | false | Emit the manifest-validation PR check (`.github/workflows/cascade-validate.yaml`) | + +The check validates cascade's own configuration only. It does not run the repository's build or test suites, requests `contents: read` alone, and has no dry-run or comment side effects. + +### Merge-queue workflow (opt-in) + +Set `merge_queue.enabled: true` and cascade emits a `merge_group`-triggered workflow (`.github/workflows/cascade-merge-queue.yaml`) that validates the prospective trunk commit: it runs `cascade parse-config` as a validity gate and a dry-run `cascade orchestrate setup` to preview the build and deploy decisions against the merge-group candidate ref. + +```yaml +ci: + config: + merge_queue: + enabled: true +``` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enabled` | bool | false | Emit the merge-queue validation lane (`.github/workflows/cascade-merge-queue.yaml`) | + +The lane is read-only: no state writes, no releases, no deploys. It reports a status the merge queue can require. This generator owns the lane behavior; the raw `merge_group` trigger itself is expressible separately under `extra_triggers.merge_group`, and the two are intentionally distinct. + ## State Section The `state` section tracks deployment state per environment plus a synthetic `release` slot. The framework manages it automatically. Do not hand-edit. From ee2dbe5c12a03fad4aa7ecc891b900687b33ed53 Mon Sep 17 00:00:00 2001 From: Joshua Temple Date: Tue, 30 Jun 2026 21:53:16 -0400 Subject: [PATCH 2/2] docs(configuration): correct action_pins override to a bare ref Signed-off-by: Joshua Temple --- docs/src/content/docs/configuration.md | 6 +++--- internal/generate/action_pins.go | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/src/content/docs/configuration.md b/docs/src/content/docs/configuration.md index 1bbda2a..edc48ea 100644 --- a/docs/src/content/docs/configuration.md +++ b/docs/src/content/docs/configuration.md @@ -155,17 +155,17 @@ cascade governs how the third-party actions it emits into your workflows (for ex The default `sha` values come from a single committed pin table (`internal/generate/action_pins.yaml`); no per-repo configuration is needed to adopt SHA pinning beyond setting `pin_mode: sha`. -`action_pins` overrides the built-in table for individual actions, keyed by action path. An override is applied regardless of `pin_mode`, so use it to point at a fork or an org-mirrored action: +`action_pins` overrides the built-in ref for individual actions, keyed by action path. The map value is the bare ref emitted after `@` for that same action path (a tag or a commit SHA); it cannot repoint an action to a different owner or repository. An override is applied regardless of `pin_mode`, so use it to hold an action at a known-good commit or tag: ```yaml ci: config: pin_mode: sha action_pins: - actions/checkout: my-org/checkout@0123456789abcdef0123456789abcdef01234567 + actions/checkout: 0123456789abcdef0123456789abcdef01234567 ``` -An action that is neither in the built-in table nor overridden is emitted unchanged. +That emits `uses: actions/checkout@0123456789abcdef0123456789abcdef01234567`. An action that is neither in the built-in table nor overridden is emitted unchanged. ### Token authentication diff --git a/internal/generate/action_pins.go b/internal/generate/action_pins.go index 0f9cd3f..f0b4e10 100644 --- a/internal/generate/action_pins.go +++ b/internal/generate/action_pins.go @@ -116,8 +116,10 @@ func mustParseActionPins(data []byte) map[string]actionPin { // uniformly and no ref is missed. // // Resolution order: -// 1. config.action_pins[action]: explicit per-action override (any ref/sha), -// applied regardless of pin_mode. Use this for forks or org-mirrored actions. +// 1. config.action_pins[action]: explicit per-action ref override (a tag or +// sha), applied regardless of pin_mode. The override is the bare ref after +// "@" for the same action path; it cannot repoint to a different owner/repo. +// Use it to hold an action at a known-good commit or tag. // 2. pin_mode: sha: emit @ # from the built-in table. // 3. pin_mode: tag (default): emit @, today's behavior, never // @latest for a third-party action.