Sonnet Markdown audit + Opus TOML audit (post-publish) caught two infrastructure identity leaks in the public KeiSeiKit-1.0 mirror: 1. Tailscale CGNAT IP `100.91.246.53` (private Forgejo server) appeared 5×: - BACKUP-INDEX.md:6,17 — including a PR URL exposing branch naming convention - .forgejo/README.md:3,41,75,87 Replaced with `<private-forgejo>` placeholder. PR URL is now a template form (no real branch name leaked). 2. Real AWS EC2 instance ID `i-0a8b747023809d451` appeared 2× in _manifests/infra-implementer.toml:39,104 — directly inside an agent prompt shipped publicly. Replaced with `<ec2-instance-id>` placeholder. The IP itself is not internet-routable (Tailscale CGNAT), but the leak still narrows OSINT scope and reveals our Forgejo-on-Tailscale topology. The EC2 instance ID is a real production resource identifier in our shared-tenancy deployment; leaking it gives an attacker a confirmed target for AWS-API enumeration if any other vector ever yields IAM access. These leaks were already pushed to github main in commits23b818a+7cc544f. The HEAD-only scrub clears the working tree and the next commit; full git history scrub via git-filter-repo is a follow-up if the historical exposure window matters operationally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
109 lines
3.5 KiB
Markdown
109 lines
3.5 KiB
Markdown
# Forgejo Actions — self-hosted CI
|
|
|
|
Parallel CI on the private Forgejo (Tailscale `<private-forgejo>:3000`)
|
|
that doesn't depend on github.com — keeps private code on
|
|
self-hosted infrastructure while still getting per-commit
|
|
verification.
|
|
|
|
## Why a separate `.forgejo/workflows/` and not just `.github/workflows/`?
|
|
|
|
Forgejo Actions reads BOTH directories by default. We split them
|
|
because the GHA workflow has 2 quirks irrelevant on self-hosted:
|
|
|
|
1. **GHA Linux runner has 7 GB RAM + 14 GB on `/mnt`** — workspace OOMs
|
|
during link. Self-hosted runner can have whatever RAM the host has.
|
|
2. **Per-category matrix** is faster on self-hosted (parallel jobs)
|
|
but *slower* on GHA (each matrix job = full container + cache pull).
|
|
So we keep GHA monolithic, split self-hosted into 8 logical groups.
|
|
|
|
## One-time runner setup
|
|
|
|
Pick a host (the same VPS that runs Forgejo, or a separate beefier
|
|
box). Tailscale is fine — runner only needs to reach Forgejo.
|
|
|
|
```bash
|
|
# 1. Get the binary
|
|
wget -O /usr/local/bin/forgejo-runner \
|
|
https://code.forgejo.org/forgejo/runner/releases/download/v6.5.0/forgejo-runner-amd64
|
|
chmod +x /usr/local/bin/forgejo-runner
|
|
|
|
# 2. Get a registration token from Forgejo:
|
|
# Forgejo web UI → Site Administration → Actions → Runners → Create new
|
|
# (OR per-org: Org settings → Actions → Runners)
|
|
# (OR per-repo: Repo settings → Actions → Runners — narrowest scope)
|
|
|
|
# 3. Register
|
|
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/forgejo-runner forgejo-runner
|
|
sudo mkdir -p /var/lib/forgejo-runner
|
|
sudo chown forgejo-runner: /var/lib/forgejo-runner
|
|
cd /var/lib/forgejo-runner
|
|
sudo -u forgejo-runner forgejo-runner register --no-interactive \
|
|
--instance http://<private-forgejo>:3000 \
|
|
--token <REGISTRATION_TOKEN_FROM_WEB_UI> \
|
|
--name "$(hostname)-runner" \
|
|
--labels self-hosted,docker,linux,amd64
|
|
|
|
# 4. systemd unit
|
|
sudo tee /etc/systemd/system/forgejo-runner.service <<'UNIT'
|
|
[Unit]
|
|
Description=Forgejo Actions Runner
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=forgejo-runner
|
|
WorkingDirectory=/var/lib/forgejo-runner
|
|
ExecStart=/usr/local/bin/forgejo-runner daemon
|
|
Restart=always
|
|
RestartSec=10
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
UNIT
|
|
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now forgejo-runner
|
|
|
|
# 5. Verify in Forgejo web UI:
|
|
# Site Admin → Actions → Runners → status: Idle (green dot)
|
|
```
|
|
|
|
## Repo-level enable
|
|
|
|
```bash
|
|
# Via API
|
|
curl -X PATCH http://<private-forgejo>:3000/api/v1/repos/denis/KeiSeiKit \
|
|
-u "denis:$FORGEJO_TOKEN" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"has_actions": true}'
|
|
|
|
# OR via web UI:
|
|
# Repo → Settings → Repository → enable "Actions"
|
|
```
|
|
|
|
## Trigger
|
|
|
|
Push to `main` triggers the workflow automatically. Watch progress:
|
|
http://<private-forgejo>:3000/denis/KeiSeiKit/actions
|
|
|
|
## Differences from GHA workflow
|
|
|
|
| Job | GHA | Forgejo |
|
|
|---|---|---|
|
|
| `rust-assembler` | ubuntu+macOS matrix | docker (Linux only) |
|
|
| `rust-primitives` | monolithic (OOM-prone) | **8-group matrix** (parallel, fast) |
|
|
| `ts-packages` | node 20+22 matrix | node 22 only |
|
|
| `install-dry-run` | 3 profiles | (skip — runs locally on dev machines) |
|
|
| `shell-lint` | ubuntu+shellcheck apt | shellcheck-alpine container |
|
|
| `workflow-lint` | actionlint | (skip — handled by GHA mirror) |
|
|
|
|
## Cost
|
|
|
|
Free. No GitHub Actions minutes. No GitHub LFS bandwidth.
|
|
Sensitive-IP never leaves Tailscale.
|
|
|
|
## Maintenance
|
|
|
|
The runner pulls images on first run for each container reference; subsequent
|
|
runs are cached. Periodic `docker system prune -af` recommended (cron job
|
|
on the runner host).
|