Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/actions/cut-release/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: cut-release
description: >-
Cuts a deploy repo's release snapshot: regenerates the rolling src/generated/candidate/ pins from the current source, formats, and only then freezes a byte-identical copy as src/generated/<tag>/ for the foundry.toml [package].version. The ordering is the reason this is a tool and not a consumer script — freezing before regenerating writes a stale candidate into a dir the frozen-snapshots-append-only gate protects forever while the regeneration moves candidate on, so the release publishes one address and permanently records another, and nothing downstream compares the two. Refuses a version that is not strict X.Y.Z (its tag dir would be invisible to that gate — an orphan snapshot nothing protects), a missing or empty candidate, and any tag dir that already exists.
inputs:
generate-cmd:
description: >-
Command that regenerates src/generated/candidate/ from the current source. Empty (the default) uses the org convention, `forge script ./script/BuildPointers.sol`. This is the ONLY repo-specific part of the freeze; everything else — the version read, the guards, the format, the copy and the byte-identity assertion — is the same everywhere and lives in rainix-static. It runs strictly BEFORE the freeze, so the inverted order cannot be expressed through it.
required: false
default: ''
runs:
using: composite
steps:
- name: Cut the release snapshot
shell: bash
env:
# Via env, not interpolated into the script body: a `with:` value spliced
# into `run:` text is a template-injection surface, and the binary reads
# it as a single argv element either way.
RAINIX_GENERATE_CMD: ${{ inputs.generate-cmd }}
run: |
set -euo pipefail
# Single source of truth: the Rust rainix-static binary (its unit tests
# run inside the nix build). The path: flake ref runs it — and the forge
# it drives, from the same sol-shell — out of this composite's own
# checkout, so the freeze logic always matches the action version
# regardless of any RAINIX_SHA the caller pins, and a new subcommand is
# usable the moment the action lands rather than after a sha bump. A
# path: ref also makes no api.github.com call, so it cannot hit the 429
# that pinning exists to avoid.
nix develop "path:$(cd "$GITHUB_ACTION_PATH/../../.." && pwd)#sol-shell" -c \
rainix-static cut-release --generate-cmd "$RAINIX_GENERATE_CMD"
31 changes: 23 additions & 8 deletions .github/workflows/rainix-tag-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ on:
required: false
type: string
default: sol-v
snapshot-generate-cmd:
pointers-generate-cmd:
description: >-
Command that regenerates the deploy-pin snapshot from the (deterministic) bytecode into src/generated/<tag>/, DEPLOY_TAG and any pointer libs, then formats. Run after [package].version is set to the release version, so the generated tag matches it. e.g. `forge script ./script/BuildPointers.sol && forge fmt`.
required: true
Command that regenerates the rolling `src/generated/candidate/` pins from the current source, e.g. `forge script ./script/BuildPointers.sol` — which is also the default when this is empty, so a repo following the convention passes nothing. This is the ONLY repo-specific part of a release freeze: the version read, the guards, the format, the copy into `src/generated/<tag>/` and the byte-identity assertion are identical everywhere and live in `rainix-static cut-release`. It is deliberately a GENERATE command, not a freeze script — it runs strictly before the freeze, so the freeze-then-regenerate order (which permanently records an address the release does not publish) cannot be expressed.
required: false
type: string
default: ''
test-cmd:
description: >-
Pre-publish verification gate. Run against the regenerated snapshot; for a deploy repo this is the fork suite that reads the live chain and asserts it matches the fresh pins, so a release that snapshots addresses the chain does not actually carry fails loud BEFORE publishing. Default `forge test`.
Expand Down Expand Up @@ -196,11 +197,25 @@ jobs:
echo "::error::foundry.toml has no [package] version line to set to ${VERSION}" >&2
exit 1
}
- name: Regenerate the deploy-pin snapshot
# Deterministic: the pins are computed from bytecode (address = f(bytecode)
# under CREATE2), so this needs no chain access and produces the exact
# src/generated/<tag>/ the release publishes and commits.
run: nix develop github:rainlanguage/rainix/${{ env.RAINIX_SHA }}#sol-shell -c bash -c '${{ inputs.snapshot-generate-cmd }}'
- name: Cut the release snapshot
# Regenerate the rolling candidate pins, format, then freeze a
# byte-identical copy as src/generated/<tag>/. Deterministic: the pins are
# computed from bytecode (address = f(bytecode) under CREATE2), so this
# needs no chain access and produces the exact snapshot the release
# publishes and commits.
#
# The ORDER is the reason this is a rainix tool rather than a consumer
# script (rainlanguage/rainix#301). Freezing before regenerating writes a
# drifted candidate into an append-only dir while the regeneration moves
# candidate on, so the release publishes one address and permanently
# records another — invisible downstream, because the repo's
# self-consistency test checks the REGENERATED candidate against source and
# nothing compares a numbered dir to candidate. The consumer supplies only
# the generate command, which runs strictly first, so the inversion has
# nowhere to live.
uses: rainlanguage/rainix/.github/actions/cut-release@main
with:
generate-cmd: ${{ inputs.pointers-generate-cmd }}
- name: Commit the release snapshot
# Commit BEFORE the append-only gate and Soldeer push so both operate on a
# clean, inspectable tree. The commit is what lands on main below.
Expand Down
Loading
Loading