feat(ci): install through a private npm registry on self-hosted runners - #88
Merged
Merged
Conversation
Consuming repositories may run on runners inside a private network where registry.npmjs.org is unreachable and every package must come from an internal Artifactory. Neither publishing action nor the reusable build workflow could be pointed anywhere else, and build-image.yml hard-coded ubuntu-latest. The lockfiles need no change: npm's replace-registry-host (default `npmjs`) rewrites the default host to the configured registry at fetch time and the integrity hashes still verify against the mirror's tarballs. Both actions and the workflow now take npm-registry / npm-token and node-mirror / node-mirror-token; the workflow also takes runs-on. All default to the current behaviour. The registry is applied as project-level npm config for that one install, with the token read from the environment rather than written to disk. The corollary is a rule CI now enforces: every `resolved` in both lockfiles stays on registry.npmjs.org, because npm rewrites only the default host. Closes #87 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PYtmxSeSXFg4wEXRcKCmAi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Consuming repositories may run on self-hosted runners inside a private network where
registry.npmjs.orgis unreachable and every package must come from an internal Artifactory. Neither publishing action nor the reusable build workflow offered a way to install from anywhere but the public registry, andbuild-image.ymlhard-codedubuntu-latest.The lockfiles stay exactly as they are. npm's
replace-registry-host(defaultnpmjs) rewrites aresolvedhost that is the default registry to the configured one at fetch time, and the integrity hashes still verify because the mirror serves the same tarballs. So one lockfile, one action ref and one workflow serve both runner populations; what was missing was a way to name the registry. Both actions and the workflow now takenpm-registry/npm-token(andnode-mirror/node-mirror-tokenforsetup-node), and the workflow takesruns-on. All default to the current behaviour.The registry is applied as project-level npm config next to the lockfile being installed, for that install only: the runner's own npm configuration stays layered underneath (a runner with an
~/.npmrcnaming the mirror needs no input at all), nothing is exported into the calling workflow's later steps, and the token is referenced from the environment rather than written to disk.The corollary is a rule CI now enforces: every
resolvedin both lockfiles must stay onregistry.npmjs.org, because npm rewrites only the default host and a lockfile regenerated behind a corporate.npmrcinstalls in one network only.Changes
actions/lib/npm-registry.sh— writes the project.npmrcfromKB_NPM_REGISTRY/KB_NPM_TOKEN; no-op when unset; rejects anything that is not a single http(s) URL.actions/publish-docs/action.yml,actions/publish-single-page-docs/action.yml— the four new inputs;setup-nodegetsmirror/mirror-token; the install runs the script first and carries the token in its environment..github/workflows/build-image.yml— inputsruns-on(a label, or JSON for several labels / a runner group),npm-registry,node-mirror; secretsnpm-token,node-mirror-token; the same.npmrclogic inlined against theknowledge-base/checkout so an older pinnedkb-refstill honours it;ASTRO_TELEMETRY_DISABLEDon the build..github/workflows/ci.yml— the deployment dry run passesruns-onin its JSON form, so the parsing branch of the expression runs in CI.tests/private-registry.spec.js— the lockfile rule, the inputs on all three manifests, and the script (no-op, URL normalisation, token never on disk, bad input rejected)..gitattributes—*.shchecked out with LF so the script runs under Git bash on a CRLF checkout.contract/DEPLOYMENT.md(a "Private networks" section and checklist items, including what no input can cover: the Docker daemon's mirror, GitHub's cache service),actions/publish-docs/README.md,contract/SINGLE_PAGE.md(inputs, a private-network subsection, troubleshooting rows),examples/deployment-repo(the inputs, commented),AGENTS.md/CONTRIBUTING.md(the lockfile rule),CLAUDE.md(the new spec).Verification
npm ciofactions/was run locally through a logging reverse proxy standing in for Artifactory, with a fresh cache each time:--registry=<proxy>,replace-registry-host=npmjs(npm's default).npmrcwritten bynpm-registry.shwith a tokenAuthorization: Bearer …on every request, exit 0--registry=<proxy>,replace-registry-host=neverresolvedhost would getnpm run build:headless— greennpm test— green (includes the new spec: 10 tests)npx playwright test --config=playwright.config.ci.js— greencd actions && npm run selftest— greenyamlpackage CI usesNot verified: an actual self-hosted runner behind Artifactory, and the
runs-onJSON form on a runner group. The CI dry run exercises the JSON-array branch onubuntu-latest.Closes #87
🤖 Generated with Claude Code
https://claude.ai/code/session_01PYtmxSeSXFg4wEXRcKCmAi