Commit Graph

10235 Commits

Author SHA1 Message Date
rcourtman 0e6d99af65 Fix isolated rootful attester loading 2026-09-02 01:53:48 +01:00
rcourtman 5f0a487404 Merge pull request #1823 from rcourtman/pulse/secure-runtime-rootful-qualification
Add rootful runtime qualification packet
2026-09-02 01:48:16 +01:00
rcourtman 9e33945b55 Merge pull request #1833 from rcourtman/claude/assistant-bias-to-act-v2
Submit advertised lifecycle actions through pulse_control, not prose
2026-09-02 01:36:05 +01:00
rcourtman 7996848b64 Submit advertised lifecycle actions through pulse_control, not prose
A paying operator asked the Assistant to reboot five Proxmox VMs matching
a name pattern (GitHub #1782, support mail 2026-08-26 and 2026-08-29). The
model resolved the VMs and then ended with a report that invented a
prerequisite: a QEMU guest agent on 6.3.2, a "discovery binding" on stable
6.4.0. It never planned the action. Three defects made the governed path
fail whenever the model did try it, and nothing refused the prose ending
when it did not:

- pulse_control handed the session-scoped id (vm:<node>:<vmid>) to the
  action lifecycle, whose registry keys on canonical unified ids, so a
  Proxmox guest plan could never resolve.
- pulse_control gated the action on the legacy per-executor action list,
  which never carried the canonical "reboot" capability Proxmox guests
  advertise, so "reboot" was refused as not permitted before planning.
- A reference absent from the session context was refused with "resource
  discovery is required" even when the unified inventory resolved it.

pulse_control now binds its target to the canonical unified resource
(session alias first, then a unique inventory match, refusing ambiguity
with candidate ids and naming the pulse_query recovery on a miss), passes
the canonical id to the planner, and answers "not available" only from
the resource's current advertised capabilities. The FSM ordering block
and the shared operating instructions state that a recoverable block is
not a limitation to report, and the instructions require the governed
action tool for advertised capabilities. The agentic loop adds a bounded
advertised-action gate: when the operator asked for a lifecycle action,
pulse_control was offered but never submitted, and a session-resolved
resource advertises the action, a tool-free final answer is refused once
with the exact per-target calls.

Covered by tools and loop unit tests (the #1782 transcript against a
scripted provider fails on the previous code with the two exact errors
above), a prompt-contract test, and the live eval scenario
ProxmoxBulkLifecycleActionScenario.
2026-09-02 00:19:08 +01:00
rcourtman 14a7d0bdaf Merge action-runner replay and Windows portability fixes 2026-09-02 00:16:26 +01:00
rcourtman d3ea482827 Merge branch 'main' into pulse/secure-runtime-rootful-qualification 2026-09-02 00:14:50 +01:00
rcourtman 2de076a9bc Merge main into claude/hostagent-replay-reconnect-wait
Pick up the browserslist advisory fix (#1827) so the required Frontend
dependency audit can pass on this pull request.
2026-09-02 00:14:41 +01:00
rcourtman 62003caaea Merge pull request #1827 from rcourtman/pulse/fix-browserslist-audit
Raise browserslist above security advisory floor
2026-09-02 00:13:37 +01:00
rcourtman 73b3d8eff3 Complete rootful artifact source closure 2026-09-02 00:07:39 +01:00
rcourtman 500cc1bf17 Harden rootful qualification evidence boundary 2026-09-01 23:53:36 +01:00
rcourtman c022a0dfe6 Raise browserslist above security advisory floor 2026-09-01 23:33:55 +01:00
rcourtman b1044cd8a4 Let replayed request ids wait for the in-flight handler instead of dropping
Since 60d0651a88 every typed request registers a per-connection cancellable
slot that its handler goroutine releases in a deferred cleanup after sending
its result. The server replays a request id when it wants the durable receipt
again, and that replay can reach the reader before the previous handler's
deferred release runs. launchCancellableRequest treated that as a duplicate
and dropped it, so the server waited out the operation's full timeout for a
result the agent already held. The Linux x64 native-verification leg failed
this way on 12 of the last 25 main runs, always on a "replay 1" dispatch of
host update, storage cleanup, or Docker lifecycle.

Give each slot a done channel that closes on release. A replay whose id is
still registered on the same connection now waits for that release and then
runs, answering from the durable receipt. Invalid ids and over-capacity
requests are still dropped. A unit test pins the wait-then-run behaviour and
the agent-lifecycle contract records the replay rule.
2026-09-01 23:22:55 +01:00
rcourtman b763b80680 Build the FIFO lifecycle installer test only on unix
agent_state_dir_lifecycle_test.go calls syscall.Mkfifo, which does not
exist on Windows, so scripts/installtests has failed to compile in the
Windows leg of Unified Agent Native Verification since 53267e149d and the
install.ps1 contract tests there have not run. Every test in the file
drives install.sh through bash and systemd, so tag the file unix-only,
matching the other lifecycle lab files. GOOS=windows go vet now passes.
2026-09-01 23:05:22 +01:00
rcourtman e1e4c3e700 Wait for the server to observe runner disconnect before replay reconnect
The cancellation replay test stopped the first action runner and started a
second one as soon as the client goroutine exited. The server observes the
socket close on its own reader, so under GOMAXPROCS=1 with the race detector
the second startRunner saw the stale session as still connected and the
replay was dispatched to the dead socket, timing out after 30s on the
sharded release preflight while passing on multi-core hosts. Wait until the
server reports the agent disconnected before reconnecting, as the agentexec
server tests already do.
2026-09-01 22:51:56 +01:00
rcourtman 584cef81a1 Add rootful runtime qualification packet 2026-09-01 22:40:50 +01:00
rcourtman 813c2b6837 Match CI temp layout in the preflight worker and isolate agent helper tests
go test places t.TempDir under GOTMPDIR, and the preflight worker nested that
under its per-run directory, so unix socket fixtures in cmd/pulse-agent-helper,
internal/agenthelper, and internal/dockeragent exceeded the 108-byte sun_path
limit and failed with "bind: invalid argument". GitHub runners leave GOTMPDIR
unset, and the longest rootless Podman fixture sits exactly at the limit under
/tmp, so the worker now leaves GOTMPDIR unset by default and only honours an
explicit PULSE_RELEASE_PREFLIGHT_GO_TMP_DIR override.

Two cmd/pulse-agent helper tests ran without a state directory, so the agent
consulted the platform default /var/lib/pulse-agent. On a host where that
path exists as a private directory the pending-update handoff lookup fails
with permission denied. Give those tests an isolated state directory.
2026-09-01 22:35:55 +01:00
pulse-triage[bot] 020eb11edb Merge pull request #1821 from rcourtman/maintainer/20260901T212928Z
Keep release-candidate builds bound to the dispatched compiler run
2026-09-01 22:34:34 +01:00
pulse-triage[bot] 5fb7177b8a Require compiler dispatch run details
Change-source: pulse-maintainer
2026-09-01 22:26:46 +01:00
rcourtman 96a4dceb9d Pin umask 022 in installtests so trust fixtures are host-independent
install.sh refuses connection state, token, and lifecycle files whose
parent directory is group- or world-writable. The fixtures build those
parents with t.TempDir, which inherits the process umask, so on a worker
with umask 002 the state directory came out 775 and seven TestInstallSH
cases failed on the pulse-dev release preflight while passing on GitHub
runners and macOS. Set umask 022 for the package on unix so the tests
prove the installer contract rather than the host's umask.
2026-09-01 22:20:15 +01:00
pulse-triage[bot] 95b4eceaa0 Merge current origin/main before publication
Incorporate upstream rootless-runtime qualification evidence while preserving the reviewed maintenance batch and additive trust-gate correction.

Change-source: pulse-maintainer
2026-09-01 22:14:49 +01:00
pulse-triage[bot] 5b204cdc75 Close mirrored workflow scalar syntax gaps
Recognize bare sequence entries and every valid block scalar header across executable action inputs, run scripts, and step environment boundaries.

Change-source: pulse-maintainer
2026-09-01 22:13:37 +01:00
rcourtman 45dd45fe29 Record rootless runtime qualification evidence 2026-09-01 22:09:22 +01:00
pulse-triage[bot] 544b7fd575 Merge batch-start origin/main
Change-source: pulse-maintainer
2026-09-01 21:51:21 +01:00
pulse-triage[bot] f581f955e2 Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 21:40:47 +01:00
rcourtman 152ef86d33 Activate mise shims in the release preflight worker
The exact-SHA preflight streams the worker script over a non-login ssh
shell, so /etc/profile.d/mise.sh is never sourced and a stale system Node
binary on the worker shadows the infra-managed mise toolchain. pulse-dev
carried a manually installed Node 20 symlink in /usr/local/bin, so the
worker failed its Node 24 check while a login shell resolved 24.19.0.
Activate mise shims when mise is installed so the worker uses the same
toolchain the bootstrap provisions, regardless of how it is invoked.
2026-09-01 21:40:05 +01:00
rcourtman 62bfdbca7e Prepare v6.4.3-rc.1 release
Open the v6.4.3 candidate line from main. The v6.4.2 tag was staged on
2026-08-31 but never activated: its release run was cancelled after the
private Pro build failed the compiler memory gate, so the latest published
stable is still v6.4.1. This candidate carries the complete v6.4.2 change
set plus the corrections landed since that tag, including the stale PBS
Backup Running state (#1815), the Windows Unified Agent auto-update 404
(#1820), and shared-token same-hostname agent identity collapse (#1753).

Packet: VERSION, compose and install-docker defaults, Helm chart metadata,
release notes with a declined visual plan, changelog, pointer docs and
the shipped docs mirror, and the deployment-installability cutoff note.
Rollback target is v6.4.1 and the mobile decision is no-mobile-impact.

Tests: the packet tests now describe the 6.4.3 train, v6.4.2 is recorded
as an unpublished stable so it is never derived as the previous stable or
rollback target, and the Python v6.4.2 notes expectation matches the
phrase the notes actually use.
2026-09-01 21:37:41 +01:00
pulse-triage[bot] 22cc59cc2c Reject template injection in executable action inputs
Change-source: pulse-maintainer
2026-09-01 21:35:35 +01:00
pulse-triage[bot] 73bd27a0f5 Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 21:30:09 +01:00
rcourtman 60041ad9e6 Validate each rootless socket identity 2026-09-01 21:26:49 +01:00
pulse-triage[bot] a869475bf1 Reject flow-nested YAML trust aliases
Change-source: pulse-maintainer
2026-09-01 21:21:45 +01:00
pulse-triage[bot] 8cd5c2cae5 Reject hidden workflow trust structure
Change-source: pulse-maintainer
2026-09-01 21:18:26 +01:00
rcourtman b87ab75965 Limit planning status audit to tracked documents 2026-09-01 21:18:24 +01:00
rcourtman bc3dd3b704 Give rootless qualification hosts unique identities 2026-09-01 21:18:24 +01:00
pulse-triage[bot] 4fda8f146e Merge batch-start origin/main
Change-source: pulse-maintainer
2026-09-01 20:58:31 +01:00
rcourtman feff95934c Remove the Home tab and page, keep the fleet health verdict engine
The fleet health Home surface reached main on 2026-09-01 by implementing
a July agent-handoff spec with no demand-ledger entry. Exercised live on
the 1,510-resource mock estate it rendered 572 tiles on first paint with
275 in "Needs attention", 232 of them backup age, against two real
criticals; per-node storage mounts, disks, and swarm secrets appeared as
fleet members with no host context; and the critical node tile opened
its platform overview with the node below the fold. No stable release
carries it yet, so remove the route, navigation tab, page, i18n keys,
Assistant page context, route preload, and e2e cases now rather than
spend lane turns polishing an ungraded bet.

The server-side ResourceHealth verdict, its API projection, and the
/api/state/summary verdicts and attention extension stay: they are one
canonical health boundary that #1478 asked for and that any future
surface should read. The spec is parked with the 2026-09-01 review kept
as the design record.

Browser proof: desktop and 375px shells show no Home entry, /home renders
the not-found surface and its Go to workspace button lands on the
default workspace, the narrow More sheet lists Settings only, no console
errors or horizontal overflow.
2026-09-01 20:54:21 +01:00
rcourtman 2f8a4ec629 Require a Status line on planning documents
Any *_SPEC.md, *_PLAN.md, or *_CONTRACT.md under docs/ must now carry a
Status: line (or a ## Status section) in its header, enforced by the
pre-push lint. A spec, plan, or contract is a record of a decision, not
demand; the 2026-09-01 Home wall case showed what happens when a stale
handoff spec reads as a current signal. Subsystem contract markdown is
governed separately and is not scanned.

The commercial cancellation/reactivation e2e test plan gets the one
missing line so the existing set passes.
2026-09-01 20:52:25 +01:00
rcourtman f364cfc73b Reset Podman qualification storage on teardown 2026-09-01 20:49:43 +01:00
pulse-triage[bot] d81883da36 Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 20:48:30 +01:00
rcourtman 54cd77d3b1 Mark stale spec, plan, and contract docs with verified status
Repository specs, plans, and contracts are records of past decisions, not
demand. Each triaged document now carries a Status line that was checked
against the code and governance surfaces rather than against the document:

- VMware vCenter phase-1 onboarding, API runtime, resource projection, and
  alerts/assistant specs: IMPLEMENTED (shared floor shipped; live vCenter
  proof still outstanding).
- VMware execution plan and proof matrix: PARKED with a note that the
  first-lab-ready checkpoint was reached and the live proof has been
  blocked since 2026-03-30 with no ledger entry.
- Customer Account and Pulse Account portal specs: IMPLEMENTED at the L17
  RC floor; post-GA expansion is a lane follow-up, not a build signal.
- v6 bridge release foundation spec: SUPERSEDED by the resolved decision
  and lanes L18, L19, L20, and L22.
- Service assurance plan: slices A-E IMPLEMENTED, slices F-H PARKED.
- Availability history contract: IMPLEMENTED (history and fleet slices).
- Alert engine evolution: IMPLEMENTED; UI migration stays demand-gated.
- Legacy host classification audit: record; post-release queue PARKED.
- OIDC scope fix spec: closed record, fixes shipped in v6.0.4/v6.0.5.

Backup task timeline contract is left as ready for implementation because
its ledger entry is threshold-met. The HOME status wall spec, subsystem
contracts, and records are untouched.
2026-09-01 20:43:26 +01:00
rcourtman 832a4be9fd Record the 2026-09-01 Home wall review as binding spec revisions
Live exercise on the 1,510-resource mock estate showed the shipped Home
tab rendering 572 tiles on first paint with 275 in "Needs attention",
232 of them backup age, against two real criticals; per-node storage
mounts, disks, and swarm secrets rendered as fleet members with no host
context; and the critical node tile opened its platform overview with
the node below the fold. The implementation followed the July handoff
spec faithfully, so the fixes are recorded as spec revisions R1 to R6
(backup staleness out of attention, attention cap, fleet-member
granularity, host context, node deep links, plain-language reasons).

The default-route flip stays gated until R1 to R5 land and are
re-exercised in a browser. The spec now names its demand record in the
pulse-pro ledger and states that it is a decision record, not demand.
2026-09-01 20:35:47 +01:00
pulse-triage[bot] 6af9fd6105 Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 20:34:02 +01:00
rcourtman fec53eb39e Wait for rootless runtime mounts to release 2026-09-01 20:26:46 +01:00
pulse-triage[bot] 4651fae79e Make alert frequency periods accessible
Change-source: pulse-maintainer
2026-09-01 20:17:13 +01:00
pulse-triage[bot] 028ccbd35f Keep OIDC attestations on hosted runners
Change-source: pulse-maintainer
2026-09-01 20:17:13 +01:00
rcourtman 089ce2379d Clean runtime fixtures before qualification teardown 2026-09-01 20:13:15 +01:00
pulse-triage[bot] de6779de81 Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 20:06:09 +01:00
rcourtman 19f264701e Wait for stable rootless recovery evidence 2026-09-01 20:01:15 +01:00
pulse-triage[bot] 906b3dafee Merge remote-tracking branch 'origin/main'
Change-source: pulse-maintainer
2026-09-01 19:57:14 +01:00
rcourtman 861f0f07bc Persist rootless qualification receipts 2026-09-01 19:47:15 +01:00
pulse-triage[bot] c10e93943b Parse workflow job trust boundaries structurally
Change-source: pulse-maintainer
2026-09-01 19:46:57 +01:00