Continuous Integration – Gitea Actions¶
Machine translation of the French original.
The park executes its workflows using act_runner, on vm-compute-01, in mode dind: the jobs run within the Docker runner's daemon, not the host's.
The flow of a push¶
flowchart LR
dev["Poste<br/>git push"]
gitea["Gitea<br/>vm-docker:3303"]
runner["act_runner<br/>vm-compute-01"]
job["Job dans<br/>node:20-bookworm"]
hote["vm-docker<br/>deploy-hook.sh"]
dev --> gitea
gitea -.->|"le runner interroge,<br/>Gitea ne pousse pas"| runner
runner --> job
job -->|"ssh, clé verrouillée<br/>par command="| hote
hote --> ok["git pull + build<br/>+ vérification"]
The runner pulls the job by querying: Gitea never contacts it. This results in a direct IP URL in its configuration – via Caddy, this query It would resemble a highlighting technique and would likely be flagged by CrowdSec.
The most expensive trap: the scope of a runner¶
A runner act_runner has a unique scope, fixed to a specific record – instance, organization, user, or a single repository. It does not change after the fact.
flowchart TB
subgraph hote["vm-compute-01"]
r1["rtx-runner<br/>portée : dépôt homelab-vault"]
r2["docs-runner<br/>portée : dépôt homelab-docs"]
end
v["Dépôt homelab-vault"]
d["Dépôt homelab-docs"]
t["Un troisième dépôt"]
r1 --> v
r2 --> d
t -.->|"aucun runner éligible"| queued["runs « queued »<br/>indéfiniment"]
classDef bad stroke-width:3px,stroke-dasharray: 5 5
class queued bad
Runs queued that last forever do not resemble an error
When no runner is eligible, the executions appear normally
within the interface and remain queued. There are no messages, no alerts, nothing that indicates that someone will not come to take them. This reads as "the CI is not yet connected."
The build process, which breaks down into a single request:
curl -s -H "Authorization: token $TOKEN" \
https://gitea.savethemall.eu/api/v1/repos/<owner>/<repo>/actions/runners \
| jq '.runners[].name'
# tableau vide → ces jobs ne partiront jamais
Adding a repository to the CI means either adding a runner or migrating an existing runner to a wider scope – the latter option stops the CI from functioning during the operation, effectively freezing it.
The registration token requires a POST request, not a GET:
What the jobs contain – and do not contain¶
The jobs runs-on: ubuntu-latest run in node:20-bookworm.
| Present | Absent |
|---|---|
git 2.39 |
pip |
| Python 3.11 | venv |
| Access to github.com and pypi.org | SSH client |
Debian delivers pip, venv, and openssh-client separately. A workflow that assumes these will succeed fails late, after the checkout, with a message that does not indicate that a package is missing.
actions/setup-python does not work on this runner
The action downloads binaries published for the images ubuntu-XX from GitHub. None exist for Debian bookworm. This is not a network issue: the runner is able to reach github.com and pypi.org without difficulty.
Instead, install from Debian:
Deploying without a shell¶
A deployment key that opens a full shell on the production host is worth the password for that host. The form used here reduces it to a single action:
command="/opt/docker/<stack>/deploy-hook.sh",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty,restrict ssh-ed25519 AAAA…
Whatever the client sends, the server executes this script and nothing else. The proof is in the execution, rather than assuming:
ssh -i <clé> -p <port-ssh> <user>@vm-docker "cat /etc/shadow"
# doit afficher la sortie du déploiement, jamais le contenu du fichier
A corollary of the design: the script must perform its own verification, since the client cannot send a second command to check the result.
Dernière vérification de cette page : 2026-09-08