diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90bd5b41..0125d39e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,7 @@ jobs: contents: read outputs: code: ${{ steps.check.outputs.code }} + java_code: ${{ steps.check.outputs.java_code }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: @@ -33,6 +34,7 @@ jobs: # Push to main ve workflow_call (release akışı) → her zaman full build if [ "${{ github.event_name }}" != "pull_request" ]; then echo "code=true" >> "$GITHUB_OUTPUT" + echo "java_code=true" >> "$GITHUB_OUTPUT" echo "::notice::Non-PR event, running full build" exit 0 fi @@ -50,11 +52,21 @@ jobs: ':!.github/release-notes-template.md') if [ -z "$NON_DOC_FILES" ]; then echo "code=false" >> "$GITHUB_OUTPUT" + echo "java_code=false" >> "$GITHUB_OUTPUT" echo "::notice::Documentation-only change — skipping build & test matrix" else echo "code=true" >> "$GITHUB_OUTPUT" echo "::notice::Code changes detected: $(echo "$NON_DOC_FILES" | wc -l | tr -d ' ') non-doc files" echo "$NON_DOC_FILES" | head -10 + # Check if any Java/Kotlin source files changed (for CodeQL) + JAVA_FILES=$(git diff --name-only "$BASE..$HEAD" -- '*.java' '*.kt' '*.kts') + if [ -z "$JAVA_FILES" ]; then + echo "java_code=false" >> "$GITHUB_OUTPUT" + echo "::notice::No Java/Kotlin files changed — CodeQL analysis will be skipped" + else + echo "java_code=true" >> "$GITHUB_OUTPUT" + echo "::notice::Java/Kotlin files changed: $(echo "$JAVA_FILES" | wc -l | tr -d ' ') files" + fi fi build: @@ -327,7 +339,7 @@ jobs: codeql: name: CodeQL Analysis needs: [changes, build] - if: ${{ needs.changes.outputs.code == 'true' }} + if: ${{ needs.changes.outputs.code == 'true' && needs.changes.outputs.java_code == 'true' }} runs-on: ubuntu-latest permissions: actions: read diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ddc2772b..67e1988c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -478,6 +478,8 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + id-token: write + attestations: write steps: - name: Download all artifacts @@ -517,6 +519,13 @@ jobs: # Also sign the checksums file cosign sign-blob --yes SHA256SUMS.txt --output-signature=SHA256SUMS.txt.sig --output-certificate=SHA256SUMS.txt.pem + - name: Attest build provenance + uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 + with: + subject-path: | + artifacts/FreeMind-CE-* + artifacts/SHA256SUMS.txt + - name: Create Release uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index cc1dacff..88d637c7 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -81,6 +81,33 @@ jobs: with: category: "/language:java-kotlin" + grype-scan: + name: Grype Vulnerability Scan + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Run Grype scan + uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6 + id: grype + with: + path: "." + fail-build: false + only-fixed: true + severity-cutoff: high + + - name: Upload Grype results to GitHub Security tab + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + if: always() + with: + sarif_file: ${{ steps.grype.outputs.sarif }} + category: grype-scan + trivy-scan: name: Trivy Filesystem Scan runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index 763363d2..148cbdf9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,7 +79,9 @@ make help # Show all available make targets 6. Never bypass merge controls — no `--admin`, no force merge 7. Dependency updates require manual review -> [docs/merge-release-safety.md](docs/merge-release-safety.md#dependency-update-protocol) 8. Static analysis (PMD + SpotBugs) runs on every `make build` -> [CONTRIBUTING.md — Static Analysis](CONTRIBUTING.md#static-analysis-quality-gates) -9. Parallel work is sovereign — never close, absorb, or supersede another session's PR -> [CONTRIBUTING.md — Parallel Work Protection](CONTRIBUTING.md#parallel-work-protection) +9. Security audit (`make audit`) before pushing dependency changes -> [CONTRIBUTING.md — Security Audit](CONTRIBUTING.md#security-audit-vulnerability-scanning) +10. No external API dependency for security tooling — if a tool runs as CLI, use the CLI, not cloud services +11. Parallel work is sovereign — never close, absorb, or supersede another session's PR -> [CONTRIBUTING.md — Parallel Work Protection](CONTRIBUTING.md#parallel-work-protection) ### Repository Layout @@ -120,6 +122,8 @@ freemind-ce/ make build # Full build (compile + test) make run # Run the app make test # Run tests only +make audit # Security audit — Grype (fast, ~30s) +make audit-full # Full OWASP dependency-check (HTML report) make coverage # Tests + JaCoCo coverage report make debug # Debug mode (port 5005) make clean # Clean build artifacts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 514e17bc..fc5c3d89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -158,9 +158,10 @@ feat: infrastructure modernization (tests, CI, release, docs) 1. **Build must pass:** `make build` 2. **Tests must pass:** `make test` -3. **Review your diff:** `git diff --staged` — make sure no debug code, secrets, or unrelated changes are included -4. **Stage intentionally:** use `git add ` for specific files, avoid `git add -A` or `git add .` -5. **No generated artifacts:** never commit `build/`, `*.class`, `auto.properties`, or IDE-specific files +3. **Security audit (if dependencies changed):** `make audit` — fails on High+ CVEs with known fixes +4. **Review your diff:** `git diff --staged` — make sure no debug code, secrets, or unrelated changes are included +5. **Stage intentionally:** use `git add ` for specific files, avoid `git add -A` or `git add .` +6. **No generated artifacts:** never commit `build/`, `*.class`, `auto.properties`, or IDE-specific files ### After Pushing: Automated Code Review @@ -181,6 +182,57 @@ Serena is a hard requirement for every developer, every AI agent, and every suba > **[docs/serena-guide.md](docs/serena-guide.md)** — 18 tools, mandatory workflow, decision trees, examples, anti-patterns, pre-commit verification flow. +## Security Audit (Vulnerability Scanning) + +Every dependency — whether declared in Gradle or tracked as a local JAR — must be free of known high-severity vulnerabilities before release. + +### Core Principle + +> **No external API dependency for security tooling.** If a tool can run as a local CLI, we use the CLI. We do not depend on cloud services, paid APIs, or third-party dashboards for security decisions. All scanning runs offline after the initial database download. + +### Tools + +| Tool | Where | Command | What It Catches | Speed | +|------|-------|---------|----------------|-------| +| **Grype** | Local + GitHub | `make audit` | Known CVEs in JARs and Gradle dependencies (with fix versions) | ~30 seconds | +| **OWASP Dependency-Check** | Local + GitHub | `make audit-full` | Same + detailed HTML report with NVD references | ~5 minutes | +| **Trivy** | GitHub only | `security-scan.yml` | Filesystem vulnerability scan, SARIF upload | ~2 minutes | + +### Local Workflow + +```bash +# Quick scan — run before pushing (fails on High+ CVEs with known fixes) +make audit + +# Full report — run periodically or before releases +make audit-full +open freemind/build/reports/dependency-check-report.html +``` + +### Handling Findings + +| Severity | Action | Timeline | +|----------|--------|----------| +| **Critical/High** (fix available) | Update dependency immediately | Before next merge | +| **Critical/High** (no fix) | Add OWASP suppression with justification | Document in `config/owasp-suppressions.xml` | +| **Medium** | Create GitHub issue, fix in next sprint | Before next release | +| **Low** | Track, fix opportunistically | No deadline | + +### What Gets Scanned + +- Gradle dependencies (Maven Central) +- Tracked JAR files in `freemind/lib/`, `freemind/plugins/*/` +- Build tool dependencies (PMD, SpotBugs, JaCoCo — build-time only, not runtime) +- Transitive dependencies + +### Prerequisites + +Install Grype via [mise](https://mise.jdx.dev/): + +```bash +mise install grype +``` + ## Static Analysis (Quality Gates) Every `make build` runs two static analysis tools automatically. These are **not optional** — they are the first line of defense against bugs. @@ -215,14 +267,19 @@ The goal is to catch issues as early as possible, at the closest point to where Code written → Serena MCP (semantic analysis, reference checking) → PMD + SpotBugs (make build — static analysis) - → Pre-commit hook (compile verification) - → git push - → GitHub code-quality (automated PR review) - → CI 48-job matrix (6 OS × 4 Java) + → Grype (make audit — dependency vulnerability scan) + → Pre-commit hook (compile verification) + → git push + → GitHub code-quality (automated PR review) + → CI 48-job matrix (6 OS × 4 Java) + → Grype + Trivy + OWASP (weekly security-scan.yml) ``` Every layer catches different things. No layer is redundant. Skipping any layer means bugs slip through. +**Local layers** (developer machine): Serena → PMD/SpotBugs → Grype → pre-commit hooks +**Remote layers** (GitHub): code-quality → CI matrix → weekly security scans + ### Viewing Reports ```bash diff --git a/Makefile b/Makefile index c80362cf..a9035e59 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ GRADLE_CMD = JAVA_HOME=$(JAVA_HOME) $(GRADLE) .PHONY: help build run debug clean test test-gui test-performance test-chaos coverage jaxb javadoc \ package package-mac package-win package-linux \ - dist-zip install-dist check info all + dist-zip install-dist check audit audit-full info all .DEFAULT_GOAL := help @@ -112,6 +112,22 @@ coverage: ## Run tests with JaCoCo coverage report check: ## Run build + all quality checks $(GRADLE_CMD) check $(GRADLE_FLAGS) +# ── Security ──────────────────────────────────────────────────────── +##@ Security + +audit: ## Run security audit — Grype (fast, ~30s, fails on High+) + @command -v grype >/dev/null 2>&1 || { echo "Error: grype not found. Install: mise install grype"; exit 1; } + grype dir:. --only-fixed --fail-on high + @echo "" + @echo "Full OWASP report: make audit-full" + +audit-full: ## Run full OWASP dependency-check (slower, detailed HTML report) + $(GRADLE_CMD) :freemind:dependencyCheckAnalyze $(GRADLE_FLAGS) + @echo "" + @echo "Report: freemind/build/reports/dependency-check-report.html" + +##@ Code Generation + jaxb: ## Regenerate JAXB classes from XSD schema $(GRADLE_CMD) :freemind:generateJaxb $(GRADLE_FLAGS) diff --git a/docs/development-guide.md b/docs/development-guide.md index c6280a2b..dcafd84a 100644 --- a/docs/development-guide.md +++ b/docs/development-guide.md @@ -164,6 +164,40 @@ make coverage # Tests + JaCoCo coverage report | `HtmlConversionTests.java` | HTML export | | `StandaloneMapTests.java` | Standalone map operations | +## Security Audit + +Dependency vulnerability scanning catches known CVEs in project dependencies before they reach production. + +### Running Locally + +```bash +# Quick scan — Grype (requires: mise install grype) +make audit # ~30 seconds, fails on High+ with known fix + +# Full report — OWASP Dependency-Check (Gradle plugin) +make audit-full # ~5 minutes, HTML report +open freemind/build/reports/dependency-check-report.html +``` + +### What Gets Scanned + +| Source | Examples | +|--------|---------| +| Gradle dependencies | jsoup, Batik, FOP, Lucene, Logback, JUnit | +| Tracked JARs (`lib/`) | jortho.jar, SimplyHTML.jar, bindings.jar | +| Plugin JARs (`plugins/*/`) | JMapViewer.jar, jhall.jar, groovy-all.jar | +| Build tools (non-runtime) | PMD, SpotBugs, JaCoCo | + +### Core Principle + +> No external API dependency for security tooling. If a tool runs as a local CLI, we use the CLI — not cloud dashboards or paid services. All scanning runs offline after initial database download. + +### GitHub Safety Net + +Weekly `security-scan.yml` runs Grype + Trivy + OWASP on GitHub Actions with SARIF upload to the Security tab. This catches anything missed locally and provides audit trail. + +Full documentation: **[CONTRIBUTING.md — Security Audit](../CONTRIBUTING.md#security-audit-vulnerability-scanning)** + ## Static Analysis Static analysis tools (PMD + SpotBugs), configuration, reports, and the early detection chain are documented in **one place**: