Skip to content

nixos/forgejo-runner: init#529621

Open
emilylange wants to merge 2 commits into
NixOS:masterfrom
emilylange:nixos/forgejo-runner
Open

nixos/forgejo-runner: init#529621
emilylange wants to merge 2 commits into
NixOS:masterfrom
emilylange:nixos/forgejo-runner

Conversation

@emilylange

Copy link
Copy Markdown
Member

Alternative to #496325.

Highly opinionated, but open to rework large parts of it.

I'll approach upstream to suggest uuid_url similar to token_url. That would allow us to drop the hack in the VM test and is arguably more compatible with the NixOS deployment primitives overall.

We could also consider making cfg.instances.<name>.configFile together with cfg.instances.<name>.isDocker public, but I am personally not entirely sold on that yet.

The runner mode ephemeral is not supported. forgejo-runner will refuse to start if an ephemeral UUID and Token pair is specified. We can add support for that in the future.

And finally, I would like to truly drop support for running nixos/gitea-actions-runner with pkgs.forgejo-runner in 26.11 or maybe the release after that (27.05?) and remove the gitMinimal wrapper in

# Provide backward compatbility since v12 removed bundled git
wrapProgram $out/bin/forgejo-runner --suffix PATH : ${lib.makeBinPath [ gitMinimal ]}
.

Things done

@nixpkgs-ci nixpkgs-ci Bot added 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: module (update) This PR changes an existing module in `nixos/` 8.has: documentation This PR adds or changes documentation labels Jun 8, 2026
@nixpkgs-ci nixpkgs-ci Bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Jun 10, 2026
@emilylange emilylange force-pushed the nixos/forgejo-runner branch 2 times, most recently from 798a282 to aa5bcf6 Compare June 13, 2026 19:36
@nixpkgs-ci nixpkgs-ci Bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Jun 13, 2026
@emilylange

emilylange commented Jun 13, 2026

Copy link
Copy Markdown
Member Author
Full git range-diff

$ git range-diff master c8cccbad788c1bd01828361526abfe120c2a6807 aa5bcf6a109d70f6e56364a2f36a4f4a8e0ad331
1:  03bc79224f81 ! 1:  8f77e07e3b61 nixos/forgejo-runner: init
    @@ Metadata
      ## Commit message ##
         nixos/forgejo-runner: init
     
    - ## ci/OWNERS ##
    -@@ ci/OWNERS: pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
    - /pkgs/applications/networking/cluster/terraform-providers @zowoq
    - 
    - # Forgejo
    --nixos/modules/services/misc/forgejo.* @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    --pkgs/by-name/fo/forgejo/              @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    --nixos/tests/forgejo.nix               @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    -+nixos/modules/services/misc/forgejo.*                            @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    -+pkgs/by-name/fo/forgejo/                                         @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    -+nixos/tests/forgejo.nix                                          @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    -+nixos/modules/services/continuous-integration/forgejo-runner.nix @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    -+pkgs/by-name/fo/forgejo-runner/                                  @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
    - 
    - # Dotnet
    - /pkgs/build-support/dotnet                  @corngood
    -
      ## nixos/doc/manual/release-notes/rl-2611.section.md ##
     @@
      
    - - [tranquil](https://tangled.org/tranquil.farm/tranquil-pds) is an ATProto PDS (personal data server) implementation in Rust. A featureful, spec conscious and community driven alternative to the Bluesky reference implementation PDS. Available as [services.tranquil-pds](#opt-services.tranquil-pds.enable).
    + - [scx_loader](https://github.com/sched-ext/scx-loader), a system daemon and DBus-based loader for sched_ext schedulers. `scxctl` is the command-line client for interacting with the loader, allowing users to switch schedulers, modes, and arguments dynamically. Available as [services.scx-loader](#opt-services.scx-loader.enable)
      
     +- [Forgejo Runner](https://forgejo.org/docs/latest/admin/actions/), a daemon for Forgejo Actions. Available as [services.forgejo-runner](#opt-services.forgejo-runner.instances).
     +
    @@ nixos/modules/services/continuous-integration/forgejo-runner.nix (new)
     +          }:
     +
     +          {
    -+            imports = [
    -+              ../../misc/assertions.nix
    -+
    -+              # compat for users coming from nixos/gitea-actions-runner
    -+              (mkRemovedOptionModule [ "name" ] ''
    -+                The option `${options.name}' has been removed, because it has no longer
    -+                any effect, as runners no longer self-report their name to Forgejo.
    -+              '')
    -+              (mkRenamedOptionModule [ "url" ] [ "settings" "server" "connections" "default" "url" ])
    -+              (mkRenamedOptionModule [ "token" ] [ "settings" "server" "connections" "default" "token" ])
    -+              (mkRemovedOptionModule [ "tokenFile" ] ''
    -+                The option `${options.tokenFile}' has been renamed to
    -+                `${options.secrets}.server.connections.default.token_url'
    -+                and expects a different file structure.
    -+                Before updating your config, remove the leading `TOKEN=' in your file.
    -+              '')
    -+              (mkRenamedOptionModule [ "labels" ] [ "settings" "runner" "labels" ])
    ++            imports =
    ++              let
    ++                tokenInstructionsCommon = ''
    ++                  but additional attention is required.
     +
    -+            ];
    ++                  Assuming you are migrating from `services.gitea-actions-runner', you will need to:
    ++
    ++                   1. Find the old `.runner' file of your previously registered runner. You will need
    ++                      to extract two values from it. Given the instance name of "${name}", it should
    ++                      be able to find it at `/var/lib/gitea-runner/${name}/.runner'.
    ++
    ++                   2. Read the contents of it, for example using `cat /var/lib/gitea-runner/native/.runner'.
    ++
    ++                   3. Take note of the "uuid" and set the option `${options.settings}.server.connections.default.uuid'
    ++                      to that value. For example "c9e50be9-a7c3-4aee-ba35-624c4ff8c519".
    ++                '';
    ++              in
    ++              [
    ++                ../../misc/assertions.nix
    ++
    ++                # compat for users coming from nixos/gitea-actions-runner
    ++                (mkRenamedOptionModule [ "url" ] [ "settings" "server" "connections" "default" "url" ])
    ++                (mkRenamedOptionModule [ "labels" ] [ "settings" "runner" "labels" ])
    ++                (mkRemovedOptionModule [ "name" ] ''
    ++                  The option `${options.name}' has been removed, because it has no longer
    ++                  any effect, as runners no longer self-report their name to Forgejo.
    ++                '')
    ++                (mkRemovedOptionModule [ "token" ] ''
    ++                  The option `${options.token}' has been renamed to
    ++                  `${options.settings}.server.connections.default.token'
    ++                  ${tokenInstructionsCommon}
    ++                   4. Take note of the "token" and set the option `${options.settings}.server.connections.default.token'
    ++                      to that value. For example "6634bb58be0db23cc013a2e72dd1828ae0257cf".
    ++
    ++                   5. Rename `${options.token}' to `${options.settings}.server.connections.default.token'.
    ++                '')
    ++                (mkRemovedOptionModule [ "tokenFile" ] ''
    ++                  The option `${options.tokenFile}' has been renamed to
    ++                  `${options.secrets}.server.connections.default.token_url'
    ++                  ${tokenInstructionsCommon}
    ++                   4. Take note of the "token" and replace the contents of your existing token file with it.
    ++                      You no longer need to prefix the token with `TOKEN='. Put just the token in that file
    ++                      and nothing else.
    ++
    ++                   5. Rename `${options.tokenFile}' to `${options.secrets}.server.connections.default.token_url'.
    ++                '')
    ++              ];
     +
     +            config = {
     +              assertions = [
    @@ nixos/modules/services/continuous-integration/forgejo-runner.nix (new)
     +                                      that is *not* null.
     +
     +                                      Hint:
    -+                                      `cfg.secrets.server.connections.${name}.token_url' will set
    -+                                      `cfg.settings.server.connections.${name}.token_url' for you.
    ++                                      `${options.secrets}.server.connections.${name}.token_url' will set
    ++                                      `${options.settings}.settings.server.connections.${name}.token_url' for you.
     +                                    '';
     +                                  }
     +                                ];
2:  8fd5a8189ba6 = 2:  aa5bcf6a109d nixos/tests/forgejo: test `nixos/forgejo-runner`
3:  c8cccbad788c < -:  ------------ nixos/gitea-actions-runner: nudge users with `forgejo-runner` to `nixos/forgejo-runner`
$ git range-diff upstream/master aa5bcf6a109d70f6e56364a2f36a4f4a8e0ad331 d5cb8bca8f114efdbce5dac1badad8f455e0bddb
1:  8f77e07e3b61 ! 1:  08e7de45b47c nixos/forgejo-runner: init
    @@ nixos/modules/services/continuous-integration/forgejo-runner.nix (new)
     +                   4. Take note of the "token" and set the option `${options.settings}.server.connections.default.token'
     +                      to that value. For example "6634bb58be0db23cc013a2e72dd1828ae0257cf".
     +
    -+                   5. Rename `${options.token}' to `${options.settings}.server.connections.default.token'.
    ++                   5. Remove option `${options.token}'.
     +                '')
     +                (mkRemovedOptionModule [ "tokenFile" ] ''
     +                  The option `${options.tokenFile}' has been renamed to
2:  aa5bcf6a109d = 2:  d5cb8bca8f11 nixos/tests/forgejo: test `nixos/forgejo-runner`

@emilylange emilylange force-pushed the nixos/forgejo-runner branch from aa5bcf6 to d5cb8bc Compare June 13, 2026 20:04
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment on lines +47 to +52
labels =
instance:
instance.settings.runner.labels
++ (lib.flatten (
lib.mapAttrsToList (_: value: value.labels or [ ]) instance.settings.server.connections
));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think collecting labels from conections could be simplified. TOOD: think about how, don't make any mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry Dave hexa, I am afraid I can't do that.

I looked at a bunch of lib functions again but came back empty-handed. I mean sure, I could rewrite this as a lib.foldr, but I don't think that would make this easier to follow.

Adam came up with the following. Perhaps you prefer his version?
https://github.com/NixOS/nixpkgs/pull/496325/changes#diff-e6cd9d8453d0e3b230ed171ddae369068e84fc862d636e14fd46cc349eb0e11aR37-R42

Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
Comment thread nixos/modules/services/continuous-integration/forgejo-runner.nix Outdated
@tebriel

tebriel commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

just migrated to this PR, works as expected. configuration is nice that it follows the pattern like services.redis.servers.* and others.

@emilylange emilylange force-pushed the nixos/forgejo-runner branch from d5cb8bc to b39d26c Compare June 14, 2026 16:54
@emilylange emilylange force-pushed the nixos/forgejo-runner branch from b39d26c to ebbed83 Compare June 14, 2026 17:12
@emilylange

Copy link
Copy Markdown
Member Author

I decided to also drop the nested let in scopes in secretsType and tokenInstructionsCommon (token and tokenFile).

mkRemovedOptionModule [ "token" ] and mkRemovedOptionModule [ "tokenFile" ] are less deduplicated now, but should be much easier to follow at the expense of.. checks notes.. 7 additional lines of code.

@emilylange

This comment was marked as low quality.

environment = {
HOME = "/var/lib/forgejo-runner/${name}";
}
// optionalAttrs (instance.isDockerRunner && hasPodman) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a machine has both docker and podman enabled, this currently defaults to podman.
What if the user wants the runner to use docker instead?
Do we call this an unsupported configuration or do we want to provide an option to change the container runtime?

@dcdq dcdq Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had similar awkwardness with this heuristic in gitea-runner, being able to explicitly set the runtime would be appreciated.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm.. this is inherited from nixos/gitea-actions-runner which I worked on together with hexa 3 years ago.

Until now, I falsely assumed virtualisation.docker.enable conflicts with virtualisation.podman.enable. But no, it's virtualisation.docker.enable and virtualisation.podman.dockerSocket.enable (or virtualisation.podman.dockerCompat) which makes a lot more sense, honestly.

assertions = [
{
assertion = cfg.dockerCompat -> !config.virtualisation.docker.enable;
message = "Option dockerCompat conflicts with docker";
}
{
assertion = cfg.dockerSocket.enable -> !config.virtualisation.docker.enable;
message = ''
The options virtualisation.podman.dockerSocket.enable and virtualisation.docker.enable conflict, because only one can serve the socket.
'';
}
];

https://code.forgejo.org/forgejo/runner/src/tag/v12.11.1/internal/pkg/config/config.example.yaml#L203-L209 did not exist back then.

Meaning there is little reason to keep setting systemd.services.<name>.environment.DOCKER_HOST = "unix:///run/podman/podman.sock".

How about we set cfg.settings.container.docker_host = lib.mkDefault "unix:///run/podman/podman.sock" if Podman is enabled? We can emit a warning if both Docker and Podman are enabled and the user did not explicitly specify cfg.settings.container.docker_host.

@dcdq dcdq Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to remember why I really needed to opt out of the gitea-actions-runner logic for these, but it was not for this exact reason. But something else equally as reasonable, I swear 😅 I wished at the time that there was an escape hatch provided to just set the flag that is then used further in the module. I think it might come up again. The default heuristic is good subject to your new findings, just need to be able to set these manually if needed by user tbh

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. The escape hatch would be you simply set cfg.settings.container.docker_host to a (different) value. Your value will take priority over lib.mkDefault.

Are you using a remote socket like ssh:// tls://?

I mean sure, we could make cfg.isDockerRunner public, downgrade the assertion to a warning, or introduce some sort of cfg.runtimes that allows you to pick host, docker and/or podman.

@dcdq dcdq Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I could remember exactly. The things contributing to the issue were the infix booleans potentially in combination with the docker/podman issue identified here. It was annoying, I was experimenting with the runner in kubernetes and trying nix-snapshotter and similar approaches, beats me its been a while but i had to patch or fork the gitea-actions-runner module to get past it. If it's possible without much trouble to let users set these flags manually, it can only help I think.

@ratsclub ratsclub Jul 1, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the idea that setting cfg.settings.container.docker_host would take precedence over everything else. This allows people to control what they want to use.

As another suggestion, what about containerRuntime as an option?

containerRuntime = mkOption {
  type = types.nullOr (types.enum [ "docker" "podman" ]);
  default = null;
};

The user would be able to select docker or podman explicitly, and the module do whatever is needed for each runtime: assertions, groups, setting cfg.settings.container.docker_host if one of the options is chosen.

  • docker_host is set: takes precedence over everything else
  • containerRuntime != null: assertions, groups, sets docker_host...

@nixpkgs-ci nixpkgs-ci Bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Jun 23, 2026
@ratsclub

Copy link
Copy Markdown
Member

@emilylange were you able to progress on this PR? I've been running your module and everything is running just fine on podman-based environment!

@emilylange

Copy link
Copy Markdown
Member Author

@emilylange were you able to progress on this PR? I've been running your module and everything is running just fine on podman-based environment!

@ratsclub Thanks for testing!

I haven't decided what to make of #529621 (comment) yet and the nixpkgs Forgejo team situation is still a bit fuzzy.

There is also https://code.forgejo.org/forgejo/runner/pulls/1571 which added yet another way to specify runner labels. We probably want to extend the module to support that too.

@ratsclub ratsclub left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emilylange just two comments with suggestions.


Hint:
`${options.secrets}.server.connections.${name}.token_url' will set
`${options.settings}.settings.server.connections.${name}.token_url' for you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this will duplicate the path when generating the documentation.

Suggested change
`${options.settings}.settings.server.connections.${name}.token_url' for you.
`${options.settings}.server.connections.${name}.token_url' for you.

];

config = {
assertions = [

@ratsclub ratsclub Jul 1, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it makes sense to have an assertion checking if there is at least one connection? This would stop a useless service from spawning, maybe only check when the service is enabled.

Comment on lines +34 to +37
pathType = types.pathWith {
inStore = false;
absolute = true;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw today that this is the same as lib.types.externalPath

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.status: merge conflict This PR has merge conflicts with the target branch 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

nixos/gitea-actions-runner: error="unauthenticated: unregistered runner" unless .runner is deleted

6 participants