CI / CD pipeline
GreekManage uses GitHub Actions for CI. Five workflows currently live in .github/workflows/.
Overview
ci.yml — main CI gate
Trigger: push or PR to main
Jobs:
- changes — path filter detects which areas of code changed. Drives later jobs to skip unaffected work.
- backend —
pytest(scoped to changed Django apps if filter matched, else full). Postgres + Redis services in the runner. - frontend —
npm test(Vitest) +npm run build(production Vite build). - android-build —
npx cap sync android+./gradlew assembleDebug. Generates a dummygoogle-services.jsonfor CI. - security:
- Bandit — Python SAST, fail on HIGH+
- Semgrep — multi-language SAST with custom rules in
.semgrep.yml - pip-audit — Python CVE scan
- npm audit — JS CVE scan (high severity blocks)
- Trivy — filesystem scan
- e2e (in
e2e.yml, runs in parallel via reusable workflow):- Backend migrations + seed data
python manage.py runserver+ frontend dev server- Playwright
@smoketagged tests (gate; full suite is overnight) - ZAP API scan (credentialed) — verifies API surface against vulns
- ZAP baseline scan (frontend) — passive only
- Artifacts uploaded for any failures (Playwright traces, ZAP reports)
All required checks must pass before merge.
e2e.yml — end-to-end tests + DAST
Trigger: push or PR; also reusable from ci.yml
What it does:
- Spins up the full stack via
docker-compose.e2e.yml - Runs Playwright tests (~132 tests) —
@smoketag for gate, full suite optional - Runs OWASP ZAP active scan against the API with valid credentials
- Runs ZAP baseline (passive) against the frontend
- Captures traces, screenshots, video on failure
security-nightly.yml — nightly DAST
Trigger: cron at 0 11 * * * (06:00 ET)
What it does:
- Spins up a clean stack
- Runs full ZAP active scan (more aggressive than baseline) against API + frontend
- Opens a GitHub issue with findings if any are HIGH+ severity
- Issues are deduplicated by date (groups multiple findings into one issue per day)
- 60-minute timeout
claude-code-review.yml — AI code review
Trigger: PR opened, ready-for-review, or reopened
What it does:
- Runs
anthropics/claude-code-action@v1against the PR diff - Posts review comments inline
continue-on-error: true— never blocks merge; advisory only
docs-site.yml — documentation site
Trigger: push or PR touching docs-site/** or the workflow itself
What it does (current):
- Builds the Docusaurus site
- Verifies zero broken links / MDX errors
- Uploads build artifact
What it does (when deploy steps are uncommented):
- On push to
mainonly: deploy the build to GitHub Pages - Cloudflare Pages alternative also commented in
→ See the workflow file
Quality gate (SonarQube)
sonar-project.properties defines the SonarQube project. The CI pipeline reports coverage + code quality to SonarQube; the quality gate enforces:
- Coverage on new code ≥ 80%
- No new HIGH or CRITICAL issues
- No duplications above threshold
A failing quality gate blocks merge.
Required vs optional checks
| Check | Required to merge? |
|---|---|
| Backend tests | ✅ Required |
| Frontend tests | ✅ Required |
| Frontend build | ✅ Required |
| Android build | ✅ Required (catches Capacitor sync issues) |
| Bandit / Semgrep / pip-audit / npm audit / Trivy | ✅ Required (blocking on HIGH+) |
| SonarQube quality gate | ✅ Required |
E2E @smoke | ✅ Required |
| ZAP API + ZAP baseline | ✅ Required (no HIGH findings) |
| Claude Code Review | ❌ Advisory |
| Nightly full ZAP | ❌ Async — failures open an issue |
Caching
GitHub Actions caches:
~/.cache/pipkeyed byrequirements.txthashnode_moduleskeyed bypackage-lock.jsonhash~/.gradle/cachesfor Android builds
Drops cache hit ratio noticeably when lockfiles change — expected.
Secrets
Required repository secrets (configure in repo Settings → Secrets):
| Secret | Used by |
|---|---|
SONAR_TOKEN | SonarQube quality gate |
CLAUDE_CODE_OAUTH_TOKEN | Claude code review action |
E2E_ADMIN_PASSWORD | E2E test fixture (creates a known admin user) |
GITHUB_TOKEN | Auto-provided; used for issue creation in nightly scan |
For deployment workflows (when you wire them up):
| Secret | Used by |
|---|---|
KUBECONFIG (base64) | Production deploy |
GHCR_TOKEN | Image registry push |
CLOUDFLARE_API_TOKEN (optional) | Cloudflare Pages docs deploy |
Local CI parity
To run the full security suite locally before pushing:
npm run security:full
This wraps Bandit + Semgrep + pip-audit + npm audit + Trivy + secret scanning. Faster than waiting for CI.
For backend tests:
docker compose exec backend pytest
For E2E:
cd e2e && npm test
Adding a new workflow
- Create
.github/workflows/<name>.yml - Use path filtering to avoid running on unrelated changes:
on:push:paths: ['<directory>/**', '.github/workflows/<name>.yml']
- If it's a check that should block merge, add it to the required status checks in repo Settings → Branches → main
- Document it here
When CI is red
| Failure | Common cause | Fix |
|---|---|---|
| Backend tests fail | Migration not run | Add migration to PR |
| Frontend build fails | TypeScript error | Run npm run typecheck locally |
| Android build fails | Capacitor sync failed | npx cap sync android locally |
| Semgrep new finding | New code matches a rule | Fix the issue or add a comment-suppression with a TODO + ticket |
| pip-audit / npm audit | New CVE in a dep | Update the dep, or pin a known-good version with a justification |
| ZAP HIGH | New endpoint without auth, or missing CSRF | Audit the endpoint |
| SonarQube quality gate | Coverage drop | Add tests for new code |