Run Sonda in GitHub Actions
Scan every push and pull request with Sonda in GitHub Actions — install the CLI, gate on new code, upload SARIF to code scanning or results to a Sonda server.
This guide adds Sonda to a repository's GitHub Actions: every push and pull request is scanned, new code is judged by the quality gate, and a failing gate fails the job. There are two ways to see the results:
- CLI only, with code scanning: findings appear in GitHub's Security tab and as annotations on pull requests. No server needed.
- With a Sonda server: analyses are kept with their history, and the server posts each pull request's result on it.
Prerequisites
- A repository in JavaScript/TypeScript, Python, Java, C# or C/C++.
- For code scanning on a private repository, GitHub Code Security (part of GitHub Advanced Security). Public repositories have it.
- For the server option, a running Sonda server that the runner can reach.
1. Add a quality gate
Run sonda init locally and commit the sonda.toml it writes. It holds the default gate: no new bugs or
vulnerabilities, at least 80% coverage and at most 3% duplication on new code. Quality gates
explains each condition and how to change them.
2. Install Sonda in the job
On GitHub's Linux runners, download the release binary and check it against the release's checksums. It takes seconds:
- name: Install sonda
run: |
v=0.1.0
curl -fsSLO https://github.com/lvaoliveira/sonda/releases/download/v$v/sonda-$v-x86_64-linux
curl -fsSL https://github.com/lvaoliveira/sonda/releases/download/v$v/SHA256SUMS | sha256sum -c --ignore-missing
install -D -m 755 sonda-$v-x86_64-linux "$HOME/.local/bin/sonda"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"On an arm64 runner, use aarch64 instead of x86_64. On macOS or Windows runners there's no release binary yet:
build it with cargo install --locked --git https://github.com/lvaoliveira/sonda --tag v0.1.0 sonda, which takes a few
minutes.
3a. CLI only: upload SARIF to code scanning
Create .github/workflows/sonda.yml:
name: sonda
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
security-events: write # upload the SARIF report to code scanning
jobs:
sonda:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # new code is judged against the base branch
- name: Install sonda
run: |
v=0.1.0
curl -fsSLO https://github.com/lvaoliveira/sonda/releases/download/v$v/sonda-$v-x86_64-linux
curl -fsSL https://github.com/lvaoliveira/sonda/releases/download/v$v/SHA256SUMS | sha256sum -c --ignore-missing
install -D -m 755 sonda-$v-x86_64-linux "$HOME/.local/bin/sonda"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: sonda scan
run: sonda scan . --format sarif -o sonda.sarif
- uses: github/codeql-action/upload-sarif@v4
if: always() # upload the findings even when the gate fails the scan
with:
sarif_file: sonda.sarifThere's no --new-code here on purpose. In a pull request, Sonda compares with the pull request's base branch; on a
push, with the pushed commits. fetch-depth: 0 gives it the history to do that.
3b. With a Sonda server: upload every analysis
The server's web app writes this workflow for you: on an empty server, Connect a repository asks for the
repository's URL, creates the project and an analysis token, and opens GitHub's editor with the file filled in. Here it
is for GitHub's runners, with one change: Connect's version builds the CLI with cargo install, and this one installs
the release binary from step 2, which is faster.
name: sonda
on:
push:
branches: [main]
pull_request:
jobs:
sonda:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # new code is judged against the base branch
- name: Install sonda
run: |
v=0.1.0
curl -fsSLO https://github.com/lvaoliveira/sonda/releases/download/v$v/sonda-$v-x86_64-linux
curl -fsSL https://github.com/lvaoliveira/sonda/releases/download/v$v/SHA256SUMS | sha256sum -c --ignore-missing
install -D -m 755 sonda-$v-x86_64-linux "$HOME/.local/bin/sonda"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: sonda scan
env:
SONDA_TOKEN: ${{ secrets.SONDA_TOKEN }}
# Through env, not inline: a branch name is untrusted input.
BRANCH: ${{ github.head_ref || github.ref_name }}
run: >
sonda scan . --upload
--server https://sonda.example.com --project my-project
--branch "$BRANCH" --commit "$GITHUB_SHA"- Add the token as the repository secret
SONDA_TOKEN. - The server must be reachable over HTTPS from GitHub's runners: the CLI sends the token over plain HTTP only to
localhost. For a server on your own network, run the job on a self-hosted runner on the server's machine and upload tohttp://localhost:9000. - With an upload, the server's gate decides the exit code, so issues accepted on the server stop failing the build.
- To see results on the pull request itself, as a check run, annotations and one summary comment, configure the
server with a GitHub App (
scripts/setup-server.sh --github-app ID KEY.pem).
4. Read the results
- In the job log: the scan prints the issues on new code and each gate condition with its actual value.
- In code scanning (3a): the Security tab lists the findings, and pull requests show them as annotations. Security rules carry their CWE ids and OWASP Top 10 categories.
- On the server (3b): the analysis page shows what the change introduced and resolved, and the project's history.
To report without blocking merges, add continue-on-error: true to the scan step, or pass --no-gate.
Troubleshooting
- "New code" is the whole project, or nothing. The checkout is shallow: set
fetch-depth: 0. - The SARIF upload fails with a permissions error. The job needs
security-events: write, and private repositories need GitHub Code Security. - The job fails even though the findings uploaded. That's the gate: the scan exits
1when it fails. The upload step runs anyway because ofif: always(). - A pull request from a fork isn't uploaded. Its workflow gets no secrets, so there's no token. The scan still runs and says so.
- A pull request could weaken its own gate by editing
sonda.toml. Load the config from the base branch:git show origin/main:sonda.toml > /tmp/sonda.tomlandsonda scan . --config /tmp/sonda.toml. - The log warns that workers aren't fully sandboxed. The scan continues. To refuse to scan without the sandbox,
pass
--sandbox require.
Pin what you run
GitHub recommends pinning third-party actions to a full commit SHA rather than a tag. The release binary is already
pinned to v0.1.0 and checked against its checksum; bump v when you upgrade.