diff --git a/.github/ISSUE_TEMPLATE/security-triage.md b/.github/ISSUE_TEMPLATE/security-triage.md new file mode 100644 index 000000000..907d7d800 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security-triage.md @@ -0,0 +1,25 @@ +--- +name: Security Vulnerability Triage +about: Track and triage dependency or container vulnerability remediation. +title: '[SECURITY] CVE-XXX: Package Name - Severity/SLA' +labels: security +assignees: '' +--- + +## Vulnerability Details +- **CVE ID**: +- **Package**: +- **Vulnerability Link**: +- **CVSS Score**: +- **EPSS Score**: + +## SLA Triage +- [ ] Critical (24h) +- [ ] High (1w) +- [ ] Medium (2w) +- [ ] Low (Next scheduled release) + +## Remediation Plan +- [ ] Upgrade dependency version +- [ ] Apply code fix / workaround +- [ ] Document exception diff --git a/.github/workflows/reusable-tests.yml b/.github/workflows/reusable-tests.yml index 664b7dc1f..1b4723489 100644 --- a/.github/workflows/reusable-tests.yml +++ b/.github/workflows/reusable-tests.yml @@ -36,7 +36,25 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - env: + - name: Wait for backend health check + env: + BASE_URL: https://${{ env.PREFIX }}.${{ env.DOMAIN }} + run: | + echo "Waiting for backend health check at ${BASE_URL}/api/health..." + for i in {1..30}; do + status=$(curl -k --connect-timeout 5 --max-time 10 -s -o /dev/null -w "%{http_code}" "${BASE_URL}/api/health" || true) + if [ "$status" -eq 200 ]; then + echo "Backend is healthy!" + exit 0 + fi + echo "Waiting for health check (HTTP $status), retrying in 10s... ($i/30)" + sleep 10 + done + echo "ERROR: Backend did not become healthy in time." + exit 1 + + - name: Run Integration Tests + env: API_NAME: nest BASE_URL: https://${{ env.PREFIX }}.${{ env.DOMAIN }} run: | diff --git a/SECURITY.md b/SECURITY.md index 7fd70c96f..d71a4c441 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -29,3 +29,12 @@ Out of the box, this QuickStart repository is hardened to satisfy Level 1 and Le | **V14.4** | HTTP Secure Headers | Strips identifying `Server` headers and enforces secure HTTP response headers (CSP, HSTS, X-Frame-Options, same-origin, and MIME sniffing blocks). | Configured natively in the frontend [frontend/Caddyfile](file:///home/derek/Repos/quickstart-openshift/frontend/Caddyfile) and verified by weekly OWASP ZAP scans. | | **V14.4** | Container Hardening | Restricts container execution permissions and prevents host system modifications. | Enforces `readOnlyRootFilesystem: true`, `runAsNonRoot: true`, `allowPrivilegeEscalation: false`, drop all `capabilities`, and default `seccompProfile` in [backend/openshift.deploy.yml](file:///home/derek/Repos/quickstart-openshift/backend/openshift.deploy.yml) and [frontend/openshift.deploy.yml](file:///home/derek/Repos/quickstart-openshift/frontend/openshift.deploy.yml). | | **V14.4** | Network Segmentation | Controls pod communication, isolating network traffic between frontend, backend, and database tiers. | Hardened [NetworkPolicies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) defined in [common/openshift.init.yml](file:///home/derek/Repos/quickstart-openshift/common/openshift.init.yml). | + +## Vulnerability Triage SLAs + +All security issues are triaged using CISA KEV status and CVSS scores: +- **Critical** (CVSS 9.0-10.0 or CISA KEV): Remediation within 24 hours. +- **High** (CVSS 7.0-8.9): Remediation within 1 week. +- **Medium** (CVSS 4.0-6.9): Remediation within 2 weeks. +- **Low** (CVSS 0.0-3.9): Remediation next scheduled release. + diff --git a/backend/package-lock.json b/backend/package-lock.json index 3af106de8..88aee4389 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -6817,9 +6817,9 @@ } }, "node_modules/hono": { - "version": "4.12.18", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", - "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", + "version": "4.12.25", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", + "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -8914,9 +8914,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" diff --git a/common/openshift.database.yml b/common/openshift.database.yml index 762a20821..d92acf609 100644 --- a/common/openshift.database.yml +++ b/common/openshift.database.yml @@ -19,10 +19,7 @@ parameters: - name: MEMORY_LIMIT description: Memory limit for the database container (bounds the pod's working set). value: 4Gi - - name: RANDOM_EXPRESSION - description: Random expression to make sure deployments update - from: "[a-zA-Z0-9]{32}" - generate: expression + objects: - apiVersion: apps/v1 kind: StatefulSet @@ -71,8 +68,7 @@ objects: secretKeyRef: name: ${NAME}-${ZONE}-database key: database-user - - name: RANDOM_EXPRESSION - value: ${RANDOM_EXPRESSION} + volumeMounts: - name: data mountPath: /var/lib/postgresql/data