Skip to content

Take the two pins the index has published past [#224] - #228

Merged
iderex merged 2 commits into
mainfrom
ci/the-pins-follow-the-index-with-a-sign-off
Sep 2, 2026
Merged

Take the two pins the index has published past [#224]#228
iderex merged 2 commits into
mainfrom
ci/the-pins-follow-the-index-with-a-sign-off

Conversation

@iderex

@iderex iderex commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What was wrong

The newest completed run of Pins on the default branch concluded failure,
and #224 is the entry that records it. What it refused on is two of the four
pins in pins.json sitting behind what the index publishes:

gh run view 33388004039 --repo Flowfin/site --log | sed -n '/Run go run . pins/,/Process completed/p'
pins: 4 declared in pins.json
  prettier: current at 3.9.6, npm says the same
  zizmor: BEHIND, pinned 1.29.0, pypi says 1.30.0
  semgrep: BEHIND, pinned 1.174.0, pypi says 1.175.0
pins: 2 pin(s) are behind their upstream
  golang-image: current at sha256:53eeac89074db483fdf0ab3be1df32bf6e47562263d2d0d6baa7f26acb4957dd, docker-hub says the same
4 pin(s) declared, 4 compared, 2 behind, 0 unresolved.

Run 2026-09-02, elided for length. That run is from 2026-08-31, and the index
has moved once more since: semgrep is at 1.176.0 rather than the 1.175.0 the run
above read.

git checkout 6541274 -- pins.json && go run . pins
pins: 4 declared in pins.json
  prettier: current at 3.9.6, npm says the same
  zizmor: BEHIND, pinned 1.29.0, pypi says 1.30.0
  semgrep: BEHIND, pinned 1.174.0, pypi says 1.176.0
  golang-image: current at sha256:53eeac89074db483fdf0ab3be1df32bf6e47562263d2d0d6baa7f26acb4957dd, docker-hub says the same
4 pin(s) declared, 4 compared, 2 behind, 0 unresolved.
pins: 2 pin(s) are behind their upstream

Run 2026-09-02 against 6541274. Nothing but a change to pins.json clears
that verdict: the comparison reports and never bumps, and it runs on a weekly
schedule, so the refusal stands until somebody writes the versions.

What this does

zizmor moves from 1.29.0 to 1.30.0 and semgrep from 1.174.0 to 1.176.0.
Nothing else in the file changes. Neither entry gains a checksum, because both
are resolved against what the index publishes rather than against the wheel,
which is what each why field already states.

The two versions are read by their workflows out of this file with jq, so
there is no second copy of either to keep in step, and the invariant that
refuses a version written into a workflow step is what keeps it that way. Both
of those workflows run on this pull request, so the check that the new releases
still pass over this tree is made here rather than after the merge.

Why the drift is worth clearing rather than waiting out. The two why fields
name the same failure from two directions: an audit that has stopped
understanding the syntax it audits, and a rule engine release that turns a
pattern which refuses something into one that refuses nothing. Both leave every
run green, so this is the drift with no other witness in this tree.

The means

pins.json and the verb that already reads it. The change is two values in the
file the comparison is written against, so it is decided by the same run that
found the drift, needs no language, runtime or dependency this tree does not
carry, and the claim above carries the command that produced it in both
directions. Writing the versions into the two workflow steps instead would be
refused by the invariant gate, which is the same rule read from the other side.

No second reader

Nothing on this board reviewed this change but the account that wrote it. The
evidence in place of one is the run below and the checks on this pull request,
which include the two tools whose versions this changes.

Closes

Closes #224.

What was run

go run . ci
gate: 7 legs, in order: format, vet, test, build, links, sitemap, invariants
  needs-network was not asked for. Asking costs a request to the public name from whatever machine runs it, and a verdict that moves when somebody else's service does rather than when this tree changes. Ask with: go run ./harness/needs-network
  format: ok, 74 file(s)
  vet: ok
  test: ok, 37 test file(s)
  build: ok, 22 file(s)
  links: every reference that stays inside this site resolves to a file the build wrote
  sitemap: every page the build wrote is listed once, and every entry has a page behind it
  invariants: ok, 39 rule(s) decided, 2 owed and not decided
7 of 7 legs ran. None was skipped.

go run . pins
pins: 4 declared in pins.json
  prettier: current at 3.9.6, npm says the same
  zizmor: current at 1.30.0, pypi says the same
  semgrep: current at 1.176.0, pypi says the same
  golang-image: current at sha256:53eeac89074db483fdf0ab3be1df32bf6e47562263d2d0d6baa7f26acb4957dd, docker-hub says the same
4 pin(s) declared, 4 compared, 0 behind, 0 unresolved.

Both run 2026-09-02 at 37782bf, the first commit of this branch. The second
commit changes no value in pins.json.

The pin does not go green on its own, and the second commit is why

zizmor 1.30.0 carries a rule 1.29.0 does not, and the gate runs that tool at
--min-severity=low, so the release this pin moves to refuses two lines of this
tree:

gh run view --repo Flowfin/site --job 100149949752 --log
INFO zizmor: zizmor v1.30.0
help[self-repository]: use GitHub's dedicated self-repository syntax
  --> ./.github/workflows/package-caller.yml:32:11
  --> ./.github/workflows/release.yml:76:11
12 findings (10 suppressed, 2 safe fixes): 0 informational, 2 low, 0 medium, 0 high

Read 2026-09-02 from the run of the first commit of this branch, elided for
length. So a branch carrying only the pin cannot go green, and the two changes
arrive together rather than one of them landing red.

Both sites are calls to the packing workflow and they are the only two in the
tree:

grep -rn 'uses: ./.github/workflows/package.yml' .github/workflows/
.github/workflows/package-caller.yml:32:    uses: ./.github/workflows/package.yml
.github/workflows/release.yml:76:    uses: ./.github/workflows/package.yml

Run 2026-09-02 at 37782bf, before the second commit.

$/ names the calling repository at the commit that called and takes no
reference; ./ is a path on the runner's workspace, so a step that writes there
ahead of the call decides what runs. GitHub documents the first as the
recommended form for a reusable workflow in the same repository, and the audit
that arrived with 1.30.0 asks for exactly that.

What that costs is stated rather than left to be met: $/ is unavailable on
GitHub Enterprise Server. This repository is published from github.com, so the
form is free here and would not be everywhere.

The other tool in this bump needs nothing. Static analysis (semgrep) passed at
1.176.0 on the first commit of this branch.

Two files this issue does not name

.github/workflows/release.yml and .github/workflows/package-caller.yml are
not files #224 is about. They are here because the pin cannot land without them,
and the change to each is one line. No open pull request touches either:

gh pr list --repo Flowfin/site --state open --json number,headRefName,files --jq '.[] | "\(.number)\t\([.files[].path]|join(","))"'
228	pins.json
179	.github/workflows/codeql.yml,.github/workflows/scorecard.yml,.github/workflows/semgrep.yml,.github/workflows/zizmor.yml

Run 2026-09-02, before the second commit was pushed.

Why this is the second pull request for one change

#227 carries the same one-line change to pins.json and no Signed-off-by
trailer, so the DCO gate refused it:

gh pr checks 227 --repo Flowfin/site | grep '^DCO'
DCO sign-off	fail	5s	https://github.com/Flowfin/site/actions/runs/33599436191/job/100149640691

Run 2026-09-02. A trailer cannot be added to a commit that is already pushed
without rewriting the branch, and this project does not force-push, so the
correction is pushed under a new name and #227 is closed with the reason in its
body rather than repaired in place. The two heads carry the same tree:

git diff --stat 3692a5a 37782bf ; echo "exit=$?"
exit=0

Run 2026-09-02.

`go run . pins` refused on the default branch because the workflow audit and
the static analysis engine were both behind what PyPI publishes, and the
comparison runs weekly on a schedule, so the refusal stood for two days with
nothing that would clear it but a change to this file.

    go run . pins
      zizmor: BEHIND, pinned 1.29.0, pypi says 1.30.0
      semgrep: BEHIND, pinned 1.174.0, pypi says 1.176.0
      4 pin(s) declared, 4 compared, 2 behind, 0 unresolved.

Run 2026-09-02 at 6541274, elided for length.

What this prevents is the drift each `why` field names: a workflow audit that
has stopped understanding the syntax it audits, and a rule engine release that
turns a pattern which refuses something into one that refuses nothing, both of
which leave every run green. Neither pin carries a checksum, because the
resolver compares against what the index publishes rather than against the
wheel, which is what those two entries already say.

The bump is written by hand rather than by a run of the comparison, which
reports and never writes: a machine that rewrote a version and its checksum in
one commit has proved nothing about the bytes it just trusted.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
The audit release the pin above moves to carries a new rule, and it refuses
two lines of this tree at the severity the gate is run at:

    uvx --no-build "zizmor@1.30.0" --strict-collection --min-severity=low --format=plain .
    help[self-repository]: use GitHub's dedicated self-repository syntax
      --> ./.github/workflows/package-caller.yml:32:11
      --> ./.github/workflows/release.yml:76:11
    12 findings (10 suppressed, 2 safe fixes): 0 informational, 2 low, 0 medium, 0 high

Read 2026-09-02 from the run of that version on this branch, elided for length.
Both sites call the packing workflow, both are the only two calls to it in the
tree, and neither carries a reference, which is what the newer form requires:

    grep -rn 'uses: ./.github/workflows/package.yml' .github/workflows/
    .github/workflows/package-caller.yml:32:    uses: ./.github/workflows/package.yml
    .github/workflows/release.yml:76:    uses: ./.github/workflows/package.yml

Run 2026-09-02 before this change.

What the newer form prevents is the older one resolving to a file a previous
step wrote into the workspace rather than to the file at this commit. The
workspace-relative spelling is a path on a runner, so a step that clones or
writes ahead of the call decides what runs; `$/` names the calling repository at
the commit that called, and cannot be pointed anywhere else.

This lands beside the pin rather than after it because the pin is what makes the
rule apply: at 1.29.0 the audit does not exist, and at 1.30.0 the gate refuses
these two lines, so a branch carrying only the pin cannot go green.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit f51005f into main Sep 2, 2026
17 checks passed
@iderex
iderex deleted the ci/the-pins-follow-the-index-with-a-sign-off branch September 2, 2026 06:41
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.

Default branch: Pins did not succeed

1 participant