# 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) ```sh 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: ```bash 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: ```sh su -s /bin/sh atheos cd /var/www/atheos/workspace/blog git fsck --lost-found | grep commit # find dangling commits git ls-tree path/to/file # confirm it is there git cat-file -p > 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.)