audit-report
Turns an audit-tools evidence package into a control-mapped, auditor-ready report — Markdown, self-contained HTML, or JSON — driven by declarative rulesets.
audit-tools collects raw CSVs (IAM users, branch protections, security
groups…). audit-report reads that package, applies pass/fail rules, maps each
result to SOC 2, ISO 27001, and NIST SP 800-53 controls, and produces a
report you can hand to an auditor or gate a pipeline on.
Like gh-attest, this tool produces evidence, not a compliance verdict. A failing row means a setting is in a state that does not support a control; the final judgment belongs to the organization and its auditor.
Install
pip install audit-report
To hack on it from a clone instead, see Development.
Usage
Point it at a package directory produced by audit-tools:
# Markdown report to stdout (platform + ruleset auto-detected from the dir name)
audit-report ./output/aws_audit_default_2026-07-29
# All three formats into ./report/
audit-report ./output/github_audit_acme_2026-07-29 --format md,html,json --out report/
# Gate CI: exit non-zero if any high-severity check fails
audit-report ./output/aws_audit_prod_2026-07-29 --fail-on high --out report/
Diff mode — compare two packages
Pass --baseline to report how a package drifted from an earlier one. Both
are evaluated with the same ruleset; the report classifies each rule as
regressed, fixed, drifted (an ongoing failure whose evidence rows changed),
changed, or unchanged — and shows exactly which evidence rows appeared or
disappeared.
# How did prod change between two audit runs?
audit-report ./output/aws_audit_prod_2026-07-29 \
--baseline ./output/aws_audit_prod_2026-06-29 \
--format md,html --out drift/
# Fail CI if this change regressed any high-severity control
audit-report ./output/aws_audit_prod_2026-07-29 \
--baseline ./output/aws_audit_prod_2026-06-29 --fail-on high
In diff mode --fail-on gates on regressions at or above the given
severity, and output files are named diff.* instead of report.*.
Trend mode — track controls over time
Pass --trend and point at a folder of dated packages (for example
audit-tools' output/). Every package in the series is evaluated with the same
ruleset and laid out as a timeline — one row per rule, one column per date — so
you can watch a control drift in and out of compliance.
# Heatmap of every control across all retained prod packages
audit-report ./output --trend --format html,json --out trend/
# Disambiguate when the folder holds more than one series
audit-report ./output --trend --subject prod --out trend/
The series must share one platform and subject (use --subject to pick one) and
contain at least two packages. In trend mode --fail-on reflects the latest
package, so it can double as a snapshot gate. Output files are named trend.*.
You can also run it without installing:
python -m audit_report ./output/aws_audit_default_2026-07-29
Options
| Flag | Description |
|---|---|
--baseline PATH |
Diff mode: report how PACKAGE drifted from this earlier package. |
--trend |
Trend mode: treat PACKAGE as a folder of dated packages and chart each rule over time. |
--subject NAME |
In trend mode, pick one subject when the folder holds several series. |
--ruleset PATH |
Use a specific ruleset instead of the bundled one for the detected platform. |
--format md,html,json |
One or more output formats (default: md). |
--out DIR |
Write report.<ext> files into DIR. Without it, the first format prints to stdout. |
--fail-on low|medium|high|none |
Exit non-zero when a failing finding — or, in diff mode, a regression — meets this severity (default: none). |
What a report contains
- Summary — failing / passing / not-applicable counts.
- Control coverage matrix — every cited control, its framework, and a worst-wins status rolled up from the rules that reference it. One failing rule marks the control as not fully evidenced.
- Findings — failures first, then by severity, each with the reason, why it matters, remediation, and the exact evidence rows that failed.
Bundled rulesets
| Platform | Package prefix | Checks include |
|---|---|---|
| AWS | aws_audit_* |
Console-user MFA, access-key rotation, root MFA & keys, password policy, open SSH, public S3, CloudTrail logging |
| GitHub | github_audit_* |
Org 2FA, base permission, secret-scanning push protection, default-branch protection, required reviews |
| GitLab | gitlab_audit_* |
Force-push on protected branches, code-owner approval, approval-rule strength, public projects, instance password policy, audit logging |
Writing your own rules
A ruleset is a YAML file: a platform and a list of rules. Each rule names a
CSV table, a check, the controls it maps to, and human-readable text. Point at
one with --ruleset.
platform: aws
rules:
- id: aws.iam.console-mfa
title: Console users have MFA enabled
table: iam_users # <table>.csv inside the package
severity: high # high | medium | low
controls: [SOC2:CC6.1, ISO:A.5.17, NIST:IA-2]
rationale: A console user without a second factor is one stolen password from access.
remediation: Enforce MFA for all console users, or remove their console password.
check:
type: fail_rows_where # every matching row is a failure
when:
all:
- {column: console_password, op: is_true}
- {column: mfa_enabled, op: is_false}
Check types
| Type | Meaning |
|---|---|
fail_rows_where |
Each row matching when is a failing finding. |
fail_if_any_rows |
The presence of any row (optionally filtered by when) is a failure. |
require_any_row |
Passes only if at least one row satisfies when. |
assert_row |
Checks each condition in require against the first row of a single-row config table. |
Condition language — a condition is a leaf {column, op, value}, or one of
{all: [...]}, {any: [...]}, {not: ...}. Operators: equals, not_equals,
is_true, is_false, in, not_in, gt, gte, lt, lte, empty,
not_empty. Control codes referenced by a rule must exist in
audit_report/catalog.py.
Continuous integration
Run it on a schedule or in a pipeline to keep evidence current and gate on regressions. See docs/ci.md and the ready-to-copy examples:
The --fail-on exit code (1 = a finding/regression met the threshold, 2 =
usage error) lets a workflow separate "the audit found a problem" from "the job
is misconfigured".
Stability
audit-report is stable as of v1.0.0 and follows semantic versioning.
The JSON report schema — findings carrying their controls and
pass / fail / not_applicable status — is a committed contract that
control-coverage consumes
directly; it will not break without a major-version bump.
Development
pip install -e ".[dev]"
pytest # run from the project root
ruff check .
License
GPL-3.0-or-later. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file audit_report-1.0.0.tar.gz.
File metadata
- Download URL: audit_report-1.0.0.tar.gz
- Upload date:
- Size: 47.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d832cc41bb56ca008a9b98550564c01a0f4b49371bff47a7d35312a5794700bd
|
|
| MD5 |
ef41b1bfc8db71e1a5502475eaa2fbda
|
|
| BLAKE2b-256 |
366af7769538db24ed2a4e8cfbcb25e0f8ac69b84ecc4ed4ea03c3cb7c861c1f
|
Provenance
The following attestation bundles were made for audit_report-1.0.0.tar.gz:
Publisher:
release.yml on audit-labs/audit-report
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
audit_report-1.0.0.tar.gz -
Subject digest:
d832cc41bb56ca008a9b98550564c01a0f4b49371bff47a7d35312a5794700bd - Sigstore transparency entry: 2378386236
- Sigstore integration time:
-
Permalink:
audit-labs/audit-report@073020727e5ddc574f63690de8e559a5e43d2794 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/audit-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@073020727e5ddc574f63690de8e559a5e43d2794 -
Trigger Event:
push
-
Statement type:
File details
Details for the file audit_report-1.0.0-py3-none-any.whl.
File metadata
- Download URL: audit_report-1.0.0-py3-none-any.whl
- Upload date:
- Size: 47.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c26087591b7997e021ee44e9c84bff6a071e27b3ae4cbaf0de08dd7bec11cd19
|
|
| MD5 |
bd4579999094fa834c38522904d75219
|
|
| BLAKE2b-256 |
13a4c43ba78b68e22290710e1640837bb1ee150c58bcc8490434426419872520
|
Provenance
The following attestation bundles were made for audit_report-1.0.0-py3-none-any.whl:
Publisher:
release.yml on audit-labs/audit-report
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
audit_report-1.0.0-py3-none-any.whl -
Subject digest:
c26087591b7997e021ee44e9c84bff6a071e27b3ae4cbaf0de08dd7bec11cd19 - Sigstore transparency entry: 2378386565
- Sigstore integration time:
-
Permalink:
audit-labs/audit-report@073020727e5ddc574f63690de8e559a5e43d2794 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/audit-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@073020727e5ddc574f63690de8e559a5e43d2794 -
Trigger Event:
push
-
Statement type: