[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
#
|
|
|
|
|
# Installe Forgejo — https://forgejo.org — depuis le binaire statique officiel
|
|
|
|
|
# publié sur https://codeberg.org/forgejo/forgejo.
|
|
|
|
|
#
|
|
|
|
|
# Le binaire est statique et sans dépendance : le même fichier sert Debian,
|
|
|
|
|
# Ubuntu, AlmaLinux, Rocky, openSUSE et Arch. Ce script ne touche donc à AUCUN
|
|
|
|
|
# gestionnaire de paquets — c'est ce qui le rend portable sur les plateformes
|
|
|
|
|
# ERPLibre sans une branche par distribution.
|
|
|
|
|
#
|
|
|
|
|
# Il n'appelle PAS env_var.sh, à la différence des scripts d'installation
|
|
|
|
|
# ERPLibre : Forgejo ne dépend ni du dépôt ni de son venv, et le script doit
|
|
|
|
|
# rester utilisable hors d'un checkout.
|
|
|
|
|
#
|
|
|
|
|
# Réglages, tous par variables d'environnement :
|
|
|
|
|
# FORGEJO_VERSION version à poser (défaut : la dernière publiée)
|
|
|
|
|
# FORGEJO_HTTP_PORT port web (défaut : 3000)
|
|
|
|
|
# FORGEJO_SSH_PORT port SSH interne de Forgejo (défaut : 2222)
|
|
|
|
|
# FORGEJO_ADMIN_USER compte administrateur créé (défaut : erplibre)
|
|
|
|
|
# FORGEJO_ADMIN_PASSWORD son mot de passe (défaut : erplibre)
|
|
|
|
|
# FORGEJO_ADMIN_EMAIL son courriel (défaut : admin@erplibre.local)
|
|
|
|
|
# FORGEJO_USER compte système propriétaire (défaut : git)
|
|
|
|
|
# FORGEJO_SKIP_ADMIN à 1, ne crée aucun compte (installateur web)
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
Red='\033[0;31m'
|
|
|
|
|
Green='\033[0;32m'
|
|
|
|
|
Yellow='\033[0;33m'
|
|
|
|
|
Color_Off='\033[0m'
|
|
|
|
|
|
|
|
|
|
VERSION="${FORGEJO_VERSION:-}"
|
|
|
|
|
HTTP_PORT="${FORGEJO_HTTP_PORT:-3000}"
|
|
|
|
|
SSH_PORT="${FORGEJO_SSH_PORT:-2222}"
|
|
|
|
|
# « admin » est REFUSÉ par Forgejo — « CreateUser: name is reserved », mesuré.
|
|
|
|
|
# La liste des noms réservés couvre aussi api, assets, avatars, explore, user…
|
|
|
|
|
ADMIN_USER="${FORGEJO_ADMIN_USER:-erplibre}"
|
|
|
|
|
ADMIN_PASSWORD="${FORGEJO_ADMIN_PASSWORD:-erplibre}"
|
|
|
|
|
ADMIN_EMAIL="${FORGEJO_ADMIN_EMAIL:-admin@erplibre.local}"
|
|
|
|
|
RUN_USER="${FORGEJO_USER:-git}"
|
|
|
|
|
SKIP_ADMIN="${FORGEJO_SKIP_ADMIN:-0}"
|
|
|
|
|
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
# Ce qui a changé sur le disque pendant ce passage. Le service ne redémarre que
|
|
|
|
|
# si quelque chose a bougé : rejouer le script sur une forge saine ne doit pas
|
|
|
|
|
# l'interrompre, même deux secondes.
|
|
|
|
|
CHANGED=0
|
|
|
|
|
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
BIN=/usr/local/bin/forgejo
|
|
|
|
|
CONF_DIR=/etc/forgejo
|
|
|
|
|
CONF="$CONF_DIR/app.ini"
|
|
|
|
|
DATA=/var/lib/forgejo
|
|
|
|
|
UNIT=/etc/systemd/system/forgejo.service
|
|
|
|
|
API=https://codeberg.org/api/v1/repos/forgejo/forgejo/releases
|
|
|
|
|
DL=https://codeberg.org/forgejo/forgejo/releases/download
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
|
|
|
sed -n '5,26p' "$0" | sed 's/^# \?//'
|
|
|
|
|
exit 0
|
|
|
|
|
}
|
|
|
|
|
case "${1:-}" in
|
|
|
|
|
-h|--help) usage ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
say() { echo -e " $*"; }
|
|
|
|
|
die() { echo -e " ${Red}✗ $*${Color_Off}" >&2; exit 1; }
|
|
|
|
|
|
2026-08-19 19:43:43 -04:00
|
|
|
# Adresse par laquelle la machine est joignable, pour ROOT_URL et SSH_DOMAIN.
|
|
|
|
|
#
|
|
|
|
|
# « hostname -I » d'abord, mais PAS seulement : ce drapeau vient de net-tools et
|
|
|
|
|
# l'inetutils d'Arch ne le connaît pas. « ip route get » le remplace partout où
|
|
|
|
|
# iproute2 est là, c'est-à-dire partout. « localhost » ferme la marche : une
|
|
|
|
|
# forge joignable en local vaut mieux qu'un script qui s'arrête.
|
|
|
|
|
host_address() {
|
|
|
|
|
local h=""
|
|
|
|
|
# Chaque candidat est VALIDÉ comme adresse IPv4 avant d'être retenu : un
|
|
|
|
|
# « hostname » qui ne connaît pas -I peut rendre le nom de la machine, et
|
|
|
|
|
# une ROOT_URL bâtie sur un nom non résolvable est pire qu'un repli.
|
|
|
|
|
for h in \
|
|
|
|
|
"$(hostname -I 2>/dev/null | awk '{print $1}')" \
|
|
|
|
|
"$(ip -4 route get 1 2>/dev/null | awk '{print $7; exit}')" \
|
|
|
|
|
"$(ip -4 -o addr show scope global 2>/dev/null \
|
|
|
|
|
| awk '{split($4, a, "/"); print a[1]; exit}')"
|
|
|
|
|
do
|
|
|
|
|
case "$h" in
|
|
|
|
|
[0-9]*.[0-9]*.[0-9]*.[0-9]*) echo "$h"; return 0 ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
echo localhost
|
|
|
|
|
}
|
|
|
|
|
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
# --- 1. Architecture -------------------------------------------------------
|
|
|
|
|
# Forgejo publie amd64, arm64 et arm-6. PAS de s390x : sur cette architecture
|
|
|
|
|
# il faudrait le bâtir depuis les sources en Go, ce que ce script ne fait pas —
|
|
|
|
|
# il le dit plutôt que de télécharger un binaire qui ne s'exécutera pas.
|
|
|
|
|
case "$(uname -m)" in
|
|
|
|
|
x86_64) ARCH=amd64 ;;
|
|
|
|
|
aarch64|arm64) ARCH=arm64 ;;
|
|
|
|
|
armv6l|armv7l) ARCH=arm-6 ;;
|
|
|
|
|
*) die "Forgejo ne publie pas de binaire pour $(uname -m)" \
|
|
|
|
|
"(amd64, arm64 et arm-6 seulement)." ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# --- 2. Version ------------------------------------------------------------
|
|
|
|
|
if [ -z "$VERSION" ]; then
|
|
|
|
|
# La liste des versions est en JSON : on la lit avec python3, présent dans
|
|
|
|
|
# toutes les images cloud visées. Sans lui, on retombe sur grep — mieux
|
|
|
|
|
# qu'un abandon, et le motif est celui d'un champ JSON, pas d'une page web.
|
|
|
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
|
|
|
VERSION=$(curl -fsSL --max-time 30 "$API?limit=1" 2>/dev/null \
|
|
|
|
|
| python3 -c 'import json,sys
|
|
|
|
|
try:
|
|
|
|
|
print(json.load(sys.stdin)[0]["tag_name"].lstrip("v"))
|
|
|
|
|
except Exception:
|
|
|
|
|
pass' || true)
|
|
|
|
|
else
|
|
|
|
|
VERSION=$(curl -fsSL --max-time 30 "$API?limit=1" 2>/dev/null \
|
|
|
|
|
| grep -o '"tag_name":"v[^"]*"' | head -1 \
|
|
|
|
|
| sed 's/.*"v//;s/"//' || true)
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
[ -n "$VERSION" ] || die "Version de Forgejo introuvable (réseau ? $API)"
|
|
|
|
|
say "Forgejo $VERSION pour $ARCH"
|
|
|
|
|
|
|
|
|
|
# --- 3. Déjà posé ? --------------------------------------------------------
|
|
|
|
|
# Rejouer une installation est le cas normal. Comparer la version évite de
|
|
|
|
|
# retélécharger 34 Mo pour rien, et de redémarrer un service qui va bien.
|
|
|
|
|
if [ -x "$BIN" ] && "$BIN" --version 2>/dev/null | grep -q "version $VERSION"; then
|
|
|
|
|
say "${Green}binaire déjà en version $VERSION, téléchargement évité${Color_Off}"
|
|
|
|
|
else
|
|
|
|
|
# L'archive .xz pèse 34 Mo contre 114 Mo pour le binaire nu. On la prend
|
|
|
|
|
# quand xz est là, sans jamais l'installer : le binaire nu est le repli.
|
|
|
|
|
tmp=$(mktemp -d)
|
|
|
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
|
if command -v xz >/dev/null 2>&1; then
|
|
|
|
|
asset="forgejo-$VERSION-linux-$ARCH.xz"
|
|
|
|
|
else
|
|
|
|
|
asset="forgejo-$VERSION-linux-$ARCH"
|
|
|
|
|
fi
|
|
|
|
|
say "téléchargement de $asset"
|
|
|
|
|
curl -fsSL --retry 3 --max-time 900 "$DL/v$VERSION/$asset" \
|
|
|
|
|
-o "$tmp/$asset" || die "téléchargement impossible : $DL/v$VERSION/$asset"
|
|
|
|
|
# Somme de contrôle publiée à côté du fichier : une archive tronquée par une
|
|
|
|
|
# coupure réseau donne un binaire qui ne s'exécute pas, et l'erreur arrive
|
|
|
|
|
# alors dix étapes plus loin.
|
|
|
|
|
if curl -fsSL --max-time 60 "$DL/v$VERSION/$asset.sha256" \
|
|
|
|
|
-o "$tmp/$asset.sha256" 2>/dev/null; then
|
|
|
|
|
(cd "$tmp" && sha256sum -c "$asset.sha256" >/dev/null) \
|
|
|
|
|
|| die "somme de contrôle invalide pour $asset"
|
|
|
|
|
say "somme de contrôle vérifiée"
|
|
|
|
|
else
|
|
|
|
|
say "${Yellow}⚠ somme de contrôle indisponible, non vérifiée${Color_Off}"
|
|
|
|
|
fi
|
|
|
|
|
case "$asset" in
|
|
|
|
|
*.xz) xz -d "$tmp/$asset"; src="$tmp/${asset%.xz}" ;;
|
|
|
|
|
*) src="$tmp/$asset" ;;
|
|
|
|
|
esac
|
|
|
|
|
chmod +x "$src"
|
|
|
|
|
sudo install -m 0755 "$src" "$BIN"
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
CHANGED=1
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
say "${Green}binaire posé : $BIN${Color_Off}"
|
|
|
|
|
rm -rf "$tmp"
|
|
|
|
|
trap - EXIT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- 4. Compte système et répertoires --------------------------------------
|
|
|
|
|
if ! id "$RUN_USER" >/dev/null 2>&1; then
|
|
|
|
|
sudo useradd --system --create-home --home-dir "/home/$RUN_USER" \
|
|
|
|
|
--shell /bin/bash --comment "Forgejo" "$RUN_USER"
|
|
|
|
|
say "compte système créé : $RUN_USER"
|
|
|
|
|
fi
|
|
|
|
|
sudo mkdir -p "$DATA"/{custom,data,log} "$CONF_DIR"
|
|
|
|
|
sudo chown -R "$RUN_USER:$RUN_USER" "$DATA"
|
|
|
|
|
sudo chmod 750 "$DATA"
|
|
|
|
|
# Le fichier de configuration appartient à root et se LIT par le groupe : le
|
|
|
|
|
# service en a besoin, et Forgejo y écrit ses secrets au premier démarrage si
|
|
|
|
|
# on ne les pose pas soi-même — ce que fait l'étape suivante.
|
|
|
|
|
sudo chown root:"$RUN_USER" "$CONF_DIR"
|
|
|
|
|
sudo chmod 770 "$CONF_DIR"
|
|
|
|
|
|
|
|
|
|
# --- 5. Configuration ------------------------------------------------------
|
|
|
|
|
# JAMAIS réécrite si elle existe : elle porte les secrets, et un utilisateur a
|
|
|
|
|
# pu l'ajuster. C'est aussi ce qui rend ce script rejouable.
|
|
|
|
|
# « sudo test », et non « [ -f ] » : /etc/forgejo appartient à root:git en 770,
|
|
|
|
|
# donc l'utilisateur qui lance le script ne peut même pas y statuer un fichier.
|
|
|
|
|
# Le test échouait toujours, et CHAQUE passage réécrivait la configuration avec
|
|
|
|
|
# des secrets neufs — ce qui invalide les sessions et les jetons existants.
|
|
|
|
|
if sudo test -f "$CONF"; then
|
|
|
|
|
say "configuration conservée : $CONF"
|
|
|
|
|
else
|
2026-08-19 19:43:43 -04:00
|
|
|
host=$(host_address)
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
# Les QUATRE secrets, et pas seulement les deux évidents. Vécu : sans
|
|
|
|
|
# « oauth2.JWT_SECRET », Forgejo tente de l'écrire dans app.ini au
|
|
|
|
|
# démarrage, n'y arrive pas — le fichier appartient à root — et s'arrête
|
|
|
|
|
# sur « [F] save oauth2.JWT_SECRET failed ». Le service redémarrait en
|
|
|
|
|
# boucle, 25 fois, sans jamais écouter le port.
|
|
|
|
|
#
|
|
|
|
|
# Les poser ici garde app.ini NON inscriptible par le service : c'est la
|
|
|
|
|
# bonne posture, et ça évite un fichier de configuration qui se réécrit
|
|
|
|
|
# tout seul.
|
|
|
|
|
secret=$("$BIN" generate secret SECRET_KEY)
|
|
|
|
|
token=$("$BIN" generate secret INTERNAL_TOKEN)
|
|
|
|
|
jwt=$("$BIN" generate secret JWT_SECRET)
|
|
|
|
|
lfs_jwt=$("$BIN" generate secret JWT_SECRET)
|
|
|
|
|
# « INSTALL_LOCK = true » verrouille l'installateur web : la machine est
|
|
|
|
|
# utilisable sans passer par un formulaire, ce qui est tout l'intérêt d'une
|
|
|
|
|
# option cochée au déploiement. SQLite, pour ne pas disputer PostgreSQL à
|
|
|
|
|
# Odoo, qui vit sur la même VM.
|
|
|
|
|
sudo tee "$CONF" >/dev/null <<CONFEOF
|
|
|
|
|
APP_NAME = ERPLibre Forgejo
|
|
|
|
|
RUN_USER = $RUN_USER
|
|
|
|
|
RUN_MODE = prod
|
|
|
|
|
WORK_PATH = $DATA
|
|
|
|
|
|
|
|
|
|
[server]
|
|
|
|
|
PROTOCOL = http
|
|
|
|
|
DOMAIN = $host
|
|
|
|
|
HTTP_PORT = $HTTP_PORT
|
|
|
|
|
ROOT_URL = http://$host:$HTTP_PORT/
|
|
|
|
|
APP_DATA_PATH = $DATA/data
|
|
|
|
|
DISABLE_SSH = false
|
|
|
|
|
START_SSH_SERVER = true
|
|
|
|
|
SSH_DOMAIN = $host
|
|
|
|
|
SSH_PORT = $SSH_PORT
|
|
|
|
|
SSH_LISTEN_PORT = $SSH_PORT
|
|
|
|
|
LFS_START_SERVER = true
|
|
|
|
|
LFS_JWT_SECRET = $lfs_jwt
|
|
|
|
|
|
|
|
|
|
[database]
|
|
|
|
|
DB_TYPE = sqlite3
|
|
|
|
|
PATH = $DATA/data/forgejo.db
|
|
|
|
|
|
|
|
|
|
[repository]
|
|
|
|
|
ROOT = $DATA/data/forgejo-repositories
|
|
|
|
|
|
|
|
|
|
[security]
|
|
|
|
|
INSTALL_LOCK = true
|
|
|
|
|
PASSWORD_COMPLEXITY = off
|
|
|
|
|
SECRET_KEY = $secret
|
|
|
|
|
INTERNAL_TOKEN = $token
|
|
|
|
|
|
|
|
|
|
[oauth2]
|
|
|
|
|
JWT_SECRET = $jwt
|
|
|
|
|
|
|
|
|
|
[service]
|
|
|
|
|
DISABLE_REGISTRATION = false
|
|
|
|
|
REQUIRE_SIGNIN_VIEW = false
|
|
|
|
|
|
|
|
|
|
[lfs]
|
|
|
|
|
PATH = $DATA/data/lfs
|
|
|
|
|
|
|
|
|
|
[log]
|
|
|
|
|
ROOT_PATH = $DATA/log
|
|
|
|
|
LEVEL = info
|
|
|
|
|
CONFEOF
|
|
|
|
|
sudo chown root:"$RUN_USER" "$CONF"
|
|
|
|
|
sudo chmod 640 "$CONF"
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
CHANGED=1
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
say "${Green}configuration écrite : $CONF${Color_Off}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- 6. Service ------------------------------------------------------------
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
unit_tmp=$(mktemp)
|
|
|
|
|
cat > "$unit_tmp" <<UNITEOF
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
[Unit]
|
|
|
|
|
Description=Forgejo (Beyond coding. We forge.)
|
|
|
|
|
After=network.target network-online.target
|
|
|
|
|
|
|
|
|
|
[Service]
|
|
|
|
|
Type=simple
|
|
|
|
|
User=$RUN_USER
|
|
|
|
|
Group=$RUN_USER
|
|
|
|
|
WorkingDirectory=$DATA
|
|
|
|
|
ExecStart=$BIN web --config $CONF
|
|
|
|
|
Restart=always
|
|
|
|
|
RestartSec=5
|
|
|
|
|
Environment=USER=$RUN_USER HOME=/home/$RUN_USER GITEA_WORK_DIR=$DATA
|
|
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
|
WantedBy=multi-user.target
|
|
|
|
|
UNITEOF
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
if ! sudo cmp -s "$unit_tmp" "$UNIT" 2>/dev/null; then
|
|
|
|
|
sudo install -m 0644 "$unit_tmp" "$UNIT"
|
|
|
|
|
sudo systemctl daemon-reload
|
|
|
|
|
CHANGED=1
|
|
|
|
|
say "service défini : $UNIT"
|
|
|
|
|
fi
|
|
|
|
|
rm -f "$unit_tmp"
|
|
|
|
|
|
|
|
|
|
sudo systemctl enable forgejo.service >/dev/null 2>&1 || true
|
|
|
|
|
# « restart » et NON « enable --now » quand quelque chose a changé : « --now »
|
|
|
|
|
# ne touche pas à un service déjà actif, qui garde alors sa configuration en
|
|
|
|
|
# MÉMOIRE. Vécu, et le symptôme ne désigne pas la cause : le serveur comparait
|
|
|
|
|
# son ancien INTERNAL_TOKEN à celui que le hook venait de lire sur le disque, et
|
|
|
|
|
# répondait 403 à son propre hook. Tout push finissait sur « Forgejo: Internal
|
|
|
|
|
# Server Error Decoding Failed », le hook ne sachant pas décoder un 403.
|
|
|
|
|
if [ "$CHANGED" = 1 ]; then
|
|
|
|
|
sudo systemctl restart forgejo.service \
|
|
|
|
|
|| die "le service refuse de démarrer : sudo journalctl -u forgejo -n 40"
|
|
|
|
|
say "service redémarré (configuration ou binaire modifié)"
|
|
|
|
|
elif ! systemctl is-active --quiet forgejo.service; then
|
|
|
|
|
sudo systemctl start forgejo.service \
|
|
|
|
|
|| die "le service refuse de démarrer : sudo journalctl -u forgejo -n 40"
|
|
|
|
|
fi
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
|
|
|
|
|
# --- 7. Attendre qu'il RÉPONDE --------------------------------------------
|
|
|
|
|
# Une requête HTTP, pas un « systemctl is-active » : le service est « active »
|
|
|
|
|
# bien avant d'écouter, et « activating » en boucle de redémarrage ressemble à
|
|
|
|
|
# un démarrage en cours. /api/v1/version prouve que l'application SERT — la
|
|
|
|
|
# création du compte administrateur qui suit a besoin de la base migrée.
|
|
|
|
|
#
|
|
|
|
|
# Et surtout pas « exec 3<>/dev/tcp/... » : « exec » est un builtin spécial, et
|
|
|
|
|
# une redirection qui échoue termine le shell. Le script mourait donc en
|
|
|
|
|
# silence, au premier tour de la boucle, code 1 sans un mot — vécu.
|
|
|
|
|
ready=0
|
|
|
|
|
for i in $(seq 1 60); do
|
[FIX] script forgejo: redémarrer le service quand la configuration change
Tout push finissait sur « Forgejo: Internal Server Error Decoding Failed », et
le message ne désigne pas la cause. Le journal, lui, la donne : 403 sur
/api/internal/hook/pre-receive, refusé par le contrôle du jeton interne. Le
serveur comparait l'INTERNAL_TOKEN qu'il tenait EN MÉMOIRE à celui que le hook
venait de lire sur le disque — deux valeurs différentes — et répondait 403 à son
propre hook, que celui-ci ne sait pas décoder.
La cause est ici : « systemctl enable --now » ne touche pas un service déjà
actif. Le script redémarre donc quand le binaire, la configuration ou l'unité
ont changé, et se tait sinon. Vérifié sur la VM : configuration régénérée
service actif -> redémarrage -> push accepté ; relance sur forge saine ->
aucun redémarrage, push toujours accepté.
--- EN ---
Every push ended on "Forgejo: Internal Server Error Decoding Failed", and the
message does not name the cause. The log does: 403 on
/api/internal/hook/pre-receive, refused by the internal token check. The server
was comparing the INTERNAL_TOKEN it held IN MEMORY with the one the hook had
just read from disk — two different values — and answered 403 to its own hook,
which cannot decode a 403.
The cause is here: "systemctl enable --now" does not touch an already active
service. The script now restarts when the binary, the configuration or the unit
changed, and stays quiet otherwise. Verified on the VM: config regenerated with
the service active -> restart -> push accepted; replay on a healthy forge -> no
restart, push still accepted.
Assisted-by: Claude Opus 5
2026-08-20 02:04:50 -04:00
|
|
|
# « -fs » sans « -S » : dans une boucle de réessai, le message de curl est
|
|
|
|
|
# du bruit — « Failed to connect » au premier tour est normal, le service
|
|
|
|
|
# vient de redémarrer. C'est le die final qui parle si rien ne répond.
|
|
|
|
|
if curl -fs -o /dev/null --max-time 3 \
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
"http://127.0.0.1:$HTTP_PORT/api/v1/version"; then
|
|
|
|
|
ready=1
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
sleep 2
|
|
|
|
|
done
|
|
|
|
|
[ "$ready" = 1 ] || die "aucune réponse sur le port $HTTP_PORT après 120 s" \
|
|
|
|
|
"(sudo journalctl -u forgejo -n 40)"
|
|
|
|
|
|
|
|
|
|
# --- 8. Compte administrateur ---------------------------------------------
|
|
|
|
|
# Créé seulement s'il n'y a AUCUN compte : rejouer le script ne doit pas
|
|
|
|
|
# échouer sur « user already exists », ni écraser un mot de passe choisi.
|
|
|
|
|
if [ "$SKIP_ADMIN" = 1 ]; then
|
|
|
|
|
say "aucun compte créé (FORGEJO_SKIP_ADMIN=1)"
|
|
|
|
|
elif sudo -u "$RUN_USER" "$BIN" admin user list --config "$CONF" 2>/dev/null \
|
|
|
|
|
| tail -n +2 | grep -q .; then
|
|
|
|
|
say "comptes déjà présents, administrateur non recréé"
|
|
|
|
|
else
|
|
|
|
|
sudo -u "$RUN_USER" "$BIN" admin user create --admin \
|
|
|
|
|
--username "$ADMIN_USER" --password "$ADMIN_PASSWORD" \
|
|
|
|
|
--email "$ADMIN_EMAIL" --must-change-password=false \
|
|
|
|
|
--config "$CONF" >/dev/null \
|
|
|
|
|
|| die "création de l'administrateur impossible"
|
[FIX] security: the KeePass password leaves the command line too
Same exposure as the master password, same fix. kdbx_manager put the Odoo
password straight into the web_login command; /proc/<pid>/cmdline is
readable by every user on the machine, and no downstream filter reaches
that.
The command now carries the NAME of an environment variable, never the
value. One name per entry, because several credentials go out in a single
"parallel" call and a single variable could not tell them apart.
get_extra_command_user therefore returns (fragments, variables), and the
two call sites hand the variables to exec_command_live, which already
merged an environment.
Two things found on the way. web_login re-sent config.default_password_auth
when it retried after dismissing a modal, ignoring whatever the caller had
passed -- the retry silently fell back to "admin". And install_forgejo
printed the admin password back to the terminal, hence into the install log
and any CI capture; its own header already documents the default.
A test pins the guarantee: the fragment must not contain the password.
--- FR ---
Même exposition que pour le mot de passe maître, même correctif.
kdbx_manager mettait le mot de passe Odoo directement dans la commande
web_login ; /proc/<pid>/cmdline est lisible par tout utilisateur de la
machine, et aucun filtre en aval ne l'atteint.
La commande porte désormais le NOM d'une variable d'environnement, jamais
la valeur. Un nom par entrée, car plusieurs identifiants partent dans un
seul appel « parallel » et une variable unique ne saurait les distinguer.
get_extra_command_user rend donc (fragments, variables), et les deux
appelants confient les variables à exec_command_live, qui fusionnait déjà
un environnement.
Deux trouvailles en chemin. web_login renvoyait config.default_password_auth
à la reprise après une modale, ignorant ce que l'appelant avait fourni — la
reprise retombait en silence sur « admin ». Et install_forgejo réaffichait
le mot de passe administrateur, donc dans le journal d'installation et
toute capture de CI ; son propre en-tête documente déjà le défaut.
Un test verrouille la garantie : le fragment ne doit pas porter le secret.
Assisted-by: Claude Opus 5
2026-08-23 00:25:03 -04:00
|
|
|
# Le mot de passe n'est PAS réaffiché : cette sortie part dans les
|
|
|
|
|
# journaux d'installation et dans toute capture de CI. Celui qui a
|
|
|
|
|
# posé FORGEJO_ADMIN_PASSWORD le connaît déjà ; les autres ont le
|
|
|
|
|
# défaut, documenté en tête de ce fichier.
|
|
|
|
|
say "${Green}administrateur créé : $ADMIN_USER${Color_Off}"
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- 9. Résumé -------------------------------------------------------------
|
2026-08-19 19:43:43 -04:00
|
|
|
host=$(host_address)
|
[ADD] script forgejo: installer une forge git en option cochable
Une case au déploiement, et une forge git auto-hébergée répond sur le port 3000,
git par SSH sur 2222. Le travail vit dans un script dédié, appelable seul sur
une machine existante : une seule autorité pour les deux usages.
Le binaire officiel est statique, donc le même fichier sert apt, dnf, pacman et
zypper — c'est ce qui rend l'option portable sans une branche par distribution.
Les architectures suivent l'amont (amd64, arm64, arm-6) ; la case se grise sur
s390x plutôt que de poser un binaire inexécutable. Les quatre secrets sont
écrits par le script : sans oauth2.JWT_SECRET, Forgejo tente de les persister
lui-même et boucle sur un app.ini qu'il n'a pas le droit d'écrire.
Vérifié sur une VM : somme de contrôle validée, service actif, API qui répond,
dépôt créé puis cloné par git, et relance en 1,5 s sans rien réécrire.
--- EN ---
One checkbox at deploy time, and a self-hosted git forge answers on port 3000,
git over SSH on 2222. The work lives in a dedicated script, callable on its own
for an existing machine: one authority for both uses.
The official binary is static, so the same file serves apt, dnf, pacman and
zypper — that is what makes the option portable without a branch per
distribution. Architectures follow upstream (amd64, arm64, arm-6); the checkbox
greys out on s390x rather than dropping a binary that cannot run. The script
writes all four secrets itself: without oauth2.JWT_SECRET, Forgejo tries to
persist them and loops on an app.ini it is not allowed to write.
Verified on a VM: checksum validated, service active, API answering, a repo
created then cloned over git, and a replay in 1.5 s rewriting nothing.
Assisted-by: Claude Opus 5
2026-08-19 19:41:39 -04:00
|
|
|
version=$("$BIN" --version 2>/dev/null | head -1)
|
|
|
|
|
say "${Green}Forgejo prêt${Color_Off} : http://$host:$HTTP_PORT/"
|
|
|
|
|
say " $version"
|
|
|
|
|
say " git par SSH : port $SSH_PORT (serveur interne de Forgejo)"
|
|
|
|
|
say " service : sudo systemctl status forgejo"
|
|
|
|
|
say " journal : sudo journalctl -u forgejo -f"
|