homelab-codex-ws/kb/services/kb-site.md
oskar 41d3543082 docs(kb): kb-site — dokument serwisu (public) + runbook deployu (private)
kb/services/kb-site.md (type: service, visibility: public) — opis samej
wystawki: co jest publikowane (regula fail-closed na `visibility`), jak
renderowane sa odnosniki do dokumentow nieopublikowanych, struktura builda,
stopka z commitem, bramka --check. Napisany tak, zeby sam przechodzil --check:
zero adresow, portow i sciezek hosta — szczegoly operacyjne siedza w runbooku.

kb/runbooks/kb-site-deploy.md (type: runbook, visibility: private) — pelna
procedura: deploy na PIHA, generacja + kontrola wyciekow jako bramka
publikacji, podmiana tresci w wolumenie helperem alpine (wzorzec z
services/narty27/README.md, rozszerzony z pliku na drzewo), rekord A w
Cloudflare + Pi-hole local DNS (split-horizon), proxy host i cert przez
scripts/npm/npm_api.py, weryfikacja, rutynowa aktualizacja jednym lancuchem
&&, tabela rollback/typowe problemy.

Dwie rzeczy zapisane wprost, bo latwo je przeoczyc:
- kolejnosc DNS -> NPM host -> cert (HTTP-01 wymaga dzialajacego vhosta),
- `rm -rf /content/*` przed rozpakowaniem — bez tego dokument przelaczony z
  public na private zostaje w wolumenie i dalej jest serwowany.

Runbook notuje tez aktualny wynik --check (22 trafienia /opt/homelab w
dokumentach public) jako decyzje do podjecia przed pierwsza publikacja:
wyczyscic zrodla albo swiadomie wpisac wyjatek do whitelisty.
2026-08-04 18:01:56 +02:00

2.8 KiB

okf type visibility status updated links
0.1 service public active 2026-08-04
../runbooks/kb-site-deploy.md

kb-site

Public slice of this knowledge base, served as static HTML at kb.okit.pl. Plain nginx:alpine on the PIHA node reading one Docker named volume — no build step at runtime, no database, no dependencies.

The site is a rendering, not a source. Every page is generated from the Markdown documents of the knowledge base by scripts/kb/gen_pages.py and copied into the volume; the HTML is never edited by hand and never committed.

What gets published

Only documents that carry an explicit visibility: public field in their frontmatter. The generator is fail-closed: a document with no frontmatter, with unparseable frontmatter, with no visibility field, or with any other value is treated as private and stays out of the build.

The same rule applies to cross-references. A link pointing at a document that was not published is not rendered as a link — only the label survives, marked [private]. A public page therefore never exposes the location of an internal document and never produces a dead link.

Frontmatter shown on a page is deliberately partial: type, status and the last update date. The links field is omitted, because a path to a private document is already a leak of its name.

Structure of the build

build/kb-site/
  index.html            list of all published documents, grouped by type
  <directory>/<name>.html   one page per document, mirroring the source tree

Each page carries a footer with the generation timestamp and the short commit hash of the repository state it was rendered from, so any page can be traced back to an exact revision.

Leak gate

gen_pages.py --check re-reads the generated HTML — not the sources — and fails on anything that looks like infrastructure detail leaking into a public page: private, carrier-grade and public IP addresses (v4 and v6), high service port numbers, absolute host paths, and long hex or base64 strings that look like credentials. Deliberate exceptions live in a whitelist file that starts out empty, so every exception is a recorded decision.

The check is a release gate: content is copied to the host only after it passes.

Operations

Deployment, content refresh, reverse-proxy and DNS setup are described in the kb-site deployment runbook, which is internal — on this site the reference above is plain text, exactly as described in the previous section.

Content lifetime

The volume holds an artifact, not data. There is no backup job — recovery is a regeneration from the repository. Because the generator writes a fresh tree on every run and the publish step replaces the volume contents wholesale, a document that flips from public to private disappears from the site on the next publish.