Pillars analysis jobs and configuration
Pillars selects common source-analysis jobs unless their switches disable them.
Most image-analysis jobs additionally require the file at DOCKERFILE_PATH.
Set the listed switch to "false" to disable a job. Enabling a job does not provision
a scanner service, create an account, or provide the application's test configuration.
Each tool's command determines what counts as a finding or an execution error. The job context rules then determine whether a failed job blocks the pipeline. Reports, skipped jobs, and allowed failures all need review when assessing a build.
Source analysis
| Job | Disable switch | Inputs, output, and failure condition |
|---|---|---|
megalinter-all | MEGALINTER | Uses .mega-linter.yml. When absent, creates a default disabling SPELL_LYCHEE, HTML_DJLINT, REPOSITORY_KINGFISHER, and REPOSITORY_OSV_SCANNER. Retains config and reports under ${EVIDENCE_DIR}/megalinter-reports; enabled linters determine findings. Retries once. |
semgrep | SEMGREP | Uses the image's semgrep-SEMGREP_RULESET-ruleset.yml, with SEMGREP_RULESET: ci. Runs with --error and writes JSON, JUnit, SARIF, GitLab SAST, secret-detection, and text outputs. The named ruleset must exist in the image. |
trufflehog | TRUFFLEHOG | Scans Git history from the merge-request target branch, or SINCE_BRANCH, default ${CI_DEFAULT_BRANCH}. Supports .trufflehogignore and .trufflehog.yaml. Uses --fail; writes findings and logs as JSON. |
dependency-check | DEPENDENCY_CHECK | Scans the checkout with experimental analyzers enabled, excluding Yarn audit and NodeJS analysis and skipping dev dependencies for the named Node analyzers. Uses --failOnCVSS 7; writes all supported report formats. Retries once. |
dockerfile-lint | DOCKERFILE_LINT | Requires the Dockerfile selection path, reads .hadolint.yaml when present, and fails at Hadolint's error threshold. Writes text, SARIF, JSON, Checkstyle, Code Climate, and SonarQube outputs. |
malcontent | MALCONTENT | Scans the checkout, including data files. MALCONTENT_THRESHOLD: "3" fails on a risk score at or above 3; the scale is low 1, medium 2, high 3, critical 4. Writes JSON, Markdown, YAML, terminal output, and logs. |
sonarqube | SONARQUBE | Requires a SonarQube project, token, and properties file. Waits for the configured server quality gate. Retains scanner logs, metadata, and available server evidence. |
commitlint | COMMITLINT | Creates a Conventional Commits configuration when commitlint.config.js is absent. Validates the merge-request title after removing the Draft: prefix. Also validates commits; the individual-commit check is nonblocking when squash-on-merge is enabled. Outside a merge request, checks commits since the merge base with the default branch. |
Configure SonarQube
Create or identify your application's SonarQube project and obtain a token permitted
to analyze it. Store the token as SONAR_TOKEN. SONARQUBE_TOKEN is a compatibility
fallback when SONAR_TOKEN is empty. Set SONARQUBE_HOST to your installation's URL;
the declared default is https://sonarqube.${PLATFORM_DOMAIN}.
Add a root sonar-project.properties. Replace the sample project key and source directory:
sonar.projectKey=example-service
sonar.projectName=Example service
sonar.sources=src
sonar.sourceEncoding=UTF-8
Do not put the token in that file. The job passes SONAR_PROJECT_PATH, default
sonar-project.properties, to the scanner, but its prerequisite check still requires
the root file. Keep the default path unless your installation corrects that mismatch.
The job requires dependency-check; disabling it without changing the SonarQube job
leaves a required dependency missing. Other listed framework build/test dependencies
are optional. Recognized evidence includes npm LCOV, Gradle JaCoCo, Python coverage XML,
Go coverage, and .NET OpenCover output at the shared jobs' standard locations.
Changing those paths can require matching SonarQube configuration. The server's
quality-gate policy determines its thresholds; Pillars does not define one universal
SonarQube threshold for every project.
Configure Dependency-Check
| Setting | Default | Use |
|---|---|---|
NVD_API_KEY | Unset | Credential for the connected NVD update. A failed update is logged but does not by itself stop the scan. |
OSS_INDEX_USERNAME, OSS_INDEX_PASSWORD | Unset | Optional OSS Index credentials; both must be populated to add the authenticated arguments. |
SUPPRESSIONS_FILE | dependency-check-suppressions.xml | Optional suppression file; copied into evidence when present. |
DEPENDENCY_CHECK_EXTRA_ARGS | Empty | Additional scanner arguments after the fixed arguments. Use reviewed suppressions and thresholds; do not assume they affect another tool. |
The scan uses the locally available database after the update attempt. A report can therefore reflect older data when updating fails. Retain the log with the report.
Configure MegaLinter and commit checks
Keep .mega-linter.yml and commitlint.config.js in the application project when
customizing these checks. Pillars configures JSON, Markdown-summary, and SARIF reporting
for MegaLinter and disables its configuration reporter. Environment settings can take
precedence over the file. Full declared reporting defaults are in the
variable catalog.
The commitlint setup checks specifically for commitlint.config.js before creating
its default. A differently named config file can coexist with a newly created default;
use that filename for predictable behavior.
Image and application analysis
These jobs inspect the registry image built by container-image. Its image.env
artifact supplies the resolved image coordinates to downstream jobs. They do not
wait for a separate container-publication gate because the image is already pushed.
| Job | Disable switch | Behavior and output |
|---|---|---|
grype | GRYPE | Scans the image directly with GRYPE_FAIL_ON_SEVERITY: high, default search scope all-layers. Produces JSON, CycloneDX XML/JSON, SARIF, and tables. Supports .grype.yaml or .grype/config.yaml. |
neuvector | NEUVECTOR | Requests a repository scan from the NeuVector API and applies the count and score thresholds below. Produces a JSON report and text summary. |
syft | SYFT | Inventories the image and checkout separately. Produces Syft text, SPDX JSON, and CycloneDX XML/JSON. It has no vulnerability threshold; execution can still fail. |
trivy | TRIVY | Scans image vulnerabilities and secrets. Writes JSON, text, SARIF, CycloneDX, and SPDX outputs. The job sets no explicit nonzero findings exit code; do not treat its report as a guaranteed blocking vulnerability gate. Supports trivy.yaml. |
clamscan | CLAMSCAN | Invokes the installed ClamAV wrapper against the image. Retains clamscan-report.txt for 30 days. The wrapper's exit result is subject to the normal job context rules. |
oscap | OSCAP | Invokes the installed OpenSCAP wrapper. Its matching Dockerfile rules allow failure; review results even when the overall pipeline succeeds. |
crane | CRANE | Reads image configuration and requires a numeric USER, optionally uid:gid. An absent or named user fails. Numeric 0 matches the current check; this does not establish a non-root runtime. |
zap | ZAP | Starts the built image as a service, runs a baseline web scan, and normally a full scan. Requires container-image and crane. Retains HTML, Markdown, XML, JSON, SARIF, and logs. |
cypress | CYPRESS | Starts the built image as a service and runs the project's Cypress tests. Requires container-image, crane, and cypress.config.js or cypress.config.ts. Retains JUnit, logs, downloads, screenshots, and videos. |
A GitLab report declaration does not guarantee that every GitLab edition or report schema renders a security dashboard. Job artifacts are the direct record to inspect. Pillars does not convert every scanner report into the native GitLab security schema.
Configure NeuVector
The runner must reach the controller, and the controller must be able to pull the
image. Store NV_X_AUTH_APIKEY as a secret CI/CD variable.
| Setting | Default |
|---|---|
NV_API_HOST | neuvector-svc-controller.neuvector.svc.cluster.local |
NV_API_PORT | 10443 |
NV_API_SCAN_URL | https://$NV_API_HOST:$NV_API_PORT/v1/scan/repository |
NV_REGISTRY_URL, NV_REGISTRY_USER, NV_REGISTRY_PASSWORD | https://${REGISTRY}, ${REGISTRY_USER}, ${REGISTRY_PASSWORD} |
NV_REPOSITORY, NV_TAG | ${IMAGE}, ${IMAGE_TAG} |
THRESHOLD_HIGH, THRESHOLD_MEDIUM, THRESHOLD_LOW | 0, 5, 99 |
THRESHOLD_SCORE_V3 | 7.0 |
REPORT_FILE, SUMMARY_FILE | ${EVIDENCE_DIR}/scan-repository.json, ${EVIDENCE_DIR}/scan-summary.txt |
The job fails when the number of High, Medium, or Low findings exceeds the
corresponding limit, or any finding's score_v3 exceeds 7.0. These are distinct
conditions. The current request uses curl -k; this job's success does not prove that
the controller's TLS certificate was validated. Scanning repeats while the report is
empty and remains subject to the GitLab job timeout.
Configure application tests
APP_HTTP_PORT defaults to 8080. ZAP's ZAP_TARGET and Cypress's CYPRESS_BASE_URL
default to http://${CI_PROJECT_NAME}:${APP_HTTP_PORT}. The service must start from
the built image with its normal entrypoint and expose the application at that address.
Supply required application configuration through the project's service-compatible
variables. Neither job provisions a database or adds a universal application readiness
check.
ZAP optionally consumes zap.conf, zap-progress.json, and zap.context.
ZAP_FULL_SCAN_DISABLED: "true" skips the full scan; baseline remains enabled.
The scripts use -I, and the full-scan path contains an explicit success exit. Treat
ZAP outputs as scan evidence, not a universally enforced findings gate. Use only an
authorized test target, especially when overriding the default URL for the full scan.
Cypress fails early if neither config file exists. When both exist, the setup records the TypeScript filename last; avoid duplicate configurations. The configured test runner must be able to reach the service and execute its tests.
For a container that does not provide an HTTP application, disable those two jobs:
variables:
ZAP: "false"
CYPRESS: "false"
If you also disable CRANE, keep ZAP and Cypress disabled or deliberately replace
their required dependencies. The jobs otherwise refer to a missing prerequisite.
Disconnected scanning
With AIRGAP_MODE: "true":
- Grype disables automatic database updates and database-age validation. The common
image job also sets
GRYPE_DB_MAX_ALLOWED_BUILT_AGEto120h, but validation is off. - Trivy sets
TRIVY_OFFLINE_SCAN,TRIVY_SKIP_CHECK_UPDATE,TRIVY_SKIP_DB_UPDATE, andTRIVY_SKIP_JAVA_DB_UPDATEto"true". - ClamAV's wrapper receives
OFFLINE: "true". - Dependency-Check skips its update attempt and adds
--disableOssIndex. - npm audit is omitted.
These switches require prepopulated scanner data and reachable internal services. They do not make all other tools offline-capable. Record scanner versions and database freshness when interpreting the evidence. Installed image defaults, including the wrapper behavior for ClamAV and OpenSCAP, must match your platform's supported toolchain.
Locate results
Open the relevant job in your project's pipeline and download or browse its artifacts.
The default evidence root is JOB_NAME_SLUG/evidence; SBOMs use JOB_NAME_SLUG/sbom.
For example, inspect grype/evidence/grype-output.txt and
syft/sbom/syft-image-sbom.cyclonedx.json. An application test's logs are separate
from the scanner findings.
If a credential was detected, revoke or rotate it using your incident process; deleting the string from a later commit does not invalidate it. For other findings, retain the report and image reference, review the affected package or code, fix or approve an exception through the responsible team, and run a new pipeline.