Kubernetes workloads are grouped by their Helm instance label into
applications, each offering what is worth backing up: data volumes, a
PostgreSQL dump instead of the database's own volume, and optionally the
namespace manifests. Caches are listed but not preselected. Host
applications come from running systemd services that declare a state or
working directory. Selecting components creates one strategy each.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The call site still deserialized into a struct whose serde alias breaks
on Docker Hub, which sends token and access_token; every Hub image
therefore reported that no token was returned. The integration test now
answers with both fields so the call site is covered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Docker Hub answers with both token and access_token, which made the
serde alias fail as a duplicate field, so every Hub image reported that
no token was returned. Candidates now also have to match the shape of
the running tag; cert-manager v1.14.5 was otherwise offered an upgrade
to the build id 608111629.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gitea publishes thousands of tags; the client stopped after ten pages of
200 and never saw a version newer than the running one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Container findings now name the workloads that run the image and link
into the Kubernetes view, which highlights them. An update check asks the
registry for newer tags of the same variant, scans the newest one and
records which of the open findings are gone in it. The image row then
shows the candidate tag, how many findings it fixes and how many remain,
marks those CVEs in the expanded list, and offers to roll every workload
over to it. The check runs as a job, nightly for all running images or on
demand for one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The findings table listed every CVE, which is thousands of rows on a real
host. It now shows one row per affected package (host) or image
(containers) with its severity split, how many findings it has and how
many of them have a fix. Clicking a row loads and shows the CVEs of that
group; collapsing keeps them cached.
The rollup is a GROUP BY in SQLite behind a new groups endpoint, so the
page loads a few dozen rows instead of the full finding list, and the
flat list gained a package filter to expand one group.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A rescan only touched the timestamp of findings it had seen before, so a
newly published fix version, a changed severity and the package source
never reached existing rows. The repository now updates those fields
while keeping first_seen and the status the user set.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The findings of the Debian host (OS packages and applications found in the
root filesystem) and of the container images in the cluster were mixed in
one flat table. They are now two prominent categories: a card each with its
own severity split and target count, acting as the primary selector, and a
table that adapts to the selection. Host findings show the package source
reported by the scanner (debian, gobinary, node-pkg …) instead of the
target, container findings show the image.
Backend: findings carry the scanner's package source, the list endpoint
takes ?scope=host|container, and the targets endpoint reports each target
with its category and open count.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dev fixtures only had short package and version strings, so the
layout tests never exercised the widths that made the real findings
table overflow.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SMB (smbclient) and FTP/FTPS (curl with netrc) targets with encrypted
credentials and connection test; strategies with cron schedule, retention,
optional openssl AES-256 encryption; sources: PVC hostpath tar, pg_dumpall
in the Postgres pod, namespace manifests, host directory. Backup job
collects, encrypts, uploads, verifies size, records sha256 and applies
retention on the target; scheduler starts due strategies. Backups page
with target/strategy forms, run now and history. Restore guide in docs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Trivy scanner still had unimplemented stubs, which panicked the scan
task in the deployed test instance and left the run in 'running' forever.
JobRunner now runs handlers in their own task and marks a panic as a
failed run; on startup runs left 'running' by a previous process are
marked failed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
kube-rs gateway (nodes, namespaces, deployments/statefulsets/daemonsets with
images, PVCs; rollout restart, scale, set image via patches) using the
microk8s kubeconfig by default, fake gateway for dev, /api/cluster routes,
Kubernetes page with node cards, workload table with admin actions and PVC
list. Also implements the streaming command runner that WP-11 relied on.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
package_upgrade job streams apt-get output into the job log (streaming
CommandRunner, DebianUpdater with dist-upgrade or --only-upgrade), refreshes
the inventory afterwards and flags reboot-required. POST /api/system/upgrade
(admin), package name validation, selectable package table with confirm
dialog and live log on the Updates page. Fake updater for dev.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
AES-256-GCM secret storage keyed by MASTER_KEY, SMTP settings with test mail
(lettre), persisted job runs with log and status, JobRunner with per-kind
concurrency guard, 6-field cron schedules with defaults, scheduler loop.
Settings and Jobs pages in the UI. FAKE_HOST mode for dev machines.
Tests: 30 application, 8 infrastructure, 23 API, 16 Vitest, 6 Playwright.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>