From 9174a50cbe6060768a817ff24a2cc29835827e28 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Wed, 7 Oct 2026 18:57:49 +0530 Subject: [PATCH] ci: add SCA, Scorecard and malware scan workflows --- .github/workflows/rl.yml | 117 ++++++++++++++++++++++++++++++++ .github/workflows/sca.yml | 36 ++++++++++ .github/workflows/scorecard.yml | 81 ++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 .github/workflows/rl.yml create mode 100644 .github/workflows/sca.yml create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/workflows/rl.yml b/.github/workflows/rl.yml new file mode 100644 index 00000000..68ac031a --- /dev/null +++ b/.github/workflows/rl.yml @@ -0,0 +1,117 @@ +name: RL Scan +run-name: rl-scan + +# Reusable malware-scan workflow — call this from your release or CI pipeline via +# workflow_call. The trigger lives in the calling workflow; the build steps are +# defined here as a placeholder that you replace with your own toolchain setup, +# compilation, and packaging steps before merging. +# +# Caller pattern (minimal): +# jobs: +# release-and-scan: +# uses: ./.github/workflows/rl.yml +# with: +# artifact-name: my-artifact +# artifact-path: dist/my-artifact.tgz +# version: ${{ github.event.release.tag_name }} +# secrets: inherit +# +# Artifact contract +# ───────────────── +# artifact-path MUST be a concrete file path — the action's internal existence +# check uses [ -f ], which does NOT expand globs. A missing artifact fails the job. +# +# Required org secrets (configured at org level in auth0/): +# RLSECURE_LICENSE — ReversingLabs license key +# RLSECURE_SITE_KEY — ReversingLabs site key +# SIGNAL_HANDLER_TOKEN — scan-service telemetry auth +# SIGNAL_HANDLER_DOMAIN — scan-service endpoint domain +# PRODSEC_TOOLS_ARN — AWS role ARN for ProdSec tools +# PRODSEC_TOOLS_USER — ProdSec Python tools repo user +# PRODSEC_TOOLS_TOKEN — ProdSec Python tools repo token +# PRODSEC_PYTHON_TOOLS_REPO — ProdSec Python tools repo URL + +on: + workflow_call: + inputs: + artifact-name: + description: Name assigned to the artifact (used for RL reporting) + type: string + required: true + artifact-path: + description: Concrete file path of the built artifact on the runner — no globs + type: string + required: true + version: + description: Version string for the artifact (e.g. release tag) + type: string + required: true + secrets: + RLSECURE_LICENSE: + required: true + RLSECURE_SITE_KEY: + required: true + SIGNAL_HANDLER_TOKEN: + required: true + SIGNAL_HANDLER_DOMAIN: + required: true + PRODSEC_TOOLS_ARN: + required: true + PRODSEC_TOOLS_USER: + required: true + PRODSEC_TOOLS_TOKEN: + required: true + PRODSEC_PYTHON_TOOLS_REPO: + required: true + +jobs: + # ── Malware scan via ReversingLabs composite action ───────────────────────── + rl-scan: + name: RL Scan + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write # required for AWS OIDC federation (PRODSEC_TOOLS_ARN) + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + # ── Build the artifact ──────────────────────────────────────────────────── + # Replace this placeholder with ALL steps required to produce the artifact, + # including: runtime/toolchain setup (e.g. actions/setup-node, setup-go, + # setup-dotnet), dependency installation, compilation, and packaging (e.g. + # tar, zip, docker save). The final step must place the artifact at the + # path passed as inputs.artifact-path. The rl-scan action uses [ -f ] to + # verify the file exists — a missing or incorrect path fails the job. + - name: Build artifact # TODO: replace with your toolchain setup + build + package steps + run: | + echo "TODO: replace this step with your build commands" + echo " The built file must be at: ${{ inputs.artifact-path }}" + + - name: Run RL malware scan + id: rl-scan-conclusion + uses: auth0/devsecops-tooling/.github/actions/rl-scan@e29f26478db18ff0bcbe4bc447a8fbd54fbeec9e + with: + # ── Artifact inputs ───────────────────────────────────────────────── + artifact-name: ${{ inputs.artifact-name }} + artifact-path: ${{ inputs.artifact-path }} + version: ${{ inputs.version }} + # ── Required secrets ──────────────────────────────────────────────── + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + SIGNAL_HANDLER_DOMAIN: ${{ secrets.SIGNAL_HANDLER_DOMAIN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_PYTHON_TOOLS_REPO: ${{ secrets.PRODSEC_PYTHON_TOOLS_REPO }} + + - name: Gate on scan result + if: always() + env: + SCAN_STATUS: ${{ steps.rl-scan-conclusion.outputs.scan-status }} + run: | + if [ "$SCAN_STATUS" != "success" ]; then + echo "::error title=Malware::RL scan did not pass (status: ${SCAN_STATUS:-none})" + exit 1 + fi diff --git a/.github/workflows/sca.yml b/.github/workflows/sca.yml new file mode 100644 index 00000000..1c17eac4 --- /dev/null +++ b/.github/workflows/sca.yml @@ -0,0 +1,36 @@ +name: SCA Scan + +# Example: invoke the reusable sca-scan workflow from auth0/devsecops-tooling. +# Reusable workflows are called at job level via `uses:`. +# A remediation PR adds this workflow to your .github/workflows/ directory — review and merge it, adjusting if needed. +# +# Required org secrets (configured at org level in auth0/): +# SNYK_TOKEN — Snyk organisation token +# SIGNAL_HANDLER_TOKEN — scan-service telemetry auth +# SIGNAL_HANDLER_DOMAIN — scan-service endpoint domain + +on: + push: + branches: ['6.x'] + pull_request: + branches: ['6.x'] + +jobs: + # ── SCA / Snyk scan via reusable workflow ─────────────────────────────────── + sca: + uses: auth0/devsecops-tooling/.github/workflows/sca-scan.yml@e29f26478db18ff0bcbe4bc447a8fbd54fbeec9e + # All inputs are optional — defaults shown. To override, uncomment `with:` and any line below. + # with: + # node-version: '16' + # java-version: '11' + # go-version: '1.22' + # python-version: '3.10' + # ruby-version: '4.0' + # php-version: '8.5' + # dotnet-version: '6' + # dotnet-install-dir: '/usr/share/dotnet/' + # snyk-version: 'v1.1292.0' + # additional-arguments: '' # extra Snyk CLI flags, e.g. '--severity-threshold=high' + # pre-scan-commands: '' # shell commands to run before Snyk (e.g. 'npm ci') + # runner: 'ubuntu-latest' + secrets: inherit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000..bcc747ea --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,81 @@ +name: Scorecard analysis + +# Runs OpenSSF Scorecard supply-chain analysis directly via ossf/scorecard-action +# (no composite wrapper, no cross-org dependency). All action refs are SHA-pinned. +# +# Scorecard requirements +# ────────────────────── +# • Supported triggers (per OSSF) are push and schedule on the default branch. +# pull_request is added below ONLY as a smoke test on a real runner from the PR. +# workflow_dispatch provides manual smoke tests after this workflow exists on the default branch. +# OSSF officially documents both triggers as EXPERIMENTAL ("The pull_request and +# workflow_dispatch triggers are experimental" — scorecard-action README); the docs do not +# detail how results differ on them. Because they are experimental, treat a PR run as a +# smoke signal only — this workflow is fully validated only after merge to the default branch. +# • The checkout step MUST set persist-credentials: false (required by Scorecard's +# security model to avoid leaking the GITHUB_TOKEN into the analysis environment). +# • publish_results: true publishes to the public Scorecard API and enables the +# Scorecard badge. It requires id-token: write on the job AND a push/schedule +# event — it must stay false on pull_request/workflow_dispatch. Set to 'false' to +# keep results private (id-token can then be omitted from the job permissions). + +on: + push: + branches: ['6.x'] + pull_request: + branches: ['6.x'] # EXPERIMENTAL per OSSF: smoke test only, not an authoritative result + workflow_dispatch: {} # EXPERIMENTAL per OSSF: manual re-run, available only after merge (default-branch copy) + schedule: + - cron: '30 1 * * 6' # weekly, Saturday 01:30 UTC + +permissions: read-all # default: restrict everything; the job overrides what it needs + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + # No event guard: pull_request and workflow_dispatch are allowed to run as an + # experimental smoke test (see the header). Keep publish_results: false on those + # events — publishing requires a push/schedule event and id-token: write. + permissions: + security-events: write # upload SARIF to the Security tab / Code Scanning dashboard + # id-token: write # OIDC token for Scorecard's public API publishing (publish_results: true) + # Uncomment this line only when you set publish_results: true + contents: read # checkout the repository + + steps: + - name: Checkout code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false # required by Scorecard — do not remove + + - name: Run analysis + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # publish_results: true publishes to the Scorecard public dataset and enables the badge. + # Requires id-token: write above and a push/schedule event. + # Set to 'true' (and enable id-token: write) to publish results to the Scorecard public dataset. + publish_results: false + + # Upload SARIF as a workflow artifact (optional — comment out to disable). + # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 # adjust as needed + + # Upload SARIF to GitHub Code Scanning dashboard (optional — comment out to disable). + # Skipped on pull_request: a fork PR gets a read-only GITHUB_TOKEN with no + # security-events: write, so this step would fail and break the PR smoke test. + # The SARIF still uploads on push/schedule (default branch) where the token can write; + # the artifact upload above keeps results reachable from the PR run. + - name: Upload to code-scanning + if: github.event_name != 'pull_request' + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + sarif_file: results.sarif + category: scorecard