Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
attestations: write

steps:
- name: Download all artifacts
Expand Down Expand Up @@ -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:
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/security-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
71 changes: 64 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <file>` 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 <file>` 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

Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)

Expand Down
34 changes: 34 additions & 0 deletions docs/development-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**:
Expand Down
Loading