Metadata-Version: 2.4
Name: devsecops-orchestrator
Version: 0.2.0
Summary: Orchestrates security scanning, policy-as-code enforcement, and SBOM generation as a CI/CD step.
Project-URL: Homepage, https://github.com/jaricsng/devsecops-orchestrator
Project-URL: Repository, https://github.com/jaricsng/devsecops-orchestrator
Project-URL: Documentation, https://github.com/jaricsng/devsecops-orchestrator/tree/main/docs
Author-email: Jaric Sng <jaric.sng@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: ci-cd,devsecops,policy-as-code,sast,sbom,security
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Requires-Dist: pydantic<3.0,>=2.6
Requires-Dist: typer<1.0,>=0.12
Provides-Extra: dev
Requires-Dist: black>=24.0; extra == 'dev'
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: policy
Requires-Dist: checkov>=3.2; extra == 'policy'
Provides-Extra: scanners
Requires-Dist: bandit>=1.7; extra == 'scanners'
Requires-Dist: pip-audit>=2.7; extra == 'scanners'
Requires-Dist: semgrep>=1.60; extra == 'scanners'
Provides-Extra: test
Requires-Dist: hypothesis>=6.100; extra == 'test'
Requires-Dist: pytest-cov>=5.0; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# devsecops-orchestrator

A Python CLI that orchestrates security scanning, policy-as-code enforcement, and
SBOM generation as a CI/CD step. It is designed to be invoked inside pipelines
scaffolded by [repo-forge](https://github.com/jaricsng/repo-forge): repo-forge
handles repo scaffolding and distribution, this tool handles the
scanning / policy / reporting logic that runs inside the pipeline.

> **Status:** Phase 5 (SBOM + Full Integration). `scan`, `report`, `policy-check`,
> and `sbom` are live, wired into a reusable CI workflow. Phase 4 (cloud
> cross-reference) is deferred as an optional plugin. See `CLAUDE.md` for the plan.

## Installation

Requires Python 3.11+.

```bash
# From a clone, for development:
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Once published (repo-forge pipelines will pin a version):
pip install devsecops-orchestrator==0.2.0
```

## Usage

```bash
orchestrator --help
orchestrator --version

# Run all available scanners against a target; writes report.md, report.sarif,
# and report.json into the output directory (default: current dir).
orchestrator scan . --output-dir ./reports

# Run a subset of scanners (repeatable --select / -s).
orchestrator scan . -s bandit -s pip-audit

# Re-render a previous scan's report.json without re-scanning.
orchestrator report --input ./reports --format markdown
orchestrator report --input ./reports --format sarif

# Evaluate policy-as-code and gate the build (non-zero exit on violation).
orchestrator policy-check .                 # gate at MEDIUM+ (default)
orchestrator policy-check . --fail-on high  # only HIGH/CRITICAL block

# Generate a CycloneDX SBOM with syft.
orchestrator sbom . -o ./reports            # sbom.cyclonedx.json + sbom.md
```

`scan` runs each wrapped tool as a subprocess and normalizes its output into a
common `Finding` model. A tool that is not installed (or crashes, or emits
unparsable output) is recorded under "scanners skipped/failed" and the scan
continues — it never aborts the whole run. Findings are written in three formats:
`report.md` (human-readable), `report.sarif` (SARIF 2.1.0 for GitHub code
scanning upload), and `report.json` (canonical machine-readable form that
`report` reloads).

| Command | Purpose | Status |
| --- | --- | --- |
| `scan` | Run wrapped security scanners, normalize findings, write reports | ✅ live |
| `report` | Re-render a saved report as Markdown or SARIF | ✅ live |
| `policy-check` | OPA + Checkov + gitleaks policy gate (non-zero exit on violation) | ✅ live |
| `sbom` | Generate a CycloneDX SBOM with syft | ✅ live |
| `cloud-check` | Live AWS drift vs. policy baseline (plugin) | ✅ via plugin |

### Policy-as-code

`policy-check` evaluates starter policies across three engines and fails the
build on violations. See [`docs/runbook.md`](docs/runbook.md) for full details.

| Policy | Engine | Severity | Checks |
| --- | --- | --- | --- |
| `required-license` | OPA/Rego | HIGH | LICENSE file at repo root |
| `branch-protection-config-present` | OPA/Rego | MEDIUM | Branch protection declared as code |
| `no-root-containers` | Checkov | HIGH | Dockerfiles set a non-root `USER` |
| `no-hardcoded-secrets` | gitleaks | HIGH | No secrets in the tree |

Requires the `opa` binary and `pip install devsecops-orchestrator[policy]`
(Checkov). A missing engine degrades its policies to non-blocking ERROR rather
than aborting the gate.

### Plugins

The core tool is provider-agnostic. Optional plugins register extra subcommands
via the `orchestrator.plugins` entry-point group — install one alongside the core
and its command appears automatically.

| Plugin | Adds | Detects |
| --- | --- | --- |
| [`orchestrator-cloud-aws`](plugins/orchestrator-cloud-aws) | `cloud-check` | Live AWS drift — resources that diverge from the IaC/policy baseline (public S3 buckets, `*:*` IAM policies), cross-referenced to the matching Checkov checks |

```bash
pip install devsecops-orchestrator orchestrator-cloud-aws
orchestrator cloud-check --region us-east-1 --fail-on high
```

Needs read-only AWS credentials at runtime (resolved via the standard boto3
chain); the plugin's own tests run entirely against `moto`, no account required.

### Wrapped scanners

| Scanner | Detects | Install |
| --- | --- | --- |
| `bandit` | Python source security issues (SAST) | `pip install .[scanners]` |
| `pip-audit` | Known-vulnerable Python dependencies | `pip install .[scanners]` |
| `semgrep` | Multi-language pattern-based SAST | `pip install .[scanners]` |
| `gitleaks` | Hardcoded secrets | binary (see gitleaks releases) |
| `trivy` | Filesystem vulns, misconfigs, secrets | binary (see trivy releases) |

## Development

```bash
pip install -e ".[dev]"
pre-commit install          # install git hooks (dogfoods our own tooling)

pytest                      # run tests with coverage
ruff check .                # lint
black --check .             # formatting
mypy                        # type-check
pre-commit run --all-files  # run every hook
```

## Continuous integration

`.github/workflows/ci.yml` runs on every pull request and on pushes to `main`:

- **lint** — `ruff`, `black --check`, `mypy`
- **test** — `pytest` across Python 3.11, 3.12, and 3.13
- **self-scan** — dogfoods the orchestrator against its own source (bandit +
  pip-audit) and uploads the SARIF report to GitHub code scanning
- **policy-gate** — runs `policy-check` against this repo (OPA + Checkov)

## Branch protection

Configure the following on `main` (Settings → Branches → Branch protection rules)
so the CI gate is enforced:

- Require a pull request before merging, with at least **1 approving review**.
- Require status checks to pass before merging — select the `lint` and `test`
  jobs from the CI workflow.
- Require branches to be **up to date** before merging.
- Require **signed commits**.
- Do not allow bypassing the above (apply to administrators).

Releases use semantic versioning and are tagged on `main` (`vX.Y.Z`).

## License

Apache 2.0 — see [`LICENSE`](LICENSE). Third-party tools invoked by this
orchestrator are attributed in [`NOTICE`](NOTICE); their source is not bundled.
