prj-forgejo-org-refactor/workplans/ORGREF-WP-0002-forge-closure-netkingdom-access.md
tegwick bc83a2fb16 ORGREF-WP-0002-T02 done: ArgoCD and k3s pull anonymously
Founder checks: no ArgoCD repository credentials; k3s registries.yaml holds
auth only for the frozen Gitea host, none for forgejo.coulomb.social.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
2026-10-08 16:54:05 +02:00

14 KiB
Raw Blame History

id type title domain repo status flavor owner topic_slug created updated depends_on related_repos state_hub_workstream_id
ORGREF-WP-0002 workplan Close the forge: NetKingdom access control first, then private by default infotech prj-forgejo-org-refactor active implementation worsch railiance 2026-10-08 2026-10-08
key-cape
railiance-forge
railiance-platform
railiance-apps
ops-warden
fluid-telegram
pr-hall-of-helix
the-custodian
f873c10f-1408-5bf2-a834-fed88387804b

ORGREF-WP-0002 - Close the forge: NetKingdom access control first, then private by default

Why

forgejo.coulomb.social does not distinguish public-facing repositories from private ones. The 2026-09-28 anonymous inventory listed 141 server repositories, all public. That includes hall-of-helix draft seats, agent session accounts, operational docs and workplans. Anyone can read them, and their raw files can be fetched anonymously.

The founder's decision (2026-10-08): switch repositories to private, but only after Forgejo access control is integrated with NetKingdom (key-cape). Every human, agent and service reader then has a governed identity before anonymous access ends. A flip without that would push every consumer to ad-hoc local accounts and tokens that would later have to be unwound.

Relation to ORGREF-WP-0001

This plan is independent of the ORGREF-WP-0001 entry gate. It moves no repository between orgs, renames nothing and changes no repository content, so the org-migration gate (validator, deployable coverage, G1, transfer rollback) does not apply. It changes who may read, not where things live.

It reuses ORGREF-WP-0001's preparation: the inventory/ collectors, the stewardship assignments in taxonomy/ (as owners for each consumer) and the reference scan. It also gives back to ORGREF-WP-0001: once the forge is closed, the anonymous collector can no longer see private repositories, so T09 moves it to an authenticated read identity. That resolves the access half of decision 5f3680fc (authenticated metadata).

Target state

  • Forgejo signs humans in through NetKingdom OIDC (key-cape). Agents and services use NetKingdom-issued identities or scoped Forgejo tokens with an owner and a rotation path. A local administrator account remains only as sealed break-glass, with its credentials in OpenBao.
  • Organisations and repositories are private by default. Public visibility is an explicit, recorded allowlist entry with a reason.
  • Every consumer that read the forge anonymously reads it with its own credential, with least privilege, before its repositories close.
  • Campaign images that must stay world-readable (Telegram posts fetch them by URL) come from a deliberate public asset location, not from a forge repo that happens to be public.
  • Anonymous probes show only the allowlist; the evidence is recorded.

Boundaries

This project may:

  • decide sequencing, run read-only inventories and anonymous/authenticated probes
  • rehearse on throwaway repositories and packages it creates for that purpose
  • open and track child work records in owner repos, linked by ID, not copied

It must not:

  • configure key-cape, Forgejo, OpenBao or any consumer itself. Each change lands through the owner repo's own workplan.
  • flip a production repository's visibility before T07's rehearsal passes and the founder approves that wave
  • read or print secret values (credential routing: warden route)
  • move, rename or restructure repositories (that is ORGREF-WP-0001)

Visibility changes are reversible; exposure is not. Content that has been public stays public in clones, caches and archives. T03 treats that history as a separate review, not something the flip repairs.

Tasks

id: ORGREF-WP-0002-T01
status: wait
needs_human: true
blocking_reason: "The founder decides the visibility policy, the public allowlist and whether an interim lockdown runs before the integration."
priority: high
state_hub_task_id: "6387cb32-dd73-5ee0-b51e-d4aea475bcca"

T01 — Decide the visibility policy

Record a founder decision covering:

  1. Default: private for organisations and repositories, plus whether instance-level REQUIRE_SIGNIN_VIEW is set so that nothing is anonymous except the allowlist.
  2. Public allowlist: which repositories stay public and why (for example, intentionally open-source repos or a published campaign repo). Each entry names an owner.
  3. Packages: container images and charts follow repository visibility or are private independently (28 running workload images come from forgejo.coulomb.social; see inventory/runtime-2026-09-28.json).
  4. Public assets: where world-readable campaign images live once hall-of-helix and pr-hall-of-helix close (a public asset repo, object storage, or attaching the image as an upload instead of a URL).
  5. Interim lockdown: whether to close a short list of sensitive repositories now with existing local accounts. If yes: which ones, accepting that their consumers move to local tokens temporarily and are re-homed in T06.
id: ORGREF-WP-0002-T02
status: done
priority: high
state_hub_task_id: "ace26a22-50e2-58c6-b4ad-85d95c284fce"

T02 — Inventory every anonymous reader

Read-only. Extend inventory/ with an access-consumer inventory: every party that reads the forge today without credentials, the repositories or packages it reads, and the owner (from taxonomy/assignments.csv) who will give it an identity. Known classes to cover:

  • cluster pulls: ArgoCD/Flux repoURLs, Helm chart repositories, and image pulls by k3s nodes from the Forgejo registry (namespaces lacking imagePullSecrets)
  • Forgejo Actions runners: checkouts and cross-repo uses: of reusable actions
  • agent and workstation clones, go/pip/npm fetches of forge-hosted modules
  • State Hub, repo-manager and forge-projection reads; ORGREF's own collector
  • fluid-telegram: Telegram fetching post images from raw URLs
  • external links: READMEs, badges, docs, published sites and canon links

Output a machine-readable inventory/access-consumers-<date>.json plus a summary listing, per consumer class, the owner and the proposed credential kind. Uncertain entries are flagged, not dropped.

2026-10-08: inventory done except two founder checks. tools/access_consumers.py over 161 working trees and a fresh runtime capture (inventory/runtime-2026-10-08.json) produced inventory/access-consumers-2026-10-08.json, reviewed in inventory/access-consumers.md. Breaks on closure: 43 workloads pulling forge images without imagePullSecrets (anonymous registry pulls confirmed working); 10 ArgoCD applications over 5 repos; CI in about 20 repos downloading source tarballs anonymously; PyPI index reads; reuse-surface federation (about 60 raw indexes); about 8 code readers without token handling; campaign images. Local clones are SSH and unaffected. Open: founder presence checks for ArgoCD repository credentials and k3s node registry auth (commands in the summary), and owner confirmation of the code readers.

2026-10-08: T02 done. Founder checks: ArgoCD has no repository credentials (all 10 Applications read anonymously); k3s registries.yaml holds auth only for the frozen Gitea host 92.205.130.254, none for forgejo.coulomb.social (all 43 pulls anonymous). One node-level registry auth entry would cover every pull (T06). The stale Gitea credential on the node is a cleanup item. Code-reader confirmation moves to the owners under T06.

id: ORGREF-WP-0002-T03
status: todo
priority: high
state_hub_task_id: "9c2ca7be-23f8-58c5-9bfd-e44a26ce4584"

T03 — Review what has already been public

Before closing, and independent of it: run a secret and sensitive-content scan over the public repositories' history (credentials, tokens, private keys, internal hostnames or IPs, personal data). Findings go to their owners for rotation through warden route. Closing a repository does not un-publish history, so a leaked credential needs rotating either way. Record the scan scope and results without reproducing any value.

id: ORGREF-WP-0002-T04
status: wait
depends_on: [ORGREF-WP-0002-T01]
blocking_reason: "The NetKingdom side follows the visibility and identity decisions; open the key-cape child workplan once T01 is resolved."
priority: high
state_hub_task_id: "112617e1-a7c3-59c1-bf25-235d58ec118b"

T04 — NetKingdom: Forgejo as an OIDC client (child workplan in key-cape)

Open a key-cape workplan, linked here by ID, to:

  • register Forgejo as a confidential OIDC client (redirect URI, scopes, PKCE) with its client secret in OpenBao, through the railiance-platform custody path
  • define the claims Forgejo consumes: subject, email, groups mapped to Forgejo organisations and teams, and principal_type, so that human, agent and service identities are distinguishable
  • apply the MFA policy for forge administrators, and decide which agent and service identities get forge access as NetKingdom service identities, not as user accounts

Acceptance: a test login against a staging client returns the expected claims for one human, one agent and one service identity.

id: ORGREF-WP-0002-T05
status: wait
depends_on: [ORGREF-WP-0002-T04]
blocking_reason: "Forgejo can only add the authentication source once the NetKingdom client and claims exist."
priority: high
state_hub_task_id: "6c635b25-a4ae-5259-9317-de3fe38f6234"

T05 — Forgejo: NetKingdom login and team mapping (child workplan in railiance-forge)

Open a railiance-forge workplan, linked here by ID, to:

  • add the NetKingdom OIDC authentication source and claim-to-team mapping; disable open registration; link existing local accounts (founder, agent accounts) to their NetKingdom identities
  • seal the local administrator as break-glass, with its credentials in OpenBao and recovery documented
  • create the organisation teams with least-privilege read/write that T06's consumers will use
  • change no repository visibility yet

Acceptance: the founder and one agent sign in through NetKingdom and see what their team grants. Break-glass login is verified once and recorded.

id: ORGREF-WP-0002-T06
status: wait
depends_on: [ORGREF-WP-0002-T02, ORGREF-WP-0002-T05]
blocking_reason: "Each consumer gets its credential from the T02 inventory, using the identities T05 makes available."
priority: high
state_hub_task_id: "1285f94d-3b57-502b-8aeb-96fab9578287"

T06 — Give every consumer its own read identity

For each consumer class in T02, its owner provisions a scoped credential and proves it works against a private canary repository and package created by this project, while anonymous access to that canary fails:

  • cluster: deploy tokens for ArgoCD/Flux repo credentials, imagePullSecrets for registry pulls (railiance-apps, railiance-platform)
  • runners: tokens or OIDC for checkout and reusable actions (railiance-forge)
  • agents and workstations: NetKingdom identities or scoped tokens routed through ops-warden; nothing pasted into repositories
  • State Hub, repo-manager and the ORGREF collector: authenticated read identity
  • fluid-telegram and pr-hall-of-helix: images moved to the T01 public asset location, with the compose visual raw-URL bases updated

Each owner records its proof in its own workplan. This plan tracks the list.

id: ORGREF-WP-0002-T07
status: wait
depends_on: [ORGREF-WP-0002-T06]
blocking_reason: "Rehearsal needs every consumer class migrated onto the canary."
priority: high
state_hub_task_id: "0dcf25e2-cda1-5f87-b7fe-5b7e27635565"

T07 — Rehearse the flip and the rollback

On throwaway repositories and packages: switch public → private → public, and verify consumer reads, anonymous denial, web links, Actions runs and image pulls at each step. Record the exact commands or API calls, the time each step takes, and what a rollback restores (visibility) and what it does not (anything already fetched). This rehearsal is the gate for T08.

id: ORGREF-WP-0002-T08
status: wait
depends_on: [ORGREF-WP-0002-T07]
needs_human: true
blocking_reason: "Each production visibility wave needs founder approval after a green rehearsal."
priority: high
state_hub_task_id: "42724077-9837-5aef-ad3b-6551f2103aa2"

T08 — Close the forge in waves

Change production visibility in founder-approved waves. Each wave lists its repositories and packages and the consumers that read them. Proposed order:

  1. repositories with no consumers outside their owner (fastest proof of the path)
  2. sensitive repositories (operational docs, workplans, agent sessions)
  3. repositories read by the cluster and runners
  4. instance-level REQUIRE_SIGNIN_VIEW, if T01 chose it

After each wave: consumer health checks, anonymous probe, and a recorded rollback point. A failing consumer rolls its repositories back to public and stops the wave. The fix lands with the consumer's owner.

id: ORGREF-WP-0002-T09
status: wait
depends_on: [ORGREF-WP-0002-T08]
blocking_reason: "Verification and handback follow the final wave."
priority: medium
state_hub_task_id: "82f53328-02f5-5953-830a-00019d7dee92"

T09 — Verify, hand back and record

  • Anonymous probe of the server: only the T01 allowlist is visible. Record the evidence under inventory/.
  • Move ORGREF-WP-0001's collector to the authenticated identity from T06 and note the effect on decision 5f3680fc.
  • Add a row to the-custodian docs/security-close-down-checklist.md recording that the forge is closed by default, plus anything relaxed along the way that must be re-armed.
  • Record any consumer still on a temporary credential as live owner work, not as prose in this file.

Open questions for review

  • Owner: is the founder the right owner, or should an agent own the driver with the founder holding T01/T08?
  • Should T03 (history review) block T08, or run in parallel and only gate rotations?
  • Is an interim lockdown (T01 point 5) worth the temporary-token churn, given how long T04–T07 will take?