- Delete tracked knoe-db/.prole_user_password (dead secret, rotated in ansible since the original commit) - Remove postgres-password.txt and build/ copy from working tree - Add explicit ignore rules for *_password, postgres-password*, .prole_user_password, *-secret variants Add docs/plans/customer-deploy-resync.md with the upstream/downstream migration plan and update CLAUDE.md to reflect prole's role as a customer deploy of knoe-db.
16 KiB
Resync prole as a Customer Deploy of knoe-db
Status: Active plan. Not yet executed. Owner: chrisfu Audience: Jr/mid engineer joining the project. No prior knowledge of the prole↔knoe-db split assumed.
1. Context
This working tree (~/dev/prole) and ~/dev/knoe-db started life as the same project. Over time knoe-db has become the canonical upstream — the "Knoe" infrastructure platform, hosted at git@git-ssh.knoe.dev:knoe.dev/knoe-db.git — while prole has continued as a separate fork on GitHub with its own diverging history.
The strategic decision the team has made is: stop forking, start branching. knoe-db is the platform's source of truth. Customer deployments — currently prole.org, eventually others — live as branches in knoe-db, not as separate repositories. A customer branch carries only the customer-specific divergence (config files, branding, on-prem manifests, kubeconfig handling). Platform changes always land on knoe-db/main and customer branches rebase or merge from main on a regular cadence.
This plan describes how to bring ~/dev/prole into that shape.
Why a branch and not a fork
- One pull-request review surface for platform changes. A change that affects all deployments goes through MR review on
knoe-db/mainonce. In a fork model the same change has to be re-reviewed (or, more often, silently re-implemented) per fork. - Customer-specific divergence is observable. A
git diff main..proleis the complete answer to "what's special about the prole.org deploy?" In a fork model that question requires a manual cross-repo diff that quickly goes stale. - Resync is mechanical.
git rebase mainorgit merge mainupdates the deploy branch. In a fork model resync is a recurring tax that engineers underinvest in until the forks have drifted past easy reconciliation — which is roughly where prole is today. - Customer-specific platform changes get attention. If a customer needs a platform-level change to support their deploy, it lands on
main(and is therefore available to all customers) instead of being hidden in a fork that never makes it back.
What's already done
-
prole has
knoe-dbconfigured as a git remote namedknoe:knoe git@git-ssh.knoe.dev:knoe.dev/knoe-db.git (fetch) knoe git@git-ssh.knoe.dev:knoe.dev/knoe-db.git (push) origin git@github.com:dredx/prole.git (fetch) origin git@github.com:dredx/prole.git (push)So the network plumbing for
git fetch knoeis in place.originis the legacy GitHub fork. -
knoe-dbalready hasdocs/plans/with the architectural references forknoe-auth Round 1and the four-mode installer — seeknoe-db/docs/plans/(path relative to your~/dev/root).
What's not yet done
- Most of
prole/mainhas not seenknoe-db/main's recent work (the prole→knoe rebrand, the welcome-mode-selector Phase 0, the fully implementedauthority/module, the 1Password CLI cutover, etc.). - Prole still tracks
infrastructure/(the prole.org-specific Ansible tree) whichknoe-dbexcised in commit5a769f2. - Prole still tracks the old
prole-*directory names that knoe-db has renamed (prole-app/,prole-tools-app/,prole.sh,prole.spec,prole_requirements.txt). - Prole's working tree carries credentials and runtime artifacts that should never have been near git in the first place —
postgres-password.txt,prole-k3s.kubeconfig*,secrets/,ssh-keys/. None are committed (verified withgit ls-files), but they exist in the working copy and are a data-leak risk.
2. Target shape
When this plan is done:
- The
proleworking directory tracks a branch inknoe-db— name to be confirmed, proposedcustomer/prole.orgor simplyprole. git remotelooks like:
The legacy GitHuborigin git@git-ssh.knoe.dev:knoe.dev/knoe-db.gitoriginis either retired entirely or kept asarchivefor historical reference.git diff origin/main(i.e.knoe-db/main) shows only prole-specific divergence:- Customer-branded config (
conf/prole.cfg, host names, realmPROLE.LOCAL, etc.) - On-prem manifests scoped to
prole.orginfrastructure (deploy/opentofu/k3s/manifests/prole/*) - Customer-specific docs (
docs/plans/customer-deploy-resync.md— this file — and any future prole-only plans)
- Customer-branded config (
- All tracked platform code (
authority/,knoe/,etc/init_*.sh,deploy/gcp/gke/*, the test pipeline) is byte-identical toknoe-db/main. Changes to those files happen onknoe-db/mainfirst and reach prole via merge/rebase. - Working-tree credentials and runtime files are removed, gitignored, and replaced with the 1Password-driven equivalents already used in
knoe-db.
What "customer-specific" actually means here
It's a short list, and the discipline is to keep it short:
| Type | Example | Where it lives on the branch |
|---|---|---|
| Customer config | conf/prole.cfg (cluster contexts, realm, hostnames) |
conf/ |
| Customer realm | PROLE.LOCAL Kerberos manifests |
deploy/opentofu/k3s/manifests/prole/prole-kdc-*.yaml |
| Customer cluster glue | k3s prole.org host inventory, anything host-pinned to merlin/myrddin/pi.prole.org |
deploy/opentofu/k3s/manifests/prole/ |
| Customer docs | docs/plans/customer-deploy-resync.md, any future prole-only specs |
docs/plans/ |
Anything that doesn't fit one of those four lines is probably platform code that should land on main.
3. Migration plan
The migration is in four phases. Each phase is reviewable on its own; do not collapse them.
All git work in this plan should run in Claude Code, not in Cowork. Cowork's bash sandbox has no network access and cannot reach
git-ssh.knoe.dev. Open a Code session in~/dev/proleand drive the commands from there.
Phase 1 — Snapshot and inventory
The goal of this phase is to produce a complete account of what's currently special about prole, before anyone starts deleting things. Output is a file checked into the working tree (docs/plans/resync-inventory.md, net-new) listing every file that differs from knoe-db/main, classified as one of:
- PLATFORM-DRIFT — file should match
knoe-db/main. Discrepancy is just stale prole. Action: take knoe-db's version. - CUSTOMER-SPECIFIC — file is genuinely prole-only. Action: keep, plan to land on the customer branch.
- WORKING-TREE-NOISE — credentials, build artifacts, kubeconfigs. Action: gitignore upstream if not already; remove from working tree; never commit.
- AMBIGUOUS — needs human review. Action: discuss before acting.
Concrete commands (run in Code in ~/dev/prole):
# fetch knoe-db
git fetch knoe
# list all files that exist in prole but not in knoe-db/main
git diff --name-only --diff-filter=D knoe/main..HEAD > /tmp/prole-only.txt
# list all files that exist in both but differ
git diff --name-only knoe/main..HEAD | grep -v '^docs/plans/customer-deploy-resync.md$' > /tmp/prole-modified.txt
# list all files that exist in knoe-db/main but not in prole
git diff --name-only --diff-filter=A knoe/main..HEAD > /tmp/knoe-db-new.txt
Walk through each list and classify. Expected hot spots based on the current state:
infrastructure/— entirely PLATFORM-DRIFT (excised upstream by commit5a769f2).prole-app/,prole-auth/,prole-mssql-db/,prole-net/,prole-tools-app/,prole.sh,prole.spec,prole_requirements.txt— PLATFORM-DRIFT (renamed upstream during the prole→knoe rebrand).authority/src/main/java/org/prole/authority/HealthController.javaetc. — PLATFORM-DRIFT (stale Spring Boot skeleton; upstream has the full module).deploy/opentofu/k3s/manifests/prole/*— likely CUSTOMER-SPECIFIC (theprole.orgrealm and host pinning belongs on the customer branch).conf/prole.cfg,conf/prole.silent.all.cfg— CUSTOMER-SPECIFIC.postgres-password.txt,prole-k3s.kubeconfig*,secrets/,ssh-keys/— WORKING-TREE-NOISE. These should not be tracked anywhere.
Output of phase 1 is the inventory file plus a short summary commit on a fresh branch (proposed name resync/phase-1-inventory).
Phase 2 — Bring prole/main to knoe-db/main
⚠️ Read this whole phase before running any of it. This is where the divergence collapses; recovery from a botched merge is much harder than waiting an hour to do it right.
Approach: do not try to merge upstream into prole's diverged main. Instead:
- Create a backup tag at the current state:
git tag prole-pre-resync-$(date +%Y%m%d). Push it toorigin(the GitHub fork) for safety. - Create a fresh customer-deploy branch off
knoe-db/main:git checkout -b customer/prole.org knoe/main - Cherry-pick only the CUSTOMER-SPECIFIC commits/files from the inventory. The cleanest way is a one-pass apply:
Commit in coherent groups (e.g. one commit per logical scope: "config", "k3s manifests", "customer docs").# for each file in the customer-specific list, copy from old prole main git checkout prole-pre-resync-<date> -- <path> git add <path> - Push the new branch to the
knoeremote:git push knoe customer/prole.org - Open an MR in
knoe-dbfor the customer branch (it doesn't merge to main — it's a long-lived branch — but the MR makes it visible and reviewable).
After this phase, customer/prole.org is byte-identical to main except for the (small) customer-specific delta.
Phase 3 — Retire the GitHub fork and clean the working tree
- Update the local working tree's
originremote to point atknoe:
Or, if you want to delete the GitHub fork outright, drop thegit remote rename origin archive git remote rename knoe origin git fetch originarchiveremote. Either is fine; the GitHub copy is no longer authoritative. - Switch the working tree to the new branch:
git checkout customer/prole.org - Delete working-tree noise (the WORKING-TREE-NOISE bucket from phase 1). For each file:
- Confirm it's not tracked:
git ls-files --error-unmatch <path>. - Confirm it's covered by
.gitignore(or add it). - Delete it:
rm -rf <path>. - Special case:
postgres-password.txt. Treat the contents as compromised because it was sitting in a working tree synced to who-knows-where. Rotate the password through the standard process, do not just delete the file.
- Confirm it's not tracked:
- Replicate
knoe-db's 1Password CLI workflow:etc/already has the 1Password integration afterknoe-dbcommitb421f49. Set up the 1Password CLI and verifyop signinworks before relying on the new flow.
Phase 4 — Establish the resync cadence
Going forward, prole resyncs from knoe-db/main on a deliberate cadence (proposal: weekly, or after any commit on main that touches a file the customer branch carries a divergent copy of).
Mechanism — pick one:
- Rebase
customer/prole.orgontoknoe-db/main. Linear history, clean diff against main, but rewrites the customer-branch SHAs on every resync. Choose this if no other tooling has hardcoded references to customer-branch commits. - Merge
knoe-db/mainintocustomer/prole.org. Preserves history, no SHA rewriting, but thegit log --onelinegets messy andgit diff main..customer/prole.orgincludes merge artifacts.
Recommendation: rebase. Customer divergence is small enough to keep clean, and the simpler diff is worth more than the merge-commit history.
Set up CI on knoe-db to run the customer-deploy smoke test against the rebased branch nightly. Failure of that smoke test is an early signal that platform changes have broken the customer deploy and need a customer-side fix.
4. Out of scope
These are real items but they are not part of the resync. Each becomes its own plan when its time comes.
- Migrating the running prole.org cluster to the new branch's deployment shape. Resync is a code-level operation; the live cluster is a separate migration governed by
etc/init_*.shand the installer. - Bringing prole's existing Supabase work back into knoe-db/main. Recent prole commits include Supabase fixes (
fix(supabase): ...) that aren't in upstream. Some of that may be platform code that should land onmain; some may be prole-specific. Sort that out as a follow-up MR. - The active "knoe-db Init:0/1 on myrddin" debug. That's a runtime-state problem on the prole.org cluster, unrelated to the source-code resync. Track in its own ticket.
- Onboarding additional customer deploys. Once one customer branch is healthy, the second is mostly mechanical, but not part of this plan's scope.
5. Verification
The resync is done when all of these are true.
git remote -vin~/dev/proleshowsoriginpointing atknoe-db. The legacy GitHub remote is either gone or namedarchive.git statusis clean on branchcustomer/prole.org.git diff knoe/main(orgit diff origin/mainpost-rename) shows only files in the four categories listed in §2 ("What 'customer-specific' actually means"). Noinfrastructure/, noprole-app/, no stale Java skeletons.git ls-filesdoes not listpostgres-password.txt,prole-k3s.kubeconfig*, or any file undersecrets/orssh-keys/.- The Postgres password that was previously sitting in
postgres-password.txthas been rotated. ./install.shor./knoe.sh installruns end-to-end on the customer branch inminandk3dmodes (the cheap modes to verify locally).customer/prole.orgis pushed toknoe-dband visible in the upstream repo's branch list.docs/plans/customer-deploy-resync.md(this file) anddocs/plans/resync-inventory.md(created in phase 1) are committed on the customer branch.
6. Risks and call-outs
- Don't run any of this with the prole.org cluster in a degraded state if the cluster recovery depends on a script that the resync deletes. The current
knoe-dbInit:0/1 debug is a live ops problem; finish that first, or be very careful that the scripts you're about to delete from prole are not the ones the cluster needs to come back. - The Postgres password file is a real incident. A credential file in a working tree synced via Dropbox / iCloud / network home directory has a non-trivial blast radius. Treat as compromised, rotate, do not just delete.
- The GitHub
originmay have copies of secrets in its history. Before retiring the fork, audit its commit history for committed credentials (git log -p | grep -iE 'password|secret|token|key'is a starting point). If anything is in there, rotate before retiring. GitHub's "delete repository" does not retroactively un-disclose anything that was scraped while the repo was up.
7. Glossary
Upstream / downstream — Upstream is the canonical project (knoe-db); downstream is a deployment of it (prole.org customer branch). Changes flow from upstream to downstream, never the other way without an MR back.
Customer deploy — A specific deployment of the knoe.dev platform for one organization. Carries customer-specific config (hostnames, realm, branding) on top of the platform's main branch. Lives as a long-lived branch in the platform repo, not a fork.
Long-lived branch — A branch that's not intended to merge back to main. It's continuously rebased onto main as platform work lands, but its own divergence stays as a divergence forever.
Resync — The act of bringing a customer branch up to a newer main. A periodic, deliberate operation; not a continuous one.
Phase 0 — The most recent platform-side rebrand and test-pipeline foundation work (commit 0052a4d in knoe-db). Context here only because it's what customer/prole.org is rebasing onto.