Add server-side tracking for asynchronous container operations: introduce ContainerActionJob with RecordActionJob/GetActionJob and update runAsyncContainerAction to acquire a docker client from the registry, run actions in a goroutine, and record pending/success/failure status (callers updated to accept client). Move test bot endpoints into the mutating (ReadOnly) group so they respect read-only mode. Tighten Discord token handling in settings handlers to return 400 if the secret mask is used but no stored token exists.
Improve bot/telegram robustness: fetch container stats concurrently in command handler (with synchronization), add restart mutex around bot restart/config update, and sanitize HTTP errors to mask tokens. Frontend changes: provide a richer Tabs test mock, show "N/A" when history stats are missing to avoid panics, fix uptime sort to use elapsed time, and add aria-labels to container action buttons for accessibility. Also add a test env var for Discord allowed channel in config tests.
Enhance CI to calculate built Docker image size and update README. Updates .github/workflows/docker-publish.yml to ignore Readme.md on triggers, emit an image_size_human output from the build job, build a linux/amd64 image locally (no push) to measure size, and add a commit-readme-image-size job that updates a placeholder marker in Readme.md with the calculated size. The workflow includes safety checks (branch-only conditions, continue-on-error for size steps, remote-branch verification) so README updates won't block image publication. Also adds a README table row containing the <!-- VPS_MONITOR_IMAGE_SIZE_START -->/<!-- VPS_MONITOR_IMAGE_SIZE_END --> markers for automated replacement.
Bump frontend package version to 2.0.0. Update Footer component to improve layout (wrap, spacing) and add Google Play and Apple App Store links with SVG icons and accessible labels; also tidy anchor class ordering. Regenerate/update routeTree to reorder/include the /scan-history route entries (no behavioral change expected beyond regeneration).
Add an observable SBOM job mechanism and integrate it into the UI: introduce useObservedSBOMJobs (with toast and query invalidation on completion), track active SBOM job IDs in ImagesTable, and surface job creation from SBOMDialog via onJobCreated. Make SBOM download robust by parsing Content-Disposition filenames and returning {blob, filename} from downloadSBOMHistoryFile. Improve accessibility and UX in history pages by converting row text to buttons and adding explicit sort buttons with aria-sort. Add frontend test scaffolding (vitest setup, new/updated unit tests) and adjust several React tests. Update scanner DB and handlers to include SBOM format in image SBOM state (schema change, primary key now includes format) and add migration logic; also tighten NewScanDB initialization (file: path + PRAGMAs). Update Go tests to use t and TempDir where appropriate.
Add full SBOM generation and history support across frontend and backend. Frontend: add SBOM link in header, SBOM history route/page and components, SBOM dialog UI improvements (show regen-blocked state, view history), images table SBOM status indicator, API client for SBOM history, new react-query hooks (sbomHistory, sbomHistoryDetail, sbomedImages), types for SBOM results/components, and routeTree entries. Backend: register new SBOM history endpoints (list, detail, images, download, delete) and enforce a regeneration gate that returns 409 when an image is unchanged unless force=true. Wire filename selection for downloads and add handler implementations. Add tests and testdata for SBOM handlers and client changes. Also include query invalidation after SBOM generation so UI updates when new SBOMs are created.
Improve SBOM generation and scan error handling:
- Add syftStreamResult type and syftStreamFailureCause helper to detect stream read errors or non-empty stderr.
- Update runSBOMGeneration to concurrently wait for the syft log stream and container exit, surface stream failures as primary cause, remove partial files on failure, and mark jobs accordingly.
- Add unit tests for syftStreamFailureCause (home/internal/scanner/sbom_test.go).
- Introduce classifyScanFailure to centralize mapping of context/scan errors to job status/messages and use it in runScan; add tests for its behavior.
- Minor import and formatting tweaks.
These changes ensure streaming errors from syft are reported reliably and scan failures are classified consistently.
Multiple fixes and enhancements across the scanner, DB, tests, and docs:
- Surface stream read errors immediately in grype/trivy/syft flows to avoid masking I/O failures behind exit-code messages.
- Improve ringBuffer to handle non-positive capacity, preallocate buffer, and copy trailing bytes to allow GC of large backing arrays.
- Use os.OpenFile with explicit flags/mode when writing log files.
- Make parseIntSetting accept a per-setting default, trim and atoi the value, and return the supplied default for missing/malformed/non-positive values; update DB to pass appropriate defaults.
- Introduce package-level heartbeatTickInterval (default 5s) so tests can shorten the cadence; update heartbeat tests to use a helper and assert progress behavior.
- Test and test helper fixes: countingWriter, file writes check errors, additional assertions, and strengthened manager_test to exercise each env var separately.
- Frontend tests updated for explicit ScannerConfig typing, rename pollInterval to pollIntervalMinutes, add onNewCVEs notification flag, and minor expectations adjustments.
- README: correct docker image reference.
These changes improve error visibility, resource handling, test robustness, and tighten parsing of numeric settings.
Add scannerContainerLogsOptions (enables Follow) and have StreamContainerStdoutToFile use it. Introduce enrichParseErrorForEmptyOutput to wrap EOF parse errors when the scanner produced an empty output file (includes a truncated stderr tail up to 512 chars). Use this helper in RunGrypeScan and RunTrivyScan to provide clearer diagnostics for empty/no-output parser failures. Add tests and helpers (writeDockerLogFrame, delayed-frame test, options test, and enrichParseError tests) and import/time adjustments to validate behavior.
Introduce configurable scanner resource limits and timeouts across frontend and backend. Adds new config fields (scanTimeoutMinutes, bulkTimeoutMinutes, scannerMemoryMB, scannerPidsLimit) with defaults (20, 120, 2048, 512) and environment/file overrides; persists settings in DB and merges file/env values. Frontend: expose controls for timeouts, memory and PID limits. Backend: add parsing, manager/file config support, model fields, and DB save/load updates. Add docker_io helpers to pull images with progress, ensure cache volumes, build host configs, stream container stdout to disk (with stderr tail capture and ring buffer) and unit tests. Refactor Grype/Trivy/Syft SBOM flows to stream outputs to files, apply resource limits, use cache volumes, and add heartbeat/progress updates to keep memory usage low for large scans.
Frontend: add exportScanHistory/deleteScanHistory API calls, wired UI actions (export + delete buttons) in scan history table, and enhance SBOM dialog to fetch, parse and display SBOM components with export. Update route tree to remove trailing slashes. Hooks: add useDeleteScanHistory mutation and integrate exports.
Backend: register new routes for exporting and deleting scan history; implement ExportScanHistory (CSV attachment) and DeleteScanHistory handlers and DB DeleteScanResult. Scanner: add gcWorker to purge old jobs, return copies from getters to avoid races, and remove unused Trivy SBOM helper. Config: change scanner config env parsing to use strconv.ParseBool with safer defaults and remove deprecated helper code/tests.
Overall: enables CSV export and deletion of scan results, improves SBOM UX, tightens routing, and adds server-side cleanup and safety improvements.
Frontend: add explicit severity options/type and update severity filter handling so the UI sends min_severity only when a real severity is selected.
Backend: validate and return 400 for invalid query params (page, page_size, start_date, end_date) to avoid silent parsing errors; add new ScanJobStatus "expired"; include SCANNER_SYFT_ARGS in config env detection; make autoscanner Start idempotent (initialize stop channel and skip if already enabled) and set image last_scan_at to current time when scheduling scans; stop autoScanner when autoscan disabled in main.go.
Scanner/store updates: make ScanResultStore.Add return an error and handle/store.Add failures in runScan (log on failure); tighten CancelJob to only mark jobs cancelled if they are pending/pulling/scanning; include Negligible and Unknown counts in anomaly messages.
Overall: fixes for parameter validation, safer autoscan lifecycle, more accurate scan state recording, and clearer severity filtering.
Detect and surface scans that are blocked because the image is unchanged: introduce RescanBlockedError (thrown on 409 from start-scan), handle it in ScanDialog to show an "already scanned" UI with a link to scan history, and reset state on close. Add useScannedImages usage in ImagesTable to show a green check / link to /scan-history for already-scanned images instead of the scan button. In bulk scans, surface a banner for skipped (unchanged) images and mark those jobs with a "Skipped" badge. Imports and small UI/icon updates added accordingly.
Introduce scan history browsing and persistent autoscan support.
Frontend: add Scan History page, route and navigation link; implement API client (get-scan-history), React Query hooks (use-scan-query), types, and UI components for listing, filtering, pagination and detail dialog. Update generated route tree and add a mobile ScanHistory page.
Backend: integrate a scanner SQLite DB (configurable via SCANNER_DB_PATH), migrate/load scanner settings from DB, wire an AutoScanner service and start/stop it based on config; expose autoscan and history endpoints in the API router and pass AutoScanner to handlers. Add/model config mapping function (configToScannerConfig) and update hot-reload behavior to apply DB-backed scanner settings and autoscan toggles.
Other: bump Go toolchain and add dependencies in go.mod/go.sum required for the scanner DB and related changes.
Frontend: escape backslashes as well as pipe characters when building Markdown table cells in scan-results-export to avoid breaking table formatting for values containing backslashes.
Remove home/internal/static/embed.go which provided the embedded dist FS and SPA handler (file deleted).
Backend: tighten error handling in home/internal/system/stats.go by capturing the physical CPU count error separately and only setting cachedCPU values when both logical and physical counts succeeded; also removed an unused comment line. These changes prevent incorrect CPU metadata from being cached when one of the syscalls fails.
Multiple fixes and improvements across scanner, API, frontend and system code:
- Frontend: escape pipe characters when exporting scan results to Markdown to avoid table breakage.
- Server: extract buildScannerConfig helper in main to centralize scanner config construction.
- API: validate requested scanner values and notification severity; check SBOM file existence before download; return persisted config in UpdateScannerConfig response; import os.
- Scanner models: add ScanJobExpired status for expired/cleaned up SBOMs.
- SBOM generation: clear job file path and mark job as expired when the temporary file is removed.
- Grype integration: use shlex.Split to robustly parse custom Grype args (supports quoted args/placeholders).
- Notifier: disable automatic HTTP redirects for webhook calls and adjust Discord embed color logic to treat Negligible/Unknown as yellow; improve webhook client settings.
- Scanner service: handle empty bulk scans, tighten CancelJob to only cancel active jobs, ensure cancel contexts are cleaned up, and skip sending bulk notifications when there are no eligible jobs.
- System stats: simplify CPU counts caching with a mutex and lazy initialization (remove sync.Once and associated loader).
- Config: bump Syft image version.
Overall these changes increase robustness, prevent invalid inputs, ensure proper cleanup and make external command parsing and notifications more reliable.
Switch scan results endpoints to use query parameters (image & host) and update router/handlers accordingly. Add webhook URL validation to prevent unsafe/localhost targets and improve error logging for scan/SBOM operations. Filter bulk notifications by minimum severity before sending. Fix Trivy arg parsing using google/shlex and return errors; propagate docker log read errors in grype demux. Improve SBOM cleanup scheduling, CSV escaping on export, vulnerability link handling (CVE vs GHSA), and add accessibility ids for selects. Use fast-deep-equal for scanner config comparisons and prevent UI edits when scanner configured via environment variables. Also refactor CPU stats caching with mutexes. Update go.mod/frontend deps for shlex and fast-deep-equal.
Introduce a full scanner subsystem (vulnerability scanning and SBOM generation) across frontend, backend, and mobile.
Frontend:
- Add scanner UI components: ScanDialog, BulkScanDialog, SBOMDialog, ScanResultsTable, ScanResultsSummary, ScanResultsExport and hooks/use-scan-query.
- Add API clients for scan operations (start-scan, start-bulk-scan, get-scan-jobs, get-scan-results, generate-sbom, scanner-config).
- Integrate scan/SBOM controls into ImagesTable (scan per-image, bulk scan, SBOM generation, download/export).
- Update settings UI to surface scanner configuration.
Backend (home service):
- Add scanner models, handlers and scanner implementations (Grype/Trivy), notifier, SBOM support, and persistent store scaffolding for scan jobs/results.
- Add scan-related API handlers and wire routes into router.go and handlers.go; adjust main.go and config/manager to support scanner settings.
- Tests updated for auth service where required.
Mobile:
- Add scanner feature support (API, hooks, components, types, utils) and a Settings page entry.
Why: Enable users to run vulnerability scans (single and bulk), monitor job progress, retrieve and export scan results, and generate/download SBOMs for container images.