This guide shows how to run check-script in a CI pipeline and how to adopt
it progressively on code that already exists. The complete, ready-to-copy
examples are in doc/ci/; the options are described in the
user guide.
check-script exits with a code that a pipeline can act on:
| Code | Meaning |
|---|---|
0 |
Analysis performed, no threshold crossed. |
1 |
Threshold not met ( |
2 |
Usage error (invalid option, invalid configuration or report). |
3 |
Script not found or unreadable, or report file impossible to write. |
It also writes reports that CI systems know how to display:
| Output | Used by |
|---|---|
|
Baseline, |
|
GitHub Code scanning. |
|
GitLab merge request widget (Code Quality). |
|
Jenkins, GitLab Tests tab. |
|
GitHub annotations on the lines of a pull request. |
|
Artifacts, job summaries, audit reports. |
| Situation | Strategy | Example |
|---|---|---|
New code, or code that is already clean |
Threshold: the job fails below a score. |
|
Existing code with a lot of debt |
Baseline: the debt is tolerated, only new issues fail the job. |
|
Debt you want to see shrink |
Ratchet: after each merge the baseline is rewritten without the fixed issues. |
|
Review of a pull request |
Comparison with the base branch, as a Markdown table. |
|
Before the commit |
pre-commit hook on the modified scripts. |
|
-
GitHub: the action builds check-script and installs ShellCheck and shfmt (see below).
-
Elsewhere: the release archive contains
install.sh:curl -fsSL "$CHECK_SCRIPT_URL" | tar xz ./check_script-*/install.sh --prefix=/usr/local
Install the analysis tools you want next to it (ShellCheck, shfmt, Ruff, Bandit… see the user guide); a missing tool is simply skipped and the built-in rules always apply.
check-script --list-toolsshows what was found.
check-script init # writes .checkscript.yaml, suggests a profile
check-script init --exclude vendor/ --context cronThe nearest .checkscript.yaml applies to each script, so the same file is
used by developers, editors and CI. Paths to ignore go in its exclude:
key or in a .checkscriptignore file at the root of the analyzed folder
(.gitignore syntax), or on the command line with --exclude.
check-script --changed-since origin/main scripts/ # only the scripts changed on the branch
check-script --jobs 4 --no-cache scripts/ # parallel analysis, no cache between jobs
check-script --without semgrep scripts/ # machine without network access--changed-since needs the history: with GitHub, fetch-depth: 0 on
checkout. The result cache (~/.cache/check-script) is optional: keep it
between jobs to speed up large repositories, or add --no-cache.
- uses: actions/checkout@v7
- uses: chla28/CheckScript@v0.24.1
with:
paths: scripts .github
fail-under: '6' # or security=8,global=6The action annotates the lines concerned (visible in pull requests), adds
the report to the job summary and can produce a SARIF for Security → Code
scanning. Inputs: paths, fail-under, changed-since, args (any
additional option), lang, annotations, summary, sarif,
install-tools. Outputs: score, grade, scripts, sarif. Complete
example: doc/ci/github-actions.yml.
Create the baseline once, commit it, then:
- uses: chla28/CheckScript@v0.24.1
with:
paths: scripts
args: -b baseline.json --fail-on-new high --baseline-update--fail-on-new high fails the job if a new issue of severity high or worse
appears; --baseline-update (to use only on the main branch) rewrites
baseline.json without the issues that were fixed: commit it afterwards.
A script that has new issues keeps its entry, so they are never absorbed
into the tolerated debt. Complete example, with the commit step:
doc/ci/github-baseline.yml.
check-script diff base.json head.json -f md >> "$GITHUB_STEP_SUMMARY"
check-script diff base.json head.json --summary --fail-on-new high --fail-on-worsecheck-script diff compares two JSON reports (new / fixed / unchanged
issues per script, score evolution). The scripts of the two checkouts
(base/x/a.sh and head/x/a.sh) are paired by the end of their path. The
workflow doc/ci/github-pr-diff.yml analyzes the base branch and the pull
request with the action, then writes the table to the job summary.
check-script --summary -o gl-code-quality-report.json -o check-script.html \
--fail-under 6 --fail-under security=8 .The Code Quality report is shown in the merge request widget. Examples:
doc/ci/gitlab-ci.yml (threshold) and doc/ci/gitlab-baseline.yml (new
issues only on merge requests, comparison posted as a note, baseline
tightened on the default branch). The JUnit report fills the Tests tab:
check-script -q -o check-script.xml -o gl-code-quality-report.json .doc/ci/Jenkinsfile runs check-script, publishes the JUnit report
(junit 'check-script.xml') and archives the HTML report. A threshold
failure (exit code 1) fails the stage.
repos:
- repo: https://github.com/chla28/CheckScript
rev: v0.24.1
hooks:
- id: check-script
args: [--fail-under, "7"]check-script-fix applies the safe fixes instead. Without the framework,
scripts/pre-commit-hook.sh checks the staged version of the modified
scripts. See doc/ci/pre-commit-config.yaml.
# Once, from the main branch: configuration and baseline.
check-script init --baseline baseline.json
git add .checkscript.yaml baseline.json && git commit -m "chore: check-script"
# In the pipeline of a change: fail on new issues, show what changed.
check-script -q -o head.json scripts
check-script -b baseline.json --fail-on-new high scripts
check-script diff baseline.json head.json --summary --fail-on-worse
# On the main branch, after the merge: tighten the baseline.
check-script -q -b baseline.json --baseline-update scripts-
Paths: the baseline stores the paths as they were when it was created; always run check-script from the same folder (the repository root). Two extractions of the repository (
base/,head/) are fine fordiff. -
Upgrading check-script can change scores (new rules, new weights) without any change in the scripts: regenerate the baseline after an upgrade, from the main branch.
-
--changed-sincereports scores for the changed scripts only; combine it with a baseline for the rest. -
Secrets: reports never contain the line of a detected secret, but they contain paths and rule names: treat artifacts of a private repository as private.
-
Exit code 3 in a pipeline almost always means a wrong path or a script that is not text.