Share a Checkov report

Checkov reads your Terraform, CloudFormation, Kubernetes manifests and Helm charts and tells you which of them will embarrass you later. Then it tells you in a pipeline log, in colour, 400 lines long.

The people who need to act on that — a platform lead, a security reviewer, the auditor asking for evidence — are not going to read a pipeline log. Terraform plan output has the same problem, and the same fix; see share a Terraform plan.

Get HTML out of it

Checkov has no HTML writer. Two conversions, both fine:

# via SARIF — the format the rest of your security tooling speaks
checkov -d . --output sarif --output-file-path .
pip install sarif-tools
sarif html results.sarif --output checkov.html

# or via JUnit XML, if your pipeline already consumes it
checkov -d . -o junitxml > checkov.xml

SARIF is the better intermediate: the same converter then handles Semgrep, Trivy and anything else in the pipeline that emits it, so you set it up once. See share a Semgrep report.

Publish it

checkov -d . --output sarif --output-file-path . || true
sarif html results.sarif --output checkov.html

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html checkov.html \
        --arg title "IaC scan — $(git rev-parse --short HEAD)" \
        '{title: $title, html: $html}')"

One call, no assets. checkov exits non-zero when it finds failures, so the || true and an if: always() are load-bearing — a failing scan is when the report matters. Use a scoped token (reports:write) from CI secrets and PATCH a saved report id so one URL accumulates a revision per scan. See publishing from CI.

Triage, on the finding

IaC findings are unusually argumentative, because a check that is correct in general is often wrong for your architecture:

  • CKV_AWS_18 wants access logging on a bucket that exists to hold logs. Someone has to write that down once.
  • The public-read check fires on the bucket that is deliberately a public static site.
  • The baseline scan of an account you inherited, with 300 findings you are burning down over two quarters — a shared document with a trend, not a gate.

Published to a URL, each of those is a thread anchored to the finding, surviving across scans. The next engineer who trips CKV_AWS_18 on that bucket finds the reasoning attached to it instead of re-deriving it or, worse, quietly adding another skip-check comment. See commenting on HTML.

Revision diffs give the burndown honestly: two scans, one diff, which findings actually cleared — as opposed to a count that dropped because someone widened a skip.

Treat it as sensitive

The report names resources, file paths and the specific misconfiguration. Access is per report: private, team, any signed-in user with the link, or public, with view / comment / edit rights for link holders. Default to team or private; use a link deliberately when handing it to an auditor. Password gates and expiring links are Enterprise. See sharing & access control.

Limits

  • Entry HTML: 5 MB. A first baseline scan of a large estate can exceed it — publish by severity or by directory, which is how it gets read anyway. Assets: 25 MB per file, 250 MB and 500 files total.
  • Scripts run, sandboxed (allow-scripts, no allow-same-origin).
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish an IaC scan →

Related