The workflow audit asks GitHub about a repository Forgejo never fetches from GitHub #77

Closed
opened 2026-09-07 10:16:43 +00:00 by tiagoagueda · 0 comments
Owner

Observation

The third and last reason CI was red, after #75 (the dependency audit) and #76 (two
platform-dependent tests).

fatal: no audit was performed
'ref-confusion' audit failed on file://.forgejo/workflows/ci.yml
Caused by:
    0: error in 'ref-confusion' audit
    1: couldn't list branches for actions/checkout
    2: request error while accessing GitHub API
    3: HTTP status client error (401 Unauthorized) for url (https://github.com/actions/checkout.git/git-upload-pack)

Note the first line: no audit was performed. The step was not reporting a finding, it
was failing before it had looked at anything.

What is wrong

zizmor takes a GitHub API token from --gh-token, GH_TOKEN or GITHUB_TOKEN. Forgejo
Actions sets GITHUB_TOKEN. So zizmor decided it was online, and asked github.com about
actions/checkout while holding a Forgejo token — which github.com rejected with 401.

The token is the visible half. The other half is that the question was wrong to begin with:
Forgejo resolves a bare action name against its own instance, which the note at the top
of ci.yml already says. What GitHub believes actions/checkout@v4 refers to is not what
runs here, so the ref-confusion audit would have given a confident answer about the wrong
host even with a token GitHub accepted.

And it passed on a laptop, every time, because with no token in the environment zizmor
defaults to offline and skips the online audits entirely. Same shape as #76: green only
where it was written.

The fix

Run zizmor --offline. Not a concession — the mode that was always correct for a Forgejo
instance. The offline audits (injected expressions, over-broad permissions, unpinned
actions, and the rest) all still run; only the ones that would have questioned github.com
about a repository this CI never fetches from github.com are skipped.

Reproduced and verified locally rather than guessed:

# fails exactly as CI did
GITHUB_TOKEN=not-a-github-token uvx zizmor --no-progress --config .forgejo/zizmor.yml \
  --min-severity medium .forgejo/workflows/*.yml

# passes
GITHUB_TOKEN=not-a-github-token uvx zizmor --offline --no-progress \
  --config .forgejo/zizmor.yml --min-severity medium .forgejo/workflows/*.yml

The pattern across all three

#75, #76 and this one are the same fault wearing three coats: every check that passed
locally and failed in CI did so because it depended on something about the machine
— an
editable install, a gitignored .env, a platform's floating-point rounding, an injected
token. None of them was about the code.

They went unfound for thirty-eight runs because the CI logs are not reachable: this
Forgejo has no actions/runs/{id}/jobs route, no actions/jobs/{id}/logs, no artifacts
endpoint, and the web UI's JSON returns 500: task ... does not exist even for runs that
succeeded. All three were diagnosed from logs pasted in by hand. That is worth its own
issue against the instance's ACTIONS.LOG_RETENTION_DAYS or log storage: a build whose
failures cannot be read is a build nobody reads.

Classification

Bug.

## Observation The third and last reason CI was red, after #75 (the dependency audit) and #76 (two platform-dependent tests). ``` fatal: no audit was performed 'ref-confusion' audit failed on file://.forgejo/workflows/ci.yml Caused by: 0: error in 'ref-confusion' audit 1: couldn't list branches for actions/checkout 2: request error while accessing GitHub API 3: HTTP status client error (401 Unauthorized) for url (https://github.com/actions/checkout.git/git-upload-pack) ``` Note the first line: **no audit was performed**. The step was not reporting a finding, it was failing before it had looked at anything. ## What is wrong zizmor takes a GitHub API token from `--gh-token`, `GH_TOKEN` **or `GITHUB_TOKEN`**. Forgejo Actions sets `GITHUB_TOKEN`. So zizmor decided it was online, and asked github.com about `actions/checkout` while holding a *Forgejo* token — which github.com rejected with 401. The token is the visible half. The other half is that the question was wrong to begin with: **Forgejo resolves a bare action name against its own instance**, which the note at the top of `ci.yml` already says. What GitHub believes `actions/checkout@v4` refers to is not what runs here, so the `ref-confusion` audit would have given a confident answer about the wrong host even with a token GitHub accepted. And it passed on a laptop, every time, because with no token in the environment zizmor defaults to offline and skips the online audits entirely. Same shape as #76: green only where it was written. ## The fix Run `zizmor --offline`. Not a concession — the mode that was always correct for a Forgejo instance. The offline audits (injected expressions, over-broad permissions, unpinned actions, and the rest) all still run; only the ones that would have questioned github.com about a repository this CI never fetches from github.com are skipped. Reproduced and verified locally rather than guessed: ```sh # fails exactly as CI did GITHUB_TOKEN=not-a-github-token uvx zizmor --no-progress --config .forgejo/zizmor.yml \ --min-severity medium .forgejo/workflows/*.yml # passes GITHUB_TOKEN=not-a-github-token uvx zizmor --offline --no-progress \ --config .forgejo/zizmor.yml --min-severity medium .forgejo/workflows/*.yml ``` ## The pattern across all three #75, #76 and this one are the same fault wearing three coats: **every check that passed locally and failed in CI did so because it depended on something about the machine** — an editable install, a gitignored `.env`, a platform's floating-point rounding, an injected token. None of them was about the code. They went unfound for thirty-eight runs because **the CI logs are not reachable**: this Forgejo has no `actions/runs/{id}/jobs` route, no `actions/jobs/{id}/logs`, no artifacts endpoint, and the web UI's JSON returns `500: task ... does not exist` even for runs that succeeded. All three were diagnosed from logs pasted in by hand. That is worth its own issue against the instance's `ACTIONS.LOG_RETENTION_DAYS` or log storage: a build whose failures cannot be read is a build nobody reads. ## Classification Bug.
tiagoagueda added this to the 0.3.0 milestone 2026-09-07 10:16:43 +00:00
tiagoagueda modified the milestone from 0.3.0 to 0.2.0 2026-09-07 11:44:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#77
No description provided.