The official action bochmann-software/codeguard@v1 is the fastest way to integrate
CodeCharter into a GitHub workflow. It handles the CLI download, caching, and publishing
findings as PR annotations.
Recommended: also install the CodeCharter GitHub App. The action then publishes a branded CodeCharter check run and PR comment through the app — no
pull-requests: writepermission and no GitHub token on the runner. Without the app the action still works and falls back to a workflow-token comment.
Minimal setup
.github/workflows/codecharter.yml:
name: CodeCharter
on:
pull_request:
push:
branches: [main]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- uses: bochmann-software/codeguard@v1
with:
solution: Acme.Web.sln
api-key: ${{ secrets.CODECHARTER_API_KEY }}
Done. Findings automatically appear as inline annotations on the PR.
Getting an API key
- Generate a key in the portal under API Keys.
- Store it as
CODECHARTER_API_KEYin the GitHub repo underSettings → Secrets → Actions.
The action reads the key, authenticates against the portal, and pulls the CLI
version selected by the version input (default latest).
Execution model
The action runs the CLI natively on the runner — it does not use Docker and does not pull a container image. On each run it:
- downloads the self-contained CLI archive matching the runner's platform
(
win-x64,linux-x64,osx-x64,osx-arm64) from the portal, authenticated with the API key, - verifies the archive against the SHA-256 checksum the portal advertises,
- runs the CLI directly against your checked-out solution.
The downloaded binary is cached between runs (see Caching). Because no container is involved, Linux x64, Windows x64, and macOS (x64 and arm64) runners all work — GitHub-hosted and self-hosted alike. Other platforms (for example Linux arm64) fail with an explicit error.
Inputs
| Input | Default | Description |
|---|---|---|
api-key |
Required. API key from the portal. | |
solution |
first .sln / .slnx |
Which solution to analyze. When omitted, the action picks the first .sln/.slnx it finds (sorted alphabetically). It fails with an error when none is found and warns when multiple exist. |
fail-on |
error |
Threshold for build failures (info, warn, error, never). warning is also accepted as a synonym for warn. |
severity-threshold |
info |
Minimum severity to report and annotate (info, warn, error). |
rules |
(empty) | Path to a rules directory in your repository (e.g. .codecharter/rules). Leave empty to use the built-in default rules. |
diff |
false |
On pull requests, scope both the reported findings and the fail-on gate to the lines changed by the PR. The PR base commit must be reachable on the runner; use actions/checkout with fetch-depth: 0. Has no effect on non-pull_request events. |
version |
latest |
Which CLI version to download. Recommendation: pin it. Accepts latest, v1, v1.4, or an exact pin like v1.4.2. |
sarif-output |
If set, SARIF is additionally written to this file. | |
cache |
true |
Cache the downloaded CLI binary between workflow runs. |
portal-base-url |
Override the portal endpoint, e.g. for a self-hosted or staging portal. Defaults to the public portal. | |
require-rules |
false |
Fail instead of silently using bundled sample rules when no rules directory exists. |
baseline |
Path to a baseline file; only findings not present in it fail the build. Generate a baseline via the CLI's --write-baseline flag. |
|
telemetry |
false |
Opt-in usage event. It contains aggregated finding counts per rule (rule ID, severity, count) plus your account and installation identifiers. No source code, file paths, or finding locations are sent. |
comment |
true |
Post or update a sticky PR summary comment. Requires permissions: pull-requests: write when not using the CodeCharter app. |
comment-key |
Discriminator string so multiple CodeCharter steps in one workflow keep separate sticky comments. | |
github-token |
${{ github.token }} |
Token used to post the PR comment. |
Outputs
| Output | Description |
|---|---|
findings-total |
Total number of findings |
findings-error |
Number of error findings |
findings-warn |
Number of warn findings |
findings-info |
Number of info findings |
sarif-path |
Path to the SARIF file, if generated |
Full setup: SARIF + Code Scanning
If you want to see findings in the Security tab of your GitHub repo:
- uses: bochmann-software/codeguard@v1
id: codecharter
with:
solution: Acme.Web.sln
api-key: ${{ secrets.CODECHARTER_API_KEY }}
sarif-output: codecharter.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: codecharter.sarif
if: always() ensures the upload step runs even when a previous step failed
(for example, if CodeCharter exits with a non-zero code because findings exceeded
the fail-on threshold). Without it, GitHub Actions would skip the upload
whenever an earlier step did not succeed.
Matrix builds
If your solution builds on multiple OSes but CodeCharter is deterministic, the analysis only needs to run once:
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: dotnet build
codecharter:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: bochmann-software/codeguard@v1
with:
api-key: ${{ secrets.CODECHARTER_API_KEY }}
Self-hosted runners
Works without any changes as long as the runner meets these prerequisites:
- Network access to
codecharter.tools. The action always downloads the CLI from the portal; there is no mode that uses a pre-installed binary. The CLI also mints its short-lived license from the API key against the portal on each run. - A .NET SDK that can build your solution. The action logs a warning when
no
dotnetis detected on the runner. zstdorgzipon the PATH if you want the CLI binary cached between runs. Without either of them the action skips the cache with a warning and downloads the CLI fresh on every run; setcache: 'false'to silence the warning.
On runners without portal access the action cannot be used. Install the CLI
binary on the runner manually, place a full codecharter.license there, and call
codecharter directly in a run: step instead — see
Offline or long-lived runners.
Version pinning
Recommendation: pin the action to a specific minor version and upgrade infrequently.
- uses: bochmann-software/codeguard@v1 # Major pinning, gets v1.x.y updates
- uses: bochmann-software/[email protected] # Minor pinning, static
- uses: bochmann-software/codeguard@<sha> # SHA pinning, most conservative
We follow SemVer (see Versioning) and do not break contracts within a major version.
Caching
The action automatically caches the downloaded CLI binary between workflow runs,
keyed by runner platform and CLI version. Exact pins (e.g. v1.4.2) are cached
indefinitely; moving selectors (latest, v1, v1.4) are re-resolved daily so
a cache hit never serves a stale build for long. The analysis itself runs in
full on every invocation; analysis results are not cached between runs.
On a medium-sized solution a warm run typically completes in 5–15 seconds.
Disable manually when debugging unexplained cache effects:
- uses: bochmann-software/codeguard@v1
with:
cache: 'false'
api-key: ${{ secrets.CODECHARTER_API_KEY }}
If PR annotations don't appear
GitHub shows inline annotations in the Files changed view only for pull requests.
On direct push runs the annotations still appear on the workflow run summary, just
not inline in the code. If you expect inline PR annotations, make sure the workflow
triggers on pull_request.
When results are published through the CodeCharter app, the check run shows at most 50 inline annotations per run; with more findings, only the first 50 appear as annotations.
Permissions
With the CodeCharter GitHub App installed, the action
posts results through the app and the workflow only needs contents: read.
Without the app the action falls back to posting a comment via the workflow token,
which additionally requires pull-requests: write:
permissions:
contents: read
pull-requests: write # only needed without the CodeCharter app
If you also upload SARIF to GitHub Code Scanning, add security-events: write:
permissions:
contents: read
security-events: write
pull-requests: write # only needed without the CodeCharter app