feat: Implement Automated Security Scanning and Vulnerability Management - #78
Merged
Conversation
Adds the Vulnerability/SecurityEvent entities and a parser that normalizes SARIF (Semgrep/Trivy/ZAP), npm-audit, and Gitleaks reports into a common shape, deduplicated by a fingerprint of (source, rule, component, location) so repeat scans update a finding instead of duplicating it. Part of ChianLojistics#70.
VulnerabilityManagementService ingests parsed scan results (upserting by fingerprint, preserving triage status on re-scan), exposes assign/resolve/ ignore lifecycle transitions, and aggregates a dashboard (open counts by severity/type, 30-day trend). SecurityAlertService logs and optionally webhooks (SECURITY_ALERT_WEBHOOK_URL) every CRITICAL finding. Part of ChianLojistics#70.
SecurityController adds POST /security/scans/ingest (guarded by a shared x-scan-token header via ScanIngestGuard, for CI rather than user sessions), GET /security/dashboard, GET/POST /security/vulnerabilities* for listing, assigning, resolving, and ignoring findings behind the existing admin JWT guards. SecurityModule is registered in AppModule. Part of ChianLojistics#70.
Parser tests cover SARIF severity mapping (security-severity score vs. level fallback), CVE extraction, fingerprint stability across re-scans, npm-audit and Gitleaks mapping, and empty-payload handling. Service tests cover create-vs-update-on-ingest, critical-finding alerting, status preservation on re-scan, assign/resolve, and dashboard grouping. Part of ChianLojistics#70.
Runs SAST (Semgrep), dependency scanning (npm audit on backend and frontend), secret scanning (Gitleaks), container scanning (Trivy on the backend image), IaC scanning (Checkov), and OWASP ZAP baseline DAST against the backend on push/PR/daily schedule. SARIF results upload to the GitHub Security tab; each job optionally forwards results to POST /security/scans/ingest when SECURITY_API_URL/SECURITY_SCAN_TOKEN secrets are configured. Dependabot opens weekly PRs for backend/frontend npm deps, the backend Docker base image, and GitHub Actions versions. Closes ChianLojistics#70.
Custom Semgrep rules for hardcoded secrets, string-concatenated SQL, weak hashes, and disabled TLS verification (layered on top of the p/security-audit and p/secrets community rulesets in CI). Gitleaks allowlist excludes test fixtures/.env.example from secret matches. ZAP baseline rules.tsv suppresses two alerts that are expected noise for a cookieless JSON API. Part of ChianLojistics#70.
Explains what each CI job checks, how to enable CI-to-dashboard reporting and critical-finding webhook alerts, local commands to run each scanner, and known gaps (no SonarQube/Snyk/Burp Suite - free equivalents used instead; no Terraform directory yet for the IaC scan to target). Adds the new SECURITY_SCAN_TOKEN/SECURITY_ALERT_WEBHOOK_URL env vars to .env.example. Part of ChianLojistics#70.
26 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[Feature] Automated Security Scanning and Vulnerability Management
Closes #70
Overview
Adds continuous, automated security scanning (SAST, dependency, secret,
container, IaC, and DAST) plus an in-app vulnerability management system,
where security checks were previously manual and inconsistent.
SonarQube, Snyk, and Burp Suite from the original issue were intentionally
left out — they need paid accounts/tokens this repo doesn't have. Semgrep,
npm audit, and OWASP ZAP cover the same categories (SAST / dependency /DAST) for free, with no external account required to run in CI. See
"Known gaps" in the docs below for the rest of what's out of scope here.
What's included
CI security scanning (
.github/workflows/security-scan.yml) — runs onpush to
main/develop, PRs intomain, and daily on a schedule:p/security-audit,p/secrets,p/typescript,p/nodejsscanrulesets plus custom rules(
.semgrep/security-rules.yaml) for hardcoded secrets, string-concatenatedSQL, weak hashes (MD5/SHA1), and disabled TLS verification.
npm audit --audit-level=highacrossbackend/andfrontend/(matrix job), fails the build on high/critical findings.(
.gitleaks.toml) for test fixtures and.env.example.docker-compose.yml(no Terraform directory exists yet to point it at).
docker compose(Postgres + Redis + backend) and health-checked beforescanning. Runs on push/schedule only, not PRs, to keep PR CI fast.
Security tab via
github/codeql-action/upload-sarif.(
POST /security/scans/ingest) whenSECURITY_API_URL/SECURITY_SCAN_TOKENsecrets are configured — a no-op otherwise..github/dependabot.yml— weekly PRs forbackend/frontendnpm deps,the backend's Docker base image, and GitHub Actions versions.
Vulnerability management (
backend/src/security/)Vulnerability/SecurityEvententities (entities/).ScanResultParsernormalizes SARIF (Semgrep/Trivy/ZAP),npm audit, andGitleaks reports into a common shape, deduplicated by a fingerprint of
(source, rule, affected component, location) — re-ingesting a known
finding updates its details but never touches
status/assigned_to, sotriage state survives repeat scans.
VulnerabilityManagementService— ingest, list/get, assign, resolve,ignore, and a dashboard (open counts by severity/type, 30-day trend).
Every state transition is recorded as a
SecurityEventfor audit history.SecurityAlertService— logs every CRITICAL finding and optionally POSTsa summary to
SECURITY_ALERT_WEBHOOK_URL(e.g. a Slack incoming webhook).SecurityController:POST /security/scans/ingest— guarded by a shared-secretx-scan-tokenheader (
ScanIngestGuard), since CI posts here, not a logged-in user.GET /security/dashboard,GET /security/vulnerabilities[/:id],POST /security/vulnerabilities/:id/{assign,resolve,ignore}— behindthe existing
JwtAuthGuard+RolesGuard(Role.ADMIN).AppModule.Docs —
docs/SECURITY_SCANNING.mdcovers what each job checks, how toenable CI→dashboard reporting and webhook alerts, local commands to run each
scanner, and known gaps.
SECURITY_SCAN_TOKEN/SECURITY_ALERT_WEBHOOK_URLadded to
.env.example.Testing
backend/src/security/**/*.spec.ts): SARIF severitymapping (CVSS score vs. level fallback), CVE extraction, fingerprint
stability across re-scans, npm-audit/Gitleaks mapping, create-vs-update-
on-ingest, critical-finding alerting, status preservation on re-scan,
assign/resolve, and dashboard grouping — all passing.
tsc --noEmitclean for the new module.(pre-existing failures in
crypto/distributed-ledgerspecs areunrelated — ESM import issues and a private-property access, both present
before this branch).
security-scan.yml,dependabot.yml, Semgrep rules)validated with a YAML parser.
Manual verification still needed
actions, docker-compose health-check timing) hasn't run in GitHub Actions
yet — needs a live run on this PR to confirm each job passes end-to-end.
tests only; wiring real secrets and confirming an ingested finding shows
up in
GET /security/dashboardagainst a deployed backend is a follow-up.