chore: add CVE audit skill and scheduled GitLab CI jobs (#704)

Closes #704 (closed)

Adds a CVE audit protocol with two entry points:

  • local: /cve-audit slash command (.claude/commands/cve-audit.md). runs the three scanners, writes artifacts to cve-reports/, produces SUMMARY.md with fixable vs unfixed CRITICAL/HIGH grouped by remediation.
  • CI: new .gitlab-ci-security.yml, included from root .gitlab-ci.yml. four jobs in a security stage (govulncheck, pnpm-audit, trivy-image, summary). gated on SECURITY_AUDIT=1 so it only runs on dedicated schedules or manual triggers.

Files

  • .claude/commands/cve-audit.md (new) — local skill
  • .gitlab-ci-security.yml (new) — CI jobs
  • .gitlab-ci.yml — include the security file with include:rules: gated on SECURITY_AUDIT
  • .gitignore — exclude cve-reports/ and .trivycache/
  • ui/.gitlab-ci.yml, ui/packages/ce/.gitlab-ci.yml, ui/packages/shared/.gitlab-ci.yml — see UI CI cleanup below

UI CI cleanup (bundled)

.ui_checks, .only_ui_feature, and .only_ui_master had no changes: filter, so UI build, lint, and e2e jobs ran on every MR regardless of diff. Added changes: ui/**/* guards to mirror engine's .only_engine pattern. After merge, MRs that don't touch ui/** will skip UI jobs.

Run locally

prereqs: govulncheck, pnpm, trivy, jq

  1. build the image once: cd engine && make build-image (tags dblab_server:local)
  2. in Claude Code: /cve-audit (or /cve-audit some-image:tag)
  3. report at cve-reports/SUMMARY.md; raw JSON/text artifacts alongside

sample on current master:

  • trivy: 5 CRITICAL / 40 HIGH / 91 MEDIUM
  • govulncheck: 7 called / 13 imported
  • pnpm audit: 1 moderate
  • 0 unfixed CRITICAL/HIGH in the image — all findings have upstream fixes

Set up on CI

  1. Settings → CI/CD → Schedules → New schedule
  2. cron (UTC): e.g. 0 3 * * 1 (Mondays 03:00 UTC)
  3. variables:
    • SECURITY_AUDIT = 1 (required — gates all security jobs)
    • optional: CVE_SCAN_IMAGE = registry.gitlab.com/postgres-ai/database-lab/dblab-server:master (default) or another tag

artifacts retained: 90 days for raw scans, 365 days for SUMMARY.md (for trend/diff).

Notes

  • trivy pulls from GitLab registry via \$CI_REGISTRY_USER/PASSWORD (in-scope for CI jobs).
  • scanner jobs are allow_failure: true — a registry blip or single scanner error won't break the pipeline.
  • follow-ups (not here): auto-open issues on new CRITICAL; extend to dblab-rds-refresh, dblab-ci-checker, dblab-client images.
Edited by Artyom Kartasov

Merge request reports

Loading