Skip to content

still-to-try: read the Guests lines from the grant rows, not the chan… #310

still-to-try: read the Guests lines from the grant rows, not the chan…

still-to-try: read the Guests lines from the grant rows, not the chan… #310

Workflow file for this run

name: CI
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
schedule:
# Weekly rebuild so base-image security fixes are picked up even when no
# code changes; the digest pin on the server repo follows.
- cron: "50 17 * * 0" # Sun 17:50 UTC (Mon 03:50 AEST)
workflow_dispatch:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: "1.25.13"
cache-dependency-path: go.sum
- run: go vet ./...
- run: go test -race ./...
- run: CGO_ENABLED=0 go build ./...
- name: gofmt
run: test -z "$(gofmt -l .)"
- name: Vulnerability scan
# Pinned like everything else in this workflow (the one @latest would be
# the sole unpinned tool in the pipeline). The vuln DB itself is fetched
# fresh at run time regardless of the tool version.
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
govulncheck ./...
# Push a high-priority ntfy alert to the operator channel if anything above
# failed — most importantly a govulncheck finding on the weekly scheduled
# run, so a newly-disclosed vuln reaches the same place as the app's own
# operator alerts, independent of GitHub email settings. Soft-skips when the
# secret is unset (e.g. fork PRs, which can't read secrets anyway).
- name: Alert on failure (ntfy)
if: failure() && github.event_name != 'pull_request'
continue-on-error: true
env:
CI_NTFY_URL: ${{ secrets.CI_NTFY_URL }}
CI_NTFY_TOKEN: ${{ secrets.CI_NTFY_TOKEN }}
run: |
if [ -z "$CI_NTFY_URL" ]; then
echo "CI_NTFY_URL not set; skipping failure alert."
exit 0
fi
curl -fsS -X POST \
-H "Authorization: Bearer $CI_NTFY_TOKEN" \
-H "Title: pstonn CI failed (${{ github.ref_name }})" \
-H "Priority: high" \
-H "Tags: rotating_light" \
-d "A pstonn CI run failed: vet / race tests / build / gofmt / govulncheck. Commit ${{ github.sha }}. Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
"$CI_NTFY_URL" || echo "ntfy alert send failed"
publish:
# Build and push the image on pushes to main and on version tags.
needs: test
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
- uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
with:
images: ghcr.io/${{ github.repository_owner }}/pstonn
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha
type=ref,event=tag
# Build once and LOAD into the runner's docker: the image must boot and
# serve /healthz before anything is pushed (unit tests can pass while
# the packaged image is broken).
- name: Build image (load for smoke test)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
load: true
tags: pstonn:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Smoke test (image boots and serves /healthz)
run: |
set -e
docker run -d --name pstonn-smoke -p 8899:8080 \
-e DATA_ENCRYPTION_KEY=$(openssl rand -hex 32) \
-e DOMAIN=example.com \
pstonn:ci
code=000
for i in $(seq 1 40); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8899/healthz || true)
[ "$code" = "200" ] && break
sleep 1
done
echo "GET /healthz -> $code (after ${i}s)"
docker logs pstonn-smoke || true
docker rm -f pstonn-smoke >/dev/null 2>&1 || true
if [ "$code" != "200" ]; then
echo "::error::boot smoke failed: image does not serve /healthz"
exit 1
fi
- uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Ping the self-hosted Renovate runner for an IMMEDIATE first-party digest
# pass, so a new image deploys in minutes instead of waiting for the daily
# cron. Renovate opens + auto-merges the pin bump in markbot-server, which
# fires the ntfy deploy trigger. Soft-skips if the token isn't configured.
# The payload names the owner/repo that needs the pass so the runner only
# spins up that one matrix job scoped to that one repo (~2 billed minutes
# instead of ~10 for a full-fleet pass).
- name: Ping Renovate for an immediate digest bump
if: github.ref == 'refs/heads/main'
env:
GH_TOKEN: ${{ secrets.RENOVATE_DISPATCH_TOKEN }}
run: |
if [ -z "$GH_TOKEN" ]; then
echo "RENOVATE_DISPATCH_TOKEN not set; skipping (the cron still covers it)."
exit 0
fi
gh api repos/uppertoe/renovate-runner/dispatches \
-f event_type=renovate \
-f 'client_payload[owner]=uppertoe' \
-f 'client_payload[repository]=uppertoe/markbot-server'
echo "Pinged renovate-runner for an immediate first-party digest pass."