## Summary - Add `containers/nettest/default.nix` using `dockerTools.buildLayeredImage` with curl, jq, dnsutils, cacert, and bash — equivalent to the existing Dockerfile - Update `container-tag-and-release` to require `--nix` or `--dockerfile` flag when both build types exist for a container - Update `container-list` to show `[dockerfile+nix]` label when both exist ## Deployment and Testing - [ ] SSH to ringtail, run `nix build -f containers/nettest/default.nix -o result` to verify the nix expression builds - [ ] Tag `nettest-nix-v1.0.0`, confirm `build-container-nix` workflow runs on `nix-container-builder` runner and pushes to registry - [ ] Smoke test on ringtail k3s: `kubectl run nettest --image=registry.ops.eblu.me/blumeops/nettest:v1.0.0 --restart=Never && kubectl logs nettest` - [ ] Verify `mise run container-list` shows `[dockerfile+nix]` for nettest - [ ] Verify `mise run container-tag-and-release nettest v1.1.0` prompts for build type Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/214
3.7 KiB
| title | modified | tags | |||
|---|---|---|---|---|---|
| Forgejo | 2026-02-19 |
|
Forgejo
Git forge and CI/CD platform. Primary source of truth for blumeops (mirrored to GitHub).
Quick Reference
| Property | Value |
|---|---|
| URL | https://forge.ops.eblu.me |
| SSH | ssh://forgejo@forge.ops.eblu.me:2222 |
| Local Ports | 3001 (HTTP), 2200 (SSH) |
| Config | ansible/roles/forgejo/templates/app.ini.j2 |
Repositories
| Repo | Description |
|---|---|
eblume/blumeops |
Infrastructure as code (primary) |
eblume/alloy |
Grafana Alloy fork (CGO build) |
eblume/tesla_auth |
Tesla OAuth helper |
| Helm chart mirrors | cloudnative-pg-charts, grafana-helm-charts |
CI/CD (Forgejo Actions)
Runners:
| Runner | Host | Labels | Purpose |
|---|---|---|---|
| k8s DinD pod | indri (minikube) | k8s |
Dockerfile builds via Dagger |
| ringtail-nix-builder | ringtail (native) | nix-container-builder |
Nix builds via nix-build + skopeo |
Workflows: .forgejo/workflows/
build-container.yaml- Dockerfile builds on tag (runs onk8s)build-container-nix.yaml- Nix builds on tag (runs onnix-container-builder)build-blumeops.yaml- Documentation builds and releases
Both container workflows trigger on the same tag pattern (*-v[0-9]*). Each checks for its build file (Dockerfile or default.nix) and skips if not present. See build-container-image.
Secrets (Forgejo Config)
Server configuration secrets managed via 1Password → Ansible:
lfs-jwt-secret,internal-token,oauth2-jwt-secret- Forgejo server tokensrunner_reg- Runner registration token (also in k8s via external-secrets)
Forgejo Actions Secrets
Repository-level secrets for CI/CD workflows, synced from 1Password via Ansible.
| Secret | 1Password Field | Used By | Purpose |
|---|---|---|---|
ARGOCD_AUTH_TOKEN |
argocd_token |
build-blumeops.yaml |
Sync docs app after release |
These secrets are injected as ${{ secrets.SECRET_NAME }} in workflow files.
IaC: The forgejo_actions_secrets Ansible role syncs these secrets from 1Password to Forgejo via the Forgejo API. Run with:
mise run provision-indri -- --tags forgejo_actions_secrets
API Token Setup (Manual, One-Time)
The Ansible role authenticates to the Forgejo API using a Personal Access Token (PAT). This PAT must be created manually:
- Go to https://forge.ops.eblu.me/user/settings/applications
- Create a new token with
write:repositoryscope - Store it in 1Password → "Forgejo Secrets" item →
api-tokenfield
This is a bootstrapping requirement - the PAT enables IaC for all other secrets.
Future: Public Access
Forgejo can be exposed publicly at forge.eblu.me via flyio-proxy. Since Forgejo runs natively on indri (not in k8s), the pattern is:
- Create a k8s ExternalName Service pointing to indri's Tailscale IP
- Create a Tailscale Ingress with
tailscale.com/tags: "tag:k8s,tag:flyio-target" - Add the nginx server block and DNS CNAME
Exposing a dynamic, authenticated service like Forgejo requires a full security review before going live:
- Disable open user registration (require invites or admin approval)
- Configure fail2ban on indri with a filter for Forgejo's log format
- Ensure Forgejo logs the forwarded client IP (
X-Real-IP) rather than the proxy's Tailscale IP - Audit repository visibility defaults and permissions
- Rehearse the break-glass shutoff (
mise run fly-shutoff)
See expose-service-publicly for the full howto and dynamic service checklist.