Shared CI pipeline, pre-commit hooks, and test fixtures for LegionForge projects. Supports Python and Node/TypeScript. Rust and C planned.
| Path | Purpose |
|---|---|
.github/workflows/lint.yml |
ruff + bandit + mypy |
.github/workflows/test.yml |
pytest + coverage enforcement |
.github/workflows/sast.yml |
semgrep (p/python + p/fastapi) + CodeQL |
.github/workflows/audit.yml |
pip-audit CVE scan + pip-licenses compliance |
.github/workflows/sbom.yml |
CycloneDX SBOM generation |
| Path | Purpose |
|---|---|
.github/workflows/node-lint.yml |
tsc --noEmit + eslint (skipped if unconfigured) |
.github/workflows/node-test.yml |
vitest/jest + coverage upload |
.github/workflows/node-sast.yml |
semgrep (p/javascript p/typescript p/nodejs) + CodeQL |
.github/workflows/node-audit.yml |
npm audit CVE scan + license-checker compliance |
.github/workflows/node-sbom.yml |
CycloneDX SBOM generation |
| Path | Purpose |
|---|---|
.github/workflows/secrets.yml |
gitleaks secret scanning — works for any language |
| Path | Purpose |
|---|---|
.pre-commit-hooks.yaml |
Hook definitions consumed via pre-commit |
.pre-commit-config.yaml |
Default config to copy into new projects (includes gitleaks) |
SECURITY.md |
Vulnerability disclosure policy template — copy and adjust |
src/legionforge_dev_rig/fixtures/ |
Shared pytest fixtures (httpx mocking, etc.) |
examples/ |
Template conftest.py and example tests |
Until published to PyPI, install path-editable from a local clone:
pip install -e "../../LegionForge-dev-rig/dev-rig"
# Or once published:
pip install legionforge-dev-rigAdd to pyproject.toml:
[project.optional-dependencies]
dev = [
# ... project deps ...
"legionforge-dev-rig",
]cp ../../LegionForge-dev-rig/dev-rig/.pre-commit-config.yaml .Adjust the additional_dependencies under the mypy hook to match your project's runtime deps, then:
pre-commit install
pre-commit run --all-files# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
lint:
uses: LegionForge/dev-rig/.github/workflows/lint.yml@main
with:
source-dirs: "my_package"
test:
uses: LegionForge/dev-rig/.github/workflows/test.yml@main
with:
coverage-source: "my_package"
coverage-threshold: 80
sast:
uses: LegionForge/dev-rig/.github/workflows/sast.yml@main
with:
source-dirs: "my_package/"
permissions:
security-events: write
audit:
uses: LegionForge/dev-rig/.github/workflows/audit.yml@main
secrets:
uses: LegionForge/dev-rig/.github/workflows/secrets.yml@main# tests/conftest.py
from legionforge_dev_rig.fixtures import mock_http_client, respx_mock_base_url
__all__ = ["mock_http_client", "respx_mock_base_url"]dev-rig calls these script names directly. Add them to package.json:
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "eslint src/",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"build": "tsup"
}ESLint is optional — node-lint.yml skips it if no ESLint config file is present.
When you add ESLint, install eslint + @typescript-eslint/eslint-plugin +
@typescript-eslint/parser in devDependencies and add eslint.config.js.
Coverage threshold is enforced by the test runner config (vitest.config.ts
coverage.thresholds or jest.config coverageThreshold), not by this workflow.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
lint:
uses: LegionForge/dev-rig/.github/workflows/node-lint.yml@main
with:
source-dirs: "src"
test:
uses: LegionForge/dev-rig/.github/workflows/node-test.yml@main
with:
coverage-threshold: 80
sast:
uses: LegionForge/dev-rig/.github/workflows/node-sast.yml@main
with:
source-dirs: "src"
permissions:
security-events: write
audit:
uses: LegionForge/dev-rig/.github/workflows/node-audit.yml@main
secrets:
uses: LegionForge/dev-rig/.github/workflows/secrets.yml@mainWhen you add or change a reusable workflow or fixture:
- Bump the version in
pyproject.toml - Tag the release:
git tag v0.x.0 && git push --tags - In consuming projects, update
.pre-commit-config.yamlrev:and@mainpins
To pull the latest hooks in all projects at once:
pre-commit autoupdate| Tool | Minimum version | Config location |
|---|---|---|
| ruff | 0.4 | pyproject.toml [tool.ruff] |
| bandit | 1.7 | pyproject.toml [tool.bandit] |
| mypy | 1.10 | pyproject.toml [tool.mypy] |
| pip-audit | 2.7 | no config — runs against installed packages |
| semgrep | 1.70 | rulesets passed as CLI args |
| pytest-cov | 5 | pyproject.toml [tool.pytest.ini_options] |
| pre-commit | 3.7 | .pre-commit-config.yaml |
| Tool | Minimum version | Config location |
|---|---|---|
| typescript | 5 | tsconfig.json |
| eslint | 9 | eslint.config.js (flat config) |
| @typescript-eslint | 8 | eslint.config.js |
| vitest | 2 | vitest.config.ts |
| @vitest/coverage-v8 | 2 | vitest.config.ts coverage.* |
| license-checker | 25 | no config — allowlist passed as CLI arg |
| @cyclonedx/cyclonedx-npm | 1 | no config |
dev-rig provides multi-layered security testing aligned with OWASP SAMM maturity practices and OWASP Top 10 vulnerability categories:
| Tool | Workflow | OWASP Coverage |
|---|---|---|
| Semgrep (p/python) | lint.yml |
A01 (Broken Access Control—partial), A02 (Cryptographic Failures), A03 (Injection—SQL/CMD/SSTI), A05 (Security Misconfiguration), A08 (Software/Data Integrity) |
| Semgrep (p/fastapi) | lint.yml |
A01 (CORS/Auth misconfiguration), A07 (Identification/Authentication Failures), A02 (JWT issues) |
| CodeQL (security-extended) | sast.yml |
A03 (Injection—taint-flow), A10 (SSRF), A01 (Access Control—partial) |
| Bandit | lint.yml |
A02 (Cryptographic Failures), A06 (Vulnerable Components), A08 (Integrity) |
| Tool | Workflow | OWASP Coverage |
|---|---|---|
| pip-audit | audit.yml |
A06 (Vulnerable and Outdated Components) |
| pip-licenses | audit.yml |
A06 (License compliance—supply chain risk) |
| Tool | Workflow | OWASP Coverage |
|---|---|---|
| gitleaks | secrets.yml |
A02 (Cryptographic Failures—leaked credentials/keys) |
| Tool | Workflow | OWASP Coverage |
|---|---|---|
| OWASP ZAP | dast.yml |
A01 (Auth enforcement at runtime), A05 (Missing security headers), A06 (Session/token lifecycle), A09 (Logging/Monitoring—response leakage) |
SAST tools (semgrep, CodeQL, bandit) analyze source code and can detect injection patterns, weak crypto, hardcoded secrets, and dependency vulnerabilities. However, they cannot test behavior at runtime:
- Authentication enforcement — whether
/loginactually rejects bad credentials, whether protected endpoints block unauthenticated requests - HTTP security headers —
X-Content-Type-Options,Content-Security-Policy,Strict-Transport-Security, etc. (not added by most frameworks by default) - Session/token lifecycle — expiration, token refresh, session fixation
- Information disclosure in error responses — whether 500 errors leak stack traces or internal paths
- Rate limiting and DoS prevention — not visible in code analysis
DAST bridges this gap by running the application and probing it against real HTTP requests.
For FastAPI, Django, Flask, Node.js/Express, and other web services, integrate both SAST and DAST:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
lint:
uses: LegionForge/dev-rig/.github/workflows/lint.yml@main
with:
source-dirs: "src"
test:
uses: LegionForge/dev-rig/.github/workflows/test.yml@main
with:
coverage-source: "src"
coverage-threshold: 80
sast:
uses: LegionForge/dev-rig/.github/workflows/sast.yml@main
with:
source-dirs: "src"
permissions:
security-events: write
audit:
uses: LegionForge/dev-rig/.github/workflows/audit.yml@main
secrets:
uses: LegionForge/dev-rig/.github/workflows/secrets.yml@main
dast:
needs: [test] # Only run DAST after unit tests pass
uses: LegionForge/dev-rig/.github/workflows/dast.yml@main
with:
target-url: "http://localhost:9766"
fail-on-severity: "High"
permissions:
security-events: writeImportant: The dast.yml workflow does not start your service. The caller workflow (in your repo) is responsible for:
- Spinning up the service in Docker Compose or Kubernetes
- Polling
/healthor equivalent until the service is ready - Invoking
dast.ymlwith the target URL - Cleaning up containers/processes after scan completes
See LegionForge/LegionForge-Guardian/.github/workflows/dast.yml for a complete example.
| Category | What it is | dev-rig Coverage |
|---|---|---|
| A01: Broken Access Control | Auth/authz failures, CORS issues, privilege escalation | SAST (semgrep/CodeQL) + DAST (ZAP) |
| A02: Cryptographic Failures | Weak crypto, hardcoded secrets, TLS issues | SAST (semgrep/bandit) + Audit (gitleaks) |
| A03: Injection | SQL, command, LDAP, template injection | SAST (semgrep/CodeQL—taint-flow) |
| A04: Insecure Design | Missing controls by design (no auth model, etc.) | Not covered — requires threat modeling |
| A05: Security Misconfiguration | Missing headers, exposed services, bad defaults | SAST (semgrep p/fastapi) + DAST (ZAP headers) |
| A06: Vulnerable Components | Known CVEs in dependencies | Audit (pip-audit) |
| A07: Authentication Failures | Weak password policy, session fixation | SAST (semgrep p/fastapi) + DAST (ZAP) |
| A08: Data Integrity Failures | Serialization bugs, unsigned updates | SAST (semgrep/CodeQL) |
| A09: Logging/Monitoring Failures | Missing logs, response leakage | DAST (ZAP scans for info disclosure) |
| A10: SSRF | Server-side request forgery | SAST (CodeQL—taint tracking) |