Pulse/.github/workflows
rcourtman 54a6118d17 Fix CI false positives in the canonical completion guard
The guard judged substantive contract updates by diffing HEAD against
the index. In CI nothing is staged, the index equals HEAD, so every
contract file piped in via --files-from-stdin looked unchanged and the
guard blocked compliant pushes. Concretely, run 28944317805 blocked
7645965af even though its deployment-installability.md addition sits
inside the Current State section.

The guard now accepts --diff-base <ref> (requires --files-from-stdin),
resolves it to its merge base with HEAD so the comparison anchor
matches the three-dot changed-file list, and compares base vs HEAD
contract texts in that mode. Pre-commit keeps the index comparison.
The canonical-governance workflow passes the push or PR range base.
2026-07-08 14:35:07 +01:00
..
backfill-release-assets.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
build-and-test.yml Bound Go benchmark release gate 2026-06-14 20:47:23 +01:00
canonical-governance.yml Fix CI false positives in the canonical completion guard 2026-07-08 14:35:07 +01:00
close-needs-retest-timeout.yml Pin workflow actions and CI image versions 2026-04-22 10:12:15 +01:00
create-release.yml Add mobile impact gate to release dispatch 2026-07-07 18:21:20 +01:00
deploy-demo-server.yml ci: join tailnet via OAuth client instead of static TS_AUTHKEY 2026-07-08 14:28:51 +01:00
eval-model-matrix.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
helm-ci.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
helm-pages.yml Ensure Helm Pages publishes release chart 2026-07-07 19:21:48 +01:00
install-sh-smoke.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
issue-version-label-sync.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
issue-version-retest-comment.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
promote-floating-tags.yml Allow stable patch artifact publishing 2026-07-04 20:49:47 +01:00
publish-docker.yml Allow stable patch artifact publishing 2026-07-04 20:49:47 +01:00
publish-helm-chart.yml Verify public Helm chart publication 2026-07-05 09:40:20 +01:00
README.md ci: join tailnet via OAuth client instead of static TS_AUTHKEY 2026-07-08 14:28:51 +01:00
release-dry-run.yml Derive the rollback target for scheduled release rehearsals 2026-07-08 13:52:48 +01:00
repo-boundary-audit.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00
test-e2e.yml Queue superseded e2e runs instead of cancelling in-progress ones 2026-07-08 08:29:08 +01:00
update-demo-server.yml ci: join tailnet via OAuth client instead of static TS_AUTHKEY 2026-07-08 14:28:51 +01:00
validate-release-assets.yml Refresh workflow action pins 2026-06-14 19:26:21 +01:00

GitHub Actions Workflows

Issue Triage Automation

Files:

  • issue-version-label-sync.yml
  • issue-version-retest-comment.yml

Issue intake is split deliberately:

  • issue-version-label-sync.yml is the silent metadata path. It runs on opened, edited, and reopened issue events so version labels, needs-version-info, and needs-retest-on-latest stay correct when maintainers tidy issue metadata.
  • issue-version-retest-comment.yml is the public guidance path. It only runs on opened and reopened, and only posts reporter-facing retest guidance when the issue is an older-version bug report from a non-maintainer.
  • Both workflows load the shared helper at .github/scripts/issue-version-triage.cjs so parsing and classification logic lives in one place instead of drifting across duplicated inline scripts.

Update Demo Server

File: update-demo-server.yml

Automatically updates the governed demo target after a release is published. Stable releases update the public demo. Prerelease tags no longer update a separate v6 preview demo after GA.

Configuration Required

Create one GitHub Environment:

  1. demo-stable

The environment must define the secret names used by the governed demo target.

Required environment secrets:

  1. DEMO_SERVER_SSH_KEY

    • The private SSH key for accessing the demo server
    • Generate with: cat ~/.ssh/id_ed25519 (or your key file)
    • Should be the full private key including -----BEGIN and -----END lines
  2. DEMO_SERVER_HOST

    • The hostname or IP of the demo server
  3. DEMO_SERVER_USER

    • The SSH username for the demo server (e.g. root or a deploy user with sudo access)

Required shared secret:

  1. TS_OAUTH_CLIENT_ID and TS_OAUTH_SECRET
    • Tailscale OAuth client (business tailnet tawny-powan.ts.net, scope Auth Keys write, tag tag:infra) used by the governed demo deploy/update workflows before SSH
    • The action mints an ephemeral, pre-authorized, tagged node key per run, so runners join and garbage-collect themselves; unlike the retired static TS_AUTHKEY, the OAuth secret does not expire every 90 days
    • Allows GitHub-hosted runners to reach private demo targets such as the stable pulse-relay Tailscale host
    • May be stored as repository secrets or repeated in the selected environment if desired

Required environment variables:

  1. DEMO_EXPECTED_HOSTNAME

    • The remote hostname value the stable demo environment is expected to report
    • Stable example: pulse-relay
    • This is a host-identity guard: the workflow fails closed if the SSH secret points at the wrong machine
  2. DEMO_LOCAL_BASE_URL

    • Local URL used on the target host for version and mock-mode verification
    • Example stable value: http://localhost:7655
  3. DEMO_PUBLIC_HEALTH_URL

    • Public health endpoint for the stable demo target
    • Example stable value: https://demo.pulserelay.pro/api/health

Optional environment variables:

  1. DEMO_SERVICE_NAME

    • Stable default: pulse
    • When set, the server installer derives the instance-specific install dir, config dir, update helper, and update timer from this service identity.
  2. DEMO_AUTH_USER / DEMO_AUTH_PASS

    • Demo credentials used for post-update mock verification
    • Defaults to demo / demo when omitted

How It Works

  1. Trigger: Runs automatically when a GitHub release is published
  2. Target selection: Stable tags deploy to demo-stable; prerelease tags are skipped because the public v6 preview target is retired after GA
  3. Service identity: Stable runs default to the pulse service identity
  4. Governance check: Validates the selected tag is reachable from the governed release branch for that version
  5. Latest check: Refuses to update the public demo unless the published tag is the latest stable release
  6. Network attach: Joins Tailscale before any SSH step so governed demo targets can stay on private hostnames or Tailscale IPs
  7. Update: SSHs to the selected demo host and runs the tag-matched root installer from that exact git tag
  8. Host identity check: Verifies the SSH target reports the governed expected hostname before running installer or deploy steps
  9. Verify: Checks that the new version is running, mock mode is active, and the public demo HTML serves the same frontend entry asset as the target service
  10. Browser smoke: Uses the governed Playwright helper to prove the public demo still renders the login shell in a real browser
  11. Cleanup: Removes SSH key from runner

Testing

To test without publishing a release:

  1. Go to Actions tab in GitHub
  2. Select Update Demo Server workflow
  3. Provide a stable tag and choose stable or auto

Benefits

  • The public demo follows the stable v6 release line after GA
  • Prereleases no longer require a second public v6 preview surface
  • Validates the real server installer path on the selected target
  • Removes release-operator guesswork about which demo should move

Deploy Demo Server

File: deploy-demo-server.yml

Manually deploys the current branch build to the stable demo environment without changing the governed release workflow.

  • Uses the same demo-stable environment contract as the release-driven updater
  • Joins Tailscale before SSH so governed demo targets can stay on private addresses instead of requiring public runner reachability
  • Requires DEMO_EXPECTED_HOSTNAME, DEMO_LOCAL_BASE_URL, and DEMO_PUBLIC_HEALTH_URL
  • Supports optional DEMO_SERVICE_NAME, DEMO_INSTALL_DIR, DEMO_TEST_PORT, DEMO_AUTH_USER, and DEMO_AUTH_PASS
  • Assumes the target service and install directory already exist on the host
  • Verifies the SSH target reports the governed expected hostname before deploy
  • Verifies that the public demo shell serves the same frontend entry asset that was built and deployed
  • Uses scripts/run_demo_public_browser_smoke.sh to prove the public demo still renders the login shell in Chromium after deploy/update verification

Helm CI

File: helm-ci.yml

Runs helm lint --strict and renders the chart with common configuration combinations on every pull request that touches Helm content (and on pushes to main). This prevents regressions before they land.

  • Triggered by PRs/pushes touching deploy/helm/**, docs, or the workflow itself
  • Uses Helm v3.15.2
  • Renders both the default deployment and an agent-enabled configuration to catch template issues

Publish Helm Chart

File: publish-helm-chart.yml

Packages the Helm chart and pushes it to the GitHub Container Registry (OCI) whenever a GitHub Release is published. Also makes the packaged .tgz available as both an Actions artifact and a release asset. The same behaviour can be triggered locally via ./scripts/package-helm-chart.sh <version> [--push].

  • Triggered automatically on release: published, or manually via workflow dispatch (requires chart_version input)
  • Chart and app versions mirror the Pulse release tag (e.g., v4.24.04.24.0)
  • Publishes to oci://ghcr.io/<owner>/pulse-chart
  • Verifies the pushed OCI chart can be read from GHCR without registry credentials
  • Requires no additional secrets—uses the built-in GITHUB_TOKEN with packages: write permission