Commit Graph

1354 Commits

Author SHA1 Message Date
rcourtman 7cb45489e8 Add cloud_context_privacy dial (privacy redesign increment 1)
Introduce the single privacy dial that will govern what infrastructure context
cloud models may see, replacing the binary share_operational_context_with_cloud
toggle as the canonical operator control. This increment adds and surfaces the
setting; it does not change the redaction seam (that is increment 2).

Config (internal/config/ai.go): add AIConfig.CloudContextPrivacy with the
full|redacted|local_only levels, default "full", plus NormalizeCloudContextPrivacy
and the nil-safe GetCloudContextPrivacy getter. NewDefaultAIConfig defaults a fresh
self-hosted install to "full" so the Assistant answers with real resource detail
out of the box. The legacy ShareOperationalContextWithCloud boolean is retained as
the field the redaction seam still reads until it is wired into the dial directly.

Migration (internal/config/persistence.go): LoadAIConfig derives the dial from the
legacy toggle for pre-dial configs (legacy on -> full, off/absent -> redacted) and
persists it, leaving the legacy boolean untouched so existing installs keep their
current cloud behavior byte-for-byte. Fresh installs (no config file) default to full.

API (internal/api/ai_handlers.go): round-trip cloud_context_privacy through
/api/settings/ai field-by-field like discovery_enabled. The response always
serializes GetCloudContextPrivacy() (no omitempty) so the UI binds a 3-option
control to the concrete value; the update request carries an optional *string
validated against NormalizeCloudContextPrivacy (unknown values -> 400). When the
dial is provided it supersedes and re-syncs the legacy boolean (full -> true,
redacted/local_only -> false) so the existing seam honors the dial's full/redacted
axis without new redaction code paths.

Frontend: replace the binary "Share operational context with cloud models" toggle
with a "Cloud model privacy" 3-option FormSelect in AIRuntimeControlsSection.tsx,
bound to state.form.cloudContextPrivacy and the cloud_context_privacy payload via
useAISettingsState. CloudContextPrivacy type + payload fields in types/ai.ts;
label/help/option/summary copy in aiSettingsPresentation.ts.

Governance (ai-runtime + frontend-primitives substantive deltas; dependent
api-contracts, agent-lifecycle, storage-recovery notes): the contracts now name the
dial as canonical with the legacy boolean as the synced/migrated seam field.
Proofs: ai_config_test.go (getter/normalize/default), persistence_ai_test.go
(migration cases), ai_handlers_test.go (round-trip + legacy sync + 400),
contract_test.go JSON snapshots, settingsArchitecture + aiSettingsPresentation tests.
Live-verified in the preview drawer: dial renders with all three levels, the
migrated value (redacted) is selected, the summary updates reactively, and an
end-to-end UI save round-trips full (legacy sync true) then restores redacted.
2026-06-08 16:43:50 +01:00
rcourtman 3f76da7932 Surface cloud operational-context sharing opt-in in AI settings
Wire AIConfig.ShareOperationalContextWithCloud through /api/settings/ai so the
existing chat-path opt-in (commit 32d597267) is operator-reachable, not
config-file-only.

Backend (internal/api/ai_handlers.go): add share_operational_context_with_cloud
to the AI settings response (always serialized so a toggle can bind to the
concrete value) and to the update request as an optional *bool, applied
field-by-field exactly like discovery_enabled (omitted = persisted opt-in
unchanged).

Frontend: add a 'Share operational context with cloud models' toggle to the
Assistant runtime controls, bound to the canonical useAISettingsState form and
the api/ai.ts AISettings/AISettingsUpdateRequest payload. Help/summary copy
(PII-free scope, hostnames/IPs/aliases stay redacted, default off, local Ollama
always gets full context) lives in aiSettingsPresentation.ts.

Governance: substantive ai-runtime + frontend-primitives deltas plus
dependent-contract notes (api-contracts, agent-lifecycle, storage-recovery);
path-policy proofs in ai_handlers_test.go (round-trip), settingsArchitecture
and aiSettingsPresentation tests. JSON snapshot contracts updated for the new
always-serialized field.
2026-06-08 10:05:37 +01:00
rcourtman 13b2c33dfd Align Assistant route wait status
Use neutral assistant wait status while keeping selected model route metadata visible. Make transient retry copy explicit that Pulse retries the selected route rather than switching providers.
2026-06-08 06:37:47 +01:00
rcourtman 738fc4eb13 Reject unsupported Assistant session diff/revert 2026-06-07 18:01:55 +01:00
rcourtman 84ec1a7214 Align Assistant provider retry with OpenCode 2026-06-07 17:04:42 +01:00
rcourtman 42f4a7028d Surface Assistant idle progress on SSE streams 2026-06-07 00:06:34 +01:00
rcourtman e44b11f4d0 Improve Assistant tool activity rows 2026-06-06 21:58:17 +01:00
rcourtman 3c74fe2ca0 Start Assistant runtime in mock mode 2026-06-06 21:39:39 +01:00
rcourtman e4ac092876 Add Assistant stream idle progress 2026-06-06 19:59:34 +01:00
rcourtman 44e8a1b2bd Add Assistant turn undo and redo 2026-06-06 19:42:27 +01:00
rcourtman 5503e15d23 Add Assistant session rename
Add persisted session rename support across the chat store, API contract, and Assistant session picker.
2026-06-06 18:32:21 +01:00
rcourtman 2291924cb6 Show Assistant provider retry progress 2026-06-06 15:55:59 +01:00
rcourtman 49c23d6bed Search Assistant session history 2026-06-06 09:14:06 +01:00
rcourtman 0ad040bdf0 Resolve Assistant plain-text resource context
Attach backend-resolved current_resource context for live Assistant read prompts.
2026-06-06 07:13:05 +01:00
rcourtman ab99112ad2 Show Assistant tool starts while streaming 2026-06-06 03:12:25 +01:00
rcourtman 1f4477c27c Show live Assistant tool progress 2026-06-06 01:12:01 +01:00
rcourtman 2ab0a60e99 Speed up Assistant stream startup 2026-06-05 22:54:44 +01:00
rcourtman 0d2f2a3cc8 Anchor Assistant stream and OpenRouter default 2026-06-05 22:02:47 +01:00
rcourtman 7067a51680 Make Assistant provider fallback resilient 2026-06-05 20:15:55 +01:00
rcourtman a648afaff0 Avoid duplicate Assistant stream errors 2026-06-05 19:29:07 +01:00
rcourtman dae5daf6ac Fix Assistant provider route validation 2026-06-05 18:48:57 +01:00
rcourtman 5ea51b4b25 Harden Assistant stream output and OpenRouter token budget 2026-06-05 16:30:07 +01:00
rcourtman 064cd4bc80 Hide Assistant reasoning from message history 2026-06-05 15:43:06 +01:00
rcourtman c5bee4a785 Surface Assistant provider readiness 2026-06-05 12:50:02 +01:00
rcourtman 479ac6db2c Stream Assistant cold sessions directly 2026-06-05 11:54:01 +01:00
rcourtman 6bbbf185bb Make workload discovery repair known service results 2026-06-05 09:21:53 +01:00
rcourtman 91528f5a07 Fix Assistant resource context and model route labels 2026-06-04 23:45:15 +01:00
rcourtman a43f7cbe7f Add discovery readiness to Assistant context 2026-06-04 21:56:36 +01:00
rcourtman 3f8525a7c2 Implement resource-aware Assistant context 2026-06-04 16:36:04 +01:00
rcourtman bd6f77e093 Prepare v6.0.0 release candidate
Tighten v5-to-v6 upgrade safety, release installability, provider MSP mode handling, AI cost accounting, metrics flushing, and frontend guardrails for the v6.0.0 GA candidate.
2026-06-04 14:07:14 +01:00
rcourtman efb6976069 Diagnostics: handle blank-name instances; add report-token router test
Two follow-ups caught by independent re-review:
- #29 (8855b78c0): GetConnectionStatuses keys a name-less instance by host,
  but the diagnostics lookup used 'pve-'/'pbs-'+Name only, so the
  monitor-state merge was a silent no-op for unnamed instances. Fall back
  to host to match.
- #22 (d9da9b18f, #1254): add a full-router test asserting an UNBOUND
  agent:report token gets 404 (not 200) on config fetch — continuously
  verifying the token-binding security boundary that the scope change
  relies on.
2026-06-04 11:49:17 +01:00
rcourtman d4edd1264d Fix TestRestart_StartIfServiceMissing expectation for single config load
#23 (a6b773a85) made Restart load the AI config once and pass it to
startWithConfig, so the start path no longer re-loads it. The test still
expected LoadAIConfig().Twice(); updated to .Once() to match the fixed
single-load behavior. (Caught by running the full internal/api suite,
which the per-fix targeted runs had missed.)
2026-06-04 11:23:05 +01:00
rcourtman 1713662379 Stamp AI models with their provider for correct grouping (#1320)
Back-port the core of v5 fix 1de1392c9 to v6 (minimal, not the full
dedup refactor). The model list API now sets ModelInfo.Provider (stamped
in prefixProviderModels and passed through HandleListModels), and the
frontend groupModelsByProvider prefers the server-supplied provider over
splitting the model id, so models with opaque ids (e.g. Ollama-hosted
llama3-8b) group under the correct provider. Adds a grouping regression
test.
2026-06-04 10:47:40 +01:00
rcourtman a6b773a85f Reuse the loaded AI config when restarting the service
Back-port v5 fix 716340dcd to v6. Extracts startWithConfig from Start so
Restart passes the config it already loaded down to the start path, instead
of Start re-reading loadAIConfig a second time. Avoids starting the AI
service with a stale/inconsistent config if it changed between Restart's
load and the start. Both Restart start paths now use startWithConfig.
2026-06-04 10:30:45 +01:00
rcourtman 8855b78c0d Prefer live monitor connection state in diagnostics
Back-port v5 fix d310c257a to v6, adapted to v6's connection-status key
format. computeDiagnostics now merges a failed PVE/PBS diagnostics probe
with the monitor's live connection state: if the long-running poller still
reports the instance connected, a transient probe failure (network blip,
TLS re-check) no longer flips it to 'disconnected' in the UI. Uses v6's
'pve-<name>'/'pbs-<name>' status keys (v5 used a bare node name, which
would not match in v6). Adds a merge-logic regression test.
2026-06-04 10:07:10 +01:00
rcourtman 85ec355268 Preserve webhook mentions in list API and resolved notifications (#1118)
Back-port v5 fixes 5997fd81f and 0a7b93a84 to v6:
- GetWebhooks list response now includes the configured mention so the UI
  shows it after reload instead of blanking it.
- sendResolvedWebhook now assigns data.Mention (v6 set it for grouped/
  firing webhooks but dropped it on resolved), and the Discord/Slack/Teams/
  Mattermost ResolvedPayloadTemplate strings gained {{if .Mention}} guards.

Without these, a configured @everyone/@channel was silently omitted from
resolved/cleared notifications. Adds list-API and per-service resolved
mention regression tests.
2026-06-04 09:29:47 +01:00
rcourtman d9da9b18f2 Allow legacy report-only agent tokens to fetch their own config (#1254)
Back-port v5 fix 04a828264 to v6. canReadConfig now accepts
ScopeAgentReport (legacy host-agent:report) in addition to the config/
manage/settings scopes; resolveConfigAgent already restricts a
report-only token to the host it is bound to, so it can only read its
own config. Without this, a v5 agent upgraded to a v6 server while still
holding a report-only token gets HTTP 403 on config fetch and breaks.

Retargets TestHandleConfigMissingConfigScope to monitoring:read and adds
TestHandleConfigAllowsBoundAgentReportScope as a #1254 regression guard.
2026-06-04 08:39:31 +01:00
rcourtman 5a21f0c288 Make rate limiter sliding-window test deterministic 2026-06-03 23:14:25 +01:00
rcourtman ab2c2453c2 Synchronize auto-register reload test 2026-06-03 22:40:30 +01:00
rcourtman 0d0eb4bf11 Stabilize v6 release dry-run backend gate 2026-06-03 18:12:42 +01:00
rcourtman 7440208163 Project Kubernetes agent versions onto node rows 2026-06-03 15:57:51 +01:00
rcourtman 17e854e7b6 Use agent update target for stale notices 2026-06-03 14:42:43 +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 e17916e3bc Surface v5 agent migration security guidance
Warn when update readiness includes v5 agents and document the trusted-transport first hop.
2026-06-03 09:18:07 +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 c7e50d5602 Harden provider-hosted MSP isolation
Broker provider control-plane Docker access through a socket proxy, remove broad host mounts, align audit and rate-limit proxy trust, harden tenant runtime containers, restrict workspace report logo paths, and update provider deploy guardrails.
2026-06-02 21:10:13 +01:00
rcourtman d6964832a0 Add entitlement-gated report branding 2026-06-02 18:11:25 +01:00
rcourtman d729461cad Harden provider MSP tenant isolation
- isolate provider MSP tenant runtimes onto per-client Docker networks
- add adversarial proofs for workspace cap races, handoff retargeting, and org-bound agent report retargeting
- pin provider deploy proof to start Traefik before tenant network creation
2026-06-02 17:34:10 +01:00
rcourtman 3f20c85e86 Add provider MSP proof command
Adds a provider-hosted MSP proof command that exercises provider bootstrap, workspace creation, hosted tenant install-token generation, handoff exchange, setup-facts visibility, and cross-tenant token isolation.
2026-06-02 12:45:48 +01:00
rcourtman 57486cee88 Harden MSP onboarding proof gaps 2026-06-02 10:15:35 +01:00