CI/CD and Infrastructure Documentation
This document describes the continuous integration, security scanning, and development infrastructure used by the Local Deep Research project.
Overview
The project uses many GitHub Actions workflows and 20+ pre-commit hooks to ensure code quality, security, and reliability.
┌─────────────────────────────────────────────────────────────────┐
│ Developer Workflow │
├─────────────────────────────────────────────────────────────────┤
│ Local Development │ Pull Request │ Main/Dev │
│ ───────────────── │ ──────────── │ ──────── │
│ • Pre-commit hooks │ • All tests │ • Deploy │
│ • Unit tests │ • Security scans │ • Publish │
│ • Linting │ • Code review │ • Release │
└─────────────────────────────────────────────────────────────────┘
Pre-Commit Hooks
Pre-commit hooks run locally before each commit. Install with:
pre-commit install
pre-commit install-hooks
Standard Hooks
| Hook |
Purpose |
check-yaml |
Validate YAML syntax |
end-of-file-fixer |
Ensure files end with newline |
trailing-whitespace |
Remove trailing whitespace |
check-added-large-files |
Block files >1MB |
check-case-conflict |
Prevent case-sensitivity issues |
forbid-new-submodules |
Prevent git submodules |
Security Hooks
| Hook |
Purpose |
gitleaks |
Detect secrets, API keys, passwords in code |
check-sensitive-logging |
Prevent logging of passwords, tokens, keys |
check-safe-requests |
Enforce SSRF-safe HTTP functions (safe_get, safe_post) |
check-url-security |
Validate URL handling in JavaScript (XSS prevention) |
file-whitelist-check |
Only allow approved file types |
check-image-pinning |
Require SHA256 digests for Docker images |
Code Quality Hooks
| Hook |
Purpose |
ruff |
Python linter (with auto-fix) |
ruff-format |
Python formatter (Black-compatible) |
eslint |
JavaScript linter |
shellcheck |
Shell script linter |
actionlint |
GitHub Actions workflow validator |
custom-code-checks |
Loguru usage, UTC datetime, raw SQL detection |
Project-Specific Hooks
| Hook |
Purpose |
check-env-vars |
Environment variables must use SettingsManager |
check-deprecated-db-connection |
Enforce per-user database connections |
check-ldr-db-usage |
Prevent shared ldr.db usage |
check-research-id-type |
research_id must be string/UUID, not int |
check-datetime-timezone |
SQLAlchemy DateTime must have timezone=True |
check-session-context-manager |
Require context managers for DB sessions |
check-pathlib-usage |
Use pathlib.Path instead of os.path |
check-no-external-resources |
No external CDN/resource references |
check-css-class-prefix |
CSS classes must have ldr- prefix |
GitHub Actions Workflows
Test Workflows
| Workflow |
Trigger |
Purpose |
docker-tests.yml |
PR, push |
Consolidated Docker tests: pytest + coverage, UI tests, LLM tests, infrastructure tests (single Docker build shared across all jobs) |
api-tests.yml |
PR, push |
API endpoint testing |
critical-ui-tests.yml |
PR, push |
Essential UI flow tests |
extended-ui-tests.yml |
PR, push |
Extended UI validation |
e2e-research-test.yml |
PR, push |
End-to-end research flow |
library-ui-tests.yml |
PR, push |
Research library UI tests |
news-tests.yml |
PR, push |
News subscription tests |
metrics-analytics-tests.yml |
PR, push |
Analytics tests |
performance-tests.yml |
PR, push |
Performance benchmarks |
followup-research-tests.yml |
PR, push |
Follow-up research tests |
fuzz.yml |
Schedule |
Fuzzing tests |
Security Scanning
| Workflow |
Trigger |
Purpose |
codeql.yml |
PR, push, schedule |
GitHub CodeQL analysis |
semgrep.yml |
PR, push |
Semgrep static analysis |
osv-scanner.yml |
PR, push, schedule |
OSV vulnerability scanning (Python + npm) |
gitleaks.yml |
PR, push |
Secret detection |
security-tests.yml |
PR, push |
Security-focused test suite |
devskim.yml |
PR, push |
Microsoft DevSkim analysis |
checkov.yml |
PR, push |
Infrastructure-as-code scanning |
container-security.yml |
PR, push |
Container vulnerability scanning |
hadolint.yml |
PR, push |
Dockerfile linting |
owasp-zap-scan.yml |
Schedule |
OWASP ZAP dynamic scanning |
retirejs.yml |
PR, push |
JavaScript vulnerability scanning |
zizmor-security.yml |
PR, push |
Additional security checks |
ossar.yml |
PR, push |
OSSAR security analysis |
ossf-scorecard.yml |
Schedule |
OpenSSF Scorecard |
security-headers-validation.yml |
PR, push |
HTTP security headers |
security-file-write-check.yml |
PR, push |
File write security |
npm-audit.yml |
PR, push |
npm audit for JS dependencies |
Dependency Management
| Workflow |
Trigger |
Purpose |
dependency-review.yml |
PR |
Review dependency changes |
update-dependencies.yml |
Schedule |
Auto-update Python deps |
update-npm-dependencies.yml |
Schedule |
Auto-update npm deps |
update-precommit-hooks.yml |
Schedule |
Update pre-commit hooks |
validate-image-pinning.yml |
PR, push |
Verify Docker image pins |
UI/Accessibility
| Workflow |
Trigger |
Purpose |
accessibility-compliance-tests.yml |
PR, push |
WCAG compliance (axe-core) |
responsive-ui-tests-enhanced.yml |
PR, push |
Responsive design tests |
mobile-ui-tests.yml |
PR, push |
Mobile viewport tests |
check-css-classes.yml |
PR, push |
CSS class naming validation |
Build & Deploy
| Workflow |
Trigger |
Purpose |
docker-publish.yml |
Release, push |
Build and publish Docker images |
docker-multiarch-test.yml |
PR, push |
Multi-architecture build test |
publish.yml |
Release |
Publish to PyPI |
release.yml |
Manual |
Create releases |
Code Quality
| Workflow |
Trigger |
Purpose |
pre-commit.yml |
PR, push |
Run pre-commit hooks in CI |
mypy-type-check.yml |
PR, push |
Python type checking |
ai-code-reviewer.yml |
PR |
AI-assisted code review |
claude-code-review.yml |
PR |
Claude-based code review |
Repository Management
| Workflow |
Trigger |
Purpose |
sync-main-to-dev.yml |
Push to main |
Sync main branch to dev |
label-fixed-in-dev.yml |
Push to dev |
Auto-label fixed issues |
danger-zone-alert.yml |
PR |
Alert on sensitive file changes |
check-env-vars.yml |
PR, push |
Environment variable validation |
file-whitelist-check.yml |
PR, push |
File type validation |
version_check.yml |
PR, push |
Version consistency check |
Dependabot Configuration
Dependabot automatically creates PRs for dependency updates:
| Ecosystem |
Directories |
Schedule |
| Python (pip) |
/ |
Weekly (Monday 04:00) |
| npm |
/, /tests/* |
Weekly/Daily |
| GitHub Actions |
/ |
Weekly |
| Docker |
/ |
Daily |
Coverage Reporting
Coverage reports are generated by the docker-tests.yml workflow (pytest-tests job):
- HTML Report: Deployed to GitHub Pages at
https://learningcircuit.github.io/local-deep-research/coverage/
- PR Comments: Each PR receives a comment with coverage percentage
- Badge: Coverage badge updated via GitHub Gist
Configuration in pyproject.toml:
[tool.coverage.run]
source = ["src"]
omit = ["*/tests/*", "*/migrations/*"]
[tool.coverage.report]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
Security Architecture
Supply Chain Security
- Dependency Pinning: All GitHub Actions use SHA256 digests
- Docker Image Pinning: All base images use SHA256 digests
- Lock Files:
pdm.lock and package-lock.json committed
- Vulnerability Scanning: OSV-Scanner, npm audit, RetireJS
Runtime Security
- SSRF Protection:
safe_get(), safe_post(), SafeSession wrappers
- XSS Prevention: DOMPurify for HTML sanitization
- SQL Injection: SQLAlchemy ORM (no raw SQL)
- Secret Management: Environment variables via
SettingsManager
Container Security
- Non-root User: Containers run as
ldruser:1000
- Minimal Base Image: Python slim images
- Health Checks: Docker health check endpoints
- Read-only Where Possible: Minimal write permissions
Running Tests Locally
Quick Test (Unit Tests Only)
pdm run pytest tests/test_settings_manager.py tests/test_utils.py -v
Full Test Suite
pdm run pytest tests/ --ignore=tests/ui_tests --ignore=tests/fuzz -v
With Coverage
pdm run pytest tests/ --cov=src --cov-report=html -v
open coverage/htmlcov/index.html
UI Tests (Requires Server)
# Terminal 1: Start server
pdm run ldr-web
# Terminal 2: Run UI tests
cd tests/ui_tests && npm test
Docker Testing
Build and run tests in Docker:
# Build test image
docker build --target ldr-test -t ldr-test .
# Run tests
docker run --rm -v "$PWD":/app -w /app ldr-test \
pytest tests/ --ignore=tests/ui_tests -v
Environment Variables for CI
| Variable |
Purpose |
CI=true |
Indicates CI environment |
LDR_USE_FALLBACK_LLM=true |
Use mock LLM for tests |
LDR_TESTING_WITH_MOCKS=true |
Enable test mocks |
DISABLE_RATE_LIMITING=true |
Disable rate limits in tests |
Adding New Workflows
When adding a new workflow:
- Use pinned action versions with SHA256 digests
- Add
permissions: {} at top level (minimal permissions)
- Add job-level permissions as needed
- Include
step-security/harden-runner step
- Add workflow to this documentation
Example template:
name: New Workflow
on:
pull_request:
branches: [main]
permissions: {}
jobs:
example:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Harden the runner
uses: step-security/harden-runner@... # pinned
with:
egress-policy: audit
- uses: actions/checkout@... # pinned
with:
persist-credentials: false
1---2name: 1532-ci-cd-infrastructure-c2acbe563description: CI/CD and Infrastructure Documentation4---5# CI/CD and Infrastructure Documentation67This document describes the continuous integration, security scanning, and development infrastructure used by the Local Deep Research project.89## Overview1011The project uses many GitHub Actions workflows and 20+ pre-commit hooks to ensure code quality, security, and reliability.1213```14┌─────────────────────────────────────────────────────────────────┐15│ Developer Workflow │16├─────────────────────────────────────────────────────────────────┤17│ Local Development │ Pull Request │ Main/Dev │18│ ───────────────── │ ──────────── │ ──────── │19│ • Pre-commit hooks │ • All tests │ • Deploy │20│ • Unit tests │ • Security scans │ • Publish │21│ • Linting │ • Code review │ • Release │22└─────────────────────────────────────────────────────────────────┘23```2425## Pre-Commit Hooks2627Pre-commit hooks run locally before each commit. Install with:2829```bash30pre-commit install31pre-commit install-hooks32```3334### Standard Hooks3536| Hook | Purpose |37|------|---------|38| `check-yaml` | Validate YAML syntax |39| `end-of-file-fixer` | Ensure files end with newline |40| `trailing-whitespace` | Remove trailing whitespace |41| `check-added-large-files` | Block files >1MB |42| `check-case-conflict` | Prevent case-sensitivity issues |43| `forbid-new-submodules` | Prevent git submodules |4445### Security Hooks4647| Hook | Purpose |48|------|---------|49| `gitleaks` | Detect secrets, API keys, passwords in code |50| `check-sensitive-logging` | Prevent logging of passwords, tokens, keys |51| `check-safe-requests` | Enforce SSRF-safe HTTP functions (`safe_get`, `safe_post`) |52| `check-url-security` | Validate URL handling in JavaScript (XSS prevention) |53| `file-whitelist-check` | Only allow approved file types |54| `check-image-pinning` | Require SHA256 digests for Docker images |5556### Code Quality Hooks5758| Hook | Purpose |59|------|---------|60| `ruff` | Python linter (with auto-fix) |61| `ruff-format` | Python formatter (Black-compatible) |62| `eslint` | JavaScript linter |63| `shellcheck` | Shell script linter |64| `actionlint` | GitHub Actions workflow validator |65| `custom-code-checks` | Loguru usage, UTC datetime, raw SQL detection |6667### Project-Specific Hooks6869| Hook | Purpose |70|------|---------|71| `check-env-vars` | Environment variables must use `SettingsManager` |72| `check-deprecated-db-connection` | Enforce per-user database connections |73| `check-ldr-db-usage` | Prevent shared `ldr.db` usage |74| `check-research-id-type` | `research_id` must be string/UUID, not int |75| `check-datetime-timezone` | SQLAlchemy DateTime must have `timezone=True` |76| `check-session-context-manager` | Require context managers for DB sessions |77| `check-pathlib-usage` | Use `pathlib.Path` instead of `os.path` |78| `check-no-external-resources` | No external CDN/resource references |79| `check-css-class-prefix` | CSS classes must have `ldr-` prefix |8081---8283## GitHub Actions Workflows8485### Test Workflows8687| Workflow | Trigger | Purpose |88|----------|---------|---------|89| `docker-tests.yml` | PR, push | Consolidated Docker tests: pytest + coverage, UI tests, LLM tests, infrastructure tests (single Docker build shared across all jobs) |90| `api-tests.yml` | PR, push | API endpoint testing |91| `critical-ui-tests.yml` | PR, push | Essential UI flow tests |92| `extended-ui-tests.yml` | PR, push | Extended UI validation |93| `e2e-research-test.yml` | PR, push | End-to-end research flow |94| `library-ui-tests.yml` | PR, push | Research library UI tests |95| `news-tests.yml` | PR, push | News subscription tests |96| `metrics-analytics-tests.yml` | PR, push | Analytics tests |97| `performance-tests.yml` | PR, push | Performance benchmarks |98| `followup-research-tests.yml` | PR, push | Follow-up research tests |99| `fuzz.yml` | Schedule | Fuzzing tests |100101### Security Scanning102103| Workflow | Trigger | Purpose |104|----------|---------|---------|105| `codeql.yml` | PR, push, schedule | GitHub CodeQL analysis |106| `semgrep.yml` | PR, push | Semgrep static analysis |107| `osv-scanner.yml` | PR, push, schedule | OSV vulnerability scanning (Python + npm) |108| `gitleaks.yml` | PR, push | Secret detection |109| `security-tests.yml` | PR, push | Security-focused test suite |110| `devskim.yml` | PR, push | Microsoft DevSkim analysis |111| `checkov.yml` | PR, push | Infrastructure-as-code scanning |112| `container-security.yml` | PR, push | Container vulnerability scanning |113| `hadolint.yml` | PR, push | Dockerfile linting |114| `owasp-zap-scan.yml` | Schedule | OWASP ZAP dynamic scanning |115| `retirejs.yml` | PR, push | JavaScript vulnerability scanning |116| `zizmor-security.yml` | PR, push | Additional security checks |117| `ossar.yml` | PR, push | OSSAR security analysis |118| `ossf-scorecard.yml` | Schedule | OpenSSF Scorecard |119| `security-headers-validation.yml` | PR, push | HTTP security headers |120| `security-file-write-check.yml` | PR, push | File write security |121| `npm-audit.yml` | PR, push | npm audit for JS dependencies |122123### Dependency Management124125| Workflow | Trigger | Purpose |126|----------|---------|---------|127| `dependency-review.yml` | PR | Review dependency changes |128| `update-dependencies.yml` | Schedule | Auto-update Python deps |129| `update-npm-dependencies.yml` | Schedule | Auto-update npm deps |130| `update-precommit-hooks.yml` | Schedule | Update pre-commit hooks |131| `validate-image-pinning.yml` | PR, push | Verify Docker image pins |132133### UI/Accessibility134135| Workflow | Trigger | Purpose |136|----------|---------|---------|137| `accessibility-compliance-tests.yml` | PR, push | WCAG compliance (axe-core) |138| `responsive-ui-tests-enhanced.yml` | PR, push | Responsive design tests |139| `mobile-ui-tests.yml` | PR, push | Mobile viewport tests |140| `check-css-classes.yml` | PR, push | CSS class naming validation |141142### Build & Deploy143144| Workflow | Trigger | Purpose |145|----------|---------|---------|146| `docker-publish.yml` | Release, push | Build and publish Docker images |147| `docker-multiarch-test.yml` | PR, push | Multi-architecture build test |148| `publish.yml` | Release | Publish to PyPI |149| `release.yml` | Manual | Create releases |150151### Code Quality152153| Workflow | Trigger | Purpose |154|----------|---------|---------|155| `pre-commit.yml` | PR, push | Run pre-commit hooks in CI |156| `mypy-type-check.yml` | PR, push | Python type checking |157| `ai-code-reviewer.yml` | PR | AI-assisted code review |158| `claude-code-review.yml` | PR | Claude-based code review |159160### Repository Management161162| Workflow | Trigger | Purpose |163|----------|---------|---------|164| `sync-main-to-dev.yml` | Push to main | Sync main branch to dev |165| `label-fixed-in-dev.yml` | Push to dev | Auto-label fixed issues |166| `danger-zone-alert.yml` | PR | Alert on sensitive file changes |167| `check-env-vars.yml` | PR, push | Environment variable validation |168| `file-whitelist-check.yml` | PR, push | File type validation |169| `version_check.yml` | PR, push | Version consistency check |170171---172173## Dependabot Configuration174175Dependabot automatically creates PRs for dependency updates:176177| Ecosystem | Directories | Schedule |178|-----------|-------------|----------|179| Python (pip) | `/` | Weekly (Monday 04:00) |180| npm | `/`, `/tests/*` | Weekly/Daily |181| GitHub Actions | `/` | Weekly |182| Docker | `/` | Daily |183184---185186## Coverage Reporting187188Coverage reports are generated by the `docker-tests.yml` workflow (pytest-tests job):189190- **HTML Report**: Deployed to GitHub Pages at `https://learningcircuit.github.io/local-deep-research/coverage/`191- **PR Comments**: Each PR receives a comment with coverage percentage192- **Badge**: Coverage badge updated via GitHub Gist193194Configuration in `pyproject.toml`:195```toml196[tool.coverage.run]197source = ["src"]198omit = ["*/tests/*", "*/migrations/*"]199200[tool.coverage.report]201exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]202```203204---205206## Security Architecture207208### Supply Chain Security2092101. **Dependency Pinning**: All GitHub Actions use SHA256 digests2112. **Docker Image Pinning**: All base images use SHA256 digests2123. **Lock Files**: `pdm.lock` and `package-lock.json` committed2134. **Vulnerability Scanning**: OSV-Scanner, npm audit, RetireJS214215### Runtime Security2162171. **SSRF Protection**: `safe_get()`, `safe_post()`, `SafeSession` wrappers2182. **XSS Prevention**: DOMPurify for HTML sanitization2193. **SQL Injection**: SQLAlchemy ORM (no raw SQL)2204. **Secret Management**: Environment variables via `SettingsManager`221222### Container Security2232241. **Non-root User**: Containers run as `ldruser:1000`2252. **Minimal Base Image**: Python slim images2263. **Health Checks**: Docker health check endpoints2274. **Read-only Where Possible**: Minimal write permissions228229---230231## Running Tests Locally232233### Quick Test (Unit Tests Only)234```bash235pdm run pytest tests/test_settings_manager.py tests/test_utils.py -v236```237238### Full Test Suite239```bash240pdm run pytest tests/ --ignore=tests/ui_tests --ignore=tests/fuzz -v241```242243### With Coverage244```bash245pdm run pytest tests/ --cov=src --cov-report=html -v246open coverage/htmlcov/index.html247```248249### UI Tests (Requires Server)250```bash251# Terminal 1: Start server252pdm run ldr-web253254# Terminal 2: Run UI tests255cd tests/ui_tests && npm test256```257258---259260## Docker Testing261262Build and run tests in Docker:263264```bash265# Build test image266docker build --target ldr-test -t ldr-test .267268# Run tests269docker run --rm -v "$PWD":/app -w /app ldr-test \270 pytest tests/ --ignore=tests/ui_tests -v271```272273---274275## Environment Variables for CI276277| Variable | Purpose |278|----------|---------|279| `CI=true` | Indicates CI environment |280| `LDR_USE_FALLBACK_LLM=true` | Use mock LLM for tests |281| `LDR_TESTING_WITH_MOCKS=true` | Enable test mocks |282| `DISABLE_RATE_LIMITING=true` | Disable rate limits in tests |283284---285286## Adding New Workflows287288When adding a new workflow:2892901. Use pinned action versions with SHA256 digests2912. Add `permissions: {}` at top level (minimal permissions)2923. Add job-level permissions as needed2934. Include `step-security/harden-runner` step2945. Add workflow to this documentation295296Example template:297```yaml298name: New Workflow299300on:301 pull_request:302 branches: [main]303304permissions: {}305306jobs:307 example:308 runs-on: ubuntu-latest309 permissions:310 contents: read311312 steps:313 - name: Harden the runner314 uses: step-security/harden-runner@... # pinned315 with:316 egress-policy: audit317318 - uses: actions/checkout@... # pinned319 with:320 persist-credentials: false321```