Commit Graph

3708 Commits

Author SHA1 Message Date
rcourtman 4745b34b51 Add branch-coverage tests for three changed frontend model modules
containerUpdateBadgeModel gained update icon and button helpers since its prior
branchcov test, so this covers the three previously-uncovered functions and
their state arms (idle, confirming, updating, success, error and the default).
aiProviderPresentation route-label formatting had fourteen uncovered branches,
now exercised through the four exported entry points. dockerIdentityConflict
conflict collection reaches full branch coverage including the hostnames
fallback and the name fallback chain.

All three are new test-only files under existing __tests__ directories. No source
changed. Each was confirmed with vitest and type-check, and measured to raise
branch or function coverage over the pre-existing suite.
2026-07-17 06:35:00 +01:00
rcourtman 72c409743d Warn when two machines share one Docker agent identity
Cloned VMs that keep the same /etc/machine-id collapse into a single
Docker host in Pulse, with each clone's report silently overwriting the
other (#1584). The server now tracks per-identity hostname and machine
ID observations and flags a conflict when a value flaps back to one
already seen inside a 15-minute window, a signature a one-time rename
never produces. The conflict rides the DockerHost model through unified
resources, and the Docker page shows a warning naming the flapping
hostnames with the machine-id remedy. The warning self-clears once one
clone stops reporting for the window.
2026-07-16 20:55:09 +01:00
rcourtman 2f6bb94ed3 Classify legacy-CIS-only vCenters as unsupported version
A vSphere 6.x target fails the connect test at the Automation session
step with a generic "HTTP 500" message, because /api on those releases
routes to the JSON-RPC servlet. When /api/session fails with a non-auth
status, probe the legacy /rest CIS session API with the same
credentials; if that login works the target predates the JSON APIs
Pulse uses, so the test now reports the unsupported-version warning
naming the vCenter 8.0U1 floor instead of pointing at credentials. The
probe deletes the session it creates. Also reword the frontend guidance
for that category in plain terms.

Related to #1585.
2026-07-16 19:52:14 +01:00
rcourtman 4dcba3a1d8 Name the actual OIDC token verification failure on the login page
Every ID token verification failure rendered the issuer-mismatch
advice, sending users with audience or clock problems down the wrong
path and telling users with a genuine issuer mismatch nothing they had
not already checked (#1533). Map the distinct verification failures
(issuer, audience, expiry) to their own error codes and give each
accurate login-page copy pointing at the server log's got/want detail.
2026-07-16 10:15:42 +01:00
rcourtman 917a9e5421 Add local subscription model routes 2026-07-14 22:57:38 +01:00
rcourtman 206b68cc94 Clarify commercial offer boundaries 2026-07-14 17:18:14 +01:00
rcourtman a8341b013f Open the shipped security guide outside the SPA router
The Security Overview configure-https action linked /docs/SECURITY.md
with external: false, so Solid Router intercepted the same-origin
anchor click and rendered the SPA NotFound page instead of letting the
browser fetch the embedded doc. Mark the link external like every
other shipped-doc consumer.

Refs discussion #1505
2026-07-14 17:13:50 +01:00
rcourtman d7a73ee521 test(coverage): patrol investigation context model branch coverage
Add a purely-additive branch-coverage suite for the residual uncovered arms of
patrolInvestigationContextModel builders (assistant briefing/handoff inputs,
configuration-failure handoff secret redaction, investigation context summary
numeric clamping, proposed-fix keep/drop gating, approval-policy checks). The
existing dev test is left untouched; this exercises previously-unexecuted
exports and branch arms only. No source changed.
2026-07-14 14:48:01 +01:00
rcourtman 68dd64e768 Drive the container Update button through the governed action review flow
The Update button on the Docker containers table and workloads rows now
plans an audited update action and opens the same governed review
dialog the lifecycle controls use (approve, run, per-action audit),
instead of calling the retired direct-update endpoint. The host
drawer's bulk update-all reports honestly that updates run as reviewed
per-container actions until a reviewed bulk flow exists, and the dead
updateDockerContainer/updateAllDockerContainers API clients are
removed. Update state still tracks through the containerUpdates store,
flipping to success when the refreshed report clears updateAvailable.
2026-07-14 12:23:43 +01:00
rcourtman caa822ed92 Keep the drawer Access section in one place with an always-visible open link
In row drawers the Access disclosure sat collapsed at the very bottom, but
expanding it re-rendered the section at the top — clicking "Show access"
teleported the content away from the user, and reaching a container's web
interface meant scrolling the whole drawer down and back up (#1556).
Promote the section whenever it exists so it renders in one stable spot at
the top, and surface the saved URL as a clickable link in the disclosure
header so opening the web interface requires no expansion at all.

Refs #1556
2026-07-14 10:51:13 +01:00
rcourtman 2c6f96513b Key the resource drawer's container web-interface URL by stable identity
A URL saved from the Docker tab's container drawer went to the docker
store under the runtime container key — the lowest-priority key in the
unified customUrl projection, and one that goes stale the moment the
container is recreated (e.g. by an update). Any stable record, including
an intentionally empty cleared one, masked it forever, so the saved URL
never turned the container name into a table link even after a refresh
(#1556). The Workloads drawer was already fixed to use the stable
host-plus-container-name guest key; align the resource drawer on the
same identity.

Refs #1556
2026-07-14 10:46:07 +01:00
rcourtman 18b5b1dd58 Make web-interface name links look like links everywhere
The Proxmox nodes table styled its PVE UI link in the plain text color, so
a working link was indistinguishable from a label (#1556). The workloads
node group headers and both alerts-surface name links had the same drift.
Extract the canonical blue link classes into WEB_INTERFACE_LINK_COLOR_CLASS
on WebInterfaceNameLink and compose it at every call site.

Refs #1556
2026-07-14 10:45:13 +01:00
rcourtman b3ae6f72b6 Recognize OIDC sessions that carry no refresh token
A provider that issues no refresh token (offline_access not requested,
e.g. default Authelia) left session.OIDCIssuer unset, so
/api/security/status reported an empty ssoSessionUsername and
X-Auth-Method fell back to plain session. The frontend then skipped the
SSO fast path, and the pre-auth bootstrap short-circuit pinned the user
to the login page after ?oidc=success before the /api/state probe could
run (issue #1574). Stamp issuer/client on every OIDC session (refresh
stays gated on the token being present) and let a completed SSO
callback bypass the bootstrap short-circuit.
2026-07-14 09:42:27 +01:00
rcourtman 027185b097 Cover action-resource presentation and localStorage signal branches
Add branch-coverage tests for the fresh Actions-inbox and localStorage code:
- actionPresentation.branchcov2130.test.ts (17 cases): getActionResourcePresentation
  label/detail resolution — unknown/null resource types, canonical-kind fallback,
  opaque-suffix compaction, dashed-prefix handling, regex boundaries.
- localStorage.branchcov2130.test.ts (47 cases): createLocalStorage*Signal parse
  and stringify ternary arms (Number hex/scientific/whitespace, strict boolean
  parse, String exponential notation) across initial-read, sync-event, and write paths.

All gates green (vitest+type-check+eslint); adversarial substance review KEEP 2/2.
2026-07-13 22:10:12 +01:00
rcourtman b428fd2662 Sync shipped ICMP probe documentation 2026-07-13 18:33:02 +01:00
rcourtman a393744894 Add in-app release highlights 2026-07-13 18:30:29 +01:00
rcourtman 2d954b24ca Badge the Actions tab with the pending-approval count
Actions awaiting a decision are time-boxed, but the nav gave no signal
unless the approval happened to be Patrol-origin and the user was
already on Patrol. Poll the canonical decision queue alongside the
existing 30s open-work refresh and surface the count on the Actions
tab, matching the Alerts/Patrol badge pattern. Sessions without the
action-approve capability stop polling after the first terminal
response.
2026-07-13 17:48:33 +01:00
rcourtman 7b114f4d5a Connect Patrol action handoffs to Actions 2026-07-13 17:34:12 +01:00
rcourtman 66dc5fd7df Polish Actions layout and review details 2026-07-13 17:00:36 +01:00
rcourtman d6387b8241 Redesign the Actions inbox 2026-07-13 16:38:16 +01:00
rcourtman 4c073d6b17 Add mock action lifecycle data 2026-07-13 16:24:06 +01:00
rcourtman 95001df0bb Publish the sshsig key as an allowed_signers line so the documented verify command works
ssh-keygen -Y verify -f expects the principal in the FIRST field; the
docs published the key in authorized_keys order, so the documented
verification failed against a valid signature (customer-reported against
v6.0.5). Verified the new command against the live v6.0.5 release
artifacts.
2026-07-13 16:17:25 +01:00
rcourtman f9f90a1a27 Redesign Patrol open work queue 2026-07-13 16:12:37 +01:00
rcourtman 2e9520da81 Bind governed action intent across Patrol and web 2026-07-13 16:05:44 +01:00
rcourtman 06a6028b29 test(coverage): pulse PURE branch-cov (15 presentation/model modules) 2026-07-13 08:25:53 +01:00
rcourtman 533c3392bd test(coverage): pulse PURE branch-cov (16 presentation/model modules) 2026-07-13 08:24:29 +01:00
rcourtman 7d772acff3 feat(assistant): mid-turn steering of the running response
A follow-up sent during an active run now offers itself to the running
agentic loop via POST /api/ai/sessions/{id}/steer. Accepted steers join
the loop at its next turn boundary (the abort-check site) as plain user
messages, are announced with a steer_applied stream event so the drawer
settles the pending row, and persist through the end-of-run save. A
steer carries prompt text only: no route, control-level, or autonomy
changes, no turn-budget extension, system sessions rejected, and the
per-session inbox is bounded (steer_backlog overflow). Delivery is not
guaranteed by acceptance: a run that ends first discards the inbox and
the row drains as an ordinary queued turn, so pre-steering queue
semantics remain the fallback. Steering rows lose edit/remove once
accepted.
2026-07-12 23:01:40 +01:00
rcourtman 42fe61493c feat(assistant): show estimated session cost in the last-turn summary
Chat turns, compaction, and title calls now stamp session_id on their
cost.UsageEvent, and the done event carries session_cost_usd summed from
the operator ledger (cost.Store.SessionCostUSD). The drawer's last-turn
summary appends '$0.12 session' with a sub-cent floor. The figure is
omitted whenever any of the session's models has unknown pricing, and
free local models price known-at-zero, so no figure is ever partial.
2026-07-12 22:13:23 +01:00
rcourtman abcf7ec6ba test(coverage): harvest 20 stranded branch-coverage tests from 13:30 wave
Harvests the 13:30 c-wave's completed-but-unlanded branch-coverage tests
(315 cases across 20 PURE modules): url, settingsFeatureGates, alertDestinations,
storageAlertState, commandPalette, guestDrawer, nodeDrawer, navigation,
actionAuditPresentation, workloadTypePresentation, upgradeNavigation, and others.
Verified against current HEAD: vitest 20/20 green, full type-check clean, eslint
clean, GLM adversarial review 20 KEEP / 0 REJECT (no source edits).
2026-07-12 21:40:32 +01:00
rcourtman 8a0c6fc9a8 feat(assistant): collapse long pastes into composer chips
Pasting a log or config into the composer flooded the textarea. Pastes
over 8 lines or 800 chars now collapse into a removable chip; the full
text rejoins the prompt after the typed question at send time. Clicking
the chip body expands it back into the textarea for inline editing, and
a chip-only send is allowed.
2026-07-12 21:27:08 +01:00
rcourtman 120c80239d feat(assistant): edit-and-resend pencil on the latest user prompt
The undo flow already restores the removed prompt into the composer for
editing, but the only entry points were the header undo button and /undo.
Surface it where users look for it: a hover pencil on the latest
non-queued user prompt that undoes the turn and prefills the composer,
riding the same last-turn undo boundary as regenerate.
2026-07-12 21:15:38 +01:00
rcourtman 60ce8924bb feat(assistant): retry re-runs the turn in place and the last answer gains regenerate
Retrying a failed turn re-sent the prompt without removing the persisted
turn, so session history double-recorded the prompt. Session undo now
accepts an expected-prompt guard (a stale retry can never remove a
different turn); retry drops the replaced turn server-side before
re-sending. The latest settled assistant answer gains a hover-revealed
Regenerate button that reuses the same path.
2026-07-12 20:58:20 +01:00
rcourtman 7fd7e2b160 fix(frontend): key drawer guest web-interface URLs by the canonical workload id
The infrastructure resource drawer saved guest metadata (web interface
URLs) under the unified resource hash or the discovery resource id, a
keyspace no workloads table reads: the tables and the workloads drawer
resolve metadata by the canonical id (instance:node:vmid for PVE guests,
resource id otherwise), which is also the key v5 upgrades carry over in
guest_metadata.json. A URL saved from that drawer was stranded where
only the same drawer could read it back.

Route the drawer's guest metadata id through
getCanonicalWorkloadIdForResource, and canonicalize the resource type
inside that helper so lxc/oci-container/qemu spellings build the same
node-scoped id the workloads surfaces use.

Refs #1556
2026-07-12 19:52:21 +01:00
rcourtman 906d4823aa test(frontend): branch coverage for 7 pure modules (GLM wave 0712 tier 2d) 2026-07-12 10:49:05 +01:00
rcourtman 48ecb93848 test(frontend): branch coverage for 8 pure modules (GLM wave 0712 tier 2c) 2026-07-12 10:07:06 +01:00
rcourtman 353c5c63a4 test(frontend): branch coverage for 12 pure modules (GLM wave 0712 tier 2b) 2026-07-12 09:49:55 +01:00
rcourtman 00ff2e805c test(frontend): branch coverage for 6 pure modules (GLM wave 0712 tier 2a) 2026-07-12 09:19:35 +01:00
rcourtman 243f10f3c0 test(frontend): branch coverage for 5 pure modules (GLM wave 0712 batch 3b) 2026-07-12 08:19:49 +01:00
rcourtman 8f6888b7a4 test(frontend): branch coverage for 9 pure modules (GLM wave 0712 batch 3) 2026-07-12 08:05:51 +01:00
rcourtman 512606c40b test(frontend): branch coverage for 16 pure modules (GLM wave 0712 batch 2) 2026-07-12 07:34:44 +01:00
rcourtman 8321ed55c5 test(frontend): branch coverage for 7 pure modules (GLM wave 0712) 2026-07-12 06:36:22 +01:00
rcourtman b0ee11e162 Add trusted APT action review
Refs #1491
2026-07-12 06:33:42 +01:00
rcourtman 71ad92ef71 test(frontend): branch-coverage tests for 10 more pure presentation/model modules 2026-07-12 04:39:10 +01:00
rcourtman 516179e5fa test(frontend): branch-coverage tests for 16 more pure model/presentation modules 2026-07-12 03:30:26 +01:00
rcourtman 1968ba210c test(frontend): de-brittle actionAudit verified-outcome assertion
The 'trusted action review workspace' change (e13abf84f) reworked the verified
verification-outcome copy, breaking a branchcov2 assertion that hard-coded the old
label/detail. Assert 'VERIFIED' normalises to the canonical 'verified' result
instead of exact copy, so the test stays focused on the toLowerCase branch.
2026-07-12 03:18:07 +01:00
rcourtman e13abf84fa Add trusted action review workspace 2026-07-12 01:43:00 +01:00
rcourtman 1294695d6a test(frontend): branch-coverage tests for 28 pure model/presentation modules 2026-07-12 01:04:46 +01:00
rcourtman 0b6b97115b Addresses #1557 2026-07-11 18:30:43 +01:00
rcourtman 1d3b8e1949 Addresses #1555 2026-07-11 18:25:17 +01:00
rcourtman c0bbed1c59 test(frontend): branch-coverage tests for 19 more pure frontend modules
Wave 2 of coverage_backlog_2026-07-11 (items 17-35): new *.branchcov.test.ts
covering top uncovered-branch functions in patrolRunPresentation,
infrastructureSelectors, resourceDetailDiscoveryModel, thresholdsResourceModel,
infrastructureSummaryCache, monitoredSystemPresentation, connectionsTableModel,
activeTurnStatus, resourceStoragePresentation, storagePoolDetailPresentation,
cephSummaryPresentation, settingsNavigationModel, workloadMetricHistoryModel,
resourceCorrelationPresentation, recoveryItemTypePresentation,
setupCompletionModel, storagePageState, discoveryPresentation, searchQuery.
GLM-authored, verify-gated: vitest (888 tests) + full type-check + eslint +
adversarial GLM review (KEEP 19/19). Tests only, no source changes.
2026-07-11 13:05:13 +01:00