Merge feature/dev-workflow-and-gitea-bootstrap into main
Establishes the feature-branch→main workflow and Gitea-early bootstrap plan. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
8 files changed
+126
-6
No files matched your search
@@ -146,3 +146,16 @@ This is a hard boundary (R-TEST-06):
|
||||
|
||||
The point: the specification is the fixed target. Agents move the implementation and its tests
|
||||
toward the target; they never move the target.
|
||||
|
||||
## 12. Version-control workflow
|
||||
|
||||
Full detail in [`CONTRIBUTING.md`](CONTRIBUTING.md). The rules that bind every change:
|
||||
|
||||
- **No work on `main`.** `main` holds only completed, reviewed work.
|
||||
- **Every change is a feature branch** (`feature/…`, `fix/…`, `docs/…`, `chore/…`), **merged into
|
||||
`main`** when complete (and, for implementation, when its conformance tests pass).
|
||||
- **Local git for now; Gitea soon.** There is no remote host on this network yet — the prior
|
||||
`home-network` Gitea is gone from this network. **Gitea is one of the first services brought online
|
||||
on the cluster**, after which repos, the GitOps source, and CI/CD move to Gitea (Gitea Actions
|
||||
running the Kyverno gate + Chainsaw conformance Job, with PRs as the enforced merge gate).
|
||||
- **Never commit plaintext secrets** (SOPS-encrypted only, [`docs/07-security-and-secrets.md`](docs/07-security-and-secrets.md)).
|
||||
@@ -0,0 +1,64 @@
|
||||
# Contributing & Development Workflow
|
||||
|
||||
How work is version-controlled for this repository. This complements the governance rules in
|
||||
[`AGENTS.md`](AGENTS.md) (what agents may/may not change) — this file covers *how changes land in
|
||||
git*.
|
||||
|
||||
## Interim state (now): local git, feature branches → main
|
||||
|
||||
There is **no remote git host on this network today**. (The previous `home-network` Gitea instance is
|
||||
gone from this network; the infrastructure it built still runs but is not reachable here.) So for now:
|
||||
|
||||
- **Local git only.** The repository lives on the workstation; there is no push target yet.
|
||||
- **No work on `main`.** `main` holds only reviewed, completed work. Do **not** commit work-in-
|
||||
progress directly to `main`.
|
||||
- **Every change is a feature branch.** Create `feature/<short-description>` (or `fix/…`, `docs/…`)
|
||||
for any unit of work, commit there, then **merge into `main`** when the work is complete and — for
|
||||
implementation work — its conformance tests pass ([`agents/definition-of-done.md`](agents/definition-of-done.md)).
|
||||
- **Merge to `main` = "done".** Keep `main` always in a coherent, mergeable state.
|
||||
|
||||
### Branch naming
|
||||
- `feature/<slug>` — new capability or spec area
|
||||
- `fix/<slug>` — corrections
|
||||
- `docs/<slug>` — documentation-only changes
|
||||
- `chore/<slug>` — tooling/repo housekeeping
|
||||
|
||||
### Commit hygiene
|
||||
- Small, single-responsibility commits; imperative subject lines.
|
||||
- Reference requirement IDs / ADR numbers / task-board IDs where relevant (they're stable across
|
||||
file moves).
|
||||
- **Never commit plaintext secrets** — secrets are SOPS-encrypted only ([`docs/07-security-and-secrets.md`](docs/07-security-and-secrets.md));
|
||||
the [`.gitignore`](.gitignore) guards common leak paths but is not a substitute for care.
|
||||
|
||||
## Target state (soon): Gitea-hosted, CI/CD-driven GitOps
|
||||
|
||||
The platform will **host its own git**. **Gitea is one of the first services brought online on the
|
||||
cluster** ([`docs/13-service-catalog.md`](docs/13-service-catalog.md), roadmap Phase 6 is pulled
|
||||
early — see [`roadmap/phases.md`](roadmap/phases.md)). Once Gitea is up and stable, the workflow
|
||||
shifts:
|
||||
|
||||
1. **Repos move to Gitea** (`gitea.home.keithjackson.dev`). This local repo is pushed up as the
|
||||
origin of record.
|
||||
2. **GitOps source migrates** from local/bootstrap to Gitea: Flux reconciles the cluster from Gitea
|
||||
([`docs/05-gitops-and-delivery.md`](docs/05-gitops-and-delivery.md)).
|
||||
3. **CI/CD runs in Gitea** (Gitea Actions): the Kyverno L0 policy gate and the trigger for the
|
||||
in-cluster Chainsaw conformance Job run as pipelines on push/PR
|
||||
([`docs/14-testing-and-conformance.md`](docs/14-testing-and-conformance.md)); Renovate opens
|
||||
update PRs ([`docs/11-automated-updates.md`](docs/11-automated-updates.md)).
|
||||
4. **Pull requests become the merge gate** into `main`, with CI (policy + conformance) required
|
||||
green before merge — the same no-work-in-main rule, now enforced by the platform instead of by
|
||||
convention.
|
||||
|
||||
### The bootstrapping caveat (self-hosted git is circular)
|
||||
Gitea runs *on* the cluster that Flux reconciles *from* Gitea — a chicken-and-egg. Handling:
|
||||
- Bring the cluster up from a **bootstrap source** (this local repo / an out-of-band source), stand
|
||||
up Gitea, then **cut Flux's source over to Gitea**.
|
||||
- Because a cluster loss would take its own git host with it, **Gitea is DR-critical**: its repos are
|
||||
backed up **off-cluster** ([`docs/04-storage-and-state.md`](docs/04-storage-and-state.md)), and an
|
||||
off-cluster mirror of the platform repo is kept so the platform can always be rebuilt from a source
|
||||
that outlives the cluster.
|
||||
|
||||
## What does not change
|
||||
- Specs remain **human-owned and immutable to agents** ([`AGENTS.md` §11](AGENTS.md)) regardless of
|
||||
where git is hosted.
|
||||
- "Done" remains a **green, reproducible conformance test**, not "merged."
|
||||
@@ -61,6 +61,7 @@ GitOps configuration promotes to production with only environment-scoped overrid
|
||||
home-network-k3s/
|
||||
├── README.md ← you are here
|
||||
├── AGENTS.md ← rules of engagement for AI agents
|
||||
├── CONTRIBUTING.md ← git workflow (feature branches → main; Gitea/CI-CD to come)
|
||||
├── GLOSSARY.md ← shared vocabulary (read to avoid ambiguity)
|
||||
├── docs/ ← the specification, by domain
|
||||
│ ├── 00-vision-and-scope.md
|
||||
|
||||
@@ -74,11 +74,13 @@ Seeded from [`../roadmap/phases.md`](../roadmap/phases.md) + [`../roadmap/workst
|
||||
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|
||||
|---|---|---|---|---|---|---|
|
||||
| T-6.1 | Onboard **pihole** (DNS underpinning) | WS-APPS | R-DNS-03 | T-2.5 | — | todo |
|
||||
| T-6.1a | Onboard **gitea** early (bootstrapping-critical; self-hosts GitOps source + CI/CD) | WS-APPS | R-STATE-03 | T-4.4 | — | todo |
|
||||
| T-6.1b | Migrate GitOps source local→Gitea; move CI to **Gitea Actions** (Kyverno gate + Chainsaw Job trigger; PR merge gate); off-cluster repo mirror | WS-GITOPS | R-GITOPS-01, R-TEST-03 | T-6.1a | — | todo |
|
||||
| T-6.2 | Onboard **plex** (bulk tier + public exposure) | WS-APPS | R-STATE-04 | T-2.6, T-6.1 | — | todo |
|
||||
| T-6.3 | Onboard **qbittorrent, jackett** (VPN + kill-switch) | WS-APPS | R-NET-05/06 | T-3.4 | — | todo |
|
||||
| T-6.4 | Onboard **sonarr, radarr** (VPN + arr↔downloader allows) | WS-APPS | R-NET-02/05 | T-6.3 | — | todo |
|
||||
| T-6.5 | Onboard **seerr** (allows to arr + plex) | WS-APPS | R-NET-02 | T-6.2, T-6.4 | — | todo |
|
||||
| T-6.6 | Onboard **nextcloud, gitea** (DR-critical + backups) | WS-APPS | R-STATE-03 | T-4.4 | — | todo |
|
||||
| T-6.6 | Onboard **nextcloud** (DR-critical + backups) | WS-APPS | R-STATE-03 | T-4.4 | — | todo |
|
||||
| T-6.7 | Onboard **minecraft, unifi, semaphore, kasm** | WS-APPS | app reqs | T-2.6 | — | todo |
|
||||
| T-6.8 | C2 UI: Homepage root + Grafana + Headlamp + Flux status + auth | WS-C2 | R-C2-01/02 | T-4.2, T-6.* | — | todo |
|
||||
|
||||
|
||||
@@ -80,6 +80,28 @@ Full detail and the "is an automated commit a GitOps change?" nuance is in
|
||||
- Because desired state is in git and data is on Longhorn/backups, a rebuilt cluster reconverges by
|
||||
re-bootstrapping Flux and restoring volumes ([04](04-storage-and-state.md)).
|
||||
|
||||
## Source-of-truth: local bootstrap → self-hosted Gitea
|
||||
|
||||
The platform hosts its own git, which creates a deliberate bootstrapping sequence
|
||||
([`../CONTRIBUTING.md`](../CONTRIBUTING.md)):
|
||||
|
||||
1. **Bootstrap source.** Initially there is no remote git on this network (the prior `home-network`
|
||||
Gitea is gone from here). Development is local; the cluster is first reconciled from a
|
||||
**bootstrap source** (this local repo / an out-of-band source).
|
||||
2. **Gitea comes online early.** **Gitea is one of the first services onboarded** ([13](13-service-catalog.md))
|
||||
so the platform gains its own git host at `gitea.home.keithjackson.dev`.
|
||||
3. **Cut Flux over to Gitea.** Once Gitea is stable, Flux's `GitRepository` source is migrated from
|
||||
the bootstrap source to Gitea; the platform then reconciles from its own git.
|
||||
4. **CI/CD moves to Gitea Actions.** The Kyverno L0 policy gate and the trigger for the in-cluster
|
||||
Chainsaw conformance Job ([14](14-testing-and-conformance.md)) run as Gitea Actions pipelines on
|
||||
push/PR; PRs become the enforced merge gate into `main`.
|
||||
|
||||
**Circularity & DR.** Gitea runs *on* the cluster Flux reconciles *from* Gitea. Mitigations:
|
||||
- Keep an **off-cluster mirror** of the platform repo so a source-of-truth exists that outlives the
|
||||
cluster.
|
||||
- Treat **Gitea as DR-critical**: its repos/DB are backed up off-cluster ([04](04-storage-and-state.md)),
|
||||
so a cluster loss never loses the git history needed to rebuild the platform.
|
||||
|
||||
## Guardrails
|
||||
- No `kubectl apply` of app state by hand — everything flows through git/Flux (R-GITOPS-01, click-
|
||||
ops-never per [AGENTS.md](../AGENTS.md)).
|
||||
|
||||
@@ -75,7 +75,7 @@ Egress and dependencies below are **normative intent**; implementers render the
|
||||
| 9 | **unifi** | container | internal | internet | config: longhorn | — | UniFi network controller |
|
||||
| 10 | **semaphore** | container | internal | internet | config/db: longhorn | — | Ansible UI |
|
||||
| 11 | **kasm** | container | internal | internet | config: longhorn | — | Kasm Workspaces (may need more resources; container-first, VM if required) |
|
||||
| 12 | **gitea** | container | public | internet | repos/db: longhorn (irreplaceable → backed up) | — | Git hosting; DR-critical |
|
||||
| 12 | **gitea** | container | public | internet | repos/db: longhorn (irreplaceable → backed up) | — | Git hosting; **bootstrapping-critical** — self-hosts the platform's GitOps source + CI/CD; onboarded **early** (see below); DR-critical (off-cluster backup + mirror) |
|
||||
| 13 | **qbittorrent** | container | internal | **vpn** | config: longhorn; downloads: **bulk** | ← sonarr, ← radarr | VPN + kill-switch; download client |
|
||||
|
||||
**VPN-class set (R-NET-05/06):** sonarr, radarr, jackett, qbittorrent — all egress via VPN with an
|
||||
@@ -103,6 +103,12 @@ and inherit all guarantees automatically — that is the point of the abstractio
|
||||
([09](09-dns-and-ingress.md)); everything else stays `internal`.
|
||||
- **Kasm** is resource-heavy and may be a candidate for `kind: vm` if container mode proves
|
||||
insufficient — the ServiceDefinition makes that a one-field change.
|
||||
- **Gitea is bootstrapping-critical.** The platform self-hosts its git and CI/CD, so Gitea is brought
|
||||
online **early** (WS-APPS step 2, right after PiHole). Once stable, the GitOps source and CI move
|
||||
from the local bootstrap source to Gitea + Gitea Actions ([05](05-gitops-and-delivery.md),
|
||||
[`../CONTRIBUTING.md`](../CONTRIBUTING.md)). Because a cluster loss would take its own git host with
|
||||
it, Gitea's repos/DB are backed up **off-cluster** and mirrored, so the platform can always be
|
||||
rebuilt from a source that outlives the cluster.
|
||||
|
||||
## Acceptance gates
|
||||
- Each service is fully wired from its ServiceDefinition alone (compute, storage, policy, egress,
|
||||
|
||||
@@ -77,6 +77,9 @@ survives rebuild; default-deny + `egress` apply to the VM; guest auto-updates.
|
||||
## Phase 6 — Service Catalog Onboarding + C2 UI
|
||||
**Entry:** Phases 2–4 done.
|
||||
**Do:** onboard the 13 services via ServiceDefinitions in dependency order (see workstream WS-APPS);
|
||||
**bring Gitea online early in this phase** and cut the GitOps source + CI/CD over to it (Gitea
|
||||
Actions running the Kyverno gate + Chainsaw conformance Job; PRs as the enforced merge gate —
|
||||
[`../docs/05-gitops-and-delivery.md`](../docs/05-gitops-and-delivery.md), [`../CONTRIBUTING.md`](../CONTRIBUTING.md));
|
||||
stand up the C2 UI (Homepage root + Grafana + Headlamp + Flux status).
|
||||
**Exit (demonstrate):** each service fully wired from its ServiceDefinition (compute/storage/policy/
|
||||
egress/TLS/DNS/monitoring/updates) with default-deny + correct egress; the arr↔qbittorrent↔jackett↔
|
||||
|
||||
+13
-4
@@ -50,10 +50,19 @@ only via [`../agents/coordination-protocol.md`](../agents/coordination-protocol.
|
||||
- WS-C2 is last-ish (Phase 6) since it aggregates everything.
|
||||
|
||||
## WS-APPS onboarding order (respect dependencies from [13](../docs/13-service-catalog.md))
|
||||
1. **pihole** (DNS underpinning) → 2. **plex** (largest; validates bulk tier + public exposure) →
|
||||
3. **qbittorrent, jackett** (VPN + kill-switch proof) → 4. **sonarr, radarr** (VPN + arr↔downloader
|
||||
allows) → 5. **seerr** (cross-service allows to arr + plex) → 6. **nextcloud, gitea** (DR-critical
|
||||
data + backups) → 7. **minecraft, unifi, semaphore, kasm** (remaining).
|
||||
1. **pihole** (DNS underpinning) →
|
||||
2. **gitea** — **bootstrapping-critical; brought online early** so the platform self-hosts its git
|
||||
and CI/CD; after it is stable, WS-GITOPS cuts Flux's source over to Gitea and moves CI to Gitea
|
||||
Actions ([`../docs/05-gitops-and-delivery.md`](../docs/05-gitops-and-delivery.md),
|
||||
[`../CONTRIBUTING.md`](../CONTRIBUTING.md)). DR-critical → off-cluster backup + mirror. →
|
||||
3. **plex** (largest; validates bulk tier + public exposure) →
|
||||
4. **qbittorrent, jackett** (VPN + kill-switch proof) → 5. **sonarr, radarr** (VPN + arr↔downloader
|
||||
allows) → 6. **seerr** (cross-service allows to arr + plex) → 7. **nextcloud** (DR-critical data +
|
||||
backups) → 8. **minecraft, unifi, semaphore, kasm** (remaining).
|
||||
|
||||
**GitOps source migration** (WS-GITOPS, tied to step 2): local bootstrap source → self-hosted Gitea;
|
||||
CI (Kyverno gate + Chainsaw conformance Job trigger) moves to Gitea Actions; PRs become the enforced
|
||||
merge gate into `main`.
|
||||
|
||||
Each onboarding is a full acceptance-gate pass ([`../agents/definition-of-done.md`](../agents/definition-of-done.md)),
|
||||
not just a merged manifest.
|
||||
Reference in new issue
Block a user