Commit Graph

253 Commits

Author SHA1 Message Date
pulse-triage[bot] 123652e29b Preserve reviewed monitoring repairs with upstream Discovery removal
Compose current main e2f4bdff03 additively. Retain both subsystem records and the held change-age control while withdrawing only the obsolete Discovery identification test. Reviewed identities and ancestry, canonical guest History ownership and upstream feature removal remain intact.

Change-source: pulse-maintainer
2026-10-12 10:04:58 +01:00
pulse-triage[bot] cd2d2abf33 Synchronise the identity regression HTTP receipts
Give the server-handler captures and test assertions an explicit happens-before boundary so the new enrolment/report regression is safe under the race detector.

Change-source: pulse-maintainer
2026-10-12 01:45:52 +01:00
pulse-triage[bot] abacf3b482 Prefer Linux distribution metadata over package heuristics
Fix #2854 by reading the ordinary Linux os-release ID after appliance detection. Preserve the collector’s more precise version, machine identity, enrolment/report agreement and non-Linux fallback. Exercise malformed and unavailable metadata, all existing appliance priorities and trusted synthetic enrolment/reporting.

Contract-Neutral: Correct existing OS identity values without changing report schemas, public interfaces, credential handling or lifecycle authority.
Change-source: pulse-maintainer
2026-10-12 01:39:26 +01:00
rcourtman 39f988b220 Remove AI Discovery
AI Discovery ran a separate model-backed service scanner beside Patrol
and the Assistant: its own store, scheduler, model route, API, tool and
drawer UI. No telemetry counter ever measured its use (the telemetry
discovery_enabled flag OR'd it with network subnet discovery), the
maintainer judged it a flop, and the context it produced is already
available to the models through pulse_query, pulse_read and the
unified-resource context sections.

This deletes internal/servicediscovery, internal/ai/infradiscovery, the
pulse_discovery tool, the /api/discovery routes, the mock Discovery
fixtures, the Discovery tabs in the resource, guest, node and Docker host
drawers, the identified-service cards, readiness badges, provenance
markers, suggested web-interface URLs, the Workloads AI Context column,
the chat "Discovery is off" hint and the AI Service Context settings page.
The old settings route redirects to Assistant settings. The model-bound
sanitizer allow-list existed only to pass Discovery context through, so it
goes too, along with the CopyableCodeRow primitive that only the
Discovery tab used.

Network subnet discovery (/api/discover, the Infrastructure discovery
settings) and the discoveryTarget agent coordinates are separate features
and stay. Stored discovery_enabled, discovery_interval_hours and
discovery_model AI settings are ignored on load; the settings API decoder
is lenient, so older frontends saving those fields still succeed.
2026-10-11 22:20:25 +01:00
pulse-triage[bot] 8d6037bb66 Use the host module's actual configuration in recovery controls
EnableHost belongs to the unified CLI, not hostagent.Config. Keep this host-module fixture enabled by exercising its ordinary delivery path and assert the unchanged agent identity and command ceiling directly. The diagnostic messages and reporting behavior are unchanged.

Change-source: pulse-maintainer
2026-10-11 19:45:21 +01:00
pulse-triage[bot] ef37ea7a1b Keep reporting authentication errors factual and credential-safe
A host-report 401 cannot diagnose lost upgrade credentials, and a 403 does not require disabling host monitoring or granting command execution. Direct operators to the existing instance, record and access policy instead of another installation. Preserve rejection buffers, throttles, identities and monitoring-only ceilings; prove ordinary same-credential recovery for primary and observer reporting. This diagnostic repair does not establish Discussion #2769's cause or native recovery.

Change-source: pulse-maintainer
2026-10-11 19:41:58 +01:00
pulse-triage[bot] 5d8ea82da8 Keep ICMP permission diagnostics scoped to the observation host
Replace unsupported server-unit, reinstall and capability replacement advice with the existing Configuration guidance. Keep the full safety message inside agent report limits, and exercise synthetic ping errors, success, cancellation, public entry points and the remote-agent queue.

Contract-Neutral: Correct ICMP diagnostic advice only; probe matching, execution, outcomes, deadlines, report limits and privilege policy are unchanged.
Change-source: pulse-maintainer
2026-10-10 06:38:09 +01:00
pulse-triage[bot] e1bba156e3 Inspect LXC init before wide cgroup siblings exhaust discovery
Prioritise the payload and init scope within the existing directory and PID read budgets rather than rejecting the whole tree while queuing unrelated siblings. Retain unknown/degraded fallback, exact init identity and PrivateNetwork; prove complete measured socket-free collection with 256 sibling workloads plus boundary, cancellation and identity controls.

Change-source: pulse-maintainer
2026-10-06 13:57:13 +01:00
pulse-triage[bot] b4e4b6a827 Import strconv for the LXC boundary fixture
Complete the test fixture compilation before exact-source validation; runtime files are unchanged.

Contract-Neutral: Test-only import completion; no runtime or contract delta.
Change-source: pulse-maintainer
2026-10-06 13:16:20 +01:00
pulse-triage[bot] d0a1424c34 Keep socket-free LXC discovery truthful at its inventory limit
Inspect the remaining bounded config listing after finding 128 running guests. A 129th running guest or an unestablished later guest must fall back and remain degraded if pct cannot establish a complete list, rather than silently erase guests behind a complete status. Retain the existing PrivateNetwork and probe bounds, with 127/128/129 and stopped/unknown-tail provider regressions.

Change-source: pulse-maintainer
2026-10-06 13:15:44 +01:00
pulse-triage[bot] 123f66aee5 Synchronise guest cancellation proof with a portable child handoff
A deadline started before admission can exercise the wrong safety phase on Windows. Cancel only after a controlled child acknowledges it started, retain the uncertainty/no-retry/cooldown/resumption assertions, and separately prove cancellation before admission dispatches nothing. Use the same portable child for preflight and postflight outcomes.

Contract-Neutral: Test-only phase and portability correction; production guest execution and its safety contract are unchanged.
Change-source: pulse-maintainer
2026-10-06 13:13:51 +01:00
pulse-triage[bot] 3e88805623 Incorporate the batch-start upstream frontier
Preserve published helper filesystem collection and vSphere activity commits. Resolve mirrored helper capability documentation to the upstream implementation account and retain both parents\x27 independent helper regression tests. No frontend source resolution or receipt rebinding.

Change-source: pulse-maintainer
2026-10-06 12:16:57 +01:00
rcourtman 6b1fc6eaaf Collect LXC filesystems without pmxcfs or LXC socket IPC
The typed helper runs with PrivateNetwork=true. pct list, pct df and
lxc-info reach pmxcfs and the LXC monitor through abstract Unix
sockets, which belong to the network namespace, so inside the helper
they always fail. Least-privilege installs using the helper therefore
reported provider_unavailable for proxmox.lxc_filesystems on every
report and never got per-mount guest usage (#2511).

Discover running guests without commands: list /etc/pve/lxc through the
pmxcfs mount, find each guest's init in /sys/fs/cgroup/lxc/<vmid> (NSpid
exactly "<pid> 1", cgroup inside lxc/<vmid>), and name it by hostname or
CT<vmid> as pct list does. Discovery hands the whole node back to pct
whenever a guest's state cannot be established, so a guest it could not
read never disappears from a healthy-looking inventory.

Read usage through the shared filesystem prober instead of a second,
plain statfs path. It now accepts lxc requests: it pins the process,
requires the guest's exact cgroup and init (a nested namespace's PID 1
cannot stand in), skips declared mounts that are not mounted, and keeps
one bounded probe per guest. The helper's RestrictSUIDSGID makes
systemd answer openat2 with ENOSYS, so the prober falls back to a
component walk that refuses every symbolic link rather than resolving
it; Docker and Podman reads gain the same fallback.

Exercised on a disposable PVE 9.2.18 node under the helper unit's
sandbox properties: unprivileged and privileged guests matched pct df,
a stopped guest was omitted, and the prober's Linux tests passed as
root. A second opinion reviewed the design and the first draft; this
version addresses its findings.
2026-10-06 11:14:21 +01:00
rcourtman d52131e0d1 Close the harness command client before Windows removes its state dir
Since #2550, three command identity tests fail on Windows x64:
TempDir cleanup cannot delete operation-receipts.db because the agent's
command client still holds it open. Those tests never call run, so
nothing closes the client that New built, and Windows refuses to delete
an open file. Other platforms delete it anyway.

Stop and close the command client in a harness cleanup. It is
registered after the state TempDir, so it runs first, and Close is
idempotent for the tests that do run the agent. Production already
closes the client when Run exits or an identity supersedes it.
2026-10-06 10:21:05 +01:00
pulse-triage[bot] 8b0ed731da Close identity test clients before temporary state cleanup
Windows native verification at 9615e46d fails three command-channel tests only while removing an open receipt file. The shared fixture now invokes the existing command-client shutdown even when a test bypasses Agent.Run. A portable lifecycle regression checks staged and manually started clients, so Unix file deletion cannot hide missing teardown.

Contract-Neutral: Test fixture cleanup only; production command identity, admission and storage behaviour are unchanged.
Change-source: pulse-maintainer
2026-10-06 01:52:09 +01:00
pulse-triage[bot] 96abf2a9bc Incorporate batch-start upstream agent identity repair
Change-source: pulse-maintainer
2026-10-06 01:30:01 +01:00
rcourtman f77c8b2f3d Register agent command channels under the identity Pulse resolves
A token binds the first agent ID its command channel presents and never
moves. The agent registered that channel before its first report, under
its configured --agent-id, or an ID Pulse had forked for a cloned
machine ID or kept from an earlier enrollment. Pulse meanwhile resolved
its reports to another host ID and acknowledged it, and the agent
persisted that ID. The config gate, which judges the resolved ID, then
turned the operator's commands off, and the next restart under the
persisted ID was refused for good.

Report acknowledgements now name commandAgentId: the resolved host ID,
only when the token's binding already holds it or a registration
presenting it would take the first bind, backfill, legacy migration,
hostname rebind or deploy repair it would get anyway. The credential
must also be one command admission takes, and the host must be held
under the reporting token. Naming grants nothing that registration
would not. An established binding to another ID is never moved from
report contents, because resolution can map a report onto another
host's continuity record by machine ID, so a forged report and a stale
one look the same. The config gate takes the same decision.

The agent keeps its channel staged until a report is acknowledged and
registers under the named identity, or under its own ID when none is
named, which is what an older Pulse or an already-bound token sees.
An unreadable ack keeps it waiting, and a 403 releases it under its own
ID because Pulse can never answer that token. A running client is never
rebuilt, since that would reopen its receipt store under in-flight
operations. A superseded client can no longer take the run slot.

Tokens already bound to a diverged ID stay as they are; re-running the
install command issues a fresh token that binds the resolved identity.
2026-10-06 00:36:41 +01:00
pulse-triage[bot] 1f5e451578 Make cancellation receipt proof wait for an activated runner
Registration is visible before credential activation and the command reader. Wait for each new client’s actual activated health write and a receipt-query round trip, retaining three-second deadlines and exact durable replay assertions. A controlled failed-first activation proves that registered alone is insufficient. Install idempotent runner and dispatch cleanup before assertions so early failure cannot leave the fixture alive.

Contract-Neutral: Proof-fixture readiness and cleanup only; production admission, cancellation, receipt replay, timeouts and mutation authority are unchanged.
Change-source: pulse-maintainer
2026-10-05 23:08:55 +01:00
pulse-triage[bot] 63fcae0a3a Preserve partial PVE filesystem readings without widening helper access
Replace the rejected global host-network proposal with the unchanged private namespace on every platform, including native linux-386. Carry successful rows and omitted VMIDs through operation v2 without clearing degraded health or renewing omitted measurements; retain strict complete-only v1 compatibility. Restart the installer-owned helper only after isolated-unit and socket checks, and document the unresolved pmxcfs IPC limitation rather than claiming PVE recovery.

Change-source: pulse-maintainer
2026-10-05 18:22:01 +01:00
rcourtman 9d4ca81271 Exchange the bootstrap token before any agent module starts
A deployed agent's first run gave the remote config client, the updater, and
the Docker / Podman and Kubernetes modules the bootstrap token, which only the
host module exchanged. Pulse revokes that token on exchange, so those clients
failed with 401 until the service restarted. Enroll once at startup and build
every module from the runtime token and the server-assigned agent ID.
2026-10-05 16:01:15 +01:00
pulse-triage[bot] a2608c9fad Match guest Discovery integration proof to native platform capabilities
Native Windows and macOS correctly advertise no PVE guest guard, so their real-server fixture must assert refusal before any config or QGA handoff. Keep the existing Linux admission, outcome and resumption assertions and exercise foreign platform labels without changing runtime capability policy.

Contract-Neutral: Test-only platform evidence repair; guest execution and Discovery runtime contracts, capability advertisement and safety gates are unchanged.
Change-source: pulse-maintainer
2026-10-04 22:49:53 +01:00
pulse-triage[bot] d7ef00f2f2 Keep VM command and Discovery evidence truthful
Project verified guest status and decoded output instead of qm transport success. Reject ambiguous terminal outcomes without replay; retain known failed or truncated results as failures without inventing uncertainty. Admit only successful stdout to Discovery and preserve saved results when attempted probes yield no evidence. Keep backup precautions, source bounds and native acceptance dependencies unchanged.

Change-source: pulse-maintainer
2026-10-04 19:46:32 +01:00
pulse-triage[bot] 4188c2a9ba Reproduce false VM command and Discovery success
Add source controls for actual guest exit/output projection, ambiguous terminal receipts, failed probe evidence exclusion, and saved manual/background Discovery through explicit recovery. The fixtures never invoke PVE or QGA.

Contract-Neutral: Test-only regression controls exercise existing command and Discovery boundaries without changing production code, payloads, capabilities or budgets.
Change-source: pulse-maintainer
2026-10-04 19:35:32 +01:00
pulse-triage[bot] 419d80e2e4 Require terminal guest status before releasing VM execution admission
A zero qm CLI exit may return only a handed-off PID or an unverified guest result. Preserve actual CLI output/exit semantics but pause uncertain terminal dictionaries without another QGA command; accept complete canonical termination evidence and keep native thaw acceptance separate.

Change-source: pulse-maintainer
2026-10-04 18:20:25 +01:00
pulse-triage[bot] 2a734a5c53 Keep canceled VM lock evidence an explicit execution deferral
A cancellation before or during postflight config verification must not become an ordinary optional Discovery failure with usable output, especially on the final probe. Preserve fixed safety classification and no-handoff truth on canceled local admission.

Contract-Neutral: Completes the existing cancellation and unavailable-evidence requirements without changing protocol fields, guard version, lock/identity admission, time budgets or command catalogues.
Change-source: pulse-maintainer
2026-10-04 18:15:30 +01:00
pulse-triage[bot] d20b15b1e6 Complete Discovery compilation and accept canonical PVE config keys
The first exact proof established all ten parent no-admission failures and registered-session controls, then stopped on a missing strings import. Complete that import and preserve ordinary hyphenated PVE dictionary keys while keeping duplicate/case-conflicting lock rejection.

Contract-Neutral: Preserves the guest safety protocol and its lock, identity, budget and dispatch requirements; completes compilation and accepts canonical hyphenated config keys.
Change-source: pulse-maintainer
2026-10-04 18:05:57 +01:00
pulse-triage[bot] be319e8204 Guard VM Discovery and command execution at the owning host agent
Require local current-node lock evidence and registered guard support before QGA execution. Serialise VM probes, stop on deferral, retain actual in-flight outcomes and saved Discovery evidence, and pause uncertain completion without replay. Config checks do not reserve QGA or prove native thaw; the existing backup monitoring-outage precaution remains.

Change-source: pulse-maintainer
2026-10-04 17:59:09 +01:00
pulse-triage[bot] def087ed90 Reproduce unverified VM command admission at the host agent
Approvals and trusted Discovery commands currently cross QGA handoff without evidence of a local unlocked guest. Assert explicit no-handoff deferral without contacting a native target.

Change-source: pulse-maintainer
2026-10-04 17:41:40 +01:00
pulse-triage[bot] 14d3dc3b6c Fix MD RAID spare counts without hiding member failures
Retain configured RAID members separately from source-native totals through collection, reports and canonical read views. Correct the healthy legacy mdadm tuple from #2369 without subtracting spares from mdstat requirements or suppressing real deficits, failures and recovery warnings. Preserve observed zero-active counts through fallback, and verify collector, wire, ingestion, health and canonical activation/resolution boundaries.

Change-source: pulse-maintainer
2026-10-01 19:56:47 +01:00
pulse-triage[bot] 2fd114b3ac Keep Proxmox bootstrap credentials out of copied commands
Separate PVE/PBS setup and telemetry credentials from shell source and download URLs. Use silent root/sudo input, private-file handoff, complete downloads and the agent preflight; preserve scope, TLS defaults, single-line paste and coherent rolling-upgrade metadata. Reveal tokens through the existing dialog and discard late issuance after close. Pin executable shell, history, TLS/registration and browser contracts without using real credentials.

Change-source: pulse-maintainer
2026-10-01 05:23:08 +01:00
pulse-triage[bot] 60f455fd2a Read identified ARM CPU temperatures without lm-sensors
Fall back to bounded, type-checked thermal-zone and hwmon sysfs readings when lm-sensors is absent or empty. Classify Armada thermal JSON as a CPU reading, preserve nonempty sensor output, and cover units, invalid values, and the agent mapping.

Change-source: pulse-maintainer
2026-09-28 20:26:28 +01:00
courtmanr@gmail.com 9e2ee3d535 Fail typed dispatches fast when their agent session drops
The agentexec read loop removed a dead session from the agent map but never
closed its done channel, so any dispatch already sent on that session kept
waiting for a result that could never arrive and only returned at its
operation timeout. That's what made the Proxmox cancellation replay test
flaky on the shared CI runner. The restarted action runner dropped its first
session right after registering, the replay had already been sent there,
and the server waited the full 30s while the runner sat reconnected on a
new session.

The read loop now signals the session done on exit, so in-flight typed
dispatches and commands report the disconnect straight away. The
integration test sends the same request again on the runner's next
session when that happens, which is the same durable replay it is there
to prove, still with exactly one mutation. It also keeps the runner's log
and prints it on failure so the cause of any future drop is visible.
2026-09-28 10:31:58 +01:00
Jamin W. Collins 410134450d feat(agent): allow disabling Proxmox peer sensor collection 2026-09-23 08:18:44 -06:00
pulse-triage[bot] 92d6eae77f fix(hostagent): recover Windows host info when MachineGuid is braced
The Windows unified agent exits at startup when HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid is a braced GUID. gopsutil v4.26.6 reads the value through a fixed 74-byte buffer and rejects any length other than 36, so a braced 38-character GUID fails the whole InfoWithContext call and newAgent aborts with 'fetch host info'. Recover the host info on Windows when the host-ID read is the failing field: read MachineGuid directly, strip braces and fill the other fields from gopsutil accessors, while keeping any non-host-ID failure fatal. Canonicalise Windows machine IDs by removing braces so both forms map to one stable agent identity. Includes agent-lifecycle contract section and focused proof in the registry-accepted agent_new_test.go. Windows recovery is cross-compiled with GOOS=windows; runtime execution on Windows is not qualified in this environment.

Change-source: pulse-maintainer
2026-09-20 08:29:15 +01:00
pulse-triage[bot] c8cead7d5a fix(agents): preserve explicit disk includes at ingestion
Carry the operator include override in disk reports so server filtering does not discard selected tmpfs mounts again. Keep automatic filtering for unmarked reports and agent exclusion precedence. Cover both ingest paths, collection, forwarding and wire compatibility for #1875.

Change-source: pulse-maintainer
2026-09-09 11:35:51 +01:00
pulse-triage[bot] 3334cccfd9 fix(unraid): suppress parity warning for explicit pool-only arrays
Issue #1895 reports parity alerts when mdNumDisks=0 on a pool-only Unraid system. Array service state alone does not establish that a parity array exists.

Preserve the optional disk count from collection through canonical runtime conversion and suppress only the no-parity warning for an explicit zero. Missing or malformed counts retain legacy behaviour, and disk failure reasons remain active.

Validated focused Unraid tests in hostagent, storagehealth, monitoring, unifiedresources and alerts, including JSON zero preservation and canonical round trip. The new pool-only regression fails against the previous warning condition. Both agent and server need this change; no release or reporter retest is claimed.

Change-source: pulse-maintainer
2026-09-04 23:41:22 +01:00
pulse-triage[bot] 0f972f42f2 Isolate host and Docker CPU sampling baselines (#1894)
Near-synchronous host and Docker reports consumed a shared CPU baseline, measuring collection bursts rather than each module's reporting interval. Retain a collector per host collector and a separate Docker module collector while preserving the package-level convenience API and disk filters.

Add an interleaved-counter regression covering both collection entry points. It fails when routed through the shared baseline and passes with isolated state. All hostmetrics, hostagent and dockeragent tests pass, as do the focused CPU regression tests under the race detector.

Change-source: pulse-maintainer
2026-09-04 22:29:32 +01:00
pulse-triage[bot] ace72f8442 Ignore Unraid auto filesystem on empty slots
Treat Unraid's fsType=auto value as a placeholder rather than disk assignment evidence at both agent collection and server ingestion boundaries. Preserve real assigned and explicit missing members.

Change-source: pulse-maintainer
Contract-Neutral: Unraid fsType=auto placeholder normalization fixes false missing-slot alerts without changing wire or subsystem contracts
(cherry picked from commit fd843da7dfc51bba29bb5ddcbcdb4480d0e67079)
(cherry picked from commit 7a6456969d)
2026-09-02 05:40:46 +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 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 60d0651a88 Cancel abandoned typed agent operations 2026-09-01 11:21:26 +01:00
rcourtman 4e22a49f02 Add native PVE action qualification harness 2026-09-01 10:43:35 +01:00
rcourtman 01ff388c7e Preserve native Proxmox guest handoff 2026-09-01 09:31:40 +01:00
rcourtman 2ad094c927 Deflake typed action containment tests
The group-writable executable check wrote its fixture through os.WriteFile,
which filters the mode through the process umask, so under the runner's 022
umask the group-write bit never reached disk and validateTrustedExecutable
correctly trusted the file. Chmod the fixture to the asserted mode.

The Proxmox guest executor tests stamped their after observations one second
past the test-start clock, but actionStartedAt is stamped inside
ExecuteAction after handler setup, so a loaded runner overran the margin and
the independent observation was discarded as pre-action. Widen the
observation offset to a minute.

Both failures broke build-and-test on main (run 33454838531). Reproduced the
hostagent failure on Linux under umask 022 and verified both packages green
after the fix.
2026-09-01 06:15:46 +01:00
rcourtman f9ae289bd5 Contain typed action subprocesses with systemd 2026-09-01 01:26:39 +01:00
rcourtman f967857928 Harden secure agent recovery transports 2026-08-31 23:12:00 +01:00
rcourtman cf021bc9ce Surface typed helper container degradation 2026-08-31 15:53:50 +01:00
rcourtman d19398d82a Surface typed helper degradation in Agent Doctor 2026-08-31 13:06:28 +01:00
Richard Courtman 08f7c5f0d5 Harden secure agent runtime boundaries 2026-08-31 00:06:24 +01:00
Richard Courtman 770733fc92 Make action runner rotation activation-safe 2026-08-30 18:00:33 +01:00