From bf9b3ade959cff1c18d8fefaa4e6ceb5ef74f0c2 Mon Sep 17 00:00:00 2001 From: Silvren <237023679+Silvren@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:53:07 +0800 Subject: [PATCH] Document GitLab CI report integration --- README.md | 6 ++++ docs/integrations/gitlab-ci.md | 54 +++++++++++++++++++++++++++++++++ docs/integrations/gitlab-ci.yml | 16 ++++++++++ tests/test_gitlab_ci_docs.py | 16 ++++++++++ 4 files changed, 92 insertions(+) create mode 100644 docs/integrations/gitlab-ci.md create mode 100644 docs/integrations/gitlab-ci.yml create mode 100644 tests/test_gitlab_ci_docs.py diff --git a/README.md b/README.md index 9ed9f8e..396dcb0 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,12 @@ Exit codes are stable for automation: `0` passed, `1` reached the configured sev sarif_file: agentguard.sarif ``` +### CI integrations + +See the tested [GitLab CI example](docs/integrations/gitlab-ci.md) for severity +thresholds, machine-readable reports, artifact retention, and current +limitations. + ### Configure and suppress Create `.agentguard.yml`: diff --git a/docs/integrations/gitlab-ci.md b/docs/integrations/gitlab-ci.md new file mode 100644 index 0000000..7e91ded --- /dev/null +++ b/docs/integrations/gitlab-ci.md @@ -0,0 +1,54 @@ +# GitLab CI + +Add AgentGuard as a GitLab CI job to scan the repository, enforce a severity +threshold, and retain a machine-readable report. + +## Example job + +Copy [`gitlab-ci.yml`](gitlab-ci.yml) into your project's `.gitlab-ci.yml`, or +merge the `agentguard` job into an existing pipeline: + +```yaml +image: python:3.13-slim + +stages: + - security + +agentguard: + stage: security + before_script: + - python -m pip install --disable-pip-version-check agentguard-sast + script: + - agentguard scan . --format json --output agentguard-report.json --fail-on high + artifacts: + when: always + paths: + - agentguard-report.json + expire_in: 1 week +``` + +The job installs AgentGuard from PyPI, scans the checkout, and writes the JSON +report to `agentguard-report.json`. `artifacts.when: always` retains the report +even when the severity threshold fails the job. Adjust `expire_in` to match your +project's retention policy. + +## Threshold and exit codes + +`--fail-on high` exits with status `1` when a High or Critical finding is +present, which makes the GitLab job fail. Use another severity (`critical`, +`medium`, or `low`) to change the gate, or `--fail-on none` to publish the +report without failing on findings. + +AgentGuard uses these exit codes: + +- `0`: the scan completed and no finding reached the configured threshold; +- `1`: at least one finding reached the threshold; +- `2`: the scan could not complete, for example because of invalid arguments or + an unreadable target. + +## Report limitations + +The JSON file is an ordinary GitLab job artifact for downloading or processing +in later jobs. AgentGuard does not currently emit GitLab's native SAST report +schema, so this example does not populate GitLab security dashboards or merge +request security widgets. diff --git a/docs/integrations/gitlab-ci.yml b/docs/integrations/gitlab-ci.yml new file mode 100644 index 0000000..81aa717 --- /dev/null +++ b/docs/integrations/gitlab-ci.yml @@ -0,0 +1,16 @@ +image: python:3.13-slim + +stages: + - security + +agentguard: + stage: security + before_script: + - python -m pip install --disable-pip-version-check agentguard-sast + script: + - agentguard scan . --format json --output agentguard-report.json --fail-on high + artifacts: + when: always + paths: + - agentguard-report.json + expire_in: 1 week diff --git a/tests/test_gitlab_ci_docs.py b/tests/test_gitlab_ci_docs.py new file mode 100644 index 0000000..ab196b5 --- /dev/null +++ b/tests/test_gitlab_ci_docs.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from pathlib import Path + +import yaml + + +def test_gitlab_ci_example() -> None: + example = Path("docs/integrations/gitlab-ci.yml") + config = yaml.safe_load(example.read_text(encoding="utf-8")) + job = config["agentguard"] + + assert job["stage"] == "security" + assert job["script"] == ["agentguard scan . --format json --output agentguard-report.json --fail-on high"] + assert job["artifacts"]["when"] == "always" + assert "agentguard-report.json" in job["artifacts"]["paths"]