What
A job declares the isolation it needs:
jobs:
fetch:
image: golang:1.27-bookworm
network: bridge
bridge asks for a network, none withholds one, and a job that says nothing
keeps the runner’s own setting, so no existing workflow changes behaviour.
The request is pinned with the run and matched at the queue: a bridge job is only
leased to a runner that advertises the capability, so it waits for a capable machine
instead of failing on one that never could. The runner applies the job’s request to
its container, which means a bridge runner withholds the network from a job that
asked for none. vole workflow run applies the same rule and refuses a bridge job
when it was started without --container-network bridge, so the local answer stays
the CI answer.
Why
The choice was a runner flag, so one job needing the network gave it to every job on
that machine, and a job that needed one could be silently queued onto a machine that
had none. docs/runner.md already claimed “add bridge only when a job needs it”,
which nothing could express. This closes the network item in #138 §5.
Shape of the change
- Format (
ci/workflow.go):Job.Network,ValidNetwork, validated at push. - Queue (
ci/runs): pinnednetworkcolumn with the additive migration the queue already uses; the lease filter isr.network <> 'bridge' OR ? = 'bridge', so an unspecified ornonejob matches every runner. - Server (
server/ci.go,server/ssh/runner.go): the request travels to the queue and to the lease. - Runner (
ci/agent): the capability goes with every lease;networkForapplies the job’s request and refuses abridgejob it cannot provide. - Local run (
cmd/vole): the same rule, with a message naming the flag. - UI: the workflows page shows what a job asks for, the run page shows what the run declared.
- Docs:
docs/workflows.md, the reference’snetworksection and field table, anddocs/runner.md— including removing the two claims that a job could already ask for a network.
Not in this change
verify.yamlandrelease.yamlwould normally declarenetwork: bridgehere, but the instance validates a pushed workflow with the binary it is running, and that binary does not know the field yet. They follow in a second change once the instance and its runner run this build.- Per-job CPU, memory, and PID limits. Same shape, separate field.
- Priority for a
bridgejob waiting on a capable runner.
Checks
go build ./...,go vet ./...,gofmt -l .clean.vole workflow run verifypasses in the pinned image (format, vet, build, licenses, govulncheck, packages, links, race tests). The local run of that workflow used the default bridge network, which this change leaves alone for a job that does not declare one.- New tests:
TestJobNetworkIsParsedAndValidated(format),TestNetworkDecidesWhichRunnerMayTakeAJob(lease, including that a bridge job is never handed to a closed runner even when it is the oldest),TestNetworkForUsesTheJobsRequest(runner application and refusal),TestWorkflowRunAppliesTheJobsNetwork(local parity, both directions).
Closes #159.