Commit Graph
58 Commits
Author SHA1 Message Date
mrhid6 aa1c8e4aa1 feat: Hide secrets on api and channels
Chart Release / chart (push) Successful in 15s
Server Deploy / deploy (push) Successful in 8m5s
2026-08-14 12:23:36 +00:00
mrhid6 a0fbf5b9ba fix: Word and colour Windows workloads correctly across the UI
Server Deploy / deploy (push) Canceled after 0s
Chart Release / chart (push) Canceled after 0s
Agent Release / build (push) Successful in 14m1s
Agent Release / msi (push) Successful in 1m22s
2026-08-13 12:57:37 +00:00
mrhid6 36848a519a feat: Word the workload and update panels for Windows servers 2026-08-13 12:16:10 +00:00
mrhid6 182752d9ab feat: Manage API tokens from settings
A card in the Access group beside Members and single sign-on rather than a
new nav entry — /settings/instance was folded back in for exactly this
reason. The plaintext is shown once in a well block and never again.

Tokens outside a newly tightened lifetime policy are flagged rather than
broken, because the policy governs issuance, not existing credentials.
2026-08-12 14:58:57 +00:00
mrhid6 524ccc6412 feat: Add the API token endpoints
Create, list and revoke, with no update: editing what a credential already
deployed in CI can do, with no record of what it could do before, is worse
than requiring a rotation. Revoking a token that is not yours answers
not-found, since a 403 confirms it exists.

The audit actor stays the human and names the credential alongside, so a
person clicking and their CI job are told apart.
2026-08-12 14:44:50 +00:00
mrhid6 675689a458 feat(audit): server-side paging, search and category filter; one event format
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 8m2s
The page rendered a map of eleven event types to labels and seven to colours.
The server emits forty-seven. Everything unmapped fell through to its raw
string, so "Key Assigned" in green sat above "workflow.schedule_updated" in
grey — the same kind of fact in two formats, which made the column look like it
carried a meaning it did not.

Presentation is now derived rather than enumerated. Event types are named
<category>.<action> by every call site, so the category becomes a chip, the
action is humanised, and the tone comes from the verb. A type added to the
server tomorrow gets a sensible label and colour with no second list to update;
the override table holds only the dozen the rule reads badly for. Every row is
one treatment, and colour never carries meaning alone — the sentence beside it
says the same thing in words.

Paging and filtering are server-side, unlike the fleet lists that answer with
everything and slice in the browser. audit_retention_days is a licensed
entitlement measured in months, and this log is read to answer questions about
the past, so a browser filtering the most recent page would report "no results"
for events that exist. GET /api/audit now takes q, category, limit and skip and
answers {events, total} — a short page is not evidence of the end of the log,
which is why the total is counted rather than inferred.

audit_logs had no indexes at all: every read was a collection scan with an
in-memory sort over an append-only collection. Adds (instance_id, created_at)
and warns rather than failing, matching EnsureSecretIndexes.

Two bugs found by running the deriver over all forty-seven real types rather
than eyeballing it: the tone rules matched only past-tense verbs, leaving
auth_provider.delete drawn as neutral beside key.deleted in red; and
"unaccepted" matched "accepted", so withdrawing an acceptance read as the same
caution as granting one.
2026-08-10 15:25:48 +01:00
mrhid6 4d67341ba5 feat(web): fleet search and sort, shared empty/error states, no background polling
The fleet list had a tag filter and nothing else: no search, no sort, and an
unbounded list. Searching hostname/address/OS and sorting by hostname, status
or last seen are all client-side, since the browser already holds the fleet
the page just fetched. Sorting by status orders by how much attention each
state wants rather than alphabetically, which is the only reason to sort by it.

The filtered count is shown beside the total so a search does not read as the
fleet having shrunk, and "no results" is a distinct empty state from "no
servers", with a way back out of the search.

refetchIntervalInBackground defaults to false on the query client. Polling
pages kept refetching in a hidden tab — the fleet list pulls inventory blobs
every 30s — so a console left open in a background tab polled until its
session expired. It belongs in the defaults because the argument is identical
on every polling page.
2026-08-10 09:35:39 +01:00
mrhid6 e28238191d feat: Added vuln filter
Chart Release / chart (push) Successful in 25s
Server Deploy / deploy (push) Successful in 2m29s
2026-08-07 11:58:42 +01:00
mrhid6 483053b9a2 feat: workload registry UI 2026-08-07 09:06:36 +01:00
mrhid6 d1769fc886 feat: Updated vuln style
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 1m36s
2026-08-06 16:35:04 +01:00
mrhid6 84dfcfeac7 feat: vulnerability findings UI
Fleet board grouped by CVE, a per-server section on server detail, and
alert rules beside the channels they consume.

The server detail page has no tab pattern despite the plan saying to
follow one, so this adds a section in the existing vertical stack.

Three states are kept visually distinct because they are identical if
handled carelessly and only one is good news: never reported, no advisory
feed for the distribution, and scanned-and-clean. Database freshness sits
with the findings rather than in settings for the same reason.
2026-08-06 14:40:37 +01:00
mrhid6 50a9ac5fdc fix: count tag-matched servers in the workflows list 2026-08-04 17:28:01 +01:00
mrhid6 439bc2ed7d feat: schedule methods on the web api client 2026-08-04 14:10:04 +01:00
mrhid6 fa1fd14ed1 feat: view and edit server tags 2026-08-04 13:38:42 +01:00
mrhid6 1f08e90009 feat: Removed email alert settings
Chart Release / chart (push) Successful in 10s
Server Deploy / deploy (push) Successful in 5m15s
2026-08-03 14:40:15 +01:00
mrhid6 37f2c1457e feat: manage multiple sign-in providers from settings 2026-08-03 11:00:25 +01:00
mrhid6 3a626922a5 feat: render one login button per configured auth provider 2026-08-03 10:56:03 +01:00
mrhid6 1eb98ef962 feat: Better debugging for console
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 1m22s
2026-07-31 15:51:26 +01:00
mrhid6 766dcabfde fix: Fixes to the console focus
Server Deploy / deploy (push) Successful in 43s
2026-07-28 12:02:48 +01:00
mrhid6andClaude Opus 5 c4e6ad5485 feat(license): metered licensing — catalogue, entitlements, and enforcement
Server Deploy / deploy (push) Successful in 5m22s
Implements spec 7 tasks 2-10 on top of the six-plan payload from task 1.

Admin: plans re-keyed on (deployment, tier); new catalogue collection holds
every Paddle price ID (one row per priceable component); new entitlements
collection holds desired beside granted. admin/internal/catalogue owns both
folds — entitlement to licence limits, and entitlement to Paddle line items —
so the base allowance is subtracted in exactly one place. licensing.Issue now
snapshots the instance's granted entitlement, never desired. Free is enforced
per account AND deployment. Staff endpoints for plans, catalogue and
entitlements; Free self-hosted can be claimed and renewed on its annual term;
the reaper stays cloud-only.

Server: enforces the monitor cap, audit-log retention (daily sweep, skips
Unlimited and lapsed instances), and gates the OIDC callback. Unset limits are
filled from the seed plan at the single decode site so old blobs never read as
zero.

Frontends: adminsite gains a catalogue price-ID editor, six-plan allowance
screen, and a catalogue-driven PlanConfigurator mounted on the staff instance
page. web shows monitors, audit retention and support level on the licence page.

Docs: CLAUDE.md, spec index and plan 5 preamble updated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 09:37:39 +01:00
mrhid6 dd306e4757 feat(license): the paste form is self-hosted only
Server Deploy / deploy (push) Successful in 2m14s
A cloud instance's licence is issued in HQ and written into the control
plane by admin/internal/inject, straight to the database. The customer has
nothing to paste, so /settings/license offered them a form that could only
ever fail — and on an expired cloud instance, failed at the exact moment
they were looking for a way out.

GET /license now reports `deployment`, and the page swaps the paste form
for a short panel saying where the licence comes from, with a link to the
portal when HQ_URL is set. That is the same treatment hq-managed members
already get in the members table: read-only here, and a pointer to where
it is actually managed.

POST /license refuses with 409 cloud_managed on a cloud deployment. Hiding
a form is a courtesy; this codebase's rule is that the API is the boundary,
and the endpoint was reachable regardless of what the page rendered. It
cannot break injection, which never goes through HTTP at all.

Verified: server builds and vets clean, web builds clean.
2026-07-26 20:42:53 +01:00
mrhid6andClaude Opus 5 7b077905e2 feat(web): hq-sourced members are read-only here
Server Deploy / deploy (push) Successful in 2m56s
The lock is a courtesy — the API answers 409 either way. NEXT_PUBLIC_HQ_URL
defaults empty so a self-hosted install shows a plain label rather than a
link to a portal that does not serve them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 16:42:47 +01:00
mrhid6 8626898e5e feat(web): licence banner, settings page and feature gating 2026-07-24 15:25:29 +01:00
mrhid6 ee4dff09c9 feat: show the instance ID after setup 2026-07-24 15:20:00 +01:00
mrhid6 b70ccc97d4 refactor(web): rename Organisation to Instance 2026-07-24 14:01:19 +01:00
mrhid6 a6030ef62f feat: Updated logo
Server Deploy / deploy (push) Successful in 3m51s
2026-07-24 10:31:11 +01:00
mrhid6 e798365be2 feat: Removed comments
Server Deploy / deploy (push) Failing after 1m13s
2026-07-24 09:56:54 +01:00
mrhid6 aa31cd8a10 fix: validate roles, guard last owner, scope bootstrap status
Security review of e70b2f0. The UI gating was correctly backed by
RequireRole everywhere; these are the missing validation gaps behind it.

- UpdateUserRole and createOrgUser accepted any role string verbatim, so
  an admin could self-promote to owner, create an owner outright, or set
  a junk role that silently stripped a user's access. Roles are now
  whitelisted, only an owner may grant or remove the owner role, and an
  actor cannot change their own.
- Neither demote nor delete guarded the last owner, so an org could reach
  zero owners. Both now refuse when no owner would remain, returning 409.
  Self-delete rejected.
- CountUsers counted across all orgs, so a locked-out org could never
  re-bootstrap once another tenant existed, and the unauthenticated
  bootstrap-status endpoint reported instance-wide state. It now answers
  per-org on an org host, falling back to global only on the apex.
- HandleMe repeats the middleware's host/org check; it sits outside the
  middleware so it can still return its own 401.
- Post-bootstrap now sends the new owner to their org host's login page.
  The session cookie is deliberately scoped to the exact host, so the old
  redirect landed them unauthenticated.
- AuthProvider renders an error state instead of mounting the shell with
  a null user when /auth/me fails for a reason other than 401.
- api.ts unwraps {"error": ...} so these messages render as text.
2026-07-22 10:26:21 +01:00
mrhid6 e70b2f0e67 feat(web): login, first-run setup, org settings; org-aware AuthProvider
- Route group (app) holds AuthProvider + Sidebar, so /login and /setup
  render without app chrome and never mount the provider.
- AuthProvider drops the removed auth_enabled flag and exposes
  {user, org, isAdmin}.
- New login page (password + SSO), first-run setup page, and org settings
  page with a members table and the OIDC provider form.
- Settings page and the Organization nav entry are gated on role, since
  /api/settings now 403s for members.
- GET /api/org/oidc gains client_secret_set so the UI can show whether a
  secret is stored; the secret itself is still never serialized, and an
  empty submitted value still means "keep the stored one".
- Fix logout: the sidebar linked to /auth/logout with a GET, but the route
  is POST-only, so logout was 404ing.
2026-07-22 10:17:12 +01:00
mrhid6 0464c540b2 feat: edit monitors + notification channels; HTTP monitor insecure-TLS option
Server Deploy / deploy (push) Successful in 2m9s
Agent Release / build (push) Successful in 10m39s
Agent Release / msi (push) Successful in 35s
2026-07-21 14:55:41 +01:00
mrhid6 df6f8b6f62 feat(web): notification channel settings UI
Server Deploy / deploy (push) Successful in 1m24s
2026-07-21 14:24:38 +01:00
mrhid6 57151826ae feat(web): monitors list/detail/form UI
Server Deploy / deploy (push) Successful in 2m1s
2026-07-21 14:16:08 +01:00
mrhid6 ca2c05db14 feat(web): inventory panel on server detail
Server Deploy / deploy (push) Successful in 41s
2026-07-21 14:08:36 +01:00
mrhid6 67d729b360 feat(web): api.stepUsage binding 2026-07-21 11:36:03 +01:00
mrhid6 b543cd1b3d feat(web): api client for step import/export/inline/defaults 2026-07-21 10:28:41 +01:00
mrhid6 39348c9491 feat(web): live SSE log tail and log retention setting
Server Deploy / deploy (push) Successful in 1m35s
2026-07-20 15:18:36 +01:00
mrhid6 78194daf5f feat(web): builder tokens, Modal primitive, input-param types 2026-07-20 14:40:07 +01:00
mrhid6 6f478eb817 feat(web): workflow API client types and methods 2026-07-20 11:44:10 +01:00
mrhid6 c3c58581cc fix: Fixed scale and mouse handler
Server Deploy / deploy (push) Successful in 1m38s
2026-07-20 09:49:20 +01:00
mrhid6 c558b81471 fix: Fixed keyboard disconnect
Server Deploy / deploy (push) Successful in 41s
2026-07-20 09:42:07 +01:00
mrhid6 963fa9c877 fix: Fixed mouse position on console
Server Deploy / deploy (push) Successful in 39s
2026-07-20 09:36:57 +01:00
mrhid6 a02747d02e fix: Fixed console resolution
Server Deploy / deploy (push) Successful in 44s
2026-07-20 09:30:44 +01:00
mrhid6 d31486ae1b fix: Fixed agent windows version
Server Deploy / deploy (push) Successful in 1m28s
Agent Release / build (push) Successful in 10m34s
Agent Release / msi (push) Successful in 57s
2026-07-17 15:38:00 +01:00
mrhid6 2b4611f7ac feat: added windows install script to ui
Server Deploy / deploy (push) Successful in 1m20s
2026-07-17 14:40:00 +01:00
mrhid6 763eafa4f8 fix: Fixed guac connection
Server Deploy / deploy (push) Successful in 1m22s
2026-07-17 13:40:54 +01:00
mrhid6 a9d602d021 feat: harden console sessions + complete protocol support
Server Deploy / deploy (push) Failing after 1m9s
Agent Release / build (push) Successful in 1m52s
Agent Release / msi (push) Failing after 52s
- single-use session tokens (atomic ConsumeSessionToken) + user-bound tunnel (actor must match session opener)
- wire VNC end-to-end (stash/consume password, connect+tunnel, frontend password field)
- passphrase-protected SSH keys: passphrase_enc on Key model, capture on upload, decrypt + pass to guacd
2026-07-17 12:19:07 +01:00
mrhid6 1ad5b5d6db fix: send ssh username to guacd (default root) for console SSH 2026-07-17 11:54:33 +01:00
mrhid6 50907448d2 feat: web console page with protocol + key selection
Includes web/lib/api.ts changes (console_protocols field, connectConsole
method) required for the console page to type-check and build; the task
brief's commit file list omitted this file.
2026-07-17 11:45:19 +01:00
mrhid6 38c51e5a3e feat: vendor guacamole-common-js and console wrapper 2026-07-17 11:42:44 +01:00
domrichardson 19596ff2a3 feat: Secret management
Server Deploy / deploy (push) Successful in 1m33s
2026-07-03 10:37:43 +01:00