ci: build and deploy the site from Forgejo Actions #1
Loading…
Reference in a new issue
No description provided.
Delete branch "forgejo-actions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deploying meant remembering to bump the content submodule, build locally, and rsync
public/to nas. It had not been remembered since June..forgejo/workflows/deploy.yamldoes it on every push tov5, on the samenixrunner as nix-config's CI, and rsyncs to a login on nas pinned torrsync -wo /var/www/kvartsi.Merging this closes the loop. The rest of the chain is already proven against the live forge — a push to kartuli-ena ran its publish job, which landed
2de6fb1 content: 246d1c8…onv5, authored asforgejo-actions <owen+forgejo-actions@owenap.com>. That push triggered nothing only becausedeploy.yamlexists solely on this branch. Merging fires the first real deploy.A clean checkout did not build
npx quartz buildalone fails withCould not resolve "../../.quartz/plugins"—Head.tsxandfileTrie.tsimport an index that only exists once plugins are fetched. So installing is its own step.That step is
npx quartz plugin install— notnpm run install-plugins, and not--latest. Onlyplugin installresolves fromquartz.lock.jsonand checks each plugin out at its locked commit. The alternatives clone branch tips, which means compiling whatever 36 repos outside our control pushed that morning — and installing a plugin executes it (atsupbuild each, plus annpm iof native deps) in the samenative:hostjob that holds the nas key. This runner has no container boundary, so the pin is the control that matters most here.quartz.lock.jsonhad to be regenerated for that to work at all: its pins dated from April and had gone stale against this fork's own vendored source, failing withNo matching export in ".quartz/plugins/index.ts" for import "CustomOgImagesEmitterName". All 36 now pin to current tips. That buys reproducibility and closes the drive-by window; it does not buy trust in the code, so refreshing the pins should stay a deliberate, reviewable commit.What the first deploy will actually do
Built a clean clone of this branch at its current content pin and diffed the result against the live web root:
verbs/to-help.htmland its og-imagePurely additive — that page was written after June's manual deploy.
Worth stating because it was not always true. An earlier revision of this branch carried a local
Update contentcommit pinning June's vault whileorigin/v5still pinned April's; deploying that combination would have--deleted 19 real pages. The publish automation has since moved the pin forward on its own, so that commit was dropped in the rebase —246d1c8is a verified descendant of the old pin, not a divergence.Details worth knowing
.gitmodulesmoves to the https URL: CI's checkout has no deploy key, and kartuli-ena is public.fetch-depth: 0becausecreated-modified-datefalls back to git for dates; a shallow clone would stamp every page with the clone time.cancel-in-progress: false, also Forgejo's advice for deployments). Cancelling mid-rsync can leave the web root half-updated, and the argument for cancelling does not survive the measured rate: 11 vault commits over 4 active days in five months.-pand with--delay-updates. rrsync's allowlist has no--chmod(it dies with "option not allowed"), and preserving the runner's modes would make the site's readability a function of the runner's umask; without-p, nas applies its own.--delay-updatesis in the allowlist and stages changed files so a job that dies mid-transfer does not tear the tree.Depends on
nix-config #25 (merged) and #27 — the
kvartsi-deploylogin, andNAS_DEPLOY_KEYprovisioned without a trailing newline. Both are deployed to nas already.f18340af33to8d7bd25a67@ -0,0 +88,4 @@-e "ssh -i $ssh_dir/id -o IdentitiesOnly=yes \-o UserKnownHostsFile=$ssh_dir/known_hosts \-o StrictHostKeyChecking=yes -o CheckHostIP=no" \public/ kvartsi-deploy@nas:/Why is this
public/ kvartsi-deploy@nas:/instead ofpublic/ kvartsi-deploy@nas:/var/www/kvartsi?Because rrsync is the chroot. The forced command on nas is
rrsync -wo /var/www/kvartsi, and rrsync rewrites every path argument to sit under that root before handing them to the real rsync. So the path the client sends is already relative to the web root, and/means the root of the confined subtree — not the filesystem root.Spelling out the full path would double it. Verified against the real
rrsyncbinary with the same flags the workflow uses, by standing in for nas's sshd and feeding it the sameSSH_ORIGINAL_COMMAND:public/ …@nas:/— works, file lands in the web root:public/ …@nas:/var/www/kvartsi— fails:That is rrsync resolving the request to
/var/www/kvartsi/var/www/kvartsi.It reads oddly, which is fair — the bare
/looks alarming until you know the forced command is doing the confinement. There is a comment on the rsync invocation saying so ("rrsync roots the destination at /var/www/kvartsi, hence the bare/"), but it sits above the flags rather than next to the destination. Happy to move it onto that line if you would rather it be impossible to miss.