> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Custom Transformer OWASP Dependency Check 2

> Shows building a custom transformer that converts Jenkins OWASP Dependency Check stages into GitHub Actions steps, parsing additionalArguments to set format and failOnCVSS and upload reports

This lesson shows how to build a custom transformer that converts an OWASP Dependency-Check Jenkins stage into an equivalent GitHub Actions step. The transformer:

* Parses the Jenkins plugin configuration to find `additionalArguments`.
* Extracts key flags such as `--format` and `--failOnCVSS`.
* Emits a GitHub Actions step that runs the `dependency-check/Dependency-Check_Action` and uploads generated reports.

Goal: produce a GitHub Actions job step that runs dependency-check, writes reports to `reports/`, and uploads those artifacts.

Desired GitHub Actions step (excerpt)

```yaml theme={null}
jobs:
  depchecktest:
    runs-on: ubuntu-latest
    name: depcheck_test
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Build project with Maven
        run: mvn clean install
      - name: Depcheck
        uses: dependency-check/Dependency-Check_Action@main
        id: Depcheck
        with:
          project: "test"
          path: "."
          format: "HTML"
          out: "reports" # default; no need to specify unless overriding
          args: >
            --failOnCVSS 7
            --enableRetired
      - name: Upload Test results
        uses: actions/upload-artifact@master
        with:
          name: Depcheck report
          path: ${{ github.workspace }}/reports
```

What data do we get from Jenkins?

The Dependency-Check plugin configuration appears as a structured hash. The important field is `additionalArguments` (a multi-line string). Example:

```ruby theme={null}
{
  "name" => "dependencyCheck",
  "arguments" => [
    {
      "key" => "additionalArguments",
      "value" => {
        "isLiteral" => true,
        "value" => "
                             --scan './'
                             --out './'
                             --format 'ALL'
                             --disableYarnAudit --prettyPrint --failOnCVSS 9"
      }
    },
    {
      "key" => "nvdCredentialsId",
      "value" => {
        "isLiteral" => true,
        "value" => "owasp-dependency-check"
      }
    },
    {
      "key" => "odcInstallation",
      "value" => {
        "isLiteral" => true,
        "value" => "OWASP-DepCheck-10"
      }
    }
  ]
},
{
  "name" => "dependencyCheckPublisher",
  "arguments" => [
    {
      ...
    }
  ]
}
```

What we need to parse from `additionalArguments`

| Flag           | Purpose                                                  | Regex used to extract                | Default if missing |
| -------------- | -------------------------------------------------------- | ------------------------------------ | ------------------ |
| `--format`     | Which report format(s) to generate (e.g., `HTML`, `ALL`) | `/--format\s+['"]?([^'"\s]+)['"]?/i` | `ALL`              |
| `--failOnCVSS` | CVSS threshold that makes dependency-check exit non-zero | `/--failOnCVSS\s+(\d+(?:\.\d+)?)/i`  | `9`                |

Transformer scaffolding and environment

Add or reuse your transformer (example filename: `ci-pipeline-transformer.rb`). You can set up a runner and environment variables for the transformer runtime. Example runner/env config:

```ruby theme={null}
runner "us-west-1-ubuntu-22", "ubuntu-latest"

env "MONGO_USERNAME", "superuser"
env "MONGO_PASSWORD", secret("mongo_db_password")
env "MONGO_DB_CREDS", nil
```

Transformer implementation

The transformer locates the `additionalArguments` string, applies regular expressions to extract `--format` and `--failOnCVSS`, and builds the step hash for GitHub Actions. Defaults are applied if values are absent.

```ruby theme={null}
transform "dependencyCheck" do |item|
  # Extract additional arguments (string)
  additional_args = item["arguments"].find { |arg| arg["key"] == "additionalArguments" }["value"]["value"]

  # Parse key parameters from additional arguments
  # Accept quoted or unquoted format values
  format = additional_args.match(/--format\s+['"]?([^'"\s]+)['"]?/i)&.captures&.first || "ALL"
  # Accept integer or decimal CVSS thresholds
  fail_on_cvss = additional_args.match(/--failOnCVSS\s+(\d+(?:\.\d+)?)/i)&.captures&.first || "9"

  {
    "name" => "OWASP Dependency Check",
    # Ensure that, even if the check fails, we continue to the artifact upload step
    "continue-on-error" => true,
    "uses" => "dependency-check/Dependency-Check_Action@main",
    "with" => {
      "project" => "test",
      "path" => ".",
      "format" => format,
      "out" => "reports",
      "args" => "--failOnCVSS #{fail_on_cvss}"
    }
  }
end
```

Skip the publisher stage

Jenkins' `dependencyCheckPublisher` can be omitted for GitHub Actions because the dependency-check action writes the reports directly. Return `nil` in the transformer to skip that identifier:

```ruby theme={null}
transform "dependencyCheckPublisher" do |item|
  next nil
end
```

Run a dry-run import

Validate the transformation with a dry-run using the importer tool:

```bash theme={null}
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/ci-pipeline-poll-scm/ \
  --output-dir tmp/dry-run \
  --custom-transformers ss-pipeline-transformer.rb
```

When you run a real migration, the tool can create a pull request in the target repo:

```bash theme={null}
gh actions-importer migrate jenkins \
  --target-url https://github.com/jenkins-demo-org/solar-system \
  --output-dir tmp/migrate \
  --source-url http://139.84.149.83:8080/job/ci-pipeline-poll-scm/ \
  --custom-transformers ss-pipeline-transformer.rb
# Output:
# Pull request: 'https://github.com/jenkins-demo-org/solar-system/pull/1'
```

Pull request and converted workflow

The generated workflow keeps the original environment, runners, and converted jobs. The OWASP job contains the dependency-check action and a subsequent upload-artifact step to collect reports.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/iRlNGmU-DLlt2Ghu/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/convert-ci-pipeline-to-github-actions.jpg?fit=max&auto=format&n=iRlNGmU-DLlt2Ghu&q=85&s=f16c14bf8eebb290d634596eac776b40" alt="A screenshot of a GitHub pull request page titled &#x22;Convert ci-pipeline-poll-scm to GitHub Actions&#x22; showing a green &#x22;All checks have passed&#x22; panel with multiple successful &#x22;Solar System CI / unit-testing&#x22; checks and a green &#x22;Merge pull request&#x22; button." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/convert-ci-pipeline-to-github-actions.jpg" />
</Frame>

Excerpt of the generated workflow (converted OWASP job)

```yaml theme={null}
Dependency_Scanning_OWASP_Dependency_Check:
  name: Dependency Scanning - OWASP Dependency Check
  runs-on:
    - ubuntu-latest
  needs: Installing_Dependencies
  steps:
    - name: checkout
      uses: actions/checkout@v4.1.0
    - name: OWASP Dependency Check
      continue-on-error: true
      uses: dependency-check/Dependency-Check_Action@main
      with:
        project: test
        path: "."
        format: ALL
        out: reports
        args: "--failOnCVSS 9"
    - name: Upload Artifacts
      uses: actions/upload-artifact@v4.1.0
      with:
        if-no-files-found: ignore
        name: Dependency Check HTML Report
        path: "reports"
```

Execute the workflow and read logs

When the action runs it triggers dependency-check, which generates multiple formats (XML, HTML, JSON, CSV, SARIF, JUnit). The action receives the `--format`, `--out`, and `--failOnCVSS` settings from the `with.args` we provided.

Sample logs (trimmed):

```bash theme={null}
[INFO] Analysis Complete (4 seconds)
[INFO] Writing XML report to: /github/workspace/reports/dependency-check-report.xml
[INFO] Writing HTML report to: /github/workspace/reports/dependency-check-report.html
[INFO] Writing JSON report to: /github/workspace/reports/dependency-check-report.json
[INFO] Writing CSV report to: /github/workspace/reports/dependency-check-report.csv
[INFO] Writing SARIF report to: /github/workspace/reports/dependency-check-report.sarif
[INFO] Writing JUNIT report to: /github/workspace/reports/dependency-check-report-junit.xml

# Upload Artifacts
Uploaded bytes 209207
Finished uploading artifact content to blob storage!
SHA256 hash of uploaded artifact .zip is a71f06a5ae4d09e7be41f18401a6a577ba0635a86cecfa2f13cad1376a0a1c5f
Finished artifact upload
```

Handling failures and ensuring artifact upload

If dependency-check finds vulnerabilities above the `--failOnCVSS` threshold the process exits non-zero and the step fails. By adding `continue-on-error: true` to the dependency-check step, the job will continue and the `upload-artifact` step will still run so you can download the reports for inspection.

Example error when threshold is exceeded:

```text theme={null}
Error:
One or more dependencies were identified with vulnerabilities that have a CVSS score greater than or equal to '2.0':
package-lock.json?formidable (pkg:npm/formidable@2.1.2): GHSA-75v8-2h7p-7m2m (3.1), CVE-2025-46653 (6.9)
See the dependency-check report for more details.
```

Because `continue-on-error: true` is set, the Upload Artifacts step still runs and uploads the reports for inspection.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/iRlNGmU-DLlt2Ghu/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/github-actions-owasp-dependency-check-failure.jpg?fit=max&auto=format&n=iRlNGmU-DLlt2Ghu&q=85&s=8e6afb8049d0f814184679aebf3bb58f" alt="Screenshot of a GitHub Actions workflow run for the jenkins-demo-org/solar-system repo. The run &#x22;Update ci-pipeline-poll-scm.yml&#x22; shows Failure because the &#x22;Dependency Scanning - OWASP Dependency Check&#x22; job failed while steps like Installing Dependencies and NPM scanning succeeded." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/github-actions-owasp-dependency-check-failure.jpg" />
</Frame>

<Callout icon="lightbulb" color="#1CB2FE">
  Using `continue-on-error: true` for the dependency-check step lets subsequent steps (for example, uploading artifacts) run even if dependency-check exits non-zero. If you prefer the job to fail on vulnerabilities, omit `continue-on-error` (or set it to `false`) and make the upload conditional (for example, `if: failure()` or use `if: always()` for unconditional uploads depending on your policy).
</Callout>

Final notes and verification

* After merging the generated PR, your repository will contain the converted GitHub Actions workflow. The OWASP dependency check will run as a job, produce multiple report formats, and upload them as artifacts.
* To have the job fail on vulnerability findings, keep the required `--failOnCVSS` value and remove `continue-on-error`.
* To always collect reports regardless of findings, keep `continue-on-error: true` and upload artifacts afterward.
* The example transformer is intentionally simple: it extracts `--format` and `--failOnCVSS` and hard-codes `project`, `path`, and `out`. Extend the transformer to pull additional parameters (project name, report directory, credentials, etc.) from other Jenkins arguments as needed.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/iRlNGmU-DLlt2Ghu/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/github-actions-ci-pipeline-poll-scm.jpg?fit=max&auto=format&n=iRlNGmU-DLlt2Ghu&q=85&s=dd38e2a1cff13a5705ec60fb8342d60b" alt="Screenshot of a GitHub Actions page for the jenkins-demo-org/solar-system repo showing the &#x22;ci-pipeline-poll-scm&#x22; workflow and three recent workflow runs on the main branch. The left sidebar shows workflow navigation and management options like Caches, Runners, and Usage metrics." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-OWASP-Dependency-Check-2/github-actions-ci-pipeline-poll-scm.jpg" />
</Frame>

That's the complete flow: parse Jenkins `additionalArguments`, implement a custom transformer that emits a GitHub Actions step using `dependency-check/Dependency-Check_Action@main`, ensure reports are written to a defined `out` directory, and upload those reports as artifacts even if the scanner step flags vulnerabilities.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/migrating-jenkins-pipelines-to-github-actions/module/3b5e500f-482a-4860-9f2c-d5f9fbc95159/lesson/cbdf13a1-838d-4b48-9287-736900d42e56" />
</CardGroup>
