ADR-005: DevSecOps Implementation¶
Status: Accepted 2026-01-03 Date: 2026-01-03 Decision Makers: @amiable-dev/maintainers Depends On: ADR-004 (CI/CD) Council Review: 2026-01-03 (Tier: High, Models: GPT-5.2, Claude Opus 4.5, Gemini 3 Pro, Grok 4.1)
Context¶
The amiable-templates project, while primarily a documentation site, requires security measures to:
- Prevent accidental secret exposure in commits
- Ensure supply chain security for dependencies
- Maintain secure CI/CD workflows
- Support safe contributions from the community (forks)
This ADR adapts the DevSecOps patterns from llm-council ADR-035 for a documentation-focused project.
Current State¶
The repository has Snyk rules in .agent/rules/snyk_rules.md but no automated security scanning.
Goals¶
- Prevent secrets from being committed
- Keep dependencies up-to-date and secure
- Maintain fork-friendly CI (no secrets required for PR checks)
- Minimize false positives and noise
Non-Goals¶
- Runtime security (static site has no runtime)
- Container scanning (no containers in this project)
- SAST for application code (minimal Python scripts)
- Full SLSA compliance (overkill for docs site)
Decision¶
Implement a 3-layer security pipeline adapted for documentation projects:
Layer 1: Pre-Commit (Developer Workstation)¶
Tools run locally before commits:
| Tool | Purpose |
|---|---|
| Gitleaks | Secret detection |
| yamllint | YAML syntax validation |
Configuration: .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/adrienverge/yamllint
rev: v1.33.0
hooks:
- id: yamllint
args: [--strict]
Layer 2: Pull Request (Fork-Compatible)¶
Checks that run without secrets (safe for external PRs):
| Tool | Purpose |
|---|---|
| Gitleaks Action | Secret scanning |
| Dependency Review | License and vulnerability check |
| YAML validation | Configuration syntax |
Workflow: .github/workflows/security.yml
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
dependency-review:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
Layer 3: Main Branch (Post-Merge)¶
Additional checks after merge:
| Tool | Purpose |
|---|---|
| Dependabot | Automated dependency updates |
| GitHub Secret Scanning | Native secret detection |
Configuration: .github/dependabot.yml (already created in ADR-001)
Tool Selection Rationale¶
| Tool | Why Selected |
|---|---|
| Gitleaks | Fast, configurable, pre-commit + CI support |
| Dependency Review | Native GitHub integration, zero config |
| Dependabot | Automatic PRs, built into GitHub |
| yamllint | Catches YAML errors before they break builds |
Tools NOT Used (and Why)¶
| Tool | Reason for Exclusion |
|---|---|
| CodeQL | No significant codebase to analyze |
| Snyk | Dependabot sufficient for this project size |
| Trivy | No containers or complex dependencies |
| SonarCloud | Overkill for docs site |
| Semgrep | No application code requiring SAST |
Fork-Friendly Design¶
All PR checks work without repository secrets:
- Gitleaks uses only GITHUB_TOKEN (automatic)
- Dependency Review is token-free
- No external services requiring API keys
Gitleaks Configuration¶
.gitleaks.toml to reduce false positives (example patterns only):
[extend]
useDefault = true
# Note: We do NOT globally exclude .md files from scanning.
# Only specific example patterns are allowlisted.
[[rules]]
id = "example-api-key"
description = "Ignore example API keys in documentation"
regex = '''sk-example-[a-zA-Z0-9]+'''
allowlist = { regexes = ['''sk-example-'''] }
[[rules]]
id = "placeholder-key"
description = "Ignore placeholder API keys"
regex = '''YOUR_API_KEY|your-api-key|xxx+'''
allowlist = { regexes = ['''YOUR_API_KEY|your-api-key|xxx+'''] }
Consequences¶
Positive¶
- Prevents secret leaks: Gitleaks catches secrets pre-commit and in CI
- Fork-friendly: External contributors can submit PRs without issues
- Low maintenance: Leverages GitHub-native features
- Minimal noise: Focused toolset avoids alert fatigue
Negative¶
- Less comprehensive: Smaller toolset than full DevSecOps
- No runtime monitoring: Static site limitation
Neutral¶
- Security posture appropriate for project risk level
- Can expand later if project scope grows
Implementation Phases¶
Phase 1: Foundation¶
- [x] Create
.pre-commit-config.yaml - [x] Create
.gitleaks.toml - [x] Update
SECURITY.mdwith pre-commit instructions
Phase 2: CI Integration¶
- [x] Create
.github/workflows/security.yml - [x] Enable GitHub Secret Scanning (repository settings)
- [x] Verify Dependabot is active
Phase 3: Documentation¶
- [x] Document security setup in CONTRIBUTING.md
- [x] Add security badge to README
Compliance / Validation¶
- [x] Pre-commit hooks install and run successfully
- [x] Gitleaks catches test secrets in CI
- [x] Dependency Review blocks vulnerable dependencies
- [x] External PR can pass all checks without secrets
LLM Council Review Summary¶
Reviewed: 2026-01-03 Tier: High (4 models: GPT-5.2, Claude Opus 4.5, Gemini 3 Pro, Grok 4.1)
Verdict: Accepted¶
Fork-friendly security design is appropriate for community-driven documentation projects.
Key Findings Incorporated¶
| Finding | Resolution |
|---|---|
Gitleaks allowlist too broad for .md files |
Removed global .md$ exclusion; only specific example patterns allowlisted |
| Consider SBOM generation | Deferred; overkill for docs site with minimal dependencies |
| Pre-commit hook installation friction | Added instructions to CONTRIBUTING.md |
| Link checking for security | Weekly link validation added to prevent malicious link injection |
Dissenting Views¶
- All models agreed the 3-layer security approach is appropriate for project scope.
- Minor discussion on whether Snyk should be included; consensus is Dependabot sufficient for this project size.