GitLab CI/CD¶
This page describes how to integrate MethodAtlas into a GitLab CI/CD pipeline. The techniques can be used individually or combined:
- Merge request annotations — findings posted as MR notes via
::notice/::warningcommands - SARIF upload to Security Dashboard — findings appear in the GitLab MR security widget
- AI result caching — skips re-classification of unchanged test classes
- Security test count gate — pipeline fails when security test coverage drops
Prerequisites¶
| Requirement | Details |
|---|---|
| Java runtime | Java 21 or later; the examples use the eclipse-temurin:21-jdk Docker image |
| MethodAtlas | Downloaded at job start from the GitHub release; the binary is cached between runs using the cache directive |
| AI provider API key | Stored as a GitLab CI/CD variable (masked); not required for static inventory mode |
| GitLab tier | SARIF upload to the Security Dashboard requires GitLab Ultimate; annotation output has no tier requirement |
Project configuration¶
Store your AI provider API key as a masked, protected CI/CD variable. In the GitLab UI navigate to Settings → CI/CD → Variables and add:
| Variable | Value | Flags |
|---|---|---|
OPENAI_API_KEY |
Your OpenAI API key | Masked, Protected |
Use a different variable name and the -ai-provider flag if you are using
a provider other than OpenAI. See AI Providers.
Minimal pipeline: static inventory¶
The following job requires no AI provider and produces a CSV inventory of all test methods with their structural metadata:
methodatlas-inventory:
image: eclipse-temurin:21-jdk
stage: test
cache:
key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- methodatlas.jar
policy: pull-push
script:
- |
if [ ! -f methodatlas.jar ]; then
curl -fsSL -o methodatlas.jar \
https://github.com/Accenture/MethodAtlas/releases/latest/download/methodatlas.jar
fi
- java -jar methodatlas.jar src/test/java > inventory.csv
artifacts:
paths:
- inventory.csv
expire_in: 30 days
AI-enriched scan with SARIF upload¶
GitLab CI supports SARIF reports as a first-class artefact type through the
artifacts.reports.sast key. Reports uploaded this way are parsed by GitLab
and displayed in the merge request security widget and the project Security
Dashboard (GitLab Ultimate required for the dashboard).
methodatlas-scan:
image: eclipse-temurin:21-jdk
stage: test
cache:
- key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- methodatlas.jar
policy: pull-push
script:
- |
if [ ! -f methodatlas.jar ]; then
curl -fsSL -o methodatlas.jar \
https://github.com/Accenture/MethodAtlas/releases/latest/download/methodatlas.jar
fi
- |
java -jar methodatlas.jar \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-sarif -security-only \
-content-hash \
src/test/java \
> methodatlas.sarif
artifacts:
reports:
sast: methodatlas.sarif
paths:
- methodatlas.sarif
expire_in: 90 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
GitLab Ultimate
The artifacts.reports.sast integration and the Security Dashboard
require GitLab Ultimate. On lower tiers the SARIF file is still produced
and available as a downloadable job artefact; it can be reviewed manually
or imported into an external code scanning tool.
Caching AI results across runs¶
Use GitLab's cache directive to persist the MethodAtlas result file across
pipeline runs. The cache key is set per branch so that each branch maintains
its own classification state:
methodatlas-scan:
image: eclipse-temurin:21-jdk
stage: test
cache:
- key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- methodatlas.jar
policy: pull-push
- key: "methodatlas-ai-$CI_COMMIT_REF_SLUG"
paths:
- .methodatlas-cache.csv
policy: pull-push
script:
- |
if [ ! -f methodatlas.jar ]; then
curl -fsSL -o methodatlas.jar \
https://github.com/Accenture/MethodAtlas/releases/latest/download/methodatlas.jar
fi
- |
CACHE_ARG=""
if [ -f .methodatlas-cache.csv ]; then
CACHE_ARG="-ai-cache .methodatlas-cache.csv"
fi
# Pass 1: CSV — refreshes cache, calls AI only for changed classes
java -jar methodatlas.jar \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-content-hash \
-security-only \
$CACHE_ARG \
src/test/java \
> .methodatlas-cache-new.csv
mv .methodatlas-cache-new.csv .methodatlas-cache.csv
# Pass 2: SARIF — reads exclusively from cache, zero AI calls
java -jar methodatlas.jar \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-sarif -security-only \
-content-hash \
-ai-cache .methodatlas-cache.csv \
src/test/java \
> methodatlas.sarif
artifacts:
reports:
sast: methodatlas.sarif
paths:
- methodatlas.sarif
expire_in: 90 days
On the first run for a branch (cache miss) every class is classified via the
AI provider. On subsequent runs only classes whose content_hash has changed
incur an API call.
Security test count gate¶
Fail the pipeline when the number of security-relevant test methods drops compared to the baseline on the default branch:
stages:
- build
- test
- gate
save-baseline:
image: eclipse-temurin:21-jdk
stage: test
cache:
key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- methodatlas.jar
policy: pull-push
script:
- |
if [ ! -f methodatlas.jar ]; then
curl -fsSL -o methodatlas.jar \
https://github.com/Accenture/MethodAtlas/releases/latest/download/methodatlas.jar
fi
- |
java -jar methodatlas.jar \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-security-only -content-hash \
src/test/java > baseline.csv
artifacts:
name: methodatlas-baseline
paths:
- baseline.csv
expire_in: 90 days
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
security-gate:
image: eclipse-temurin:21-jdk
stage: gate
needs:
- job: save-baseline
artifacts: true
optional: true
cache:
key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- methodatlas.jar
policy: pull
script:
- |
if [ ! -f methodatlas.jar ]; then
curl -fsSL -o methodatlas.jar \
https://github.com/Accenture/MethodAtlas/releases/latest/download/methodatlas.jar
fi
- |
java -jar methodatlas.jar \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-security-only \
src/test/java > current.csv
if [ ! -f baseline.csv ]; then
echo "No baseline available — skipping count gate."
exit 0
fi
baseline=$(tail -n +2 baseline.csv | wc -l)
current=$(tail -n +2 current.csv | wc -l)
echo "Baseline security tests: $baseline"
echo "Current security tests: $current"
if [ "$current" -lt "$baseline" ]; then
echo "ERROR: Security test count dropped from $baseline to $current"
exit 1
fi
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
Full pipeline¶
The following .gitlab-ci.yml combines binary caching, AI result caching,
SARIF upload, and the count gate. Adjust stage names and needs references
to match your project's existing pipeline structure.
stages:
- build
- test
variables:
METHODATLAS_JAR: methodatlas.jar
METHODATLAS_VERSION: latest # pin to a version tag for reproducibility, e.g. 1.2.0
.methodatlas-binary-cache: &methodatlas-binary-cache
key: "methodatlas-binary-$CI_COMMIT_REF_SLUG"
paths:
- $METHODATLAS_JAR
policy: pull-push
.download-methodatlas: &download-methodatlas
- |
if [ ! -f "$METHODATLAS_JAR" ]; then
curl -fsSL -o "$METHODATLAS_JAR" \
"https://github.com/Accenture/MethodAtlas/releases/${METHODATLAS_VERSION}/download/methodatlas.jar"
fi
methodatlas-scan:
image: eclipse-temurin:21-jdk
stage: test
cache:
- <<: *methodatlas-binary-cache
- key: "methodatlas-ai-$CI_COMMIT_REF_SLUG"
paths:
- .methodatlas-cache.csv
policy: pull-push
script:
- *download-methodatlas
- |
CACHE_ARG=""
if [ -f .methodatlas-cache.csv ]; then
CACHE_ARG="-ai-cache .methodatlas-cache.csv"
fi
# Pass 1: classify and update cache
java -jar "$METHODATLAS_JAR" \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-content-hash \
-security-only \
$CACHE_ARG \
src/test/java \
> .methodatlas-cache-new.csv
mv .methodatlas-cache-new.csv .methodatlas-cache.csv
# Pass 2: emit SARIF from cache (zero AI calls)
java -jar "$METHODATLAS_JAR" \
-ai -ai-provider openai -ai-api-key-env OPENAI_API_KEY \
-sarif -security-only \
-content-hash \
-ai-cache .methodatlas-cache.csv \
src/test/java \
> methodatlas.sarif
# Count gate (compare against baseline from previous run on this branch)
if [ -f baseline.csv ]; then
baseline=$(tail -n +2 baseline.csv | wc -l)
current=$(tail -n +2 .methodatlas-cache.csv | wc -l)
echo "Baseline: $baseline Current: $current"
if [ "$current" -lt "$baseline" ]; then
echo "ERROR: Security test count dropped from $baseline to $current"
exit 1
fi
fi
cp .methodatlas-cache.csv baseline.csv
artifacts:
reports:
sast: methodatlas.sarif
paths:
- methodatlas.sarif
- baseline.csv
expire_in: 90 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Using a YAML configuration file¶
For teams that prefer to keep MethodAtlas settings in version control rather
than in pipeline YAML, create a methodatlas.yml at the project root:
Reference it from the pipeline with the -config flag:
The API key must still be supplied via an environment variable at runtime; do not store secrets in the configuration file committed to version control.