feat: auto-deploy tagged releases to CT 126 via signed webhook (0.3.1)
CI's new deploy job (tags only) sends the house HMAC webhook to CT 126; the listener runs /usr/lib/devdesk/devdesk-deploy, which waits for the version in the apt registry and upgrades devdesk with --force-confold. Running sessions are untouched. Hook setup is documented in docs/DEPLOY.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -149,10 +149,32 @@ jobs:
|
||||
"$api/releases/$id/assets?name=$name" >/dev/null
|
||||
echo "release $TAG: $GITEA_URL/$REPO/releases/tag/$TAG"
|
||||
|
||||
deploy:
|
||||
name: Deploy to CT 126
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
# CT 126's webhook listener runs /usr/lib/devdesk/devdesk-deploy, which
|
||||
# waits for this version in the apt registry and upgrades the package.
|
||||
- name: Trigger devdesk-deploy webhook
|
||||
env:
|
||||
WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }}
|
||||
GIT_REF: ${{ github.ref }}
|
||||
run: |
|
||||
PAYLOAD="{\"ref\":\"${GIT_REF}\"}"
|
||||
SIG=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
|
||||
curl -sf --connect-timeout 10 \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Gitea-Signature: ${SIG}" \
|
||||
-d "$PAYLOAD" \
|
||||
"http://10.10.10.58:9000/hooks/devdesk-deploy"
|
||||
|
||||
notify-failure:
|
||||
name: Notify on failure
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
needs: [build, deploy]
|
||||
if: failure() && github.event_name == 'push'
|
||||
steps:
|
||||
- name: Send Matrix alert
|
||||
|
||||
@@ -39,7 +39,8 @@ install: all
|
||||
install -m 0755 bin/devdesk $(DESTDIR)$(PREFIX)/bin/devdesk
|
||||
install -m 0644 libexec/devdesk-lib.sh $(DESTDIR)$(LIBDIR)/devdesk-lib.sh
|
||||
install -m 0755 libexec/devdesk-picker libexec/devdesk-claude-run libexec/devdesk-session-hook \
|
||||
libexec/devdesk-tmux-ready libexec/devdesk-serve libexec/devdesk-statusline $(DESTDIR)$(LIBDIR)/
|
||||
libexec/devdesk-tmux-ready libexec/devdesk-serve libexec/devdesk-statusline \
|
||||
libexec/devdesk-deploy $(DESTDIR)$(LIBDIR)/
|
||||
install -m 0755 build/ttyd $(DESTDIR)$(LIBDIR)/bin/ttyd
|
||||
install -m 0644 dist/index.html share/tmux.conf share/claude-settings.json $(DESTDIR)$(SHAREDIR)/
|
||||
install -m 0644 etc/env $(DESTDIR)$(SYSCONFDIR)/devdesk/env
|
||||
|
||||
@@ -71,8 +71,8 @@ apt install ../devdesk_*_amd64.deb
|
||||
|
||||
CI (`.gitea/workflows/build-deb.yml`):
|
||||
- Every push lints, tests, builds and smoke-tests the package and uploads it as an artifact.
|
||||
- A `v*` tag also publishes to `https://code.lotusguild.org/api/packages/LotusGuild/debian` and creates a release.
|
||||
- A `v*` tag also publishes to `https://code.lotusguild.org/api/packages/LotusGuild/debian`, creates a release, and auto-deploys to CT 126. A signed webhook runs `devdesk-deploy`, which upgrades the package; see [docs/DEPLOY.md](docs/DEPLOY.md).
|
||||
|
||||
## Roadmap
|
||||
- **v1.1:** `devdesk-api` sidecar for the Repo/CI panel, Matrix notifications when you're away, and auto-deploy.
|
||||
- **Next:** Matrix notifications when you're away (needs the Ci-Alert hookshot URL).
|
||||
- **v2:** Ops Alerts (Grafana) with "Ask Claude" prompts, and file drop.
|
||||
|
||||
Vendored
+8
@@ -1,3 +1,11 @@
|
||||
devdesk (0.3.1) bookworm; urgency=medium
|
||||
|
||||
* Auto-deploy: tagged releases trigger CT 126's webhook listener (house HMAC
|
||||
pattern), which runs /usr/lib/devdesk/devdesk-deploy to upgrade the
|
||||
package from the apt registry. Running sessions are untouched.
|
||||
|
||||
-- Jared Vititoe <jjvititoe1@gmail.com> Wed, 07 Oct 2026 13:20:58 -0400
|
||||
|
||||
devdesk (0.3.0) bookworm; urgency=medium
|
||||
|
||||
* Repo / CI panel is live: branch, ahead/behind, uncommitted changes, the
|
||||
|
||||
+24
-1
@@ -36,7 +36,30 @@ Then run `authelia validate-config --config /etc/authelia/configuration.yml && s
|
||||
- **Cloudflare:** add a CNAME `dev` → apex, DNS-only (grey cloud).
|
||||
- **Pi-hole:** add `"10.10.10.27 dev.lotusguild.org"` to `dns.hosts` in `pve-infra/containers/163-pihole/etc/pihole/pihole.toml`. A push auto-deploys it, and LAN clients then reach NPM directly instead of hairpinning.
|
||||
|
||||
## 5. Optional hardening
|
||||
## 5. Auto-deploy on release
|
||||
A `v*` tag makes CI publish the package, then send a signed webhook (the house HMAC pattern) to CT 126's existing `webhook` listener on :9000. The listener runs `/usr/lib/devdesk/devdesk-deploy <ref>`, which waits for that version in the apt registry and upgrades only `devdesk` with `--force-confold`. Running Claude sessions are untouched. The log is `/var/log/devdesk-deploy.log`.
|
||||
|
||||
**Setup, done once:**
|
||||
1. Generate a secret.
|
||||
2. Add this hook to `/etc/webhook/hooks.json`, next to `126-config-deploy`. The file is local and untracked because it holds secrets.
|
||||
```json
|
||||
{
|
||||
"id": "devdesk-deploy",
|
||||
"execute-command": "/usr/lib/devdesk/devdesk-deploy",
|
||||
"command-working-directory": "/",
|
||||
"pass-arguments-to-command": [{"source": "payload", "name": "ref"}],
|
||||
"trigger-rule": {"and": [
|
||||
{"match": {"type": "payload-hash-sha256", "secret": "<WEBHOOK_SECRET>",
|
||||
"parameter": {"source": "header", "name": "X-Gitea-Signature"}}},
|
||||
{"match": {"type": "regex", "regex": "^refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"parameter": {"source": "payload", "name": "ref"}}}
|
||||
]}
|
||||
}
|
||||
```
|
||||
3. Run `systemctl restart webhook`.
|
||||
4. Store the same secret as the devdesk repo's Actions secret `WEBHOOK_SECRET`.
|
||||
|
||||
## 6. Optional hardening
|
||||
Enable the Proxmox firewall on CT 126 (`firewall=1` on net0) and allow tcp/7681 only from 10.10.10.27. The same rule suits code-server on :8680.
|
||||
|
||||
## Operations
|
||||
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# Upgrade DevDesk from the LotusGuild apt registry. Run by the host's webhook
|
||||
# listener (hook "devdesk-deploy") when CI publishes a v* tag; the tag's ref is
|
||||
# passed as $1. Safe for running sessions: package upgrades restart only
|
||||
# devdesk.service (ttyd), never devdesk-tmux.service where Claude lives.
|
||||
set -euo pipefail
|
||||
|
||||
LOG=${DEVDESK_DEPLOY_LOG:-/var/log/devdesk-deploy.log}
|
||||
SOURCES=${DEVDESK_APT_SOURCES:-sources.list.d/lotusguild.list}
|
||||
|
||||
log() {
|
||||
printf '%s %s\n' "$(date '+%F %T')" "$*" >>"$LOG"
|
||||
}
|
||||
|
||||
exec 9>/run/devdesk-deploy.lock
|
||||
flock -w 900 9 || {
|
||||
log "another deploy is still running; giving up"
|
||||
exit 1
|
||||
}
|
||||
|
||||
want=${1:-}
|
||||
want=${want#refs/tags/}
|
||||
want=${want#v}
|
||||
before=$(dpkg-query -W -f='${Version}' devdesk 2>/dev/null || echo none)
|
||||
log "=== deploy: installed $before, release ${want:-latest}"
|
||||
|
||||
refresh() {
|
||||
apt-get update -q -o Dir::Etc::sourcelist="$SOURCES" -o Dir::Etc::sourceparts=- \
|
||||
-o APT::Get::List-Cleanup=0 >>"$LOG" 2>&1
|
||||
}
|
||||
|
||||
# The registry can lag the release by a few seconds: wait for the tagged version.
|
||||
candidate=""
|
||||
for _ in $(seq 1 18); do
|
||||
refresh || true
|
||||
candidate=$(apt-cache policy devdesk | awk '/Candidate:/ {print $2}')
|
||||
if [ -z "$want" ] || [ "$candidate" = "$want" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
if [ -n "$want" ] && [ "$candidate" != "$want" ]; then
|
||||
log "registry still offers $candidate, not $want; giving up"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$candidate" = "$before" ]; then
|
||||
log "already at $before; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -q --only-upgrade \
|
||||
-o Dpkg::Options::=--force-confold devdesk </dev/null >>"$LOG" 2>&1
|
||||
log "devdesk $before -> $(dpkg-query -W -f='${Version}' devdesk)"
|
||||
Reference in New Issue
Block a user