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 ''; }; };