diff --git a/docs/scheduler/ci.md b/docs/scheduler/ci.md index b64ffcf9..2009da2b 100644 --- a/docs/scheduler/ci.md +++ b/docs/scheduler/ci.md @@ -201,25 +201,27 @@ the forge admin panel as offline until an admin deletes it. The runner the old under its own name and token. Delete it under Site administration, Actions, Runners. -## Actions checkout mirror +## Actions mirrors With `services.hyperhive.deploy.forgejo.actionsFromSelf` enabled, the swarm -controller seeds an `actions/checkout` pull-mirror on the forge and Forgejo's -`DEFAULT_ACTIONS_URL` points at the forge itself. CI -`uses: actions/checkout@vN` steps then resolve on the forge, with no external -DNS on the CI critical path. +controller seeds `actions/checkout` and `actions/upload-artifact` pull-mirrors +(from `github.com/actions/*`) on the forge and Forgejo's `DEFAULT_ACTIONS_URL` +points at the forge itself. CI `uses: actions/@vN` steps then resolve on +the forge, with no external DNS on the CI critical path. A workflow that names +any other bare `actions/*` action fails at job setup with "repository not +found" until that action joins the list in `nix/host-modules/hive-forge/default.nix`. -A forge host that runs the swarm controller therefore resolves -`uses: actions/checkout` from itself, with or without a runner on that host. +A forge host that runs the swarm controller therefore resolves those actions +from itself, with or without a runner on that host. Set `actionsFromSelf = false` there to resolve actions from `data.forgejo.org` and seed no mirror. The option defaults to whether the forge's host also runs the swarm controller (`services.hyperhive.deploy.swarm-controller.enable`): on when it does, off otherwise. Setting it `true` on a forge host without the controller leaves -`actions/checkout` unresolved, because nothing seeds the mirror; evaluation +the actions unresolved, because nothing seeds the mirrors; evaluation warns about it. diff --git a/docs/swarm/README.md b/docs/swarm/README.md index 1b45c78f..2ab9facd 100644 --- a/docs/swarm/README.md +++ b/docs/swarm/README.md @@ -283,7 +283,8 @@ one per hive. It ensures them at start and every five minutes after whitelists = the `operators` team, and no user. The controller leaves a repo with no `main` rule alone; - the pull-mirrors from `deploy.forgejo.mirrors` on the controller's - host (with the `actions/checkout` one `deploy.forgejo.actionsFromSelf` adds); + host (with the `actions/checkout` and `actions/upload-artifact` ones + `deploy.forgejo.actionsFromSelf` adds); - `internal/docs` (private) and `internal/knowledge` (public, with a seed `README.md` while empty); - the `agent-configs` org avatar diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index de97be3e..1dfe06db 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -88,18 +88,24 @@ let effectiveRootUrl = if cfg.rootUrl != null then cfg.rootUrl else defaultRootUrl; # `actionsFromSelf` resolves `uses:` against this forge, which then has to - # hold the action. + # hold every action a workflow in `.forgejo/workflows/` names. actionsFromSelf = deployCfg.forgejo.actionsFromSelf; - actionCheckoutMirror = { - upstream = "https://github.com/actions/checkout"; - dest = "actions/checkout"; - }; - # Unless the operator already declared that dest, which would duplicate it. + actionMirrors = + map + (name: { + upstream = "https://github.com/actions/${name}"; + dest = "actions/${name}"; + }) + [ + "checkout" + "upload-artifact" + ]; + # Minus any dest the operator already declared, which would duplicate it. effectiveMirrors = deployCfg.forgejo.mirrors - ++ lib.optional ( - actionsFromSelf && !(lib.any (m: m.dest == actionCheckoutMirror.dest) deployCfg.forgejo.mirrors) - ) actionCheckoutMirror; + ++ lib.optionals actionsFromSelf ( + lib.filter (a: !(lib.any (m: m.dest == a.dest) deployCfg.forgejo.mirrors)) actionMirrors + ); # Share host netns — forgejo's HTTP / SSH listeners then look # exactly like a host-side service, no port forwarding dance, @@ -199,8 +205,9 @@ in failure on whatever reads it. With {option}`services.hyperhive.deploy.forgejo.actionsFromSelf` - enabled (the default on a host that runs the swarm-controller), an - `actions/checkout` mirror is appended to this list. + enabled (the default on a host that runs the swarm-controller), + `actions/checkout` and `actions/upload-artifact` mirrors are appended + to this list. ''; }; @@ -211,17 +218,16 @@ in example = false; description = '' Resolve a workflow's `uses: /@vN` against this forge - instead of `data.forgejo.org`, and add an `actions/checkout` - pull-mirror to {option}`services.hyperhive.deploy.forgejo.mirrors` - so the checkout step has something to resolve to. A CI job's - checkout then needs no external DNS; only the mirror's re-sync - does. + instead of `data.forgejo.org`, and add `actions/checkout` and + `actions/upload-artifact` pull-mirrors to + {option}`services.hyperhive.deploy.forgejo.mirrors` so those steps + have something to resolve to. A CI job's actions then need no + external DNS; only the mirrors' re-sync does. Defaults to on when this host runs the swarm-controller, which seeds - the `actions/checkout` mirror, and off otherwise. Setting it `true` on - a host without the controller leaves `actions/checkout` unresolved: - nothing seeds the mirror, and the warning about unseeded mirrors - fires. + the mirrors, and off otherwise. Setting it `true` on a host without + the controller leaves both actions unresolved: nothing seeds the + mirrors, and the warning about unseeded mirrors fires. Any other action a workflow names has to be mirrored here too. Set to `false` to resolve actions from `data.forgejo.org` and seed no mirror. @@ -663,7 +669,7 @@ in # reads it. actions.ENABLED = true; # With `actionsFromSelf`, resolve `uses: /@vN` from - # THIS instance (the seeded `actions/checkout` pull-mirror) + # THIS instance (the seeded `actions/*` pull-mirrors) # instead of the upstream default `data.forgejo.org` — keeps # the checkout step on loopback, immune to a host-resolver # blip. `self` = forgejo expands actions against its @@ -1196,7 +1202,7 @@ in systemd.services.swarm-controller.environment.SWARM_CONTROLLER_FORGE_MIRRORS = lib.mkIf deployCfg.swarm-controller.enable (builtins.toJSON effectiveMirrors); warnings = lib.optional (effectiveMirrors != [ ] && !deployCfg.swarm-controller.enable) '' - services.hyperhive.deploy.forgejo.mirrors (or the actions/checkout mirror + services.hyperhive.deploy.forgejo.mirrors (or the actions/* mirrors deploy.forgejo.actionsFromSelf adds) is set on a host that does not run the swarm-controller. The controller seeds mirrors from its own host's list, so these are not seeded: declare them on the swarm-controller's host. diff --git a/nix/module-eval/swarm-services-switch.nix b/nix/module-eval/swarm-services-switch.nix index 77a1a772..36be82f6 100644 --- a/nix/module-eval/swarm-services-switch.nix +++ b/nix/module-eval/swarm-services-switch.nix @@ -479,9 +479,10 @@ let warns mirrorsNoController && !(warns controllerWithMirrors); } { - # The mirror is what `self` resolves `actions/checkout` to, so the two - # come together. The control is the same forge without the option. - name = "actionsFromSelf adds the checkout mirror and resolves actions from the forge"; + # The mirrors are what `self` resolves `actions/*` to, so the two come + # together: one per action `.forgejo/workflows/` names. The control is + # the same forge without the option. + name = "actionsFromSelf adds the actions mirrors and resolves actions from the forge"; ok = let mirrorsOf = @@ -489,7 +490,11 @@ let actionsUrlOf = m: m.containers.hive-forge.config.services.forgejo.settings.actions.DEFAULT_ACTIONS_URL or null; in - lib.elem "actions/checkout" (map (m: m.dest) (mirrorsOf controllerWithSelfActions)) + map (m: m.dest) (mirrorsOf controllerWithSelfActions) == [ + "mirrors/tool" + "actions/checkout" + "actions/upload-artifact" + ] && actionsUrlOf controllerWithSelfActions == "self" && mirrorsOf controllerWithMirrors == [ aMirror ] && actionsUrlOf controllerWithMirrors == null; diff --git a/swarm-controller/src/forge/objects.rs b/swarm-controller/src/forge/objects.rs index 52b3348a..1b98f3d0 100644 --- a/swarm-controller/src/forge/objects.rs +++ b/swarm-controller/src/forge/objects.rs @@ -117,7 +117,7 @@ Do **not** push directly to `main` — agents have read-only access. "; /// The operator-declared pull-mirrors (nix `deploy.forgejo.mirrors`, plus the -/// `actions/checkout` entry `deploy.forgejo.actionsFromSelf` adds), JSON-encoded by `hive-forge/default.nix`. +/// `actions/*` entries `deploy.forgejo.actionsFromSelf` adds), JSON-encoded by `hive-forge/default.nix`. /// Absent or empty means no mirrors. const MIRRORS_ENV: &str = "SWARM_CONTROLLER_FORGE_MIRRORS";