Skip to content

GitHub Action installs Aster and exposes the cache token only to Aster - #173

Merged
calvin-archastro merged 2 commits into
mainfrom
factory/tsk_2MlzD9CjYHeORzH4bYP3fl-549fcef4-9428-4798-b59c-
Oct 21, 2026
Merged

calvin-archastro merged 2 commits into
mainfrom
factory/tsk_2MlzD9CjYHeORzH4bYP3fl-549fcef4-9428-4798-b59c-

Conversation

@calvin-archastro

@calvin-archastro calvin-archastro commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Epic: Aster restores real build artifacts from a shared cache, including the GitHub Actions cache
Task: GitHub Action installs Aster and exposes the cache token only to Aster

Local git hooks skipped: pre-push on the submission push and the publish push. CI is the gate for what those hooks check.

Problem and author intent

Workflows had no in-repo way to install a pinned Aster release and run one command against the GitHub Actions cache. The cache client already speaks the Actions cache API, but nothing installed the binary or passed ACTIONS_RESULTS_URL, ACTIONS_RUNTIME_TOKEN, ASTER_REMOTE_CACHE=gha, and ASTER_CACHE_MODE only to that process. Exporting the runtime token into the job environment would leave a write-capable credential available to later steps.

The author intent is a Node 24 JavaScript action under action/, used as ArchAstro/aster/action@vX, that installs Aster, selects cache mode, and scopes those variables to the spawned aster process. auto should write only for push, schedule, and workflow_dispatch on the default branch, and read otherwise. A hidden aster-path input should skip the release download so tests can use a local binary. The GHA cache client previously always pinned TLS roots to WebPKI, so a loopback HTTPS fake could not stand in for the Actions cache without a test-only trust hook.

What changed

Before, there was no action, and build_agent in src/cache/gha/client.rs always set RootCerts::WebPki. A private loopback certificate failed verification, and any workflow that wanted the cache token had to plumb it itself, including the risk of core.exportVariable / GITHUB_ENV leaking it forward.

After, action/action.yml runs dist/index.js on Node 24 with inputs version, run, cache-mode (default auto), working-directory, and test-only aster-path. action/src/index.ts resolves the default branch from GITHUB_EVENT_PATH, installs Aster, and spawns the command. selectCacheMode returns rw only when the event is push, schedule, or workflow_dispatch, the default branch is non-empty, and ref is refs/heads/<default>. Missing payload, pull requests, and other branches stay read. Explicit rw, read, and off override that; anything else throws. Empty version picks the first non-draft, non-prerelease tag from the first 20 GitHub releases; a set version accepts an optional leading v. Install uses the tool cache and release assets aster-linux-x64.tar.gz, aster-darwin-x64.tar.gz, and aster-darwin-arm64.tar.gz, then chmod +x. aster-path returns that local binary if it exists.

childEnv copies the parent environment and sets ACTIONS_RESULTS_URL, ACTIONS_RUNTIME_TOKEN, ASTER_REMOTE_CACHE=gha, and ASTER_CACHE_MODE on the object passed to @actions/exec. action/src does not call exportVariable or exportSecret. splitCommand splits run on whitespace and does not interpret quotes. A non-zero aster exit fails the step.

build_agent no longer hard-codes RootCerts::WebPki. If ASTER_GHA_EXTRA_CA is unset or empty, roots are left to the builder (the new comment says that keeps WebPKI). If it is set, that one PEM replaces WebPKI via RootCerts::new_with_certs, because ureq's specific-root mode cannot add to WebPKI. A missing file or non-PEM panics. The integration test sets this so its loopback server is the only host the client talks to.

Docs in action/README.md and docs/ci/github-actions.md describe the usage and the non-export. .gitignore ignores node_modules/. .github/workflows/ci.yml adds an action job on ubuntu-latest that checks out, sets up Node 24, installs the Rust toolchain, and runs npm ci then npm test in action/.

Both frozen revisions (heads 61b59cf9d9628b02cc7d2d0f5e148ee4eb72741e and ca4996dd8eb999b931283fc8b47ea46c95481a2b, same base) carry this change. The later head only reformats the extra-CA panic lines; visible behavior matches.

Scope

Same 24 paths in both revisions: new action/ sources, tests, fixture, package metadata, ncc dist/ outputs, CI job, docs, .gitignore, and src/cache/gha/client.rs. About 31,661–31,663 lines added and 5 removed across 28 hunks; almost all of the addition is the committed bundle and lockfile. One hunk per revision was omitted. action/dist/index.js is truncated in the first revision and absent from the second revision's excerpts, so the bundle was not fully reviewed.

Risk assessment

Medium. The action handles a write-capable Actions runtime token. The mitigation in the visible source is process-scoped exec env, not core.exportVariable. It does not strip a token the runner already injected into the job. cache-mode: rw can still be set explicitly on pull requests.

ASTER_GHA_EXTRA_CA replaces WebPKI rather than adding a root. If set outside the test, the client trusts only that certificate and will not validate the real Actions cache with WebPKI. The explicit .root_certs(RootCerts::WebPki) call was removed; production trust when the variable is unset now depends on the ureq builder default, which the comment claims is WebPKI but which these excerpts do not prove.

Install is unix-oriented (extractTar, chmod +x) and has no Windows asset. latestTag only inspects 20 releases. Whitespace splitting will mis-handle quoted arguments. The omitted hunk and truncated bundle are review gaps, not evidence the bundle matches src/.

User impact

Workflows can install Aster and run one command with the Actions cache enabled, for example uses: ArchAstro/aster/action@v0.21.0 with run: run //app:build. Default auto writes on default-branch push, schedule, and workflow_dispatch, and reads otherwise. Later steps are not given the token through this action's env export. Unsupported platforms fail at asset selection. Unset ASTER_GHA_EXTRA_CA is the production path; setting it changes TLS trust for the cache client.

Testing

Canonical tests added in-tree, not proven by the supplied check excerpts:

  • action/test/mode.test.js: push to the default branch selects rw, schedule on the default branch selects rw, workflow_dispatch on the default branch selects rw, pull_request selects read, push to a non-default branch selects read, cache-mode input overrides auto, and run does not export ACTIONS_RUNTIME_TOKEN (source must not call exportVariable / exportSecret; childEnv sets the token only on the returned env).
  • action/test/integration.test.js: second aster run reports the fixture target cached. It runs dist/index.js with a local aster via aster-path, a fake event payload, and an in-test TLS Twirp/blob server. It expects a cache miss then a hit for //app:build, the bearer token on the fake server, restored out/file.txt, a single command execution, and no runtime token or results URL on the parent test process.

CI wiring is the new action job (npm ci and npm test). That is intent, not a passed run. Advisory pipeline outcomes report format, lint, and test succeeded, but those excerpts are truncated and the visible test text is Rust (migrations, startup, ui, upgrade), not the Node action tests. No supplied check id is action. Author-reported local npm test (8 passed) is not treated as CI evidence. Patch presence is not proof those tests passed.

Follow-ups and known issues

  • Evidence is incomplete: two omitted hunks, truncated dist/index.js, and truncated check excerpts. Do not treat the bundle or CI action job as fully verified.
  • No Windows asset or Windows CI for the action. chmod +x will not fit a Windows runner.
  • run is not a shell; quotes are not interpreted.
  • Latest-stable lookup stops at 20 releases and ignores drafts and prereleases only within that page.
  • ASTER_GHA_EXTRA_CA must stay unset in production. Confirm the ureq default is still WebPKI now that the explicit RootCerts::WebPki call is gone.
  • README says npm test does not use the network. The integration test uses loopback TLS, openssl, and may cargo build a local aster; it is written to avoid GitHub and published releases, but that was not re-run in the supplied pipeline excerpts.

The action installs a pinned release, or a test-only local binary, and
passes the Actions cache token only to the spawned aster process. auto
mode writes on push, schedule, and workflow_dispatch to the default branch.
@calvin-archastro
calvin-archastro requested a review from a team October 21, 2026 13:57
@calvin-archastro
calvin-archastro merged commit bb82371 into main Oct 21, 2026
13 checks passed
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.

1 participant