From c1c2e042b087e407568cb9440574a80c69011f1d Mon Sep 17 00:00:00 2001 From: Rex Raphael Date: Fri, 4 Sep 2026 11:31:33 -0500 Subject: [PATCH] feat(go-ci): fetch private modules when given a token kgkit is private, so every xraph repo depending on it fails at go mod download with "repository not found". That reads like a bad import path. It is not: go asked proxy.golang.org, got a 404 back, and never tried git, because nothing had marked the path private in the first place. The workflow takes an optional XRAPH_REPO_TOKEN. When it is set, every job that downloads dependencies rewrites the org's HTTPS clone URL to carry the token and exports GOPRIVATE so those paths bypass the proxy. Without the secret the step does nothing at all, so existing callers are unaffected. Two things are scoped deliberately narrow. The rewrite covers https://github.com/xraph/ and not all of github.com, so it cannot clobber a credential a consumer already configured for somewhere else. GOPRIVATE comes from a new input instead of being hardcoded, because it also sets GONOPROXY: a glob wider than the modules that are genuinely private drags public ones off the proxy and clones each of them per job, per run. foundry is the case in point, with twenty-two xraph modules and exactly one of them private. The default stays github.com/xraph/*, which is the right answer for a caller that has not thought about it. nested-modules is left alone. It reads go.mod files and never downloads. --- .github/workflows/go-ci.yml | 91 +++++++++++++++++++++++++++++++++++++ README.md | 37 +++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/.github/workflows/go-ci.yml b/.github/workflows/go-ci.yml index 32f325a..08229c8 100644 --- a/.github/workflows/go-ci.yml +++ b/.github/workflows/go-ci.yml @@ -67,9 +67,16 @@ on: description: 'Check that nested go.mod files require their siblings at versions the module proxy can serve. A nested module replace is ignored once the module is somebody else dependency, so a require naming an unpublished version breaks go get for every consumer while every local build keeps working. No-op in a repo with a single go.mod.' type: boolean default: true + goprivate: + description: 'GOPRIVATE glob applied when XRAPH_REPO_TOKEN is set. Narrow it to what is genuinely private - the glob also sets GONOPROXY, so a broad one drags every public module under it off the proxy and onto a full git clone per job, for nothing. Comma-separated for more than one.' + type: string + default: 'github.com/xraph/*' secrets: CODECOV_TOKEN: required: false + XRAPH_REPO_TOKEN: + description: 'Read access to the private repositories in this org. Without it, private modules are never fetched and a repo that needs one fails at download.' + required: false jobs: setup: @@ -129,6 +136,27 @@ jobs: - name: Checkout uses: actions/checkout@v7 + # kgkit and any other private xraph module is not on the public proxy, and + # an unauthenticated fetch comes back "repository not found", which reads + # as a missing repo rather than a missing credential. Carry the token on + # the org's clone URL and take the private paths off the proxy. + # + # The rewrite is scoped to the org rather than to all of github.com, so it + # cannot clobber a credential a consumer has already set for somewhere + # else. No-op without the secret, so public-only consumers are unaffected. + - name: Configure Go module auth + shell: bash + env: + XRAPH_REPO_TOKEN: ${{ secrets.XRAPH_REPO_TOKEN }} + GOPRIVATE_GLOB: ${{ inputs.goprivate }} + run: | + set -euo pipefail + if [ -n "${XRAPH_REPO_TOKEN:-}" ]; then + git config --global url."https://x-access-token:${XRAPH_REPO_TOKEN}@github.com/xraph/".insteadOf "https://github.com/xraph/" + echo "GOPRIVATE=${GOPRIVATE_GLOB}" >> "$GITHUB_ENV" + echo "- private modules: \`${GOPRIVATE_GLOB}\`, fetched over the token" >> "$GITHUB_STEP_SUMMARY" + fi + - name: Set up Go uses: actions/setup-go@v7 with: @@ -267,6 +295,27 @@ jobs: - name: Checkout uses: actions/checkout@v7 + # kgkit and any other private xraph module is not on the public proxy, and + # an unauthenticated fetch comes back "repository not found", which reads + # as a missing repo rather than a missing credential. Carry the token on + # the org's clone URL and take the private paths off the proxy. + # + # The rewrite is scoped to the org rather than to all of github.com, so it + # cannot clobber a credential a consumer has already set for somewhere + # else. No-op without the secret, so public-only consumers are unaffected. + - name: Configure Go module auth + shell: bash + env: + XRAPH_REPO_TOKEN: ${{ secrets.XRAPH_REPO_TOKEN }} + GOPRIVATE_GLOB: ${{ inputs.goprivate }} + run: | + set -euo pipefail + if [ -n "${XRAPH_REPO_TOKEN:-}" ]; then + git config --global url."https://x-access-token:${XRAPH_REPO_TOKEN}@github.com/xraph/".insteadOf "https://github.com/xraph/" + echo "GOPRIVATE=${GOPRIVATE_GLOB}" >> "$GITHUB_ENV" + echo "- private modules: \`${GOPRIVATE_GLOB}\`, fetched over the token" >> "$GITHUB_STEP_SUMMARY" + fi + - name: Set up Go uses: actions/setup-go@v7 with: @@ -299,6 +348,27 @@ jobs: - name: Checkout uses: actions/checkout@v7 + # kgkit and any other private xraph module is not on the public proxy, and + # an unauthenticated fetch comes back "repository not found", which reads + # as a missing repo rather than a missing credential. Carry the token on + # the org's clone URL and take the private paths off the proxy. + # + # The rewrite is scoped to the org rather than to all of github.com, so it + # cannot clobber a credential a consumer has already set for somewhere + # else. No-op without the secret, so public-only consumers are unaffected. + - name: Configure Go module auth + shell: bash + env: + XRAPH_REPO_TOKEN: ${{ secrets.XRAPH_REPO_TOKEN }} + GOPRIVATE_GLOB: ${{ inputs.goprivate }} + run: | + set -euo pipefail + if [ -n "${XRAPH_REPO_TOKEN:-}" ]; then + git config --global url."https://x-access-token:${XRAPH_REPO_TOKEN}@github.com/xraph/".insteadOf "https://github.com/xraph/" + echo "GOPRIVATE=${GOPRIVATE_GLOB}" >> "$GITHUB_ENV" + echo "- private modules: \`${GOPRIVATE_GLOB}\`, fetched over the token" >> "$GITHUB_STEP_SUMMARY" + fi + - name: Set up Go uses: actions/setup-go@v7 with: @@ -366,6 +436,27 @@ jobs: - name: Checkout uses: actions/checkout@v7 + # kgkit and any other private xraph module is not on the public proxy, and + # an unauthenticated fetch comes back "repository not found", which reads + # as a missing repo rather than a missing credential. Carry the token on + # the org's clone URL and take the private paths off the proxy. + # + # The rewrite is scoped to the org rather than to all of github.com, so it + # cannot clobber a credential a consumer has already set for somewhere + # else. No-op without the secret, so public-only consumers are unaffected. + - name: Configure Go module auth + shell: bash + env: + XRAPH_REPO_TOKEN: ${{ secrets.XRAPH_REPO_TOKEN }} + GOPRIVATE_GLOB: ${{ inputs.goprivate }} + run: | + set -euo pipefail + if [ -n "${XRAPH_REPO_TOKEN:-}" ]; then + git config --global url."https://x-access-token:${XRAPH_REPO_TOKEN}@github.com/xraph/".insteadOf "https://github.com/xraph/" + echo "GOPRIVATE=${GOPRIVATE_GLOB}" >> "$GITHUB_ENV" + echo "- private modules: \`${GOPRIVATE_GLOB}\`, fetched over the token" >> "$GITHUB_STEP_SUMMARY" + fi + - name: Set up Go uses: actions/setup-go@v7 with: diff --git a/README.md b/README.md index b81899d..c5c330e 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,43 @@ npm-global-packages: 'typescript@5.8.2 esbuild@0.28.1' Both default to empty, so nothing is installed unless asked. +## Private modules + +`kgkit` is private. Anything that depends on it dies at `go mod download` with +"repository not found", which reads like a typo in the import path and isn't +one: Go asked proxy.golang.org, got a 404 back, and never got as far as trying +git, because nothing had told it that path was private to begin with. + +Hand the workflow a token with read access and it sorts out the rest: + +```yaml +jobs: + ci: + uses: xraph/workflows/.github/workflows/go-ci.yml@v1 + with: + goprivate: github.com/xraph/kgkit + secrets: + XRAPH_REPO_TOKEN: ${{ secrets.XRAPH_REPO_TOKEN }} +``` + +Every job that downloads dependencies rewrites `https://github.com/xraph/` +to carry that token, then sets `GOPRIVATE` so those paths skip the proxy and go +straight to git. Leave the secret out and the step does nothing. A public-only +repo never has to think about it. The rewrite is scoped to the org and not to +all of github.com, so it won't stamp on a credential you already set up for +somewhere else. + +Keep `goprivate` narrow. It sets `GONOPROXY` too, so a glob wider than your real +private modules drags perfectly public ones off the proxy and clones each of +them from scratch, in every job, on every run. foundry names a single module for +that reason: it pulls in twenty-two xraph modules and exactly one of them is +private. The default is `github.com/xraph/*`, which is the safe answer when you +do not know and the slow one when you do. + +Read access on the private repos is all the token needs. A fine-grained PAT +works. So does a GitHub App installation token. The default `GITHUB_TOKEN` does +not, and cannot: it only ever reaches the repo the workflow is running in. + ## Escaping the Makefile probe `go-ci.yml` prefers a Makefile target when one matching the step exists. That