ci: move Nix workflows to the self-hosted ARM runner + warm cache for aarch64-linux#1793
Conversation
release-rs, release-js, release-py (build), and update-flake all use Nix and produce architecture-independent output (crates.io publish, npm/JSR publish, pure-python wheel, flake.lock update), so they can run on the moq-dev self-hosted A1 (aarch64) runner with its warm /nix/store instead of a GitHub-hosted runner. These trigger only on trusted events (push to main, tag, schedule, dispatch), so unlike check.yml they need no fork fallback. Per the established self-hosted pattern: drop the nix-installer-action (the box already has Nix) and run Nix steps in a login shell so /etc/profile.d puts Nix on PATH. release-rs also reuses the persistent CARGO_TARGET_DIR. update-flake's update-flake-lock action invokes nix directly rather than through a shell, so it gets a step that resolves nix via a login shell and writes its dir to GITHUB_PATH, plus an owner guard so a fork's manual dispatch doesn't queue forever on a runner that doesn't exist. Left arch-specific workflows alone: cachix (caches x86_64-linux), the per-binary release builds, libmoq, and release-py-ffi. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an aarch64-linux matrix leg to the cachix release job, built on the moq-dev self-hosted A1 (the cache previously covered only x86_64-linux and aarch64-darwin). Tag pushes are trusted, so no fork concern. The matrix moves to `include` so each leg carries its own `runs-on` (string for the hosted runners, [self-hosted, nix] for the box) while `os` stays the cache pin label, keeping existing pins stable. Self-hosted adjustments: gate the nix-installer on github-hosted (the box has Nix), add Nix to PATH via a login shell for the cachix action and `nix build`, and set skipAddingSubstituter on self-hosted. The box's runner user isn't a Nix trusted-user and it substitutes only from its warm local store, so `cachix use` must not rewrite nix.conf there; push auth is unaffected and this leg only pushes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughAll five GitHub Actions workflows (release-js, release-py, release-rs, update-flake, cachix) are updated to run on self-hosted Nix runners instead of 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/release-js.yml (1)
24-24: ⚡ Quick winInconsistent
if:syntax across workflows.This file uses a bare
if:condition without${{ }}delimiters, while the other three workflows in this PR (release-py.yml,release-rs.yml,update-flake.yml) wrap the identical condition in${{ }}. Both syntaxes are valid, but consistency improves maintainability.♻️ Standardize syntax
- if: github.repository_owner == 'moq-dev' + if: ${{ github.repository_owner == 'moq-dev' }}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release-js.yml at line 24, The `if:` condition on line 24 uses bare syntax without `${{ }}` delimiters, which is inconsistent with the identical conditions in the other workflow files (release-py.yml, release-rs.yml, update-flake.yml). Wrap the condition `github.repository_owner == 'moq-dev'` with `${{ }}` delimiters to standardize the syntax across all workflows and improve maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/update-flake.yml:
- Around line 21-22: The checkout action in the "Checkout" step does not
explicitly disable credential persistence, which means the GITHUB_TOKEN will be
available to all subsequent workflow steps by default. Add the
`persist-credentials: false` option to the `actions/checkout` configuration to
ensure credentials are not persisted in the git config, following the principle
of least privilege and matching the pattern used in the other workflows. This
ensures the `update-flake-lock` action uses only its own authentication
mechanism.
---
Nitpick comments:
In @.github/workflows/release-js.yml:
- Line 24: The `if:` condition on line 24 uses bare syntax without `${{ }}`
delimiters, which is inconsistent with the identical conditions in the other
workflow files (release-py.yml, release-rs.yml, update-flake.yml). Wrap the
condition `github.repository_owner == 'moq-dev'` with `${{ }}` delimiters to
standardize the syntax across all workflows and improve maintainability.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8f372179-f308-43a9-b1f2-ad7f98738a16
📒 Files selected for processing (4)
.github/workflows/release-js.yml.github/workflows/release-py.yml.github/workflows/release-rs.yml.github/workflows/update-flake.yml
| - name: Checkout | ||
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 |
There was a problem hiding this comment.
Set persist-credentials: false on checkout.
The workflow does not explicitly disable credential persistence on checkout. By default, actions/checkout sets persist-credentials: true, making the GITHUB_TOKEN available to all subsequent steps. The update-flake-lock action creates pull requests and should use only its own authentication mechanism (via the default GITHUB_TOKEN passed to it), not rely on a persisted token in the workspace .git/config.
Explicitly setting persist-credentials: false follows the principle of least privilege and matches the pattern used in the other three workflows in this PR.
🛡️ Add persist-credentials setting
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
+ with:
+ persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Checkout | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - name: Checkout | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 21-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/update-flake.yml around lines 21 - 22, The checkout action
in the "Checkout" step does not explicitly disable credential persistence, which
means the GITHUB_TOKEN will be available to all subsequent workflow steps by
default. Add the `persist-credentials: false` option to the `actions/checkout`
configuration to ensure credentials are not persisted in the git config,
following the principle of least privilege and matching the pattern used in the
other workflows. This ensures the `update-flake-lock` action uses only its own
authentication mechanism.
Source: Linters/SAST tools
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/cachix.yml:
- Around line 16-34: The release job in cachix.yml lacks a repository owner
guard that other similar workflows (release-rs.yml, release-py.yml) have in
place. When a fork pushes a tag, the aarch64-linux matrix entry will queue
indefinitely waiting for the self-hosted nix runner that doesn't exist in the
fork. Add a job-level condition guard using `if: github.repository_owner ==
'moq-dev'` to the release job to ensure it only executes in the main repository
and prevent forks from triggering self-hosted runner requests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 38afc496-3ff9-41ab-92ec-4ffb227adfde
📒 Files selected for processing (1)
.github/workflows/cachix.yml
| release: | ||
| name: Release (${{ matrix.os }}) | ||
| runs-on: ${{ matrix.os }} | ||
| runs-on: ${{ matrix.runs-on }} | ||
| permissions: | ||
| contents: read | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: | ||
| - ubuntu-latest | ||
| - macos-latest | ||
| include: | ||
| # `os` is just the cache pin label; keep the existing values stable so | ||
| # old pins aren't orphaned. | ||
| - os: ubuntu-latest # x86_64-linux | ||
| runs-on: ubuntu-latest | ||
| - os: macos-latest # aarch64-darwin | ||
| runs-on: macos-latest | ||
| # aarch64-linux on the moq-dev self-hosted A1 (warm /nix/store). Tag | ||
| # pushes are trusted, so no fork concern. | ||
| - os: aarch64-linux | ||
| runs-on: [self-hosted, nix] |
There was a problem hiding this comment.
Add repository owner guard to prevent fork CI failures.
Unlike the other workflows (release-rs.yml, release-py.yml, etc.), this workflow lacks an if: github.repository_owner == 'moq-dev' guard. If a fork pushes a tag, the aarch64-linux matrix entry will queue indefinitely waiting for the non-existent [self-hosted, nix] runner, while the other two matrix entries would succeed.
Consider either:
- Adding a job-level guard:
if: github.repository_owner == 'moq-dev'(consistent with other workflows), or - Making the aarch64-linux matrix entry conditional using
${{ github.repository_owner == 'moq-dev' && ...}}in a matrix exclude/include expression.
Option 1 is simpler and consistent with the pattern established in release-rs.yml (context snippet 1).
🛡️ Proposed fix: Add repository owner guard
release:
name: Release (${{ matrix.os }})
runs-on: ${{ matrix.runs-on }}
+ if: ${{ github.repository_owner == 'moq-dev' }}
permissions:
contents: read📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| release: | |
| name: Release (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| runs-on: ${{ matrix.runs-on }} | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - ubuntu-latest | |
| - macos-latest | |
| include: | |
| # `os` is just the cache pin label; keep the existing values stable so | |
| # old pins aren't orphaned. | |
| - os: ubuntu-latest # x86_64-linux | |
| runs-on: ubuntu-latest | |
| - os: macos-latest # aarch64-darwin | |
| runs-on: macos-latest | |
| # aarch64-linux on the moq-dev self-hosted A1 (warm /nix/store). Tag | |
| # pushes are trusted, so no fork concern. | |
| - os: aarch64-linux | |
| runs-on: [self-hosted, nix] | |
| release: | |
| name: Release (${{ matrix.os }}) | |
| runs-on: ${{ matrix.runs-on }} | |
| if: ${{ github.repository_owner == 'moq-dev' }} | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # `os` is just the cache pin label; keep the existing values stable so | |
| # old pins aren't orphaned. | |
| - os: ubuntu-latest # x86_64-linux | |
| runs-on: ubuntu-latest | |
| - os: macos-latest # aarch64-darwin | |
| runs-on: macos-latest | |
| # aarch64-linux on the moq-dev self-hosted A1 (warm /nix/store). Tag | |
| # pushes are trusted, so no fork concern. | |
| - os: aarch64-linux | |
| runs-on: [self-hosted, nix] |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/cachix.yml around lines 16 - 34, The release job in
cachix.yml lacks a repository owner guard that other similar workflows
(release-rs.yml, release-py.yml) have in place. When a fork pushes a tag, the
aarch64-linux matrix entry will queue indefinitely waiting for the self-hosted
nix runner that doesn't exist in the fork. Add a job-level condition guard using
`if: github.repository_owner == 'moq-dev'` to the release job to ensure it only
executes in the main repository and prevent forks from triggering self-hosted
runner requests.
actionlint flagged `runs-on: [self-hosted, nix]` in the moved workflows because `nix` is a custom label it doesn't know. check.yml slips past only because its label is hidden inside a fromJSON() expression actionlint can't statically read. Declare the label in .github/actionlint.yaml (the fix the error itself recommends) so the literal form lints clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Moves the Nix-based, architecture-independent release workflows onto the moq-dev self-hosted A1 (aarch64) runner, following the pattern
check.ymlalready established, and adds an aarch64-linux leg to the cachix binary cache so that platform is warmed too.release-rs.ymlmainrelease-js.ymlmain(js paths)release-py.ymlmain(py paths)update-flake.ymlcachix.ymlThese all use Nix and produce arch-independent output (or, for cachix, the box natively is the target arch), so the aarch64 box is a valid runner. Unlike
check.ymlthey trigger solely on trusted events (push/tag/schedule/dispatch), so no fork fallback is needed.Per-workflow notes
For the moved jobs:
runs-on→[self-hosted, nix], droppednix-installer-action(the box already has Nix), and ran Nix steps in a login shell (bash -leo pipefail {0}) so/etc/profile.dputs Nix on PATH.CARGO_TARGET_DIR=$HOME/cargo-target/moq-$RUNNER_NAME(same warm-cache trick ascheck.yml) since release-plz compiles.buildjob moved;publishstays onubuntu-latest(no Nix, just OIDC trusted-publish to PyPI).update-flake-lockaction invokesnixdirectly rather than through a shell, so a login shell wouldn't help. Added anAdd Nix to PATHstep that resolves the binary via a login shell and writes its dir toGITHUB_PATH. Also added anif: repository_owner == 'moq-dev'guard so a fork's manual dispatch doesn't queue forever on a runner that doesn't exist.includeform so each leg carries its ownruns-on(string for hosted runners,[self-hosted, nix]for the box) whileosstays the cache-pin label, keeping existing pins stable. The new aarch64-linux leg gates the installer on github-hosted, adds Nix to PATH for the cachix action +nix build, and setsskipAddingSubstituteron self-hosted: the box's runner user isn't a Nix trusted-user and it substitutes only from its warm local store, socachix usemust not rewrite nix.conf there. Push auth is unaffected; this leg only pushes.Still left alone (arch-specific)
Caveats for the reviewer
check.yml, the moved jobs hard-target the single self-hosted box. If it's offline, a release queues until it's back (or hits the runner timeout). Matches the existing trade-off.fail-fast: falsekeeps a failing arm build from killing the x86_64 / darwin legs.🤖 Generated with Claude Code
(Written by Claude)