Files
branderson 8cb4fb0447
tests / runner-env (confined) (pull_request_target) Successful in 40s
tests / tests (pull_request_target) Successful in 1m30s
tests / compose-schema (pull_request_target) Successful in 48s
tests / runner-env (privileged) (pull_request_target) Successful in 38s
Scope a project's names to that project's jobs
Every job on the confined tier resolved against one list and was filtered by
one ipset, so a name any trusted repository declared was reachable from every
repository's jobs. One project's declaration widened all of them.

THE SET IS WHAT HAD TO BE SCOPED, not the resolver. It holds addresses with no
memory of which name put them there, and every bridge matched the same one, so
the union was at the address layer: a project that could not resolve another's
name could still connect to the address that name resolved to, and declarations
are public. A per-project resolver would have looked like progress and changed
almost nothing.

dnsmasq places a name's addresses in several sets at once, so one resolver fills
each declaring project's set and no others. The allowlist writes an ipset= line
per name listing the sets that asked for it; the firewall matches each bridge
against its own project's set and a base set every project shares.

NO SHARED FALLBACK, and no opt-in. A repository that declares names and has no
set of its own refuses the render, naming what is missing. A set every project
can reach is the thing this exists to end, and falling back to one would mean
arriving there by doing nothing rather than by choosing it. Updating is the
opt-in; not finishing the update is not a quieter way to keep the old behaviour.
Refusing installs nothing, so the allowlist already in force stays in force
while the migration is worked through - the cost is a loud error on the timer,
not a host that has lost its allowlist.

A repository that declares nothing needs no assignment, having no names to
scope, and meets the refusal on the day it declares something.

Ids are never reused. One names a set and a bridge that may still hold
addresses and still carry rules, and handing a freed id to another project would
give it whatever the last occupant left behind.

The upgrade note is a migration in five steps, ending with moving each project's
runners onto its own network - the step that decides whether any of it takes
effect, since a runner takes whatever jobs it is offered. dejima-ci-runners
gained --network for that, rather than the note naming a flag that does not
exist.

Three things caught while doing it. The name count was lines minus the header,
which doubled the moment a name emitted two lines. A guest-layer note must
require a snapshot, or this tier's scheduled rollback quietly undoes the
install. And the revocation flush from the previous change flushed the set named
by the config key, which is a prefix now and holds nothing - it would have
emptied an unused set and reported a revocation that had not happened, which is
the failure that flush was added to fix.

Capturing fetch_repo into a variable also dropped its exit status, so a forge
that rejected the token became a repository that declared nothing. It was the
last command of a pipeline before, where pipefail carried the failure out.
2026-09-01 12:03:19 -07:00

2 lines
2 B
Plaintext