Test script outputs fro test/test.sh
+
+
+ ${{ steps.details.outputs.content }}
+
+
+
diff --git a/.github/workflows/comment-test.yaml b/.github/workflows/comment-test.yaml
new file mode 100644
index 00000000..ada792fe
--- /dev/null
+++ b/.github/workflows/comment-test.yaml
@@ -0,0 +1,47 @@
+# A workflow that tests this action
+
+name: SARIF comment workflow
+
+on:
+ pull_request:
+ branches: [main]
+ workflow_dispatch:
+
+permissions:
+ pull-requests: write
+
+jobs:
+ comment:
+ runs-on: ubuntu-latest
+ name: Run the SARIF commenter
+
+ steps:
+
+ - name: Define the URL for this PR
+ id: define-url
+ run: |
+ url="https://github.com/${{ github.repository }}/pull/${{ github.event.number }}"
+ echo "::set-output name=url::$url"
+
+ - name: Owner and repo names
+ run: |
+ owner=`echo ${{ github.repository }} | awk -F[/] '{print $1}'`
+ echo "::set-output name=owner::$owner"
+ repo=`echo ${{ github.repository }} | awk -F[/] '{print $2}'`
+ echo "::set-output name=repo::$repo"
+ id: define-owner-repo
+
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Post SARIF findings in the pull request
+ if: github.event_name == 'pull_request'
+ uses: tomwillis608/sarif-to-comment-action@tom-create-action
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ url: ${{ steps.define-url.outputs.url }}
+ repo: ${{ steps.define-owner-repo.outputs.repo }}
+ owner: ${{ steps.define-owner-repo.outputs.owner }}
+ branch: ${{ github.head_ref }}
+ sarif-file: "./test/fixtures/codeql.sarif"
+ dry-run: 'false'
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..3ebd8c73
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+package*.json
+/*.sarif
+test/test-*.txt
+bin
+.actrc
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..abe53aa3
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,53 @@
+# pre-commit is a linter runner and GitHub hook manager
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+# Run `pre-commit autoupdate` now and then, why don't ya?
+
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.2.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
+ - id: check-merge-conflict
+
+ # Lint Dockerfiles
+ # This hook uses hadolint in a Docker to minimize dev environment at the cost of speed
+ - repo: https://github.com/hadolint/hadolint
+ rev: v2.10.0
+ hooks:
+ - id: hadolint
+ language: docker_image
+ entry: ghcr.io/hadolint/hadolint:v2.10.0 hadolint
+
+ # Linter for markdown files
+ # This hook uses DavidAnson Node.js markdownlint in a Docker to minimize dev environment at the cost of speed
+ - repo: https://github.com/igorshubovych/markdownlint-cli
+ rev: v0.31.1
+ hooks:
+ - id: markdownlint
+ language: docker_image
+ entry: ghcr.io/igorshubovych/markdownlint-cli:v0.31.1
+
+ # Linter for shell scripts
+ - repo: https://github.com/shellcheck-py/shellcheck-py
+ rev: v0.8.0.4
+ hooks:
+ - id: shellcheck
+
+ # Prettifier for shell scripts
+ # Try to get close to Google style guide
+ - repo: https://github.com/scop/pre-commit-shfmt
+ rev: v3.5.1-1
+ hooks:
+ - id: shfmt-docker # Docker image (requires Docker to run)
+ language: docker_image
+ entry: mvdan/shfmt -ci -s -i 2
+
+ # Detect secrets with GitLeaks
+ - repo: https://github.com/zricethezav/gitleaks
+ rev: v8.8.5
+ hooks:
+ - id: gitleaks-docker
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..63ab294d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,11 @@
+# syntax=docker/dockerfile:1
+
+FROM node:18-bullseye-slim
+
+WORKDIR /app
+
+# Install dependencies
+RUN npm install @security-alert/sarif-to-comment@1.10.4
+COPY ./entrypoint.sh ./entrypoint.sh
+
+ENTRYPOINT ["bash", "/app/entrypoint.sh"]
diff --git a/README.md b/README.md
index 9ad1bf77..ff4003fd 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,117 @@
# sarif-to-comment-action
-A GitHub action for @security-alert/sarif-to-comment
+
+This GitHub action converts a SARIF file with security vulnerability findings
+into a PR comment with the `@security-alert/sarif-to-comment` NPM package.
+
+To run `sarif-to-comment-action` you must determine these values.
+
+These are the inputs to Docker image.
+
+## Inputs
+
+### `sarif-file`
+
+Path to SARIF file to add to PR comment.
+Required.
+
+### `token`
+
+Your GitHub Access Token.
+Required.
+
+### `url`
+
+The URL of the PR to comment.
+Required.
+
+### `repo`
+
+GitHub repository with the PR.
+Required.
+
+### `owner`
+
+Owner of the GitHub repository.
+Required.
+
+### `branch`
+
+Branch the PR is on.
+Required.
+
+### `dry-run`
+
+If true, do not post the results to a PR. If false, do post the results to the PR.
+Required.
+Default: false
+
+## Example usage
+
+Add this action to your own GitHub action yaml file, replacing the value in
+`sarif-file` with the path to the file you want to convert
+and add to your pull request in this final step, likely the output of a
+security scanning tool. There are additional helper steps to determine
+the expected values of `url`, `repo`, and `owner` in the
+[comment-test.yaml workflow](./.github/workflow/comment-test.yaml).
+
+```yaml
+- name: Post SARIF findings in the pull request
+ if: github.event_name == 'pull_request'
+ uses: tomwillis608/sarif-to-comment-action@main
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ url: ${{ steps.define-url.outputs.url }}
+ repo: ${{ github.repository }}
+ owner: ${{ github.repository_owner }}
+ branch: ${{ github.head_ref }}
+ sarif-file: 'scan/results/xss.sarif'
+ dry-run: 'false'
+```
+
+If you want to test locally with `nektos/act`, you will need to add
+values that work locally with `act`.
+
+```yaml
+- name: Post SARIF findings in the pull request
+ if: github.event_name == 'pull_request'
+ uses: tomwillis608/sarif-to-comment-action@main
+ with:
+ token: fake-secret
+ # token: ${{ secrets.GITHUB_TOKEN }}
+ url: "https://github.com/owner/repo/pull/1"
+ owner: ${{ steps.define-owner-repo.outputs.owner }}
+ repo: ${{ steps.define-owner-repo.outputs.repo }}
+ branch: 'your-branch'
+ sarif-file: "./test/fixtures/codeql.sarif"
+ dry-run: 'true' # will not post to PR
+```
+
+## Testing
+
+There is a simple test that builds and runs the Dockerfile and does a dry run of
+`@security-alert/sarif-to-comment` with a test fixture file with known vulnerabilities.
+
+```console
+test/test.sh
+```
+
+## CI
+
+There are two files that perform different tests on the repository.
+[comment-test.yaml workflow](./.github/workflow/comment-test.yaml) uses the
+`tomwillis608/sarif-to-comment-actio` action as one would in their own action workflow.
+
+[cit-test.yaml workflow](./.github/workflow/ci-test.yaml) runs the same test
+script used to develop the action in this repository, ``test/test.sh`.
+
+## Notes
+
+### Support for OWASP dependency-check
+
+To make an OWASP dependency-check SARIF file work for the converter,
+you need to add an expected `defaultConfiguration` element to each `rules` object.
+
+```console
+jq '.runs[].tool.driver.rules[] |= . +
+ {"defaultConfiguration": { "level": "error"}}' test/fixtures/odc.sarif >odc-mod.sarif
+```
diff --git a/action.yml b/action.yml
new file mode 100644
index 00000000..1c045eb9
--- /dev/null
+++ b/action.yml
@@ -0,0 +1,48 @@
+# action.yml
+name: 'sarif-to-comment-action'
+author: tomwillis608
+description: 'Run @security-alert/sarif-to-comment to post the content of a SARIF file to a GitHub pull request.'
+inputs:
+ sarif-file:
+ description: 'Path to SARIF file to add to pull request comment'
+ required: true
+ token:
+ description: 'GitHub Access Token'
+ required: true
+ url:
+ description: 'URL of the pull request to comment.'
+ required: true
+ repo:
+ description: 'GitHub repository with a pull request.'
+ required: true
+ owner:
+ description: 'Owner of the GitHub repository.'
+ required: true
+ branch:
+ description: 'The branch for the pull request.'
+ required: true
+ dry-run:
+ description: 'Add "true" flag here for dry run mode. For testing.'
+ default: 'false'
+ required: true
+ sarif-folder:
+ description: 'The path of the folder where the SARIF file is. For Docker volume mounting'
+ default: 'test'
+ required: true
+outputs:
+ output:
+ description: 'The output of the docker run.'
+runs:
+ using: 'docker'
+ image: 'Dockerfile'
+ args:
+ - ${{ inputs.sarif-file }}
+ - ${{ inputs.token }}
+ - ${{ inputs.url }}
+ - ${{ inputs.repo }}
+ - ${{ inputs.owner }}
+ - ${{ inputs.branch }}
+ - ${{ inputs.dry-run }}
+branding:
+ icon: 'git-pull-request'
+ color: 'green'
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 00000000..9ba64dec
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -o pipefail
+set -exu
+set -C
+
+echo "Convert SARIF file $1"
+npx @security-alert/sarif-to-comment --dryRun "$7" --token "$2" --commentUrl "$3" --sarifContentOwner "$4" --sarifContentRepo "$5" --sarifContentBranch "$6" --title "ODC SARIF vulnerabilities report" --ruleDetails true --suppressedResult true "$1"
+echo "::set-output name=output::$?"
diff --git a/test/fixtures/codeql.sarif b/test/fixtures/codeql.sarif
new file mode 100644
index 00000000..0412f723
--- /dev/null
+++ b/test/fixtures/codeql.sarif
@@ -0,0 +1,436 @@
+{
+ "$schema" : "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
+ "version" : "2.1.0",
+ "runs" : [ {
+ "tool" : {
+ "driver" : {
+ "name" : "CodeQL command-line toolchain",
+ "organization" : "GitHub",
+ "semanticVersion" : "2.2.4",
+ "rules" : [ {
+ "id" : "js/xss",
+ "name" : "js/xss",
+ "shortDescription" : {
+ "text" : "Client-side cross-site scripting"
+ },
+ "fullDescription" : {
+ "text" : "Writing user input directly to the DOM allows for a cross-site scripting vulnerability."
+ },
+ "defaultConfiguration" : {
+ "level" : "error"
+ },
+ "properties" : {
+ "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ],
+ "kind" : "path-problem",
+ "precision" : "high",
+ "name" : "Client-side cross-site scripting",
+ "description" : "Writing user input directly to the DOM allows for\n a cross-site scripting vulnerability.",
+ "id" : "js/xss",
+ "problem.severity" : "error"
+ }
+ } ]
+ }
+ },
+ "artifacts" : [ {
+ "location" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ }
+ }, {
+ "location" : {
+ "uri" : "examples/Xss2.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 1
+ }
+ } ],
+ "results" : [ {
+ "ruleId" : "js/xss",
+ "ruleIndex" : 0,
+ "message" : {
+ "text" : "Cross-site scripting vulnerability due to [user-provided value](1)."
+ },
+ "locations" : [ {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 4,
+ "startColumn" : 20,
+ "endColumn" : 56
+ }
+ }
+ } ],
+ "partialFingerprints" : {
+ "primaryLocationLineHash" : "f10617abe5e779f0:1",
+ "primaryLocationStartColumnFingerprint" : "15"
+ },
+ "codeFlows" : [ {
+ "threadFlows" : [ {
+ "locations" : [ {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 2,
+ "startColumn" : 16,
+ "endColumn" : 33
+ }
+ },
+ "message" : {
+ "text" : "document.location"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 2,
+ "startColumn" : 16,
+ "endColumn" : 38
+ }
+ },
+ "message" : {
+ "text" : "documen ... on.href"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 2,
+ "startColumn" : 9,
+ "endColumn" : 38
+ }
+ },
+ "message" : {
+ "text" : "href"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 3,
+ "startColumn" : 17,
+ "endColumn" : 21
+ }
+ },
+ "message" : {
+ "text" : "href"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 3,
+ "startColumn" : 17,
+ "endColumn" : 59
+ }
+ },
+ "message" : {
+ "text" : "href.su ... t=\")+8)"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 3,
+ "startColumn" : 9,
+ "endColumn" : 59
+ }
+ },
+ "message" : {
+ "text" : "deflt"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 4,
+ "startColumn" : 39,
+ "endColumn" : 44
+ }
+ },
+ "message" : {
+ "text" : "deflt"
+ }
+ }
+ }, {
+ "location" : {
+ "physicalLocation" : {
+ "artifactLocation" : {
+ "uri" : "examples/Xss.js",
+ "uriBaseId" : "%SRCROOT%",
+ "index" : 0
+ },
+ "region" : {
+ "startLine" : 4,
+ "startColumn" : 20,
+ "endColumn" : 56
+ }
+ },
+ "message" : {
+ "text" : "\"