vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Let a job declare the network it needs
d79580247b8f33f7ffdf2f05847733cad12c187a · Keenan Nemetz · 6d ago · parent 4ac42680
Let a job declare the network it needs A runner's --container-network decided the network for every job it took, so a machine that could reach the network gave it to builds that never asked, and a job that did need one could be handed to a machine that had none. The docs said "add bridge only when a job needs it", which no workflow could express. A job now says `network: none` or `network: bridge`. The request is pinned with the run, and the lease only hands a bridge job to a runner that advertises the capability, so a job 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 can still withhold the network from a job that asked for none. A job that declares nothing keeps the runner's own setting, which is what every workflow meant before this field existed. The local run applies the same rule and refuses a bridge job when it was started without one, so `vole workflow run` either matches CI or says what to change on the command line. The workflows page, the run page, and the runner's log line now say what a job asked for and what it ran with. verify.yaml and release.yaml are deliberately not in this change: the instance validates a pushed workflow with the binary it is running, so they can declare the field once that binary knows it. Closes #159.
server/ssh/runner.go +12−1
| @@ -97,6 +97,12 @@ type runnerRequest struct { | |||
| 97 | 97 | // a permission: a runner that claims a label it does not have only hurts itself, | |
| 98 | 98 | // which is why this is a client claim where --repos is server-enforced. | |
| 99 | 99 | Labels []string `json:"labels,omitempty"` | |
| 100 | // Network is the network this machine can give, derived from --container-network. | ||
| 101 | // A job that declares `network: bridge` is only leased to a runner that says it can | ||
| 102 | // provide one, so the job waits for a capable machine instead of running without | ||
| 103 | // the network it asked for. A runner that claims more than it can give only fails | ||
| 104 | // its own jobs, which is the same trade as a label. | ||
| 105 | Network string `json:"network,omitempty"` | ||
| 100 | 106 | // Wait is how many seconds an idle lease may park before answering "nothing to | |
| 101 | 107 | // do". Zero answers at once, which is what a one-shot runner wants: it is here to | |
| 102 | 108 | // run the job it was started for, not to wait for the next one. | |
| @@ -161,6 +167,10 @@ type runnerJob struct { | |||
| 161 | 167 | Trigger string `json:"trigger,omitempty"` | |
| 162 | 168 | TriggerAction string `json:"trigger_action,omitempty"` | |
| 163 | 169 | EventPayload string `json:"event_payload,omitempty"` | |
| 170 | // Network is the isolation the job asked for with `network:`, or empty when the | ||
| 171 | // workflow did not say. The runner applies it to the container it starts, so a job | ||
| 172 | // that asks for none gets none even on a machine that could provide a bridge. | ||
| 173 | Network string `json:"network,omitempty"` | ||
| 164 | 174 | // Image is a registry reference or "file:<name>". For the latter, ImageDefinition | |
| 165 | 175 | // is the pinned recipe and ImageSHA is its digest; the runner builds it locally. | |
| 166 | 176 | Image string `json:"image"` | |
| @@ -278,7 +288,7 @@ func (s *Server) serveRunner(ch xssh.Channel, user string) { | |||
| 278 | 288 | // loses exactly that race. | |
| 279 | 289 | wake := cfg.Runs.Work() | |
| 280 | 290 | lease := runs.LeaseRequest{ | |
| 281 | Owner: owner, Repos: want, Labels: req.Labels, | ||
| 291 | Owner: owner, Repos: want, Labels: req.Labels, Network: req.Network, | ||
| 282 | 292 | TTL: cfg.Lease, MaxPerRepo: cfg.MaxJobsPerRepo, | |
| 283 | 293 | } | |
| 284 | 294 | run, err := cfg.Runs.Lease(lease, now) | |
| @@ -323,6 +333,7 @@ func (s *Server) serveRunner(ch xssh.Channel, user string) { | |||
| 323 | 333 | Trigger: run.Trigger, TriggerAction: run.TriggerAction, EventPayload: run.EventPayload, | |
| 324 | 334 | Image: run.Image, ImageFile: run.ImageFile, ImageDefinition: run.ImageDefinition, | |
| 325 | 335 | ImageSHA: run.ImageSHA, | |
| 336 | Network: run.Network, | ||
| 326 | 337 | Env: run.Env, | |
| 327 | 338 | Secrets: secrets, Missing: missing, | |
| 328 | 339 | Tag: run.Tag, TagAnnotated: run.TagAnnotated, ReleaseArtifacts: run.ReleaseArtifacts, | |