Export reports¶
Every scan writes its reports to reports/ in the output directory
(.ash/ash_output/reports/ by default). Thirteen reporters are on by default, and each
writes its own file (unused-suppressions writes two), so the usual way to export is to
pick the file your destination reads:
| Destination | File in reports/ |
|---|---|
| GitHub code scanning | ash.ghas.sarif |
| Other SARIF consumers (IDEs, code review tools) | ash.sarif |
| GitLab security reports | ash.gl-sast-report.json, ash.gl-dependency-scanning-report.cdx.json |
| CI test results | ash.junit.xml |
| SBOM tools | ash.cdx.json (CycloneDX), ash.spdx.json (SPDX, off by default) |
| Security data lakes, SIEMs | ash.ocsf.json |
| Spreadsheets | ash.csv |
| A person | ash.html, ash.summary.md, ash.summary.txt |
| Your own scripts | ash.flat.json |
Reporters reference lists every reporter with its options, and Output files describes the rest of the output directory.
Choose which reports to write¶
To write fewer files, pass --output-formats (or -f) with a comma-separated list:
When detect-secrets finds a secret, the scan exits 2, and reports/ holds only the two
files you asked for:
The option works like this:
- It accepts the name of every reporter ASH ships, including
github-ghas,gitlab-sast,gitlab-cyclonedx, andunused-suppressions, and the names of the AWS reporters, which write a report only when an operator loads their plugin module. It also acceptsaggregated,dict,asff, andcustom, which no reporter writes. Reporters left out of the list do not run. A reporter from your own plugin module cannot be named; it runs only when no list is given. - An unknown name stops the scan with a usage error before scanning, and exits 5.
- The list narrows the enabled reporters and does not turn on a disabled one.
yamlandspdxare disabled by default. Naming one writes nothing until you enable its reporter; ASH logs an error inash.logthat names the setting.
To make the same choice for every scan, list the names under output_formats in your
ASH config file. It also takes one name, or names separated by commas, as
--output-formats does, and a name it does not accept makes the configuration invalid
(exit 3). --output-formats replaces the configured list for one scan, and with neither,
every enabled reporter writes its report. In a workspace scan, a project's
output_formats applies to that project's reports, and the combined reports follow
--output-formats only:
To control reporters from configuration, turn each one on or off. This adds SPDX to the default set and drops HTML:
On the command line, the same settings are
--config-overrides reporters.spdx.enabled=true --config-overrides reporters.html.enabled=false.
To produce one more format after a scan, render it from the saved results with
ash report. It runs any loaded reporter, including reporters that are disabled, apart from
the AWS reporters, which run only when --config-overrides turns them on
(Rendering a reporter from saved results), and it prints the
report alone to standard output:
GitHub code scanning¶
Upload ash.ghas.sarif. It is SARIF 2.1.0 in which every rule a scanner declares gets a
security-severity, the scanner's own or one from its most severe finding (see
How ASH counts findings), so GitHub shows those findings as
Critical, High, Medium, or Low. A
scanner that declares no rules, such as detect-secrets, gives results with no rule entry,
and GitHub shows those by their SARIF level. The file leaves out suppressed findings
(exclude_suppressed, default true), because GitHub has its own dismissal workflow. The
job needs security-events: write, and the upload step has to run when the scan step
fails, because a scan with findings exits 2:
- name: Upload SARIF to code scanning
if: ${{ !cancelled() }}
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
sarif_file: .ash/ash_output/reports/ash.ghas.sarif
category: ash
Run ASH in GitHub Actions has the complete workflow, including the reusable workflows ASH ships.
GitLab¶
GitLab reads three of the files, each under its own artifacts:reports keyword:
File in reports/ |
Keyword |
|---|---|
ash.gl-sast-report.json (GitLab SAST report, schema 15.2.2) |
sast |
ash.gl-dependency-scanning-report.cdx.json (CycloneDX) |
cyclonedx |
ash.junit.xml |
junit |
GitLab uploads report artifacts whatever the job's result, but it ingests the findings of a
security report such as sast only when the job that produced it succeeds. A scan with
findings exits 2, so the job that runs ASH has to succeed and leave the verdict to a later
job. Run ASH in GitLab CI has the two jobs that do this.
The SAST report keeps suppressed findings at severity Info with the reason in their
solution field. Set reporters.gitlab-sast.options.exclude_suppressed: true to leave
them out.
JUnit¶
ash.junit.xml has one test suite per scanner and one test case per finding. Suppressed
findings and findings below the severity threshold are written as skipped test cases, so
a CI test view shows the same verdict as the scan. Actionable findings are written as
<error> elements. To report those below the threshold as errors too, set reporters.junitxml.options.respect_severity_threshold: false.
CycloneDX and SPDX¶
ash.cdx.json is the software bill of materials that syft produces. When no SBOM
scanner ran, for example because syft is not installed or --scanners left it out, the
file is still a valid CycloneDX document. Its components list is empty, and a
compositions entry with aggregate set to unknown tells a consumer that the
inventory's completeness is not known, rather than that the project has no
dependencies:
{"bomFormat":"CycloneDX","specVersion":"1.6","version":1,"components":[],"compositions":[{"aggregate":"unknown"}]}
ash.gl-dependency-scanning-report.cdx.json then has an empty component list in
GitLab's format. ash.spdx.json converts the same SBOM to SPDX 2.3 and is written only
when you enable the spdx reporter.
CSV, HTML, and the summaries¶
ash.csvhas one row per finding, with suppression status and justification columns.ash.htmlis a single page with inline styles, suitable for an artifact viewer.ash.summary.mdis a Markdown summary for pull request comments.--compact-reportshortens it.ash.summary.txtis plain text for logs.
Before you share a report¶
- Reports can contain source text. ASH masks secrets in finding messages, but a scanner that includes the matching source lines in its result passes them through to the SARIF, CSV, flat JSON, GitLab SAST, and YAML reports. Treat report files as you treat the code.
- Findings in files that ASH extracted from archives or converted from notebooks carry absolute paths from the machine that ran the scan.
- A reporter that fails does not change the exit code. ASH logs the error and the file is missing, so check that the file you upload exists.
- The AWS reporters send data off the machine. They are operator-only and off unless loaded; see AWS reporters.