Files
atheos-blog-lxc/docs/writer-branch-workflow.md
hermes c57aff3c33 docs: branch protection is a recommendation, not a blocker (operator decision)
The operator has decided not to enable branch protection on armistace/blog while the editor
is LAN-only:

  "leave it as a recommendation - I won't do that unless I take this out to the wider internet"

That is a reasonable call, so this records it as an ACCEPTED RISK rather than an open task.

Test behaviour changed to match. The suite still attempts a direct push to master with the
deploy key on EVERY run - the check is not removed, because that is what would catch the
setting being lost or never applied. But when protection is off it now reports
  ACCEPTED-RISK  master is NOT protected - the deploy key CAN push master directly
instead of FAIL, so the suite is green and CI-usable (it previously exited 1, meaning a
genuine regression would have been buried in expected noise).

The run flips back to "PASS master is protected" by itself the moment protection is enabled,
so the recommendation self-cancels with nobody having to remember it. Summary line now reads
  RESULT: 44 passed, 0 failed, 1 accepted-risk

Docs record WHY the risk is acceptable (the compensating control is reachability, not
immutability - nothing off-LAN can reach the editor, and the only LAN user is the operator)
and the two triggers that turn it back into a real finding:
  1. the editor becomes reachable off-LAN (NPM proxy, port-forward, VPN route)
  2. anyone other than the operator gets access
Written down because an accepted risk is only acceptable if it is explicit and has a
revisit trigger - otherwise it just looks like an oversight later.
2026-09-29 16:40:49 +10:00

7.2 KiB

Writer-Branch Workflow

How writing and publishing work from the Atheos editor, and why the branch is structured this way.

The model

The editor never touches master. It writes to a long-lived branch (atheos-writer), and merging into master is done by the operator in Gitea.

                     ┌──────────────────────────────────────────┐
   Atheos editor ────┤  atheos-writer   (long-lived)            │
   (macros)          │  • write here                            │
                     │  • commit + push here                    │
                     │  • can be reset --hard back to master    │
                     └───────────────┬──────────────────────────┘
                                     │  operator opens a PR in Gitea
                                     │  operator reviews
                                     ▼
                              master  (protected: RECOMMENDED, currently OFF - see §2)
                                     │
                                     ▼
                        existing Pelican build pipeline

Why: the editor is a web app with shell-exec reach (codegit + macro both run commands as the php-fpm user). Bounding what it can reach is the whole point of design decision D6. Keeping master behind a PR means a compromised or fat-fingered editor cannot publish directly — it can only propose.

Setup — do these once

1. Set your git identity (required, RUNBOOK STEP 1)

ssh root@192.168.178.57
su -s /bin/sh atheos
git config --global user.name  "Your Name"
git config --global user.email "you@example.com"

This is the same global gitconfig php-fpm uses (HOME=/home/atheos — verified), so macros commit as you. If it is not set, macro 2 refuses with an actionable error rather than committing under a bogus identity.

2. Protect master on the blog repo — RECOMMENDATION, deliberately not enabled

Status: accepted risk. Branch protection is OFF, and that is a decision, not an oversight.

"leave it as a recommendation — I won't do that unless I take this out to the wider internet" — operator

The deploy key can push master directly, which means the writer-branch model is advisory, not enforced. The operator has weighed this and chosen not to add the gate while the editor is LAN-only:

  • The compensating control is reachability, not immutability. The editor is LAN-only (FR-10). The threat this setting defends against is a compromised editor publishing straight to master; while nothing off-LAN can reach the editor, and the only user on the LAN is the operator, that is largely theoretical.
  • The cost is real now, the benefit is not. Protection adds a merge gate for the sole user, who is also the repo owner — friction with no realistic risk reduction today.

⚠️ Enable it BEFORE either of these happens

  1. The editor becomes reachable off-LAN — an NPM proxy entry, a port-forward, or a Tailscale/WireGuard route to blog-ide.aridgwayweb.com.
  2. Anyone other than the operator gets access to the editor.

At that point a deploy key that can force-push master stops being theoretical. The setting (armistace/blog → Settings → Branches → rule for master):

Setting Value
Enable push off ← direct pushes blocked, including the deploy key
Enable merge whitelist on → add armistace
Require approvals optional (you're the only human here)

Verify:

curl -s -H "Authorization: token $GITEA_TOKEN" \
  https://git.aridgwayweb.com/api/v1/repos/armistace/blog/branch_protections

It is still checked on every test run

build-and-test.sh attempts a direct push to master with the deploy key and requires it to be rejected. While protection is off that reports as ACCEPTED-RISK, not FAIL — so the suite stays green and CI-usable — but the check runs every time. It flips to PASS master is protected by itself the moment protection is enabled, and this recommendation becomes moot without anyone having to remember it.

3. The macros

Installed directly into Atheos's macro store (data/macros.db.php); a copy is kept in this repo at files/macros.db.php so a rebuild reproduces them. They appear when you right-click the blog folder in the file tree → Macros.

# Macro Command Notes
1 Start/Join Writer Branch git checkout atheos-writer || git checkout -b atheos-writer then push -u idempotent — safe to run repeatedly
2 Commit + Push Writer Branch identity guard → git add -A → commit (only if staged changes) → git push origin atheos-writer the everyday button
3 DESTRUCTIVE: Reset Writer Branch to Master git fetch → git reset --hard origin/master → git push --force-with-lease wipes the branch's commits, keeps your files
4 Status + Recent Log git status --short --branch, git log --oneline -8, git branch read-only
5 Refresh Master (ff-only) git checkout master → git pull --ff-only → back to atheos-writer brings master's merges down
6 Merge Master Into Writer Branch git merge origin/master → push for when master has moved ahead

Output is returned into the UI — you see git's actual stdout/stderr, not a silent success.

Day-to-day

  1. Right-click blog → Macros → 1. Start/Join Writer Branch (first time; also safe later)
  2. Write your post, save
  3. Right-click blog → Macros → 2. Commit + Push Writer Branch
  4. Open a PR: atheos-writer → master
  5. Review the diff in Gitea, merge

⚠️ Important: macro 2 uses git add -A

git add -A stages everything in the repo, including files you may not intend to publish (drafts, scratch files, .orig/.bak leftovers). A reset --hard will also delete any untracked file that has been staged.

Practical consequences:

  • atheos-writer is a publishing branch — everything you leave in the tree gets committed and pushed to Gitea.
  • If you want a scratch area, keep it outside the repo (e.g. workspace/scratch/, not workspace/blog/).
  • To unstage before a reset: git reset (clears the index without touching your files).

Recovering a deleted file

reset --hard does not touch the object database, so a file that was ever staged or committed is still recoverable:

su -s /bin/sh atheos
cd /var/www/atheos/workspace/blog
git fsck --lost-found | grep commit        # find dangling commits
git ls-tree <commit> path/to/file          # confirm it is there
git cat-file -p <blob-sha> > path/to/file  # restore it

git reflog --all also shows recently discarded commits. This is how the empty src/content/please_no_facebook.md was recovered after a reset --hard in testing.

Changing the branch name

Edit macros 1, 2, 3, 5 and 6 in Settings → Macro and replace atheos-writer. The branch name is literal in each command — there is no variable. (Macros have no input prompt, so a branch name that changes per task would need edit-then-run.)