A GitHub Action that launches a zkao security scan of the commit a workflow is running on. By default it starts the scan and returns; ask it to wait and it reports the findings in the job summary, and it can fail the job when open findings reach a severity you pick.
name: zkao
on:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: zksecurity/zkao-action@v1
with:
token: ${{ secrets.ZKAO_API_TOKEN }}
project: ${{ vars.ZKAO_PROJECT_ID }}That launches a quick look of every push to main and moves on; the
results are on zkao when the scan finishes. The scan runs at the budget zkao
recommends for the repository, and the action needs no checkout: zkao reads
the commit from GitHub itself.
- Add the repository to a zkao project. Scans need at least one project member with GitHub access to the repository.
- Create a project API token in the project's settings with the
readandscans:launchscopes, and store it as theZKAO_API_TOKENsecret. - Keep credits on the project. A scan reserves its budget at launch and is
billed what it spends. The budget defaults to what zkao recommends for the
scan type on the repository, sized from past runs; pass
budgetto cap it yourself.
mode |
What happens |
|---|---|
launch (default) |
Starts the scan and returns. The job never waits or fails on findings. |
wait |
Waits for the scan and writes the findings to the job summary. The job fails only if the scan itself fails. |
gate |
Waits, reports, and fails the job when open findings reach fail-on (default high). |
A gate on a pull request:
on:
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: zksecurity/zkao-action@v1
with:
token: ${{ secrets.ZKAO_API_TOKEN }}
project: ${{ vars.ZKAO_PROJECT_ID }}
scan: diff
mode: gate
fail-on: highscan picks the kind of scan:
scan |
Runs |
|---|---|
quick-look (default) |
The core techniques in one cheap pass. |
deep-audit |
The full methodology over the whole repository. |
diff |
Only the change since base. Cheap and fast. |
| any preset ref | That preset, for example builtin:Deep Audit or a custom one. |
A diff scan audits the change from the merge base of base to the scanned
commit. base defaults to the pull request's base, or the commit before a push.
The rest of the repository is context, not a target. On a pull request it scans
against the branch the change will land on, so repeat scans of the same target
reuse the map already built for it.
comment: true posts to the pull request twice: once when the scan starts, and
again with the result when the job waits for it. Both carry a link to the scan.
The job needs pull-requests: write.
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: zksecurity/zkao-action@v1
with:
token: ${{ secrets.ZKAO_API_TOKEN }}
project: ${{ vars.ZKAO_PROJECT_ID }}
scan: diff
mode: wait
comment: trueComments are posted by github-actions[bot], since the action uses the
workflow's own token. To post under your own bot, mint a GitHub App
installation token in an earlier step and pass it as github-token.
A push carries no pull request. When the pushed branch has one open, the action finds it and comments there anyway.
Trigger on issue_comment and the action takes commands from the pull request:
on:
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: write
jobs:
scan:
if: github.event.issue.pull_request && contains(github.event.comment.body, '/zkao')
runs-on: ubuntu-latest
steps:
- uses: zksecurity/zkao-action@v1
with:
token: ${{ secrets.ZKAO_API_TOKEN }}
project: ${{ vars.ZKAO_PROJECT_ID }}
scan: diff
mode: wait
comment: true| Comment | What happens |
|---|---|
/zkao scan |
Audits the pull request's change, with the kind the workflow configures. |
/zkao scan deep-audit |
Audits it as diff, quick-look or deep-audit instead. |
/zkao help |
Posts the usage. No scan. |
/zkao |
Posts the usage, rather than scanning. |
The handle is slash-prefixed, not @zkao, because GitHub turns an @handle
into a link to whoever owns that account and notifies them, and zkao belongs
to someone else. Change it with the mention input; a leading slash on the
command itself is optional, so /zkao scan and /zkao /scan are the same.
A word after scan that is not a kind is ignored, so /zkao scan this one
runs the workflow's own kind rather than failing over a word nobody meant as a
preset.
Set mention to an @handle you own and it still works, except that an
unrecognised word after it is then left alone rather than answered, since it
may be ordinary prose.
A workflow triggered by issue_comment only ever runs from the repository's
default branch. On any other branch GitHub never dispatches it, and nothing
happens with no error to explain it. On that event the action reads the pull
request to find its head, because the comment carries no commit and the
workflow itself runs on the default branch.
Only the repository's owner, members and collaborators can start a scan this way, so a passer-by cannot spend the project's credits.
The scan page links back to the pull request, and to the comment that asked for it. The action sends the numbers rather than a URL, so zkao builds that link from the repository it is scanning.
The result comment carries counts and a link, never the findings themselves: on a public repository it would otherwise disclose unfixed vulnerabilities to anyone who can read the pull request.
| Input | Required | Default | What it does |
|---|---|---|---|
token |
yes | Project API token. Use a secret. | |
project |
yes | The zkao project id. | |
budget |
recommended | Credit budget for the scan. Defaults to zkao's recommendation for this scan type on this repository. | |
mode |
launch |
launch, wait, or gate. |
|
scan |
quick-look |
quick-look, deep-audit, diff, or a preset ref. |
|
base |
see above | For scan: diff, the commit the change is measured from. |
|
fail-on |
high |
For mode: gate, the severity at which open findings fail the job: critical, high, medium, low, or info. |
|
repository |
matched by name | The zkao repository id. By default the action finds the project repository whose owner and name match the workflow's repository. | |
commit |
see below | Commit to scan. | |
branch |
workflow branch | Branch the commit is on. Lets the scan reuse the branch's repository map. | |
areas |
whole repository | Comma-separated audit area keys to scope the scan to. | |
guidance-file |
A file whose content replaces the repository's guidance for this scan. | ||
timeout |
10800 |
Seconds to wait in wait and gate modes before giving up. The scan keeps running on zkao. |
|
summary |
true |
Write the scan link, and the findings once waited for, to the job summary. | |
comment |
false |
Comment on the pull request when the scan starts and when it finishes. Needs pull-requests: write. |
|
mention |
/zkao |
What a comment says to reach zkao. | |
github-token |
the workflow's | Token used to comment, and to read the pull request on an issue_comment event. |
|
base-url |
https://zkao.io |
The zkao instance. | |
cli-version |
pinned | Version of @zksecurity/zkao-cli the action runs. |
On pull_request and pull_request_target events the action scans the head
of the pull request, since the merge commit GitHub builds for the workflow
only exists on the runner. On an issue_comment event it reads the pull
request to find its head. On every other event it scans github.sha.
| Output | Meaning |
|---|---|
scan-id |
Id of the launched scan. |
scan-url |
The scan on zkao. |
status |
QUEUED in launch mode; COMPLETED, FAILED or CANCELLED once waited for. |
findings-total |
Open findings: everything triage did not mark a false positive or a duplicate. Empty in launch mode. |
findings-critical, findings-high, findings-medium, findings-low, findings-info |
Open findings by severity. |
Use them in later steps:
- uses: zksecurity/zkao-action@v1
id: zkao
with:
token: ${{ secrets.ZKAO_API_TOKEN }}
project: ${{ vars.ZKAO_PROJECT_ID }}
mode: wait
- run: echo "${{ steps.zkao.outputs.findings-total }} open findings at ${{ steps.zkao.outputs.scan-url }}"A scan of the whole repository on every push adds up. Run on pull_request
or on main only, gate the job on the paths that matter, use scan: diff
for pull requests, or pass areas to scan the audit areas a change touches.
Area keys come from the repository's Context tab on zkao, or from
zkao areas list.
A scan of a repository zkao is still analyzing waits for that analysis to finish first.
The action is a composite step that runs the published
@zksecurity/zkao-cli
against the public API. Nothing is compiled or vendored: the CLI version is
pinned in action.yml and can be overridden with cli-version. The runner
needs node and jq, which every GitHub-hosted runner has.
Releases are GitHub releases with a semver tag (v1.2.3). Publishing one
re-points the major tag (v1) at it, so workflows pinned to @v1 follow. Tick
"Publish this Action to the GitHub Marketplace" on the release form to update
the Marketplace listing.
MIT, see LICENSE.