CollabOps

Code Quality

Code linting, static security analysis, secret detection, and SBOM generation

collabops/lint@v1

On-Premise: ❌ — recommended alternatives: sast-scan@v1, secret-detect@v1

Runs multi-language code linting based on MegaLinter. Supports 60+ languages.

InputRequiredDefaultDescription
enableNO""Linters to enable (comma-separated)
disableNO""Linters to disable (comma-separated)
apply-fixesNO"false"Apply automatic fixes
working-directoryNO"/workspace/source"Scan target directory

Examples

All languages auto-detected

jobs:
  lint:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      # Detects changed files and picks the right linters automatically.
      - name: lint
        uses: "collabops/lint@v1"

Restrict to specific languages (enable / disable)

jobs:
  lint:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: lint-typed
        uses: "collabops/lint@v1"
        with:
          # enable is an allowlist (only the listed ones). Comma-separated, uppercase.
          enable: "TYPESCRIPT,YAML,DOCKERFILE"
          # disable is a denylist. Combinable with enable.
          disable: "SPELL,COPYPASTE"

Auto-fix (apply-fixes)

jobs:
  lint-fix:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: lint-with-autofix
        uses: "collabops/lint@v1"
        with:
          enable: "TYPESCRIPT,JAVASCRIPT"
          # Formatters / fixable linters write changes back to disk.
          apply-fixes: "true"
      # Hand the fixed tree off to another Job in the same workflow.
      - name: upload-fixes
        uses: "collabops/upload-artifact@v2"
        with:
          name: lint-fixes
          path: .

Key points — The simplest form (no with) auto-selects linters for the changed files. enable and disable combine; the 60+ language keywords are uppercase (TYPESCRIPT, DOCKERFILE, …). apply-fixes: "true" mutates the workspace, so pair it with downstream commit/PR automation carefully.

collabops/sast-scan@v1

On-Premise: ✅ airgapped compatible

Runs static application security testing (SAST) based on Semgrep. Detects OWASP Top 10 and other security vulnerabilities.

InputRequiredDefaultDescription
configNO"auto"Semgrep rules config (auto, p/python, p/javascript, or file path)
severityNO"ERROR"Minimum severity filter (INFO, WARNING, ERROR)
output-formatNO"text"Output format (text, json, sarif)
working-directoryNO"/workspace/source"Scan target directory

Examples

Basic — auto ruleset

jobs:
  sast:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      # Default config: "auto" — language detection picks a standard ruleset.
      - name: sast-scan
        uses: "collabops/sast-scan@v1"

OWASP Top 10 + fail on WARNING+

jobs:
  sast:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: sast-owasp
        uses: "collabops/sast-scan@v1"
        with:
          # Standard ruleset. Accepts a Semgrep registry slug, local path, or URL.
          config: p/owasp-top-ten
          # Fail the Job when any finding meets or exceeds this severity.
          severity: WARNING

SARIF output + artifact upload

# To preserve the report even on failure, split into a separate Job with if: "always()".
jobs:
  sast:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: sast-with-sarif
        uses: "collabops/sast-scan@v1"
        with:
          config: p/security-audit
          # Standard format consumable by security dashboards and review tools.
          output-format: sarif

  archive-sast-report:
    needs: [sast]
    # Always runs regardless of upstream success/failure — report is always collected.
    if: "always()"
    steps:
      - name: archive-sarif
        uses: "collabops/upload-artifact@v2"
        with:
          name: sast-report
          path: semgrep-results.sarif

Key pointsconfig accepts a Semgrep registry slug (p/owasp-top-ten), local path, or URL. severity is INFO|WARNING|ERROR — make the failure threshold explicit. Pair the SARIF output with if: always() + upload-artifact so the report is collected even on failure.

collabops/secret-detect@v1

On-Premise: ✅ airgapped compatible

Detects secrets in source code using Gitleaks. Scans for API keys, passwords, and other sensitive credentials.

InputRequiredDefaultDescription
configNO""Gitleaks config file path (.gitleaks.toml)
report-formatNO"json"Report format (json, csv, sarif, junit)
report-pathNO"/workspace/source/gitleaks-report.json"Report output path
working-directoryNO"/workspace/source"Scan target directory

Examples

Default scan + JSON report

jobs:
  secret-scan:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
          # Secret scanning should cover the full history.
          fetch-depth: "0"
      - name: secret-detect
        uses: "collabops/secret-detect@v1"

Custom rules + SARIF upload

# Split archival into its own Job so the report survives a failed scan.
jobs:
  secret-scan:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
          fetch-depth: "0"
      - name: secret-detect-with-rules
        uses: "collabops/secret-detect@v1"
        with:
          # Use the in-repo ruleset when one exists.
          config: .gitleaks.toml
          report-format: sarif
          report-path: /workspace/source/gitleaks-report.sarif

  archive-secret-report:
    needs: [secret-scan]
    if: "always()"
    steps:
      - name: archive-report
        uses: "collabops/upload-artifact@v2"
        with:
          name: gitleaks-report
          path: gitleaks-report.sarif

Key points — Secret scanning is only meaningful over the full history — set fetch-depth: "0" (shallow clones miss historical leaks). config can point at an in-repo .gitleaks.toml; omit it for the default ruleset. The Job fails by default when a finding is reported, so use if: always() to ensure the report is always uploaded.

collabops/sonar-scan@v1

On-Premise: ✅ airgapped compatible (requires a SonarQube server reachable from the pipeline)

Static analysis that uploads code quality and security results to an external SonarQube server. The sonar-scanner CLI runs on the image's bundled JRE, so there is no runtime download.

InputRequiredDefaultDescription
sonar-host-urlYESSonarQube server URL (SONAR_HOST_URL)
sonar-tokenYESAuth token (inject via secrets)
project-keyYESProject key (sonar.projectKey)
project-nameNO""Project display name (sonar.projectName)
project-versionNO""Project version (sonar.projectVersion)
sourcesNO"."Source path to analyze (sonar.sources)
testsNO""Test source paths (sonar.tests, comma-separated)
inclusionsNO""Analysis inclusion patterns (sonar.inclusions, glob)
exclusionsNO""Analysis exclusion patterns (sonar.exclusions, glob)
test-inclusionsNO""Test inclusion patterns (sonar.test.inclusions)
test-exclusionsNO""Test exclusion patterns (sonar.test.exclusions)
coverage-exclusionsNO""Coverage exclusion patterns (sonar.coverage.exclusions)
languageNO""Primary language. Maps coverage-report-paths to the right property key (python/javascript/go/java, ...)
coverage-report-pathsNO""Coverage report path. Auto-mapped to the language-specific SonarQube property
quality-gate-waitNO"false"Wait for the Quality Gate and fail the step on failure (sonar.qualitygate.wait). Use to block CR merges
quality-gate-timeoutNO""Quality Gate wait timeout in seconds (sonar.qualitygate.timeout)
verboseNO"false"Verbose logging (sonar.verbose)
working-directoryNO"/workspace/source"Scan working directory (sonar.projectBaseDir)
skip-jre-provisioningNO"true"Use the image's bundled JRE (airgapped-safe, no runtime download)
extra-argsNO""Pass extra sonar-scanner -D options through

Examples

Basic scan

jobs:
  quality:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      # Uploads the analysis to an external SonarQube server. Server URL/token come from workspace settings.
      - name: sonar-scan
        uses: "collabops/sonar-scan@v1"
        with:
          # SonarQube server URL — register SONAR_HOST_URL in workspace variables and reference it.
          sonar-host-url: ${{ vars.SONAR_HOST_URL }}
          # Analysis token — store it in secrets (never inline plaintext).
          sonar-token: ${{ secrets.SONAR_TOKEN }}
          # Project key created on the SonarQube server.
          project-key: "<workspace>-<repository>"

Block change requests with a Quality Gate

# To use it as a CR merge gate, combine the change_request trigger with qualitygate.wait.
jobs:
  quality:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: sonar-scan
        uses: "collabops/sonar-scan@v1"
        with:
          sonar-host-url: ${{ vars.SONAR_HOST_URL }}
          sonar-token: ${{ secrets.SONAR_TOKEN }}
          project-key: "<workspace>-<repository>"
          # Wait for the server-side Quality Gate result and fail the step on failure to block the merge.
          # (Only meaningful when a Quality Gate is configured for the project on the server.)
          quality-gate-wait: true

Per-server tuning with extra-args

jobs:
  quality:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: sonar-scan
        uses: "collabops/sonar-scan@v1"
        with:
          sonar-host-url: ${{ vars.SONAR_HOST_URL }}
          sonar-token: ${{ secrets.SONAR_TOKEN }}
          project-key: "<workspace>-<repository>"
          # Source path to analyze (relative to working-directory).
          sources: "src"
          # Pass extra -D options through — multiple separated by spaces.
          extra-args: "-Dsonar.exclusions=**/*.test.ts -Dsonar.sourceEncoding=UTF-8"

Key pointssonar-host-url, sonar-token, and project-key are required. Always inject the token via secrets and the server URL via vars (never inline plaintext). Even in airgapped On-Premise, skip-jre-provisioning defaults to true so it runs without runtime downloads, but the pipeline pod still needs a reachable SonarQube server. To block CR merges, combine quality-gate-wait: true with a server-side Quality Gate.

collabops/sbom@v1

On-Premise: ✅ airgapped compatible

Generates a Software Bill of Materials (SBOM) with Syft. Runs the distroless syft image directly via exec form, so there is no runtime download.

Syft catalogs packages across many ecosystems — npm, Python (pip / poetry / pipenv), Go modules, Java (jar / pom), Ruby (gem), Rust (Cargo), PHP (Composer), .NET, and OS packages (dpkg / rpm / apk) when scanning a container image.

Directory scans need a lockfile. For a dir: scan, syft reads lockfiles and installed packages — commit package-lock.json, poetry.lock, go.sum, etc. A bare manifest (e.g. package.json alone) with no lockfile may yield few or no components.

InputRequiredDefaultDescription
formatNO"cyclonedx-json"Output format (cyclonedx-json, spdx-json, cyclonedx-xml, spdx-tag-value, syft-json)
scan-targetNO"dir:/workspace/source"Scan target (dir:&lt;path&gt; for the source tree, or registry:&lt;image&gt;)

Output formats

format valueStandardUse
cyclonedx-json (default)CycloneDX (OWASP), JSONVulnerability / supply-chain tooling
spdx-jsonSPDX (Linux Foundation), JSONLicense / compliance
cyclonedx-xmlCycloneDX, XMLXML-based pipelines
spdx-tag-valueSPDX, tag-value textHuman-readable SPDX
syft-jsonSyft native, JSONSyft ecosystem (richest metadata)

Select the format on the step with format:. The SBOM is always written to /workspace/source/sbom.json regardless of format.

- name: sbom
  uses: "collabops/sbom@v1"
  with:
    # pick any value from the table above (default: cyclonedx-json)
    format: spdx-json

Examples

Default — CycloneDX SBOM of the workspace

jobs:
  sbom:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      # Default: CycloneDX JSON of the source tree -> /workspace/source/sbom.json
      - name: sbom
        uses: "collabops/sbom@v1"

SPDX format + archive the SBOM

# SBOM generation only writes the file; chain upload-artifact to preserve it.
jobs:
  sbom:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: sbom
        uses: "collabops/sbom@v1"
        with:
          # cyclonedx-json | spdx-json | cyclonedx-xml | spdx-tag-value | syft-json
          format: spdx-json
          # dir:<path> for the source tree, or registry:<image> for a built image
          scan-target: dir:/workspace/source
      # SBOM writes /workspace/source/sbom.json - keep it as an artifact.
      - name: upload-sbom
        uses: "collabops/upload-artifact@v2"
        with:
          name: sbom
          path: sbom.json

Scan a container image

# Scan a container image's installed packages instead of the source tree.
# No checkout needed — syft pulls and analyzes the image directly.
jobs:
  sbom:
    steps:
      - name: sbom
        uses: "collabops/sbom@v1"
        with:
          scan-target: "registry:my-registry.example.com/app:1.2.3"
      - name: upload-sbom
        uses: "collabops/upload-artifact@v2"
        with:
          name: sbom
          path: sbom.json

An SBOM is a standard document — feed it to vulnerability scanners (e.g. Grype), license / compliance tools, or a dependency dashboard. This action only generates the SBOM; keep it with upload-artifact@v2 (or push it to your own store).

On-premise (air-gapped): mirror anchore/syft:v1.46.0 to your internal registry (Harbor / Nexus) beforehand — the step never downloads it at runtime. When using scan-target: registry:<image>, the target image and its registry must also be reachable from the pipeline.

Key points — SBOM generation only creates /workspace/source/sbom.json; chain upload-artifact@v2 to preserve it. format selects the standard (CycloneDX / SPDX / syft); scan-target takes dir:<path> for the source tree or registry:<image> for a built image. The pinned anchore/syft image is distroless and runs via exec (no shell, no runtime download), so it is airgapped-compatible.

Table of Contents