| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .forgejo/workflows | ||
| README.md | ||
ci-workflows
Reusable Forgejo Actions workflows shared by every Evobug project.
deploy.yml — deploy a service
Every service on the server deploys identically: /srv/docker/deploy.sh <service>
runs docker compose pull && docker compose up -d in /srv/docker/<service>.
So the only per-project difference is the service name.
name: Deploy
on:
workflow_dispatch:
jobs:
deploy:
uses: Evobug/ci-workflows/.forgejo/workflows/deploy.yml@main
with:
service: website
secrets: inherit
That is the whole file — DEPLOY_SSH_KEY is an org-level secret, so a new
project needs no secret setup at all.
Forgejo's workflow_call is not GitHub's
Every one of these cost a failed run on 2026-08-21, and none of them produces an error that points at the actual cause:
| Rule | What happens if you get it wrong |
|---|---|
secrets: inherit on the caller is mandatory |
Without it the callee sees empty strings; the job dies as an SSH auth failure with nothing pointing at secrets |
The callee must not declare secrets: under workflow_call |
Forgejo allows only inputs and outputs. With secrets: the workflow is invalid and silently ignored — the caller then reports repo does not exist |
Per-secret mapping (secrets: {NAME: ...}) does not exist here |
Same invalid-workflow path, since the callee cannot declare what it accepts |
| The shared repo must be public | A private one fails expansion with failed to access repo ci-workflows: repo does not exist, even when dispatched by an org owner |
The invalid-workflow case leaves its only trace in the server log:
ignore invalid workflow "deploy.yml": invalid value on key "workflow_call":
workflow_call only supports keys "inputs" and "outputs", but key "secrets" was found
That is why this repo is public: it holds workflow YAML and this README, no credentials, and cross-repo reuse does not work otherwise.
The host (git-ssh.evobug.com) and user (deploy) are inputs with defaults,
not secrets — they are infrastructure constants, documented in /srv/CLAUDE.md
and already in plain text in mickle's workflows. Override them with with:
if a project ever needs a different target.
What it needs on the server
| Requirement | Where |
|---|---|
The service name exists in deploy.sh |
/srv/docker/deploy.sh case block |
| A compose file | /srv/docker/<service>/docker-compose.yml |
| An image on the registry | pushed by the project's own docker.yml |
Run the project's Docker Build first — this workflow only pulls what is
already published. docker compose pull on a tag that does not exist fails the
deploy.
Two things that will bite you
runs-onmust not bedocker. That label isnode:22-bookworm: it has the dind socket mounted but no docker CLI, and its git (2.39) is too old for several actions. The default here isubuntu-latest(catthehacker), which ships an ssh client.- The SSH host must be DNS-only.
git-ssh.evobug.comis grey-clouded on purpose; Cloudflare-proxied hostnames cannot carry SSH, so pointingDEPLOY_HOSTatevobug.comorgit.evobug.comwill hang and then fail.
The CI key is restricted
DEPLOY_SSH_KEY is a forced-command key: sshd runs
/usr/local/sbin/deploy-ssh-command no matter what the client asks for, and
that wrapper accepts only /srv/docker/deploy.sh <known-service> — no shell,
no rsync, no port forwarding, one service per invocation. This matters because
deploy is in the docker group, which is root-equivalent, and the key is an
org secret readable by a workflow in any Evobug repo.
If you add a service, add it to the wrapper's allowlist as well as to
deploy.sh, or the deploy is refused.