diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 416a306d..d189b031 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,7 +139,7 @@ jobs: env: RUSTDOCFLAGS: -D warnings - # === Security === + # === Security (merge gate — blocks PRs on vulnerabilities and secrets) === audit: name: Audit runs-on: ubuntu-latest @@ -155,6 +155,108 @@ jobs: - name: Run cargo audit run: cargo audit + trivy-fs: + name: Security / Trivy (filesystem + deps) + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Create reports directory + run: mkdir -p reports/trivy + - name: Run Trivy filesystem + dependency scan + uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 + with: + scan-type: fs + scan-ref: . + scanners: vuln,misconfig + severity: HIGH,CRITICAL + ignore-unfixed: true + format: sarif + output: reports/trivy/trivy-pr.sarif + exit-code: '1' + - name: Upload Trivy SARIF + if: always() + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa + with: + sarif_file: reports/trivy/trivy-pr.sarif + category: trivy-fs + + gitleaks-pr: + name: Security / Gitleaks (PR commits only) + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 50 + persist-credentials: false + - name: Install Gitleaks CLI + run: | + curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.28.0/gitleaks_8.28.0_linux_x64.tar.gz \ + | tar -xzf - -C /usr/local/bin gitleaks + gitleaks --version + - name: Scan staged + recent commits + run: | + mkdir -p reports/gitleaks + gitleaks git \ + --config .gitleaks.toml \ + --log-opts="--all -n 50" \ + --report-format sarif \ + --report-path reports/gitleaks/gitleaks-pr.sarif \ + --exit-code 1 + - name: Upload Gitleaks SARIF + if: always() + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa + with: + sarif_file: reports/gitleaks/gitleaks-pr.sarif + category: gitleaks-pr + + semgrep-pr: + name: Security / Semgrep (SAST) + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Install Semgrep CLI + run: pip install semgrep==1.126.0 + - name: Run Semgrep SAST scan + run: | + mkdir -p reports/semgrep + semgrep scan \ + --config p/rust \ + --config p/dockerfile \ + --config p/github-actions \ + --config p/secrets \ + --severity ERROR \ + --sarif \ + --output reports/semgrep/semgrep-pr.sarif + - name: Fail on findings + run: | + # Semgrep returns non-zero when findings match severity threshold. + # --severity ERROR ensures only HIGH/CRITICAL-ish rules trigger a failure. + grep -q '"results":\[\]' reports/semgrep/semgrep-pr.sarif \ + && echo "No high-severity findings" \ + || { echo "High-severity Semgrep findings detected"; exit 1; } + - name: Upload Semgrep SARIF + if: always() + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa + with: + sarif_file: reports/semgrep/semgrep-pr.sarif + category: semgrep-pr + # === Coverage & Quality === coverage: name: Coverage diff --git a/.github/workflows/security-deep.yml b/.github/workflows/security-deep.yml index ee767ce8..55f6eede 100644 --- a/.github/workflows/security-deep.yml +++ b/.github/workflows/security-deep.yml @@ -2,6 +2,9 @@ name: Security Deep on: schedule: + # Nightly: 3:17 AM Mon-Fri — full history + deep scans for visibility + # This is a REPORTING-ONLY scan for historical evidence and triage. + # For merge-gate enforcement see ci.yml (trivy-fs, gitleaks-pr, audit). - cron: '17 3 * * 1-5' workflow_dispatch: @@ -57,9 +60,9 @@ jobs: if: always() run: | echo '### security / gitleaks-history' >> "$GITHUB_STEP_SUMMARY" - echo '- Intent: reporting-only scheduled secret scan with full repository history.' >> "$GITHUB_STEP_SUMMARY" + echo '- Intent: reporting-only nightly scan with full repository history.' >> "$GITHUB_STEP_SUMMARY" + echo '- Merge gate: none. For PR gate see `gitleaks-pr` in ci.yml.' >> "$GITHUB_STEP_SUMMARY" echo '- Publication: GitHub code scanning via SARIF and retained workflow artifact.' >> "$GITHUB_STEP_SUMMARY" - echo '- Merge gating: none. Review findings from the security tab.' >> "$GITHUB_STEP_SUMMARY" semgrep-full: name: security / semgrep-full @@ -102,9 +105,9 @@ jobs: if: always() run: | echo '### security / semgrep-full' >> "$GITHUB_STEP_SUMMARY" - echo '- Intent: reporting-only full-repository SAST and security-sensitive config scan.' >> "$GITHUB_STEP_SUMMARY" + echo '- Intent: reporting-only nightly SAST and security-sensitive config scan.' >> "$GITHUB_STEP_SUMMARY" + echo '- Merge gate: none. For PR gate see `semgrep-pr` in ci.yml.' >> "$GITHUB_STEP_SUMMARY" echo '- Publication: GitHub code scanning via SARIF and retained workflow artifact.' >> "$GITHUB_STEP_SUMMARY" - echo '- Merge gating: none. Scheduled findings should feed triage.' >> "$GITHUB_STEP_SUMMARY" trivy-full: name: security / trivy-full @@ -120,17 +123,21 @@ jobs: persist-credentials: false - name: Create reports directory run: mkdir -p reports/trivy + + - name: Install Trivy CLI + run: | + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | \ + sh -s -- -b /usr/local/bin v0.65.0 + trivy --version + - name: Run full Trivy filesystem, dependency, and IaC scan - uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 - with: - scan-type: fs - scan-ref: . - scanners: vuln,misconfig - severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - ignore-unfixed: false - format: sarif - output: reports/trivy/trivy-full.sarif - exit-code: '0' + run: | + trivy fs . \ + --scanners vuln,misconfig \ + --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL \ + --format sarif \ + --output reports/trivy/trivy-full.sarif \ + --exit-code 1 - name: Verify SARIF file exists if: always() run: | @@ -139,26 +146,27 @@ jobs: ls -lh reports/trivy/trivy-full.sarif else echo "✗ SARIF file not found" - exit 1 fi + - name: Upload Trivy SARIF - if: always() + if: always() && hashFiles('reports/trivy/trivy-full.sarif') != '' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa with: sarif_file: reports/trivy/trivy-full.sarif category: trivy-full - name: Upload Trivy artifact - if: always() + if: always() && hashFiles('reports/trivy/trivy-full.sarif') != '' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: security-deep-trivy-full path: reports/trivy/ retention-days: 21 - name: Summarize Trivy reporting channel - if: always() + if: always() && hashFiles('reports/trivy/trivy-full.sarif') != '' run: | echo '### security / trivy-full' >> "$GITHUB_STEP_SUMMARY" - echo '- Intent: reporting-only full repository filesystem, dependency, and IaC drift scan.' >> "$GITHUB_STEP_SUMMARY" + echo '- Intent: reporting-only nightly deep scan — filesystem, dependency, and IaC.' >> "$GITHUB_STEP_SUMMARY" + echo '- Merge gate: none. For PR gate see `trivy-fs` in ci.yml.' >> "$GITHUB_STEP_SUMMARY" echo '- Severity coverage: UNKNOWN through CRITICAL for deep visibility.' >> "$GITHUB_STEP_SUMMARY" echo '- Publication: GitHub code scanning via SARIF and retained workflow artifact.' >> "$GITHUB_STEP_SUMMARY" @@ -182,7 +190,7 @@ jobs: { echo '## Scheduled deep security summary' echo '' - echo 'This workflow is reporting-oriented by design. It preserves evidence with non-cancelling concurrency and retained artifacts instead of acting as a pull-request gate.' + echo 'This workflow is reporting-oriented (no merge gate). It preserves evidence with non-cancelling concurrency and retained artifacts for triage. Merge gating is handled by `audit`, `trivy-fs`, `gitleaks-pr`, and `semgrep-pr` in ci.yml.' echo '' echo '### Job results' echo "- gitleaks-history: $GITLEAKS_RESULT" diff --git a/SECURITY.md b/SECURITY.md index 034e8480..987008b0 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,20 +2,164 @@ ## Supported Versions -Use this section to tell people about which versions of your project are -currently being supported with security updates. +We actively maintain security updates for the following versions. We recommend always using the latest stable release. -| Version | Supported | -| ------- | ------------------ | -| 5.1.x | :white_check_mark: | -| 5.0.x | :x: | -| 4.0.x | :white_check_mark: | -| < 4.0 | :x: | +| Version | Supported | +| --------- | ------------------ | +| `>= 2.x` | :white_check_mark: | +| `1.x` | :white_check_mark: | +| `< 1.x` | :x: | + +### Release Cadence + +- **Major versions** (`2.x`, `3.x`): Supported for 12 months after the next major is released. +- **Minor versions** (`2.1.x`): Supported while the minor is current or previous. +- **Patch versions** (`2.1.1`): Supported within the same minor as the latest patch. + +Subscribe to [GitHub Releases](https://github.com/dallay/cortex/releases) for alerts. + +--- ## Reporting a Vulnerability -Use this section to tell people how to report a vulnerability. +**Please do not report security vulnerabilities through public GitHub Issues.** + +Send a report to **privately via GitHub Security Advisories**: + +1. Navigate to [the repository's Security tab](https://github.com/dallay/cortex/security/advisories). +2. Click **Report a vulnerability**. +3. Fill out the advisory form — we respond within **48 hours** with an acknowledgment. +4. Provide as much detail as possible: reproduction steps, affected versions, any potential fixes. + +### What to Expect After Reporting + +| Timeline | What Happens | +| -------- | ------------ | +| **< 48 hours** | Initial acknowledgment from the maintainers. | +| **< 7 days** | Preliminary severity assessment (Critical / High / Medium / Low). | +| **< 30 days** | If accepted: a fix is prepared in a private branch. Patch release timeline communicated. | +| **< 60 days** | Public disclosure on a mutually agreed date. We will reach out if extended timeline is needed. | + +### Scope + +The policy covers vulnerabilities in the cortex monorepo, including: +- Core packages (`rook` CLI, Rust backend) +- Frontend apps (`apps/`) +- Infrastructure-as-Code configurations +- GitHub Actions workflows + +**In-scope**: Remote code execution, privilege escalation, data exfiltration, authentication bypass, dependency chain compromise. + +**Out-of-scope**: Social engineering, denial-of-service against third-party infrastructure, pre-disclosure findings from automated scanners. + +--- + +## Security Best Practices for Contributors + +### Secrets Management + +- **Never commit secrets, credentials, or tokens** to the repository. Use environment variables or GitHub Secrets. +- If a secret is accidentally committed, assume it is compromised and rotate it immediately. +- Use `.gitignore`, `.env.example`, and `git-secrets` or similar tooling. + +### Dependency Management + +- All Rust dependencies are audited via `cargo audit` in CI (`ci.yml#audit`). +- Frontend dependencies are audited via `pnpm audit` where applicable. +- **Do not** add dependencies with known high/critical vulnerabilities. +- Keep lock files (`Cargo.lock`, `pnpm-lock.yaml`) up to date and committed. + +### Input Validation + +- Validate and sanitize ALL user input at trust boundaries, especially in: + - CLI argument parsing (`rook` package) + - File path handling (path traversal attacks) + - HTTP API handlers (`apps/*/api`) + - AI model prompt injection surfaces + +### Authentication / Authorization + +- Use Vercel Middleware/Routing Middleware for auth at the edge. +- Never roll custom auth — use established patterns (Clerk, Auth.js, etc.). +- Apply least-privilege scoping on all secrets and API keys. + +### Security-Sensitive Code Areas + +The following packages/configs receive elevated security scrutiny: + +| Package / Config | Reason | +| ---------------- | ------ | +| `crates/rook/` | CLI with file system and git access | +| `apps/rook/dashboard/` | User-facing web app with auth | +| `.github/workflows/` | CI/CD with secrets access | +| `infra/` | Cloud infrastructure definitions | + +--- + +## Dependency Security + +### Automated Scanning + +The project uses multiple layers of automated vulnerability scanning: + +| Tool | Scope | PR Gate (`ci.yml`) | Nightly (`security-deep.yml`) | SonarCloud | +| ---- | ----- | ------------------ | ---------------------------- | --------- | +| **cargo audit** | Rust dependencies | :white_check_mark: Blocks on vulnerable deps | N/A | — | +| **Dependabot** | `Cargo.lock`, `pnpm-lock.yaml` | :white_check_mark: Auto-merge for patch/security | N/A | — | +| **Gitleaks** (`gitleaks-pr`) | Secrets in commits | :white_check_mark: Blocks on any secret found | Reporting only (full history) | — | +| **Semgrep** (`semgrep-pr`) | SAST (rust, docker, GH actions, secrets) | :white_check_mark: Blocks on ERROR-severity findings | Reporting only (all severities) | — | +| **Trivy** (`trivy-fs`) | Filesystem, dependencies, IaC | :white_check_mark: Blocks on HIGH/CRITICAL vulns | Reporting only (all severities) | — | +| **SonarCloud** | Code quality + security hotspots | Conditional (token required) | — | :white_check_mark: If configured | + +### Keeping Dependencies Updated + +- **GitHub Dependabot** creates PRs for outdated dependencies automatically. +- Security updates are merged quickly; feature/minor updates follow regular review cadence. +- We enable **automated security updates** for critical CVEs via Dependabot. + +--- + +## Incident Response + +When a vulnerability is reported or discovered: + +1. **Triage** — The maintainer team assesses severity within 48 hours. +2. **Private fix** — A fix is developed in a private fork/branch. +3. **Coordinated disclosure** — A patch is prepared with a target disclosure date. +4. **Patch release** — A patch version (`x.y.z`) is tagged and released. +5. **Public disclosure** — A GitHub Security Advisory is published with the full write-up. + +### Severity Classification + +| Level | Definition | Response Time | +| ----- | ---------- | ------------- | +| **Critical** | Remote code execution, complete authentication bypass | < 24 hours for initial mitigation | +| **High** | Data exfiltration, privilege escalation | < 7 days for patch | +| **Medium** | Information disclosure, DoS | < 30 days for patch | +| **Low** | Minor impact, hard to exploit | Next release cycle | + +--- + +## Compliance & Standards + +This project follows: + +- **Secure by design** principles: minimal dependency surface, defense in depth. +- **Dependency audit** before each release via `cargo audit` and `pnpm audit`. +- **Secret scanning** via Gitleaks on the repository full history. +- **Reproducible builds**: Linux, macOS, and Windows binaries are built from verified build pipelines. + +No formal certifications currently (SOC2, ISO 27001, etc.). + +--- + +## Security-Related Links -Tell them where to go, how often they can expect to get an update on a -reported vulnerability, what to expect if the vulnerability is accepted or -declined, etc. +| Resource | Link | +| -------- | ---- | +| Report a vulnerability | [GitHub Security Advisories](https://github.com/dallay/cortex/security/advisories) | +| Code scanning results | [GitHub Code Scanning](https://github.com/dallay/cortex/security/code-scanning) | +| Dependabot alerts | [Dependabot Alerts](https://github.com/dallay/cortex/security/dependabot) | +| Secret scanning alerts | [GitHub Secret Scanning](https://github.com/dallay/cortex/security/secrets) | +| CI/CD workflow | [`.github/workflows/ci.yml`](.github/workflows/ci.yml) | +| Nightly security deep scan | [`.github/workflows/security-deep.yml`](.github/workflows/security-deep.yml) |