fix(forge): make Forgejo's signing key actually resolve
Forgejo reported "does not have a signing key" on PRs despite the forgejo-gpg-init service generating one. Two causes, both fixed: - SIGNING_KEY = "default" resolves through the forgejo process's git config (user.signingkey), not by scanning GNUPGHOME — and the keygen never set it, so "default" found no key. forgejo-gpg-init now sets the forgejo user's git user.signingkey to the generated key (+ commit and tag gpgsign), with HOME pinned to the state dir so the global config lands where forgejo reads it. - The keygen guard was stamp-file based, so a partial state wipe that lost the key while keeping the stamp would never regenerate. It's now keyed on the actual secret key (regenerate iff gpg shows none) and runs idempotently before forgejo on each start. Also drops the heredoc for the gpg params in favour of printf (avoids nix-string indentation fragility) and corrects the stale comment that claimed "default" scans GNUPGHOME.
This commit is contained in:
parent
3fda4ab127
commit
d6b95d22f0
1 changed files with 54 additions and 26 deletions
|
|
@ -290,9 +290,12 @@ in
|
||||||
THEMES = "catppuccin-vibec0re,forgejo-auto,forgejo-light,forgejo-dark,gitea-auto,gitea-light,gitea-dark";
|
THEMES = "catppuccin-vibec0re,forgejo-auto,forgejo-light,forgejo-dark,gitea-auto,gitea-light,gitea-dark";
|
||||||
};
|
};
|
||||||
# Point forgejo at the GPG key generated by the
|
# Point forgejo at the GPG key generated by the
|
||||||
# forgejo-gpg-init oneshot below. "default" resolves to
|
# forgejo-gpg-init service below. SIGNING_KEY = "default"
|
||||||
# the first secret key found in GNUPGHOME. GNUPGHOME
|
# resolves via the forgejo process's git config
|
||||||
# must be absolute and writeable by the forgejo user.
|
# (`user.signingkey`) — which forgejo-gpg-init sets to the
|
||||||
|
# generated key — not by scanning GNUPGHOME. GNUPGHOME is
|
||||||
|
# the keyring forgejo signs from; must be absolute +
|
||||||
|
# writeable by the forgejo user.
|
||||||
"repository.signing" = {
|
"repository.signing" = {
|
||||||
SIGNING_KEY = "default";
|
SIGNING_KEY = "default";
|
||||||
GNUPGHOME = "/var/lib/forgejo/.gnupg";
|
GNUPGHOME = "/var/lib/forgejo/.gnupg";
|
||||||
|
|
@ -321,42 +324,67 @@ in
|
||||||
pkgs.gnupg
|
pkgs.gnupg
|
||||||
];
|
];
|
||||||
|
|
||||||
# Generate a GPG signing key for Forgejo on first boot so UI
|
# Ensure Forgejo has a usable GPG signing key so UI merges / CRUD
|
||||||
# merges produce signed commits instead of erroring "no key to
|
# commits are signed instead of erroring "does not have a signing
|
||||||
# sign with". The key lives in forgejo's persistent state dir
|
# key". This service (a) generates a key in forgejo's persistent
|
||||||
# (/var/lib/forgejo/.gnupg) and survives container restarts.
|
# keyring iff one isn't already present — keyed on the actual
|
||||||
# The stamp file prevents re-generation on subsequent boots.
|
# secret key, NOT a stamp file, so a partial state wipe that loses
|
||||||
# Service runs as the forgejo user so file ownership is correct.
|
# the key still regenerates it — and (b) points the forgejo user's
|
||||||
|
# git config at it (`user.signingkey` + commit/tag gpgsign), which
|
||||||
|
# is how `SIGNING_KEY = "default"` actually resolves. Runs as the
|
||||||
|
# forgejo user before forgejo on each start; idempotent (the keygen
|
||||||
|
# is guarded, the git-config is a cheap re-set).
|
||||||
systemd.services.forgejo-gpg-init = {
|
systemd.services.forgejo-gpg-init = {
|
||||||
description = "generate GPG signing key for Forgejo (once)";
|
description = "ensure Forgejo's GPG signing key + git signing config";
|
||||||
# Start before forgejo so the key is ready when forgejo reads
|
# Start before forgejo so the key + signing config are ready when
|
||||||
# repository.signing config on startup.
|
# forgejo reads repository.signing on startup.
|
||||||
wantedBy = [ "forgejo.service" ];
|
wantedBy = [ "forgejo.service" ];
|
||||||
before = [ "forgejo.service" ];
|
before = [ "forgejo.service" ];
|
||||||
unitConfig.ConditionPathExists = "!/var/lib/forgejo/.gnupg/hive-key-init.stamp";
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
RemainAfterExit = true;
|
|
||||||
User = "forgejo";
|
User = "forgejo";
|
||||||
Group = "forgejo";
|
Group = "forgejo";
|
||||||
};
|
};
|
||||||
environment.GNUPGHOME = "/var/lib/forgejo/.gnupg";
|
# GNUPGHOME = the keyring forgejo signs from; HOME so
|
||||||
|
# `git config --global` lands where the forgejo process reads it.
|
||||||
|
environment = {
|
||||||
|
GNUPGHOME = "/var/lib/forgejo/.gnupg";
|
||||||
|
HOME = "/var/lib/forgejo";
|
||||||
|
};
|
||||||
path = [
|
path = [
|
||||||
pkgs.gnupg
|
pkgs.gnupg
|
||||||
|
pkgs.git
|
||||||
|
pkgs.gnugrep
|
||||||
|
pkgs.gawk
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
];
|
];
|
||||||
script = ''
|
script = ''
|
||||||
mkdir -p "$GNUPGHOME"
|
set -euo pipefail
|
||||||
chmod 700 "$GNUPGHOME"
|
mkdir -p "$GNUPGHOME"
|
||||||
gpg --batch --gen-key <<'EOF'
|
chmod 700 "$GNUPGHOME"
|
||||||
%no-protection
|
|
||||||
Key-Type: RSA
|
# Generate only if no secret key is present (key-based guard,
|
||||||
Key-Length: 4096
|
# not a stamp — a stamp can outlive the key after a state wipe
|
||||||
Name-Real: HyperHive Forge
|
# and wrongly suppress regeneration).
|
||||||
Name-Email: forgejo@hive
|
if ! gpg --list-secret-keys --with-colons 2>/dev/null | grep -q '^sec:'; then
|
||||||
Expire-Date: 0
|
printf '%s\n' \
|
||||||
EOF
|
'%no-protection' \
|
||||||
touch "$GNUPGHOME/hive-key-init.stamp"
|
'Key-Type: RSA' \
|
||||||
|
'Key-Length: 4096' \
|
||||||
|
'Name-Real: HyperHive Forge' \
|
||||||
|
'Name-Email: forgejo@hive' \
|
||||||
|
'Expire-Date: 0' \
|
||||||
|
| gpg --batch --gen-key
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Point git (hence Forgejo's SIGNING_KEY="default") at the key.
|
||||||
|
KEYID=$(gpg --list-secret-keys --keyid-format long --with-colons \
|
||||||
|
| awk -F: '/^sec:/ { print $5; exit }')
|
||||||
|
if [ -n "$KEYID" ]; then
|
||||||
|
git config --global user.signingkey "$KEYID"
|
||||||
|
git config --global commit.gpgsign true
|
||||||
|
git config --global tag.gpgsign true
|
||||||
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue