100 Commits
Author SHA1 Message Date
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 6dced22499 fix: Fixed agent collect packages
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 21s
Agent Release / build (push) Successful in 58s
Agent Release / msi (push) Successful in 1m34s
2026-08-06 16:20:34 +01:00
mrhid6 5cee53dc5f feat: Better button description
Chart Release / chart (push) Successful in 20s
Server Deploy / deploy (push) Successful in 2m23s
2026-08-06 15:51:18 +01:00
mrhid6 81248bb159 style: bring the vulnerabilities page onto the house page shape
Every other page under app/(app) opens with `p-4 sm:p-6 lg:p-8` and the
layout adds none of its own, so this page alone sat flush against the shell
edge. Its h1 was text-xl where every other page is text-2xl.

The findings list was a stack of separately bordered cards; it is now rows
inside one Card, separated by border-border-soft, matching the monitors and
workflows lists. Loading is the shared spinner rather than a line of text,
the error is the shared danger strip, and the empty state uses the same
proportions as the monitors one.
2026-08-06 15:49:39 +01:00
mrhid6 6354d54de8 feat: added addon price to pricing page 2026-08-06 15:48:20 +01:00
mrhid6 da6d64f95c fix: give the scratch server image a /tmp for the vulnerability database
The runtime stage is FROM scratch, which has no /tmp, so vulnsched died at
startup with "temp dir: stat /tmp: no such file or directory" and no scan
ever ran. Nothing in the server wrote to a temporary directory before the
trivy-db puller, which is why this only appeared now.

scratch cannot mkdir its own, so the directory is staged in the builder at
1777 and copied in. Also corrects CLAUDE.md, which described this image as
Alpine; the time/tzdata import it justifies is if anything more load-bearing
on scratch.
2026-08-06 15:46:30 +01:00
mrhid6 9ba3d4a61f feat: Vulnerability Scanning feature on license page
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 1m20s
2026-08-06 15:40:13 +01:00
mrhid6 eee236a072 fix: tidy server go.mod for the vulnerability database dependencies
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Canceled after 2m11s
trivy-db, oras-go, the three version comparators and robfig/cron were
recorded as indirect with an incomplete go.sum, which builds locally
against a warm module cache but fails in CI with "updates to go.mod
needed". trivy-db pulls testify into the build graph, and its hashes
were missing entirely.
2026-08-06 15:18:57 +01:00
mrhid6 9df89e2db4 fix: surface vuln_scanning across licence, staff and pricing UI
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Canceled after 59s
The catalogue row alone was not enough; the feature was invisible in
three places and mislabelled in a fourth.

PlanConfigurator rendered every key that was not "console" as "Single
sign-on", so the staff checkbox granting vulnerability scanning was
labelled single sign-on. Feature wording was duplicated between the staff
configurator and the purchase form and the copies had drifted, so it now
lives in adminsite/lib/features.ts and both read from it.

The customer licence panel showed raw keys; it now labels them.

Pricing gains a comparison row. The add-on block with a monthly price is
deliberately NOT added: that is a pricing decision, and the Paddle price
IDs for the new catalogue rows have to be pasted in before it can be sold
anyway.
2026-08-06 15:10:26 +01:00
mrhid6 f60c509b47 feat: vuln_scanning entitlement and documentation
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Failing after 1m11s
Agent Release / build (push) Successful in 1m0s
Agent Release / msi (push) Successful in 2m18s
Adds license.FeatureVulnScanning as the one name for the feature and a
catalogue row per deployment/tier, following console and oidc: features
are opt-in per customer, so no plan bundles it.

Documents the subsystem in CLAUDE.md, including that ScopedCollections is
the canonical registry instance deletion derives from — there is no
separate deletion list, which the plan had wrong.
2026-08-06 14:44:11 +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 5dda3b5c4a feat: vulnerability scanning pipeline, matcher, scheduler and API
Completes tasks 10-15 and fixes what was outstanding:

- vulndb.Pull implemented with oras-go, streaming the ~50MB layer and
  staging both files before replacing either, so a failed pull leaves the
  previous database intact rather than a half-written one.
- db.go: Vulnerability.Severity is a string, not trivy Severity, so the
  int conversion did not compile. Severity now resolves vendor (highest
  when vendors disagree) then NVD then unknown, and CVSS is read too.
- findings.go: added sweepFixedFindings plus the fleet query, severity
  counts, rescan flag and accept/unaccept the API needs.
- vulnrules.go: added rule CRUD and the digest builder. ResolveTargets
  returns []models.Server, not []string, so filterByServers was wrong.
- api/vulnerabilities.go was an empty file while handlers.go registered
  twelve routes against it; written, grouped by CVE.
- shared/mail: added the missing sender. The templates were orphaned and
  the HTML one was a copy of the text one, defining "subject" (which
  html/template would escape) and emitting no markup. render.go parses
  every template in init(), so a bad one panics server, admin and sitesvc
  at boot — go build never runs init(), which is why nothing complained.
- notify: digests dispatch through their own path so SMTP gets the digest
  template rather than arriving dressed as a monitor alert.
2026-08-06 14:33:46 +01:00
mrhid6 db64320bd8 feat: agent reports installed packages on the hourly loop
SyncKeys now returns the whole response so the poll can carry
CollectPackages; a separate RPC for one boolean would be a message every
30 seconds for a value that changes when a licence does.

The flag is an atomic: the 30s poll writes it, the hourly package loop
reads it, and they are different goroutines.
2026-08-06 13:21:13 +01:00
mrhid6 583f60771c feat: store agent package reports and serve the collect flag
VulnScanningEnabled reads GetLicenseState(...).Feature("vuln_scanning")
and requires an active licence, never switching on tier. ReportPackages
re-checks it server-side: the agent flag is the optimisation, this is
the boundary.
2026-08-06 13:19:39 +01:00
mrhid6 a92c3190c2 feat: ReportPackages wire types with hash short-circuit
The pb packages are hand-written, not protoc-generated, and the wire
codec is JSON (encoding.RegisterCodec(JSONCodec{})). Field numbers in
the .proto are documentation; JSON field names are the contract. Both pb
packages edited by hand to match.

SyncResponse.collect_packages is omitempty and absent decodes as false,
so an older server leaves agents collecting nothing rather than
collecting without a licence.
2026-08-06 13:17:44 +01:00
mrhid6 3a6d24fe0e feat: models and indexes for package inventory and CVE findings
Adds server_packages, vuln_findings and vuln_alert_rules to
ScopedCollections rather than to a separate deletion list. purgeInstance
derives its collection list from that registry, so instance deletion
follows automatically and there is no second copy to drift.
2026-08-06 11:59:00 +01:00
mrhid6 c277ecff44 feat: agent collects installed packages per package manager 2026-08-06 11:56:41 +01:00
mrhid6 bd690c94c3 feat: agent parses /etc/os-release for distro identification 2026-08-06 11:55:45 +01:00
mrhid6 a22fdf197e feat: map OS family and version to trivy-db advisory buckets 2026-08-06 11:55:01 +01:00
mrhid6 bd24b03cac feat: version comparators for distro package ordering 2026-08-06 11:54:13 +01:00
mrhid6 3afc4ab012 docs: workload registry plan; remove tests from both plans
Both plans now verify by build, vet and manual checks written into the
tasks. Spec verification sections updated to match so they no longer
describe tests that will not be written.
2026-08-06 11:27:37 +01:00
mrhid6 d1ac3e98ce docs: design for the workload registry
Agents enumerate Docker containers, compose stacks and systemd services;
start/stop/restart and bounded log snapshots from the UI.

Sub-project B, Linux only. Live log following stays in the console.
2026-08-06 11:11:26 +01:00
mrhid6 5bba54f3e5 fix: Fixed style layout on workflow run page 2026-08-06 10:50:31 +01:00
mrhid6 fe7bc300e2 docs: implementation plan for package inventory and CVE findings
17 tasks, TDD where the logic is pure. Corrects two spec claims:
the server reads features via License.HasFeature rather than admin's
entitlement directly, and shared/mail/render_test.go does not exist.
2026-08-06 10:49:10 +01:00
mrhid6 00c03c365d docs: design for package inventory and CVE findings
Agents report installed packages; the control plane matches them against
trivy-db and raises findings that link to the existing ApplyUpdatesCmd
patching path.

Scoped to sub-project A, Linux only. Container registry, image scanning
and compliance baselines are separate specs.
2026-08-06 10:33:54 +01:00
mrhid6 dc8dd3dd58 fix: Fixed step descriptions
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 35s
2026-08-04 17:45:31 +01:00
mrhid6 85a8865892 feat: restyle the steps table and add 22 default steps
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 2m46s
2026-08-04 17:34:18 +01:00
mrhid6 50a9ac5fdc fix: count tag-matched servers in the workflows list 2026-08-04 17:28:01 +01:00
mrhid6 3388d2f895 fix: Fixed padding on add step button
Chart Release / chart (push) Successful in 22s
Server Deploy / deploy (push) Successful in 41s
2026-08-04 17:24:40 +01:00
mrhid6 3a77fc2abd feat: edit target servers and tags together in the workflow modal 2026-08-04 17:21:12 +01:00
mrhid6 3d59836d0c feat: dual list box for workflow target servers
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 5m19s
2026-08-04 17:13:50 +01:00
mrhid6 d9184312aa fix: schedule card placement, preview state, and scheduled-workflow docs 2026-08-04 17:08:11 +01:00
mrhid6 b9802e6b04 docs: Updated docs 2026-08-04 17:03:29 +01:00
mrhid6 c2635ed51a fix: Fixed schedule workflow col
Chart Release / chart (push) Successful in 20s
Server Deploy / deploy (push) Successful in 41s
2026-08-04 14:42:10 +01:00
mrhid6 b21ac05547 feat: show workflow schedules in the list
Chart Release / chart (push) Successful in 24s
Server Deploy / deploy (push) Successful in 2m34s
2026-08-04 14:16:13 +01:00
mrhid6 484b620867 feat: schedule editor on the workflow page 2026-08-04 14:13:31 +01:00
mrhid6 439bc2ed7d feat: schedule methods on the web api client 2026-08-04 14:10:04 +01:00
mrhid6 a1e6986a64 feat: fire scheduled workflow runs from the housekeeping leader 2026-08-04 13:53:42 +01:00
mrhid6 d0e1cc4ad6 feat: cron arithmetic and persisted workflow schedules 2026-08-04 13:51:10 +01:00
mrhid6 b877024365 docs: server tags and workflow tag targeting 2026-08-04 13:44:16 +01:00
mrhid6 2de7ac116b feat: filter the fleet by tag and target workflows by tag selector 2026-08-04 13:42:47 +01:00
mrhid6 fa1fd14ed1 feat: view and edit server tags 2026-08-04 13:38:42 +01:00
mrhid6 d1b3cd2f74 feat: target workflow runs by tag selector 2026-08-04 13:36:43 +01:00
mrhid6 e00a0da5d9 feat: tag endpoints for servers 2026-08-04 13:34:22 +01:00
mrhid6 fef0b7c7a1 feat: read and write server tags, resolve targets from the database 2026-08-04 13:33:00 +01:00
mrhid6 efd29dc259 feat: parse tag filters and resolve targets as ids union tag selector 2026-08-04 13:31:04 +01:00
mrhid6 13cd41d202 feat: validate server tags and add the model field 2026-08-04 13:30:06 +01:00
mrhid6 3530ce6cb7 docs: implementation plans for server tags and scheduled workflows 2026-08-04 13:26:04 +01:00
mrhid6 09522c2566 docs: design for server tags and scheduled workflows 2026-08-04 13:13:12 +01:00
mrhid6 80f0afb28b feat: Updated monitors pages
Chart Release / chart (push) Successful in 13s
Server Deploy / deploy (push) Successful in 1m25s
2026-08-04 12:19:15 +01:00
mrhid6 287bd9657b fix: Fixed paddle relink sub
Chart Release / chart (push) Successful in 27s
Server Deploy / deploy (push) Successful in 1m17s
2026-08-03 17:34:39 +01:00
mrhid6 b5f684c4fe fix: Fixed paddle subs
Chart Release / chart (push) Successful in 28s
Server Deploy / deploy (push) Successful in 1m17s
2026-08-03 15:32:01 +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 6881d92d0a fix: local-login toggle no longer reverts unsaved settings edits
Chart Release / chart (push) Successful in 26s
Server Deploy / deploy (push) Successful in 4m8s
server/internal/services/settings.go SaveSettings takes alerts and
email as required (non-pointer) values and writes them unconditionally
- absent fields would blank stored settings, not just leave them
alone. onLocalLoginChange was building its payload from the stale
loaded settings object instead of the in-progress form state
(thresholdMinutes/logRetentionDays) that handleSubmit uses, so editing
the offline threshold and then flipping the toggle silently reverted
the edit. Both paths now submit the same in-progress values.
2026-08-03 14:13:05 +01:00
mrhid6 5e016c6584 fix: audit ack_notice and stop misreporting DB errors as lockouts
ackAuthProviderNotice mutated callback_notice with no audit event; it
now writes auth_provider.ack_notice like create/update/delete.

guardProviderChange's callers turned any error from
CountEnabledAuthProviders into a 409 last_provider, so a transient
Mongo error was reported to the operator as an unremovable lockout.
Only services.ErrLockout now produces the 409; anything else is a 500.
2026-08-03 14:12:21 +01:00
mrhid6 537b8758ff fix: purge auth_providers when reaping an instance
auth_providers was missing from ScopedCollections, so reap.go's
scopedCollectionsForPurge() (derived from that list) never deleted an
instance's providers, leaving orphaned rows holding encrypted client
secrets forever. Verified migration 0004's $rename over org_id->instance_id
is a no-op here since auth_providers never carried org_id.
2026-08-03 14:11:42 +01:00
mrhid6 c03360333b fix: single source of truth for local-login lockout rescue
HandleLocalLogin and HandleListPublicProviders each computed their own
answer to whether password sign-in must stay available, and they could
disagree: an instance with local login off and a licence that lapses
loses its only provider and its password form in the same moment, with
no endpoint left to recover. services.LocalLoginPermitted is now the
one predicate both call.
2026-08-03 14:11:22 +01:00
mrhid6 fa7c5d341d docs: fix stale auth-provider references in rest-api and licensing docs 2026-08-03 11:08:22 +01:00
mrhid6 b6fc8c3f77 docs: document multiple auth providers and the callback URL change 2026-08-03 11:05:40 +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 dde47de145 feat: auth provider REST API and public provider discovery 2026-08-03 10:51:35 +01:00
mrhid6 f3b9f6f286 feat: add GitHub OAuth2 provider branch 2026-08-03 10:48:19 +01:00
mrhid6 f1c3f67864 feat: per-provider SSO start and callback routes 2026-08-03 10:45:23 +01:00
mrhid6 8f5873afca refactor: carry provider id in the OIDC state token 2026-08-03 10:41:30 +01:00
mrhid6 e22faebfcd feat: migrate instance_oidc into auth_providers (0005) 2026-08-03 10:38:52 +01:00
mrhid6 e2b01b62a5 feat: add local_login_enabled setting with absent-means-on default 2026-08-03 10:36:48 +01:00
mrhid6 0858693d57 feat: add auth provider service layer and lockout guard 2026-08-03 10:33:36 +01:00
mrhid6 45f7c0c393 feat: add AuthProvider model and identity provider presets 2026-08-03 10:30:21 +01:00
mrhid6 c56bfb7270 docs: implementation plan for multiple auth providers 2026-08-03 10:23:35 +01:00
mrhid6 eb45072031 feat: Removed unused test units 2026-08-03 10:18:01 +01:00
mrhid6 1e2132c1a1 docs: Cleanup old specs and plans 2026-08-03 10:15:54 +01:00
mrhid6 19ef773690 docs: drop legacy OIDC callback from multi-provider design 2026-08-03 10:13:26 +01:00
mrhid6 c5aae0614a docs: design for multiple auth providers 2026-08-03 10:09:13 +01:00
mrhid6 17d97aaf52 feat: More logging for command stream
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 1m24s
Agent Release / build (push) Successful in 10m37s
Agent Release / msi (push) Successful in 36s
2026-07-31 17:20:35 +01:00
mrhid6 1fb9bd827f feat: Added ping command
Chart Release / chart (push) Successful in 18s
Agent Release / build (push) Successful in 39s
Server Deploy / deploy (push) Successful in 55s
Agent Release / msi (push) Successful in 40s
2026-07-31 17:10:59 +01:00
mrhid6 8699dc5b7e fix: Renew presence on sub/pub
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Successful in 56s
2026-07-31 16:58:50 +01:00
mrhid6 71240f183c fix: Fixes to server shutdown stream
Chart Release / chart (push) Successful in 21s
Server Deploy / deploy (push) Successful in 1m2s
Agent Release / build (push) Successful in 43s
Agent Release / msi (push) Successful in 49s
2026-07-31 16:44:47 +01:00
mrhid6 01e8b0ba44 feat: Better debugging for console
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 1m25s
2026-07-31 16:31:19 +01:00
mrhid6 2aa4784518 feat: Better debugging for console
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Successful in 59s
2026-07-31 16:13:51 +01:00
mrhid6 f611cae438 feat: Better debugging for console
Chart Release / chart (push) Successful in 11s
Server Deploy / deploy (push) Successful in 1m22s
2026-07-31 16:00:58 +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 6f86496f10 fix: Ffixes to console
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Successful in 1m9s
2026-07-31 15:05:21 +01:00
mrhid6 57a9b18102 fix: Guacd connection ip
Server Deploy / deploy (push) Successful in 9s
Chart Release / chart (push) Successful in 11s
2026-07-31 14:52:20 +01:00
mrhid6 36995fa62b fix: Fixed install and update scripts
Chart Release / chart (push) Successful in 9s
Server Deploy / deploy (push) Successful in 1m20s
2026-07-31 12:10:32 +01:00
mrhid6 9121fc461f fix: Fixed chart api routes for update
Server Deploy / deploy (push) Successful in 15s
Chart Release / chart (push) Successful in 10s
2026-07-31 12:03:45 +01:00
mrhid6 fc56bae5f9 chore: Bump chart version
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Successful in 8s
Agent Release / build (push) Successful in 38s
Agent Release / msi (push) Successful in 57s
2026-07-31 11:53:08 +01:00
mrhid6 ac75b3ef76 feat: chart deployment Type added
Chart Release / chart (push) Successful in 20s
Server Deploy / deploy (push) Successful in 35s
2026-07-31 11:52:31 +01:00
mrhid6 e6fe463216 feat: Updated for api ingress routes
Chart Release / chart (push) Successful in 25s
Server Deploy / deploy (push) Successful in 4m26s
2026-07-31 11:21:15 +01:00
mrhid6 8528f14ed7 feat: Added ingress to chart
Chart Release / chart (push) Successful in 10s
Server Deploy / deploy (push) Successful in 1m24s
2026-07-31 10:49:20 +01:00
mrhid6 df1d9658f5 fix: Chart build
Chart Release / chart (push) Successful in 10s
Server Deploy / deploy (push) Successful in 1m20s
2026-07-31 10:41:41 +01:00
mrhid6 9f9b384481 fix: Fixed chart version
Chart Release / chart (push) Failing after 13s
2026-07-31 10:37:04 +01:00
mrhid6 165114471f fix: Fixes to running on kubernetes
Chart Release / chart (push) Failing after 13s
Server Deploy / deploy (push) Successful in 6m35s
2026-07-31 10:34:10 +01:00
mrhid6 de78688093 feat: authenticate the server's Redis connection
InitRedis now takes a username and password, read from REDIS_USERNAME and
REDIS_PASSWORD, matching what admin has always done. Both empty keeps an
unauthenticated Redis working; a password with an empty username is what a
legacy requirepass instance needs, since go-redis then sends AUTH with one
argument instead of two.

This is what lets a Kubernetes install point at a managed Redis instead of
the bundled one.
2026-07-31 09:36:31 +01:00
mrhid6 bbf9f72fd3 feat: Docker and helm charts
Server Deploy / deploy (push) Successful in 5m26s
Agent Release / build (push) Successful in 10m45s
Agent Release / msi (push) Successful in 1m31s
2026-07-31 09:28:54 +01:00
mrhid6 978b665aa6 fix: stop local relay teardown from logging a spurious proxy_failed reason
Session.Close now closing its own accepted conn (from the prior fix wave)
made net.ErrClosed on the guacd-side reader indistinguishable from a real
remote failure, so a normal browser-tab close could race the handler's
defer and intermittently log console.proxy_failed on a healthy session.
Add a closing flag, set before Close's sync.Once body actually tears
anything down, that setReason respects -- a deliberate local teardown can
no longer produce or race in a failure reason, while Close's own explicit
reason argument still wins normally.
2026-07-31 09:25:27 +01:00
mrhid6 1fe608f531 fix: bound and complete console relay teardown, restore proxy_failed audit
- Arm the unclaimed-relay watchdog in NewSession rather than Serve, so an
  agent that never opens its ProxyStream is bounded to 10s and reports
  reason "agent_timeout", per the design spec's failure-mode table.
- Session.Close now also closes the accepted net.Conn (stored via setConn),
  so ConsoleProxy.Close() is an unconditional kill of the whole relay chain
  instead of only closing an already-idle listener.
- Emit console.proxy_failed and end the console session from a defer in
  consoleTunnel guarded on relay.Reason(), since guac's OnDisconnect never
  runs when the connect callback errors -- which is the path every relay
  failure this feature introduces takes. Update the two docsite
  troubleshooting rows to match what the audit event can now actually show.
2026-07-31 09:21:07 +01:00
mrhid6 1e1546cb60 docs: document the agent-relayed console proxy
Every console session now rides the agent's outbound gRPC connection
instead of a direct guacd-to-target dial, so it works for servers
behind NAT and now requires a live agent (409 agent_offline
otherwise). Documents PROXY_ADVERTISE_HOST / PROXY_LISTEN_HOST and
corrects reachability claims across the docsite and CLAUDE.md.
2026-07-31 09:10:05 +01:00
mrhid6 119d8694d1 feat: Reap admin free instance license 2026-07-30 14:42:06 +01:00
mrhid6 8d43c689f5 feat: Reap admin free instance 2026-07-30 14:31:43 +01:00