From 71b0f1c5b805ed74ed7a1a86d10ecb94159bffd7 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 12 Aug 2026 15:04:18 +0200 Subject: [PATCH] fix(3149): pass the oauth flags as an array, and verify the source exists The login source was never registered on any boot since it landed: forgejo-sso-source[422]: Command error: unexpected arguments: profile, email, groups' The flags were built as a shell STRING and word-split at the call site. Splitting happens after quote removal, so the quotes inside the value are just characters: --scopes 'openid profile email groups' reached forgejo as four words, three of them unexpected and one carrying an apostrophe. escapeShellArg interpolated into a string that is later word-split is a no-op that looks exactly like protection. An array carries the argument boundaries instead of re-deriving them from whitespace, and the shellcheck disable goes with it. Also assert the effect: the unit now fails if the source is absent from 'admin auth list' afterwards. The old failure exited non-zero and was still invisible to every check that read the rendered script rather than its result. --- nix/host-modules/hive-forge/default.nix | 33 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index 518a63a0..0967fafe 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -808,26 +808,45 @@ in # principals here, and root can read the resting copy # anyway. Accepted deliberately (see docs/swarm/), not # overlooked; upstream gap filed. - args="--provider openidConnect \ - --key ${lib.escapeShellArg cfg.sso.clientId} \ - --auto-discover-url ${lib.escapeShellArg autheliaDiscoveryUrl} \ - --scopes ${lib.escapeShellArg "openid profile email groups"}" + # An ARRAY, not a string. A string of arguments has to be + # word-split at the call site to become argv, and splitting + # does not honour the quotes inside the value — the shell + # already finished quote removal by then, so + # `--scopes 'openid profile email groups'` arrives as four + # words with two stray apostrophes, and forgejo rejects the + # last three as unexpected arguments. An array carries the + # boundaries instead of re-deriving them from whitespace. + args=( + --provider openidConnect + --key ${lib.escapeShellArg cfg.sso.clientId} + --auto-discover-url ${lib.escapeShellArg autheliaDiscoveryUrl} + --scopes ${lib.escapeShellArg "openid profile email groups"} + ) - # shellcheck disable=SC2086 if forgejo admin auth list | grep -q "[[:space:]]${ssoSourceName}[[:space:]]"; then id=$(forgejo admin auth list \ | grep "[[:space:]]${ssoSourceName}[[:space:]]" \ | cut -f1) forgejo admin auth update-oauth --id "$id" \ --name ${lib.escapeShellArg ssoSourceName} \ - --secret "$secret" $args + --secret "$secret" "''${args[@]}" echo "updated OIDC login source ${ssoSourceName} (id $id)" else forgejo admin auth add-oauth \ --name ${lib.escapeShellArg ssoSourceName} \ - --secret "$secret" $args + --secret "$secret" "''${args[@]}" echo "added OIDC login source ${ssoSourceName}" fi + + # Assert the EFFECT, not the command. The bug this replaced + # was a malformed argv: the unit ran the right verb, forgejo + # rejected it, and every check that read the rendered script + # still passed. A registration that does not appear in the + # source list did not happen, whatever the exit code said. + if ! forgejo admin auth list | grep -q "[[:space:]]${ssoSourceName}[[:space:]]"; then + echo "login source ${ssoSourceName} is absent after registration" >&2 + exit 1 + fi ''; }; };