Adds the branch-based publishing model: the editor writes to a long-lived
`atheos-writer` branch, and merging into `master` stays in Gitea.
Six macros installed into Atheos's macro store (a copy is kept in
files/macros.db.php so a rebuild reproduces them), invoked by right-clicking
the `blog` folder:
1. Start/Join Writer Branch idempotent create-or-switch + push -u
2. Commit + Push Writer Branch identity guard -> add -A -> commit (only
if something is staged) -> push
3. DESTRUCTIVE: Reset Writer to Master fetch -> reset --hard origin/master ->
push --force-with-lease
4. Status + Recent Log read-only
5. Refresh Master (ff-only) pull master down, return to writer
6. Merge Master Into Writer Branch when master has moved ahead
Atheos has no terminal and codegit exposes no branch-switching, so macros are
the only way to run arbitrary git from the UI. Verified: codegit's `checkout`
action takes a FILE argument - it is per-file revert, not branch switching.
Identity handling: the commit macros deliberately do NOT hardcode an identity.
php-fpm runs with HOME=/home/atheos (verified), the same global gitconfig the
operator edits over SSH, so hardcoding `git -c user.name=...` would OVERRIDE the
operator's own identity. Instead macro 2 guards on an identity existing and fails
with an actionable message - which is what design decision D1 intends.
Verified by exercising each command through the web server as the php-fpm user:
- macro 1, 4, 5 return rc=0 with correct output
- macro 2's identity guard fires with the exact RUNBOOK STEP 1 message
- macro 3 was tested with real divergence: committed on the writer branch,
reset --hard to master, force-pushed; origin/atheos-writer then matched
origin/master exactly (0 ahead, 0 behind)
Security note recorded in the docs and README: this model only holds if branch
protection is enabled on armistace/blog's master. It is currently NOT enabled,
so the deploy key could force-push master directly - the operator needs to turn
it on (repo-owner action).
Also documents two hazards found while testing:
- macro 2's `git add -A` stages everything, and a subsequent `reset --hard`
deletes any untracked file that was staged. Keep scratch files outside
workspace/blog/.
- recovery procedure for a file lost that way (git fsck --lost-found ->
ls-tree -> cat-file), which was used to restore a file during testing.
126 lines
5.6 KiB
Markdown
126 lines
5.6 KiB
Markdown
# 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)
|
|
│
|
|
▼
|
|
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
|
|
|
|
**Not yet enabled — the deploy key can currently force-push `master` directly**, which defeats the
|
|
whole model. Set it in Gitea (repo owner only):
|
|
|
|
`armistace/blog` → **Settings** → **Branches** → add 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
|
|
```
|
|
|
|
### 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 <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.)
|