From db81cb15d33686d182d75b82bc60b2e0e32a92b5 Mon Sep 17 00:00:00 2001 From: oskar Date: Wed, 5 Aug 2026 11:58:00 +0200 Subject: [PATCH] feat(kb-site): noindex + robots.txt + obscure subdomain jako domyslny base-url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warstwa "nie daj sie przypadkiem znalezc" dla publicznej wystawki KB: - gen_pages.py: w kazdej generowanej strony (page_shell, wiec takze index). - gen_pages.py: DEFAULT_BASE_URL -> https://kb-e2a24af3.okit.pl. Slug musi zgadzac sie z rekordem DNS i vhostem w npm@PIHA (runbook kb-site-deploy). - services/kb-site: static/robots.txt (Disallow: /) montowany ro na /usr/share/nginx/html/robots.txt. Plik nie jest dokumentem KB, wiec jedzie z repo, a nie z wolumenu podmienianego przy kazdej publikacji. - kb/services/kb-site.md: sekcja "Access" — token w query paramie na warstwie nginx/NPM (sekret zyje tylko w NPM, nie w repo) + obscure subdomain + noindex. Explicit: to obscurity, nie kontrola dostepu — token w URL laduje w access logach, historii przegladarki i naglowku Referer. Bramka publikacji bez zmian: gen_pages.py --check exit 0 (22 wyciszone whitelista, jak dotad). Co-Authored-By: Claude Opus 5 (1M context) --- kb/services/kb-site.md | 17 +++++++++++++++-- scripts/kb/gen_pages.py | 7 ++++--- services/kb-site/docker-compose.yml | 5 +++++ services/kb-site/static/robots.txt | 2 ++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 services/kb-site/static/robots.txt diff --git a/kb/services/kb-site.md b/kb/services/kb-site.md index 5de6e79..ea3caa7 100644 --- a/kb/services/kb-site.md +++ b/kb/services/kb-site.md @@ -3,14 +3,15 @@ okf: "0.1" type: service visibility: public status: active -updated: 2026-08-04 +updated: 2026-08-05 links: - ../runbooks/kb-site-deploy.md --- # kb-site -Public slice of this knowledge base, served as static HTML at `kb.okit.pl`. +Public slice of this knowledge base, served as static HTML from a deliberately +non-obvious subdomain of `okit.pl`. Plain `nginx:alpine` on the PIHA node reading one Docker named volume — no build step at runtime, no database, no dependencies. @@ -58,6 +59,18 @@ 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. +## Access + +Three layers keep the site out of casual sight: a query-parameter token enforced +in the nginx/NPM layer (advanced config held in NPM only — the secret is not in +this repository), an unguessable subdomain, and `noindex, nofollow` on every page +alongside a blanket `robots.txt`. + +This is obscurity, not access control. A URL token is written to access logs, +browser history and outbound `Referer` headers, so anyone who obtains a link +keeps it; nothing here resists a deliberate attacker. The leak gate above, not +this, is what keeps private material off the site. + ## Operations Deployment, content refresh, reverse-proxy and DNS setup are described in the diff --git a/scripts/kb/gen_pages.py b/scripts/kb/gen_pages.py index 58d4596..b18658f 100644 --- a/scripts/kb/gen_pages.py +++ b/scripts/kb/gen_pages.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Generator publicznej warstwy bazy wiedzy (kb.okit.pl) z dokumentów OKF v0.1. +"""Generator publicznej warstwy bazy wiedzy z dokumentów OKF v0.1. Wzorzec: ~/narty-2027/saalbach-kb/gen_pages.py — renderer markdown na samej bibliotece standardowej plus prosty, czytelny szablon HTML. Tutaj dochodzi @@ -60,7 +60,7 @@ from check_okf import parse_yaml, split_frontmatter # noqa: E402 REPO_ROOT = Path(__file__).resolve().parents[2] KB_DIR = REPO_ROOT / "kb" DEFAULT_OUT = REPO_ROOT / "build" / "kb-site" -DEFAULT_BASE_URL = "https://kb.okit.pl" +DEFAULT_BASE_URL = "https://kb-e2a24af3.okit.pl" DEFAULT_WHITELIST = Path(__file__).resolve().parent / "check_whitelist.txt" SITE_NAME = "homelab-codex — knowledge base" @@ -464,6 +464,7 @@ def page_shell( + {html.escape(title)} — {html.escape(SITE_NAME)} @@ -816,7 +817,7 @@ def check(out_dir: Path, whitelist_path: Path) -> int: def main() -> int: parser = argparse.ArgumentParser( - description="Generator publicznej warstwy KB (kb.okit.pl) z dokumentów OKF." + description="Generator publicznej warstwy KB z dokumentów OKF." ) parser.add_argument( "--base-url", diff --git a/services/kb-site/docker-compose.yml b/services/kb-site/docker-compose.yml index a7cf8d3..d30af27 100644 --- a/services/kb-site/docker-compose.yml +++ b/services/kb-site/docker-compose.yml @@ -15,6 +15,11 @@ services: # through the helper-container procedure in kb/runbooks/kb-site-deploy.md # (docker cp cannot write into a :ro mount). - kb-site_content:/usr/share/nginx/html:ro + # robots.txt nie pochodzi z generatora — nie jest dokumentem KB, więc + # jedzie z repo i nie ginie przy podmianie zawartości wolumenu. Mount + # pliku jest głębszy niż mount katalogu, więc Docker montuje go później + # i plik przykrywa (nieistniejące) robots.txt z wolumenu. + - ./static/robots.txt:/usr/share/nginx/html/robots.txt:ro # Docker on PIHA has exhausted its default address pools (~30 live stacks: # "all predefined address pools have been fully subnetted"), so this stack # must not ask for a subnet of its own. Declaring a network here suppresses diff --git a/services/kb-site/static/robots.txt b/services/kb-site/static/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/services/kb-site/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /