Skip to content

Commit 7bb042c

Browse files
committed
feat(forge): add mios-forge Quadlet -- self-hosted Git forge (Forgejo)
WHY FORGEJO (over GitLab CE / Gitea / OneDev / cgit) Per the architectural analysis recorded in CREDITS.md (\xa711 row + research-project preamble), Forgejo is the only forge that fits MiOS- BUILDER's WSL2-resident resource budget without crowding out 'podman build' of the MiOS image itself: Idle footprint: 150-300 MB RAM, single core sufficient for small teams; SQLite default removes the PostgreSQL + Redis sidecar overhead GitLab CE would require. Governance: GPLv3+ under Codeberg e.V. (German non-profit) -- aligns with MiOS's research-project / generative framing in AGREEMENTS.md. CI compatibility: Forgejo Runner consumes GitHub-Actions YAML, so .github/workflows/mios-ci.yml runs unmodified once pointed at mios-forge instead of github.com. Federation: ActivityPub / ForgeFed already implemented; future cross-instance collaboration without surrendering source-code custody. Architectural-law fit: - Law 1 USR-OVER-ETC: vendor template under /etc/mios/forge (admin-override surface; same pattern as /etc/nvidia-container-toolkit/). - Law 2 NO-MKDIR-IN-VAR: every /var/ + /srv/ path declared via usr/lib/tmpfiles.d/mios-forge.conf. - Law 3 BOUND-IMAGES: covered by the existing automation/08-system-files-overlay.sh:74-86 binder loop -- mios-forge.container symlinks into /usr/lib/bootc/bound-images.d/ at build. - Law 5 UNIFIED-AI-REDIRECTS: Forgejo has no built-in AI surface, so no vendor URL leaks (postcheck #12 passes without exemption). - Law 6 UNPRIVILEGED-QUADLETS: User=mios-forge, Group=mios-forge, Delegate=yes (no root exception needed -- contrast with GitLab CE omnibus which requires uid 0). FILES ADDED etc/containers/systemd/mios-forge.container Quadlet for codeberg.org/forgejo/forgejo:11. HTTP on :3000, git+ssh on :2222 (avoiding sshd:22), SQLite default, registration disabled, INSTALL_LOCK=true so the first hit goes straight to login. ConditionPathIsDirectory + !container gating consistent with mios-ai.container. usr/lib/tmpfiles.d/mios-forge.conf Declares /srv/mios/forge, /var/lib/mios/forge, /var/log/mios/forge, /etc/mios/forge with mios-forge ownership. /srv chosen per FHS-3.0 'data served by the system'. FILES UPDATED usr/lib/sysusers.d/50-mios-services.conf Appended 'g mios-forge 816' + 'u mios-forge 816:mios-forge ...' (next free slot in the 810- 829 reservation; nologin shell so postcheck #8 cannot trip). usr/share/mios/env.defaults MIOS_FORGE_VERSION=11, MIOS_FORGE_IMAGE, MIOS_FORGE_HTTP_PORT=3000, MIOS_FORGE_SSH_PORT=2222. usr/share/mios/mios.toml + mios-bootstrap/mios.toml [quadlets.enable] mios-forge = true (defaults policy: every flag is true; ConditionVirtualization handles the runtime gating). CREDITS.md \xa711 + \xa722 Forgejo, Forgejo Runner, ActivityPub/ForgeFed listed in storage/cluster table; mios-forge.container listed in MiOS-internal runtime-surface table. AGREEMENTS.md \xa74 Entry-points table: 'git push http://localhost:3000/ <user>/<repo>' added as the canonical 'locally hosted .git = ./' acknowledgment surface. POSTCHECK COVERAGE (all four invariant lints stay green) #11 tmpfiles --dry-run: mios-forge user is sysusers-declared, so the false-positive filter accepts it. #12 UNIFIED-AI-REDIRECTS: zero vendor URLs in the new files. #13 UNPRIVILEGED-QUADLETS: User=mios-forge present; no exception added. #14 BOUND-IMAGES: binder loop covers etc/containers/systemd/*.container automatically. OPERATOR USAGE After 'just build' picks up the new Quadlet and the host boots: # First-run admin user creation (via web UI at http://localhost:3000) # then locally: git remote add origin http://localhost:3000/<user>/<repo>.git git push origin main # OR over SSH: git remote add origin ssh://git@localhost:2222/<user>/<repo>.git Repository bytes live at /srv/mios/forge/git on the host vhdx; the SQLite DB at /srv/mios/forge/forgejo.db. Both are inside the WSL2 builder's persistent storage and survive 'just build' rebuilds.
1 parent d58ed24 commit 7bb042c

7 files changed

Lines changed: 109 additions & 1 deletion

File tree

AGREEMENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ referencing this file when it starts.
8484
| `./install-mios-agents.sh` | mios.git | Agent-launcher installer |
8585
| `./build-mios.sh`, `./build-mios.ps1` | mios-bootstrap.git | Canonical user-facing entry points (formerly `install.{sh,ps1}` / `bootstrap.{sh,ps1}`; old names are now redirector stubs) |
8686
| `mios`, `mios-llm`, `mios-agent-claude`, `mios-agent-gemini` | deployed image | Runtime CLI surface |
87+
| `git push http://localhost:3000/<user>/<repo>` | deployed image | Self-hosted Git forge (Forgejo) served by `mios-forge.container`; the locally hosted `.git = ./` pattern lives here |
8788
| `bootc upgrade`, `bootc switch ghcr.io/mios-dev/mios` | deployed image | OS lifecycle commands operating on a 'MiOS' image |
8889

8990
If you do not agree with the terms inventoried in `LICENSE`,

CREDITS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ subset. Every URL below is the source-of-truth for the named surface.
192192
| uupd | Unified updater (replaces `bootc-fetch-apply-updates.timer`) | <https://github.com/ublue-os/uupd> |
193193
| bootupd | Unified bootloader updater | <https://github.com/coreos/bootupd> |
194194

195-
## 11. Storage / cluster
195+
## 11. Storage / cluster / source-control forge
196196

197197
| Component | Role | Upstream |
198198
|---|---|---|
@@ -209,6 +209,9 @@ subset. Every URL below is the source-of-truth for the named surface.
209209
| virtio-win | Windows-guest paravirt drivers | <https://github.com/virtio-win/virtio-win-pkg-automation> |
210210
| `virt-viewer` / `virt-manager` | VM consoles + GUI | <https://gitlab.com/virt-viewer/virt-viewer> -- <https://virt-manager.org/> |
211211
| FreeRDP | RDP client used for `cloudws-guacamole` integration | <https://www.freerdp.com/> |
212+
| Forgejo | Self-hosted Git forge served by `mios-forge.container` (HTTP 3000, git+ssh 2222); SQLite-default; matches MiOS-BUILDER's resource budget without a separate PostgreSQL | <https://forgejo.org/> -- <https://codeberg.org/forgejo/forgejo> -- governance: Codeberg e.V. (German non-profit), GPLv3+ |
213+
| Forgejo Runner | GitHub-Actions-compatible CI runner that authenticates against `mios-forge` and executes `.github/workflows/` / `.forgejo/workflows/` jobs in ephemeral Podman containers | <https://code.forgejo.org/forgejo/runner> -- <https://forgejo.org/docs/latest/admin/actions/> |
214+
| ActivityPub / ForgeFed | Federation protocol for Forgejo: cross-instance issue, PR, and star without surrendering source-code custody | <https://www.w3.org/TR/activitypub/> -- <https://forgefed.org/> |
212215

213216
## 12. Desktop / graphics
214217

@@ -415,6 +418,7 @@ Aliasing files that all point to the same canonical prompt:
415418
| `usr/bin/mios` | Single CLI entrypoint that resolves `MIOS_AI_ENDPOINT` for every agent | `usr/bin/mios` |
416419
| `mios-llm` | Vendor-neutral OpenAI `/v1/chat/completions` wrapper (`install-mios-agents.sh`) | `/usr/local/bin/mios-llm` |
417420
| `mios-agent-claude`, `mios-agent-gemini` | Thin wrappers that pre-load the canonical system prompt before exec'ing the local CLI binary; no vendor logic beyond the exec | `/usr/local/bin/mios-agent-{claude,gemini}` |
421+
| `mios-forge.container` | Self-hosted Git forge (Forgejo upstream); HTTP `:3000`, git+ssh `:2222`; SQLite-default at `/srv/mios/forge/forgejo.db`; repository bytes at `/srv/mios/forge/git/` | `etc/containers/systemd/mios-forge.container` |
418422

419423
### `USER` variable resolution at build entry
420424

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# /etc/containers/systemd/mios-forge.container
2+
# 'MiOS' self-hosted Git forge (Forgejo upstream).
3+
#
4+
# Rationale: Forgejo is the resource-fit-for-MiOS forge per the analysis
5+
# in CREDITS.md / SOURCES.md (idle 150-300 MB, single-core sufficient for
6+
# small teams, GPLv3+ governance under Codeberg e.V., GitHub Actions-
7+
# compatible CI engine via the Forgejo Runner so existing
8+
# .github/workflows/ runs unmodified). The image is pulled from
9+
# codeberg.org (Forgejo's upstream registry) by default.
10+
#
11+
# Defaults policy: enabled by default. ConditionPathIsDirectory guards
12+
# the config dir; if /etc/mios/forge/ doesn't exist (incomplete bootstrap)
13+
# the unit no-ops at pre-boot rather than crash-looping. !container also
14+
# skips inside nested containers where the bind-mount pattern would clash.
15+
16+
[Unit]
17+
Description='MiOS' Git forge (Forgejo)
18+
After=network-online.target
19+
Wants=network-online.target
20+
ConditionPathIsDirectory=/etc/mios/forge
21+
ConditionVirtualization=!container
22+
23+
[Container]
24+
Image=codeberg.org/forgejo/forgejo:11
25+
ContainerName=mios-forge
26+
Network=mios.network
27+
PublishPort=3000:3000 # web UI; reverse-proxy via Cockpit/Caddy if desired
28+
PublishPort=2222:22 # git+ssh; non-22 to coexist with sshd
29+
30+
# Persistent state: the Forgejo image expects /data to hold app state +
31+
# the SQLite DB + git repository bytes. /srv/mios/forge is the FHS-3.0
32+
# 'data served by the system' location declared in usr/lib/tmpfiles.d/
33+
# mios-forge.conf and chowned mios-forge:mios-forge there.
34+
Volume=/srv/mios/forge:/data:Z
35+
Volume=/etc/mios/forge:/etc/mios/forge:Z,ro
36+
37+
# Identity inside the container. The upstream image creates a 'git' user
38+
# with USER_UID/USER_GID env vars at startup; we pin those to MiOS's
39+
# 50-mios-services.conf reservation (816 = next free slot in 810-829).
40+
Environment=USER=git
41+
Environment=USER_UID=816
42+
Environment=USER_GID=816
43+
44+
# Forgejo configuration (env-var-driven; no app.ini needed for default
45+
# deployment). Format: FORGEJO__<section>__<key>=<value>. Operators
46+
# wanting richer config can drop a custom app.ini under /etc/mios/forge/
47+
# and add Environment=FORGEJO_APP_INI_PATH=/etc/mios/forge/app.ini.
48+
Environment=FORGEJO__server__ROOT_URL=http://localhost:3000/
49+
Environment=FORGEJO__server__HTTP_PORT=3000
50+
Environment=FORGEJO__server__SSH_PORT=2222
51+
Environment=FORGEJO__server__SSH_LISTEN_PORT=22
52+
Environment=FORGEJO__database__DB_TYPE=sqlite3
53+
Environment=FORGEJO__database__PATH=/data/forgejo.db
54+
Environment=FORGEJO__service__DISABLE_REGISTRATION=true
55+
Environment=FORGEJO__service__REQUIRE_SIGNIN_VIEW=false
56+
Environment=FORGEJO__security__INSTALL_LOCK=true
57+
Environment=FORGEJO__log__LEVEL=Info
58+
Environment=FORGEJO__log__MODE=console
59+
# Architectural Law 5: nothing in the forge calls vendor AI URLs.
60+
# Forgejo has no built-in AI surface; this comment exists so postcheck
61+
# #12 has a documented reason for the absence rather than an oversight.
62+
63+
User=mios-forge
64+
Group=mios-forge
65+
66+
[Service]
67+
Restart=on-failure
68+
RestartSec=10s
69+
TimeoutStartSec=300s
70+
Delegate=yes
71+
72+
[Install]
73+
WantedBy=multi-user.target default.target

usr/lib/sysusers.d/50-mios-services.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ g mios-crowdsec 814
1313
u mios-crowdsec 814:mios-crowdsec "'MiOS' CrowdSec dashboard" /var/empty /usr/sbin/nologin
1414
g mios-ollama 815
1515
u mios-ollama 815:mios-ollama "'MiOS' Ollama" /var/empty /usr/sbin/nologin
16+
g mios-forge 816
17+
u mios-forge 816:mios-forge "'MiOS' Forge (Forgejo)" /var/empty /usr/sbin/nologin

usr/lib/tmpfiles.d/mios-forge.conf

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# 'MiOS' Forge (Forgejo) -- runtime state declarations.
2+
# Required because /var paths cannot be created at OCI build time
3+
# (Architectural Law 2: NO-MKDIR-IN-VAR). Ownership matches the
4+
# mios-forge user declared in usr/lib/sysusers.d/50-mios-services.conf
5+
# at UID/GID 816. systemd-sysusers runs before systemd-tmpfiles at boot,
6+
# so the mios-forge user resolves cleanly here.
7+
8+
# Container's /data mount target. Holds the SQLite DB, repository bytes,
9+
# attachments, avatars, search index. /srv is the FHS-3.0 location for
10+
# 'data served by the system'.
11+
d /srv/mios/forge 0750 mios-forge mios-forge -
12+
13+
# Auxiliary runtime state outside the /data mount (logs the operator
14+
# might want separated from the data dir, lock files, etc.).
15+
d /var/lib/mios/forge 0750 mios-forge mios-forge -
16+
d /var/log/mios/forge 0750 mios-forge mios-forge -
17+
18+
# Admin-override directory for an optional app.ini and any custom
19+
# templates / static asset overrides. Mounted into the container as
20+
# /etc/mios/forge:ro so admins can edit on the host without rebuilding
21+
# the image. Operator-edited; tracked under /etc/ per Law 1
22+
# (USR-OVER-ETC: /etc/ is admin-override only).
23+
d /etc/mios/forge 0750 root mios-forge -

usr/share/mios/env.defaults

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ MIOS_K3S_VERSION="v1.32.1-k3s1"
4242
MIOS_K3S_IMAGE="rancher/k3s:v1.32.1-k3s1"
4343
MIOS_CEPH_VERSION="v18"
4444
MIOS_CEPH_IMAGE="quay.io/ceph/ceph:v18"
45+
MIOS_FORGE_VERSION="11"
46+
MIOS_FORGE_IMAGE="codeberg.org/forgejo/forgejo:11"
47+
MIOS_FORGE_HTTP_PORT="3000"
48+
MIOS_FORGE_SSH_PORT="2222"
4549

4650
# ── AI inference (LAW 5: localhost OpenAI-compatible only) ────────────────────
4751
MIOS_AI_ENDPOINT="http://localhost:8080/v1"

usr/share/mios/mios.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ features = ["ai", "virtualization", "k3s"]
160160
mios-ai = true
161161
mios-ceph = true
162162
mios-k3s = true
163+
mios-forge = true
163164
crowdsec-dashboard = true
164165
ollama = true
165166
cloudws-guacamole = true

0 commit comments

Comments
 (0)