Commit Graph

6 Commits

Author SHA1 Message Date
rcourtman bdb212744c Remove the cloud_context_privacy dial; fix cloud context to a lean posture
Per maintainer decision: the cloud-context-privacy feature was bloat. The real
fix for the "useless Assistant on cloud" problem was the earlier sensitivity
recalibration (ordinary workloads = Internal, not redacted); the dial layered a
configurable knob on top of an already-solved problem, guarding mostly-non-secret
data on a destination the operator opted into, and demanded every model-bound path
stay dial-aware (a standing leak surface). The privacy control users actually
understand is the choice of model — cloud provider vs. local Ollama.

Removed entirely:
- AIConfig.CloudContextPrivacy dial + constants + GetCloudContextPrivacy /
  NormalizeCloudContextPrivacy, AND the now-dead legacy
  ShareOperationalContextWithCloud boolean + ShouldShareOperationalContextWithCloud
  (internal/config/ai.go); the config-load migration (persistence.go).
- Both fields from the /api/settings/ai request/response, validation, and sync
  (ai_handlers.go) + the JSON contract snapshots.
- The "Cloud model privacy" 3-option UI control, form field, presentation copy,
  and CloudContextPrivacy type (frontend), plus their tests.
- The dial branching in the seam: chat/service.go cloudPrivacyLevel,
  CloudContextPolicy.Level + local_only suppression + the localOnly directive
  (context_prefetch.go), the inventory resourceLabel dial logic (resource_context*),
  and the modelboundary RedactLocalOnlyResourcesOnly option.

Fixed lean posture (no setting): a cloud-routed model receives real infrastructure
context, with two always-on invariants enforced by the model-boundary sanitizer —
credentials are always stripped, and local-only/Restricted resources (the floor)
never leave the local trust boundary. Local (Ollama) always full. The sanitizer's
default is now the local-only floor; it remains the universal backstop installed on
EVERY model-bound path (chat, session compaction, discovery/report/analysis via the
shared helper). Kept the two standalone fixes from this effort: compaction now
routes through the sanitizer, and directives no longer inject the "redacted by
policy" placeholder.

Governance: ai-runtime contract rewritten to a fixed-posture rule; api-contracts /
frontend-primitives / agent-lifecycle / storage-recovery dial references removed.
Tests updated to the floor-only behavior (local-only redacted, Sensitive flows,
secrets stripped). Full internal/ai/..., config, api suites green; frontend
type-check + tests + lint green.
2026-06-09 09:43:21 +01:00
rcourtman 3e3c601317 Make the redaction seam obey the cloud_context_privacy dial (increment 2)
The dial now drives model-bound redaction directly, replacing the legacy
ShareOperationalContextWithCloud read. internal/ai/chat/service.go resolves
cloudPrivacyLevel once per turn (failing closed to "redacted" when no config
snapshot is present) and threads it into the prefetch and the model boundary:

- full: the model-bound resource-policy sanitizer is invoked with
  modelboundary.RedactLocalOnlyResourcesOnly(), so real identifiers (hostname,
  IP, alias, name) for ordinary (Internal) and Sensitive (local-first) resources
  reach the cloud model — the core "answer with real detail" win. Resources the
  policy engine routes local-only (Restricted) stay redacted as a HARD FLOOR a
  blanket dial must never override, so default-full never ships a must-not-leave
  resource to a cloud vendor. Prompt-secret sanitation (credentials) always runs.
- redacted: every policied resource's identifiers are redacted as before, and the
  prefetch surfaces the PII-free operational context for governed resources.
- local_only: the prefetch injects NO proactive infrastructure context to the
  cloud turn (only a transparency directive pointing at the setting / a local
  model), and the sanitizer still redacts identifiers as a backstop.

CloudContextPolicy now carries the dial Level (failing closed to redacted for
empty/unknown) instead of a ShareOperationalContext bool; sharesCloudOperationalContext
covers full+redacted, suppressesCloudContext covers local_only. The obsolete
"Share operational context with cloud models" transparency string is replaced by
a local_only directive referencing "Cloud model privacy".

modelboundary gains RedactLocalOnlyResourcesOnly() + localOnlyRoutedResources();
the resource-redaction pass narrows to the local-only floor at full while
prompt-secret sanitation is unconditional. Local (Ollama) models never reach the
sanitizer.

Governance: substantive ai-runtime contract delta describing the dial-driven seam
and the local-only floor. Proofs: modelboundary sanitizer tests (full keeps the
floor + redacts secrets; default redacts all identifiers), CloudContextPolicy
level semantics + prefetch full/redacted/local_only behavior, and the handoff
relationship test pinned to redacted. Full internal/ai/..., unifiedresources,
and agentcontext suites green.
2026-06-08 17:08:14 +01:00
rcourtman ddc480ff3c Recalibrate resource sensitivity: ordinary workloads aren't secret
User on a cloud model saw 'redacted by policy' everywhere. Root cause: the
default classification (classifyResourceSensitivity) treated every VM, container,
pod, k8s workload, and docker service as 'Sensitive', which redacts their
hostname/IP/alias/path for cloud models. For Pulse's homelab/SMB audience that
crippled the cloud Assistant — a workload named 'grafana' isn't a secret, and its
private LAN IP isn't either.

Recalibrate: compute workloads classify as 'Internal' (cloud-summary, no
redaction) so cloud models can see their names/IPs. Escalation to
Sensitive/Restricted is by tag (database, backup, customer-data, secret, ...) or
by genuinely sensitive TYPE: storage/data-at-rest (storage, PBS, Ceph,
physical-disk, network-share, network, k8s PV/PVC/StorageClass), configuration
(docker-config, k8s-configmap), and security (k8s RBAC, secrets, PMG). Secrets
and PMG stay Restricted; the tag-based escalation is unchanged.

Tests: new TestRefreshPolicyMetadata_PlainComputeWorkloadsAreInternalNotRedacted
+ TestComputeWorkloadPolicyIsInternalUnlessEscalated lock it in. ~13 AI-subsystem
redaction tests that assumed plain compute = Sensitive updated to tag their
fixtures so they still exercise redaction on a genuinely-sensitive resource (no
assertions weakened). Contract: unified-resources Extension Points documents the
recalibrated classification. internal/ai/... + internal/unifiedresources/... green.
2026-06-08 15:21:51 +01:00
rcourtman 73b0635c21 Improve Assistant inventory and activity flow 2026-06-06 00:17:44 +01:00
rcourtman 0fbcc90184 Harden external model prompt-secret sanitation 2026-05-13 13:03:40 +01:00
rcourtman 94a5ab1b59 Enforce data policy at AI model boundary 2026-04-25 21:13:53 +01:00