Commit Graph

160 Commits

Author SHA1 Message Date
pulse-triage[bot] 6b5369bbfa Align TrueNAS guidance with JSON-RPC runtime
Change-source: pulse-maintainer
2026-09-01 18:32:39 +01:00
pulse-triage[bot] de41ea1883 Preserve workflow taint across branches
Change-source: pulse-maintainer
2026-09-01 17:34:30 +01:00
pulse-triage[bot] 7fd93457f1 Harden workflow alias taint tracking
Change-source: pulse-maintainer
2026-09-01 16:58:55 +01:00
pulse-triage[bot] 4f7a3d0006 Close runner output alias bypasses
Change-source: pulse-maintainer
2026-09-01 16:54:07 +01:00
pulse-triage[bot] c55db584c1 Harden GitHub command file data boundaries
Change-source: pulse-maintainer
2026-09-01 16:32:15 +01:00
pulse-triage[bot] 97a39e8819 Block dispatch payload shell injection
Change-source: pulse-maintainer
2026-09-01 14:35:07 +01:00
rcourtman d28666c396 Guard shipped docs mirror sync at commit time
Docs under frontend-modern/public/docs are byte-for-byte copies of repo
docs, but the only guard was a CI vitest the git hooks never run. On
2026-09-01 two commits (f4886c2dfb, f313882a7b) each edited a mirrored
doc without its copy, passed the hooks, and broke main's Frontend job.

Add scripts/check_docs_mirror.py with an index-blob --staged mode wired
into the pre-commit hook: a commit that stages either side of an
out-of-sync pair (or an orphan shipped copy) fails with the exact sync
command, while pre-existing drift from other commits only warns. The
worktree mode runs as a named step in the public-docs workflow, with
unit tests in scripts/tests picked up by the existing runner. The
docsLinks vitest stays as the CI backstop.

Build-time generation of public/docs was considered and rejected: the
shipped set is a curated subset (61 of 421 docs), so generation still
needs a hand-maintained manifest while adding build, dev-server, and
test-order coupling.
2026-09-01 11:16:05 +01:00
pulse-triage[bot] f7d7e7af8c Clarify external watchdog direction
Change-source: pulse-maintainer
2026-09-01 11:00:03 +01:00
pulse-triage[bot] faf69f76e6 Keep workflow outputs out of generated shell
Change-source: pulse-maintainer
2026-09-01 10:16:41 +01:00
rcourtman cbd95d0141 Make Go module security floors real floor checks
The dependency-floor smoke test asserted exact go list output, so the
maintainer lane's legitimate x/crypto v0.55.0 bump (which moved x/net to
v0.57.0) failed the Script smoke tests job on main even though both
versions clear the advisory floor. Compare versions with sort -V against
the advisory-safe minimum instead: upgrades pass, only a downgrade below
the floor fails. Verified the failing direction and the equal-version
case locally.
2026-09-01 09:54:59 +01:00
pulse-triage[bot] 0f7a8683c2 Block privileged workflow code ingress
Change-source: pulse-maintainer
2026-08-31 18:21:45 +01:00
pulse-triage[bot] 8f877bee14 Bind privileged workflow runs to canonical code
Change-source: pulse-maintainer
2026-08-31 17:09:53 +01:00
pulse-triage[bot] 69cbe5f3b8 Enforce protected GitHub checkout baseline 2026-08-31 13:21:25 +01:00
pulse-triage[bot] 240adaa5e4 Authenticate every published installer 2026-08-31 04:55:15 +01:00
pulse-triage[bot] a190703fe5 Reject ambiguous release checksum manifests 2026-08-31 04:40:34 +01:00
pulse-triage[bot] fda955627f Bound GitHub Actions job runtimes 2026-08-31 02:00:09 +01:00
pulse-triage[bot] 47c1cee895 Enforce least-privilege job tokens 2026-08-30 22:11:40 +01:00
pulse-triage[bot] a0dfdadc5e Close workflow trust policy gaps 2026-08-30 15:06:00 +01:00
pulse-triage[bot] 21007a8662 Isolate private governance from pull requests 2026-08-30 15:02:41 +01:00
pulse-triage[bot] 2fca8c957b Authenticate published release sidecars 2026-08-30 09:38:23 +01:00
pulse-triage[bot] 0d32dac16e Keep release toolchains within support 2026-08-30 06:40:25 +01:00
pulse-triage[bot] d8986c139a Enforce workflow data trust boundaries
Contract-Neutral: Moves workflow expressions into environment data flow without changing deployment interfaces or behavior.
2026-08-30 04:56:34 +01:00
pulse-triage[bot] a2bfadba7b Enforce workflow execution trust boundaries 2026-08-30 04:44:25 +01:00
pulse-triage[bot] f9ffbf701a Strengthen dependency maintenance contracts 2026-08-30 04:05:02 +01:00
pulse-triage[bot] 560c2de026 Automate dependency trust maintenance 2026-08-30 04:02:27 +01:00
pulse-triage[bot] 718de25b2b Bind release activation to trusted provenance 2026-08-30 01:51:58 +01:00
Pulse Test 0df9747bd7 Add privacy-safe alert quality telemetry 2026-08-29 14:00:28 +01:00
Pulse Test b75a5aeec2 Add release service health telemetry 2026-08-29 11:24:53 +01:00
Pulse Test 473885e2ce Harden Patrol activation telemetry 2026-08-28 11:35:41 +01:00
pulse-triage[bot] 0ba57b5a68 Bound non-gating E2E probation failures 2026-08-28 04:26:34 +01:00
pulse-triage[bot] ec25ab4c13 fix(dev): preserve executable launchd wrapper mode 2026-08-27 17:54:10 +01:00
pulse-triage[bot] aa50087c08 security(build): advance release toolchain to Go 1.26.7
Use the current supported Go 1.26 security patch across source, release, dev, and production container build surfaces. Keep the immutable official builder pin and governance proofs aligned with the exact toolchain.

Change-source: pulse-maintainer
2026-08-27 05:04:03 +01:00
pulse-triage[bot] 5859f49817 security(build): upgrade release toolchain to Go 1.26.6
Advance local, release, and container build surfaces together so reachable standard-library advisories cannot re-enter shipped binaries. Pin the official amd64 builder manifest and govern the updated floor with installability and dev-runtime proofs.

Change-source: pulse-maintainer
2026-08-27 04:24:10 +01:00
rcourtman 420368e8e2 Allow standing triage disclosure link
Change-source: pulse-maintainer
2026-08-26 11:11:04 +01:00
rcourtman 095b012455 Align dev-runtime manifest smoke pin with the frontend-build-output policy
6417319b1 split frontend-modern/vite.config.ts out of the
dev-runtime-orchestration path policy into its own frontend-build-output
policy so production build output counts as proof. The
test-hot-dev-bg.sh manifest governance check still pinned the old
policy id, so the Script smoke tests job on main has failed since that
commit. Pin vite.config.ts to frontend-build-output; every other
manifest expectation is unchanged.

Reproduced the [FAIL] locally before the change; the full
test-hot-dev-bg.sh suite passes after it.
2026-08-24 11:29:57 +01:00
rcourtman 3bc613c915 Scale large-estate workload and Proxmox demo performance 2026-08-23 15:09:32 +01:00
rcourtman ae5df19b62 Give release backend tests hosted-runner headroom
The internal/api race suite now routinely exceeds the old 20-minute package timeout on hosted runners while passing. Set a governed 30-minute package timeout and 40-minute release job ceiling, pin the relationship with contract tests, and refresh the rc.4 packet with the fixes landed since preparation.
2026-08-21 08:49:05 +01:00
rcourtman 5bbee0da3d feat: scale the Proxmox demo estate 2026-08-19 16:28:07 +01:00
rcourtman 57e08985c3 fix telemetry release activity attribution 2026-08-19 15:47:53 +01:00
rcourtman 4e1d2f6d5d fix(telemetry): scale adoption reporting 2026-08-09 00:35:40 +01:00
rcourtman 79f3187d18 fix(ci): repair script smoke tests on main
Two failures landed this morning:

- test_gitleaks_ignore.py's historical-fingerprint resolution (added in
  d1fa7f38c) needs branch- and tag-reachable history, but the
  scripts-and-build job used a depth-1 checkout, so all 37 fingerprints
  failed to resolve in CI. Fetch full history like the gitleaks and
  changes jobs already do.

- d1f687c0e routed frontend-modern/package.json and package-lock.json to
  the new frontend-dependency-security path policy without updating the
  manifest expectations pinned in test-hot-dev-bg.sh. Pin the effective
  first-match policy per manifest instead of bare membership so the
  routing stays asserted and shadowed entries cannot fake coverage.

Contract-Neutral: CI-only fix: full-history checkout for gitleaks fingerprint resolution test and re-pin hot-dev manifest policy expectations to the registry routing d1f687c0e already established; no contract delta
2026-08-08 06:17:26 +01:00
rcourtman d1fa7f38c7 security: narrow historical secret scan allowlist 2026-08-08 03:17:57 +01:00
rcourtman c9e66b2295 release: pin code-signing policy link to the release tag
The docs link drift guard (test_repo_docs_link_drift.py) fails CI because
render_release_body.py links docs/CODE_SIGNING_POLICY.md at blob/main.
Release bodies must reference the docs snapshot of the release they
describe, so the installation section now links blob/v{version}, matching
how the rest of the body pins to the version being cut. The unit test pin
follows. Also skip .claude/ in the drift guard so local runs on a shared
tree are not polluted by stale agent worktrees under .claude/worktrees
that CI never checks out.
2026-08-07 01:13:56 +01:00
rcourtman 3a24d9694f Route mock toggle npm scripts through toggle-mock.sh
The mock:on and mock:off scripts used GNU 'sed -i' syntax, which fails on
the default macOS BSD sed. The '||' fallback then appended a fresh
PULSE_MOCK_MODE line on every invocation, so a local .env accumulated three
contradictory entries.

They also targeted the repo-root .env, which hot-dev.sh does not consult
when choosing the data directory. hot-dev.sh reads the canonical flag from
tmp/dev-config/.env, written authoritatively by toggle-mock.sh. The npm
wrappers were therefore a no-op that corrupted .env as a side effect, while
leaving the operator believing mock mode had switched.

Point them at toggle-mock.sh, which handles BSD sed, writes the canonical
file, syncs the runtime env and restarts the managed runtime. Add
mock:status and mock:edit; the hot-dev startup banner already advertised
'npm run mock:edit', which did not exist.

Extend the deployment-installability contract to cover the mock wrappers
alongside the existing repo-root dev entry rules, and add a regression test
asserting the wrappers delegate rather than rewriting the flag inline, and
that every mock command named in the hot-dev banner exists.
2026-08-04 00:30:28 +01:00
courtmanr@gmail.com 5c1c89a363 Guard auto-update asset staging and migrate stale update units
Adversarial review of 9db25ba60 found four residual defects in the
auto-update asset install, plus a doc line it left contradicting itself.

- install_auto_update_assets copied the bundled helper into the staged
  mktemp file with an unchecked cp, and both call sites invoke the
  function under `if !`, which suppresses errexit for its whole body. A
  failed copy (ENOSPC, EIO) fell through to
  configure_auto_update_script_repo, whose awk emits a lone GITHUB_REPO=
  line for empty input, so a shebang-less one-line stub replaced the
  working helper with a "script" that only ever exits 0 - silently
  disabling unattended updates. Check the cp, and refuse the swap unless
  the staged helper is non-empty and starts with #!.
- Both units were rendered with a bare truncating `cat > "$unit"` whose
  status was never checked, and the function's last statement is
  safe_systemctl daemon-reload, which returns 0 by design. A failing
  write truncated a working unit and still reported success. Render each
  unit to ${path}.tmp and commit it with a checked rename, so a failure
  leaves the installed unit byte-identical.
- The widened ReadWritePaths could not reach deployed boxes: the unit
  that grants the write access is itself the file that has to be
  rewritten, and on an existing install the sandbox running the
  installer excludes /etc/systemd/system and /usr/local/bin (EROFS). The
  Go update pipeline cannot carry it either - pulse.service runs as
  User=pulse with its own ProtectSystem=strict over the install and
  config dirs only. So probe each destination directory up front and,
  when one is blocked, re-exec this already-signature-verified installer
  through systemd-run with a new internal --repair-auto-update-units
  entry point: PID 1 forks the transient unit, so it starts in the host
  mount namespace instead of inheriting the sandbox. The installer is
  copied into the install dir first because the calling unit's
  PrivateTmp=yes hides its /tmp copy from PID 1. The escape needs root
  and systemd-run, and never recurses.
- Keep the ReadWritePaths entries as directory grants: every write now
  commits with a rename from a sibling staging file, and rename needs
  write access on the containing directory, so the file-level entries
  systemd would otherwise accept cannot work. Document the tradeoff in
  the unit and the subsystem contract instead.

The deployment-installability contract still claimed the update sandbox
leaves "only the install dir, config dir and /tmp" writable, which the
paragraph the same file gained in 9db25ba60 contradicts; the same stale
rationale had been copied into two test comments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 11:56:52 +01:00
courtmanr@gmail.com 0966ae9594 Measure verified telemetry outcomes 2026-07-27 10:15:48 +01:00
courtmanr@gmail.com 806cbe83dc Fix auto-update leaving service down after installer failure
Two bugs from #1630 that combined to take installs down silently:

1. perform_update()'s install-failed rollback branch restored the backup
   but never restarted pulse.service. Since the generated
   pulse-update.service gates on ExecCondition=systemctl is-active,
   every later timer run was then skipped and the install stayed down
   until manual intervention. Restart is now guaranteed by a
   service_was_active-guarded restart in that branch plus an
   ensure_service_restarted RETURN trap so no exit path can miss it
   (re-fix of #1323, originally c0b3a0e66, lost in 778a2577b and only
   partially restored in 672e81985).

2. install.sh aborted under errexit when writing the /bin/update helper
   on a read-only filesystem - after the new binary was installed and
   the service stopped, landing in bug 1's no-restart branch. The stock
   pulse-update.service uses ProtectSystem=strict, so /bin and
   /usr/local/bin are read-only on stock unattended updates; transient
   read-only remounts hit the same path. The helper write, PATH
   appends, and the /usr/local/bin/pulse symlink are now idempotent and
   non-fatal with a warning (install_binary_symlink).

Contract: deployment-installability now pins fail-closed service
availability for unattended updates and non-fatal writes outside the
hardened unit's writable set, with proofs in pulse_auto_update_test.go
and root_install_sh_test.go plus shell regression coverage in
scripts/tests/test-pulse-auto-update.sh (installer-exits-nonzero path)
and scripts/tests/test-install-update-resilience.sh (read-only helper
and symlink paths, verified under set -e, root-safe via ENOTDIR).

Fixes #1630

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 09:38:37 +01:00
rcourtman 3ad35750cb Optimize telemetry adoption reporting 2026-07-23 23:40:49 +01:00
rcourtman 0b6f7ad49a Fix notification delivery health reporting 2026-07-23 23:38:35 +01:00
rcourtman e1a05104d9 Fix remote telemetry adoption reports 2026-07-23 20:38:09 +01:00