89 Commits

Author SHA1 Message Date
pulse-triage[bot] bdf84e8adc Stabilize agent module retry lifecycle tests
The Docker and Kubernetes retry tests used a whole-runtime timeout as both
their synchronization point and shutdown trigger. Under suite load, startup
could consume that deadline before the second module initialization, producing
a false failure unrelated to retry behavior.

Wait for the successful retry explicitly, then cancel and verify clean
shutdown so the tests measure the lifecycle contract deterministically.

Change-source: pulse-maintainer
2026-09-02 03:45:22 +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] 8ca87e60bf Fix Windows installer delivery privacy check
Change-source: pulse-maintainer
2026-09-01 19:01:55 +01:00
rcourtman 53267e149d Harden least-privilege installer lifecycle state 2026-09-01 15:53:02 +01:00
rcourtman cf021bc9ce Surface typed helper container degradation 2026-08-31 15:53:50 +01:00
pulse-triage[bot] 445ebacf24 Restore delivery qualification trust
Harden release workflow input transport and make native lifecycle proof honor each platform security boundary. Refresh stale telemetry and delivery qualifications.

Contract-Neutral: Formatting-only catalog updates and browser-verified alert copy; release compiler and native lifecycle changes update their owning contracts.
2026-08-31 03:02:13 +01:00
Richard Courtman 08f7c5f0d5 Harden secure agent runtime boundaries 2026-08-31 00:06:24 +01:00
Richard Courtman a8bc2e044b Qualify helper-backed agent update recovery 2026-08-30 21:54:46 +01:00
pulse-triage[bot] e094a55b45 Integrate typed helper container summaries 2026-08-30 21:29:11 +01:00
Pulse Test 7e92ac8118 Harden secure runtime separation boundaries 2026-08-30 14:26:01 +01:00
pulse-triage[bot] 95a7191ca9 Enforce native private state permissions 2026-08-30 03:31:00 +01:00
Pulse Test d06ffc233d Harden secure agent runtime transitions 2026-08-30 01:41:57 +01:00
Pulse Test d607d5cf46 Separate agent remediation runtime 2026-08-29 23:48:28 +01:00
Pulse Test 6d4ee48000 Add typed agent privilege helper 2026-08-29 22:51:58 +01:00
Pulse Test a966264bb1 Contain agent command authority 2026-08-29 22:12:41 +01:00
rcourtman 434e1448ff Restore Docker update preflight through unified agent 2026-08-23 08:35:26 +01:00
rcourtman 48fac73ff0 Rework Patrol around outcome-driven autonomous operations 2026-08-14 12:52:51 +01:00
rcourtman 3355f7a671 Read host Docker credentials for private registry update checks
Container update detection only ever negotiated anonymous pull tokens, so
containers from registries that reject anonymous digest HEADs pinned a
permanent "authentication required" badge (#1706). The agent already runs
on the Docker host, so the checker now resolves the same credential store
docker pull uses - config.json auths entries, credsStore/credHelpers
credential helpers (docker-credential-<name> get), and Podman's auth.json -
and presents the stored login: Basic auth on Bearer token negotiation and
on the hardcoded Docker Hub / ghcr.io token endpoints, direct answers to
Basic challenges, and the refresh-token grant for identity-token logins
such as Azure ACR.

Credentials never leave the host: they are only presented to the registry
or its token endpoint, helper output stays out of reported check errors,
and lookups are cached in memory for five minutes. Helper names are
validated before exec, and a stale login falls back to the anonymous path
so checks that used to work keep working. Set
PULSE_DISABLE_REGISTRY_CREDENTIALS=true (--disable-registry-credentials)
to keep detection anonymous-only. The agent-lifecycle and security-privacy
subsystem contracts pin the host-local credential boundary.
2026-08-13 10:06:26 +01:00
courtmanr@gmail.com 4dac4dd163 Allow agents to include filtered disk mounts 2026-08-11 16:37:37 +01:00
rcourtman d699dc66a0 feat(agent): converge agent self-update within one report cycle
The server now echoes its version on unified-agent report acks, and the
agent nudges its auto-updater the moment an ack carries a newer version.
After a server upgrade, agents converge within one report interval
instead of waiting out the hourly update check, so the "older Pulse
agent" notice self-resolves in seconds once upgraded agents report in.

The hourly loop stays as the retry and backstop path. Nudges dedupe per
server version, refuse downgrades, skip disabled and development-mode
updaters, and never fire from observer destination acks — only the
authoritative server may steer an agent's updater, and a nudged check
re-validates against the server and runs the existing checksum and
self-test pipeline before swapping binaries. Agents deployed before
this change still converge on their old hourly cadence once; every
upgrade after that lands within a report cycle.

Contract deltas recorded in agent-lifecycle and api-contracts, with
boundary notes in security-privacy (no update authority in the echo),
performance-and-scalability (no steady-state work), and
storage-recovery (nothing persisted).
2026-08-07 11:40:46 +01:00
courtmanr@gmail.com 9e8b3ee6ff feat(agent): add REST custom metrics 2026-07-30 19:08:28 +01:00
courtmanr@gmail.com c0233ad56b feat(agent): add secure custom numeric sensors 2026-07-30 18:34:02 +01:00
courtmanr@gmail.com a9dad6a29c Run assigned availability checks from the host agent
The unified agent gains an availability module: probe assignments
arrive through the signed remote-config channel (missing key clears
the schedule), each enabled target runs on its own clamped interval
through the shared probe core, and results queue in a bounded
drop-oldest buffer. A result is offered to the primary server until
one delivery succeeds and never again after - buffered offline
reports are stripped of availability results so the disk buffer
cannot replay observations the queue still holds. ApplyHostReport
feeds accepted reports into the probe ingestion path, where the
ownership check and failure accounting live, and the probe agent id
is projected onto unified availability resources for source
attribution in the UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 11:13:04 +01:00
courtmanr@gmail.com e405270e89 Prepare v6.1.2 stable patch release 2026-07-26 20:38:42 +01:00
rcourtman 1ef4a68735 Clarify disk exclusion behavior 2026-07-24 09:20:26 +01:00
rcourtman b6a74576bc Integrate trust-gate reliability fixes 2026-07-20 16:03:29 +01:00
rcourtman 685a671c61 Make the agent token test platform-aware
Use the runtime-selected default token path in the token-resolution fixture so the same contract is exercised on Windows and Unix runners.

Contract-Neutral: Platform-aware agent token test fixture changes no runtime contract
2026-07-19 19:58:03 +01:00
rcourtman 3f405af0c6 Align Windows agent state with the installer
Use the installer-owned ProgramData directory consistently for token lookup, enrollment state, agent identity, receipts, and service runtime data. Pass that directory explicitly to the Windows service and retain the existing Linux default elsewhere.

Contract-Neutral: Windows agent state-path alignment preserves the existing installer and agent public contract
2026-07-19 19:41:57 +01:00
rcourtman 52ed884640 Prepare v6.1.0-rc.4 release 2026-07-19 15:52:42 +01:00
rcourtman 4b066a0f1e Add report-only Unified Agent observer destinations 2026-07-19 15:30:34 +01:00
rcourtman 93fff4f1d8 Add an explicit operator override for plaintext HTTP to non-local Pulse hosts
Fleets on networks numbered from nominally public IP space (issue
#1522: an AD estate on 192.20.0.0/16) cannot pass the agent's
local-network plaintext heuristic, and the only workaround was pointing
a .internal DNS alias at the server, which bypasses the same control
less visibly than a flag would. --allow-plaintext-http
(PULSE_AGENT_ALLOW_PLAINTEXT_HTTP) records process-wide consent once at
agent startup before any module validates a URL, covers every agent
transport including the websocket command channel, warns at startup
that the API token travels in cleartext, defaults closed, and is never
emitted by generated install commands or settable by the server.
2026-07-14 16:42:02 +01:00
rcourtman 3c778e2b26 Restore one-click Docker container updates through the typed action plane
v6.1.0-rc.1 retired the legacy update endpoints before a replacement
existed, so the UI's Update button failed with an internal-jargon 410
(issue #1564). This lands the replacement end to end: update_container
is a typed agentexec operation with its own strict codec, durable
receipts, and a request digest bound to the image digest the plan
observed; the unified agent bridges execution to the Docker module's
existing pull/backup/recreate/verify/rollback implementation (which now
reports rollback attempt and outcome); and the container action
executor plans, dispatches, and reconciles the operation with declared
backup/rollback compensation truth. Containers advertise an
admin-approval update capability while an image update with a stated
current digest is detected. The legacy endpoints stay retired but
return actionable copy.

Proven live against a Colima daemon: single-container update, the
issue-1564 shared-network-namespace update, and the full UI journey
(Update button, governed review, approve, run) all completed with the
namespace preserved and the backup retained.
2026-07-14 12:19:04 +01:00
rcourtman 3bea52b1b5 Harden native Windows agent lifecycle 2026-07-10 19:16:23 +01:00
rcourtman f4c2fd0c38 Fail closed on unknown remediation lock state for autonomous dispatches
The AI action broker treated an unreadable operator lock as unlocked:
isResourceRemediationLocked returned (false, nil) with no audit store
wired, and the caller logged store errors then dispatched anyway. An
operator's NeverAutoRemediate=true could be silently ignored whenever
the policy store was missing or erroring, which is unacceptable while
Patrol and Assistant run at assisted or full autonomy.

Posture change at the dispatch decision point:
- isResourceRemediationLocked now reports unknown state (nil store or
  lookup failure) as an ErrRemediationLockStateUnknown-wrapped error
  instead of silently defaulting to unlocked.
- New checkRemediationLockForDispatch gate: dispatches without an
  approved human decision fail CLOSED on unknown lock state and
  surface "remediation lock state unknown; operator approval
  required". Human-approved dispatches keep the historical fail-open
  behavior with a warning log. A confirmed lock still refuses even
  approved dispatches, as before.
- executeNativeActionWithAudit (TrueNAS app start/stop/restart) now
  enforces the lock too; it previously skipped the check entirely.
- Refusals persist Failed audit records with stable
  remediation_lock_state_unknown: / resource_remediation_locked:
  ErrorMessage prefixes.
- ai-runtime subsystem contract updated to pin the new posture.

Tests cover store-error and nil-store at both autonomy postures on
both dispatch paths; routing/control tests now wire an in-memory
audit store since autonomous dispatch without one is refused.
2026-07-10 00:14:01 +01:00
rcourtman 1894d2e665 Make native agent tests Windows-safe 2026-07-09 23:51:50 +01:00
rcourtman 255c7c23d4 Modernize Unified Agent lifecycle and platform support 2026-07-09 23:20:35 +01:00
rcourtman 841100caa7 Clarify Proxmox LXC Docker install path 2026-06-12 09:57:58 +01:00
rcourtman e12387489e Fold pulse-agent module init retry into one generic helper
initDockerWithRetry and initKubernetesWithRetry were the same exponential
backoff loop (5s doubling to a 5m cap, cancel-aware wait, structured
retry logging) duplicated per module; dupl flagged the pair. Extract
initModuleWithRetry[T] and keep the two as thin wrappers so the
test-overridable newDockerAgent/newKubeAgent vars and call sites stay
unchanged. Per-module log strings are preserved verbatim.

Existing cmd/pulse-agent retry tests (success, cancel-before-connect,
cancel-during-wait, both modules) pass unchanged.
2026-06-10 09:18:30 +01:00
rcourtman b707512e38 Clear all errcheck and gofmt violations so make lint gates on real findings
golangci-lint run ./... failed on ~190 pre-existing errcheck violations and
5 unformatted files, burying any new regression in noise. Fix all of them:

- Test files that hand-rolled mock-mode set/restore (vmware, truenas, and
  friends) now use the canonical setMockModeForTest/testutil.SetMockMode
  helper instead of drift copies that ignored SetEnabled errors.
- internal/mock and internal/monitoring tests get package-local
  mustSetEnabled/mustSetMockEnabled/mustSetMonitorMockMode helpers that
  fail the test on toggle errors.
- pkg/auth/sqlite_manager.go, pkg/metrics/store.go, pkg/server/server.go:
  rollbacks in defers use the explicit-discard idiom, migration renames and
  rollup commits log failures, the hosted reaper goroutine logs an error
  exit, shutdown mock-disable logs failures.
- Remaining test sites check errors with t.Fatalf/t.Errorf or explicitly
  discard best-effort calls (restore-chmods, handler-closure unmarshals)
  per existing repo style.
- gofmt: internal/api/maintenance_verification.go, internal/ai/demo.go and
  three findings test files.

Only dupl findings remain (44 pre-existing production-code duplication
pairs) — those need real refactors, not mechanical fixes.

Full test suites pass for every touched package.
2026-06-09 21:42:21 +01:00
rcourtman 0d0eb4bf11 Stabilize v6 release dry-run backend gate 2026-06-03 18:12:42 +01:00
rcourtman faefe6edc8 Remove 198 unreachable Go functions
Dead-code sweep. Functions flagged unreachable by golang.org/x/tools/cmd/deadcode
and confirmed unused across pulse, pulse-enterprise, pulse-pro and pulse-mobile by
adversarial cross-repo verification. Cross-module reachability was checked
explicitly (only pkg/ exported symbols are importable by other modules; internal/
packages and _test.go files are not). go build, go vet and test-compile all pass.
2026-06-03 12:29:37 +01:00
rcourtman 1afd708e5a Harden unified agent update preflight
Record the single pulse-agent product invariant and clarify Docker / Podman module terminology.
2026-06-02 23:54:48 +01:00
rcourtman 84c43ad3e1 Fix Windows agent installer readiness path 2026-05-26 10:19:56 +01:00
rcourtman 5a405f7f07 Protect inside-guest Docker visibility boundaries 2026-05-18 14:16:15 +01:00
rcourtman cf103ca9fe Harden root agent service defaults 2026-05-05 13:03:13 +01:00
rcourtman a8428da1ea Add agent ID file persistence
Refs #1447
2026-04-30 14:41:57 +01:00
rcourtman 5091affb1b Canonicalize Docker Podman agent CLI copy 2026-04-30 09:04:25 +01:00
rcourtman ecf8fd4299 Keep self-hosted Pro prompts opt-in 2026-04-28 11:23:49 +01:00
rcourtman c51708000f Tighten unified agent hardening proof 2026-04-23 23:37:25 +01:00
rcourtman 9bada35337 Harden unified agent runtime and installer 2026-04-23 23:04:18 +01:00