From 7b6974f1e8bf5f2c254aec79d0c3259f32b2b822 Mon Sep 17 00:00:00 2001 From: Roman Lemekha Date: Thu, 25 Jun 2026 18:50:46 +0200 Subject: [PATCH] feat: add composite actions (privacy-scan, komodo-deploy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step-level reuse for the pieces that compose inside an existing job, alongside the job-level reusable workflows: - privacy-scan/ — composite action wrapping the scan script (moved from scripts/ to privacy-scan/ so the action is self-contained). Drop it in as a step: `uses: roleme/workflows/privacy-scan@`. - komodo-deploy/ — composite action for the HMAC-signed Komodo deploy webhook, extracted from docker-publish-reusable.yml. No host hardcoded (public repo); caller supplies host/stack/secret as inputs. The privacy-scan reusable workflow and .pre-commit-hooks.yaml now point at the new privacy-scan/privacy-scan.sh path (single source of truth, shared by the composite action, the reusable workflow, and the local pre-commit hook). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/privacy-scan-reusable.yml | 29 ++++++-------- .pre-commit-hooks.yaml | 2 +- komodo-deploy/action.yml | 44 +++++++++++++++++++++ privacy-scan/action.yml | 32 +++++++++++++++ {scripts => privacy-scan}/privacy-scan.sh | 0 5 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 komodo-deploy/action.yml create mode 100644 privacy-scan/action.yml rename {scripts => privacy-scan}/privacy-scan.sh (100%) diff --git a/.github/workflows/privacy-scan-reusable.yml b/.github/workflows/privacy-scan-reusable.yml index ea16db2..ea153d3 100644 --- a/.github/workflows/privacy-scan-reusable.yml +++ b/.github/workflows/privacy-scan-reusable.yml @@ -1,11 +1,11 @@ -# Reusable privacy scan: fails if tracked files contain private-infrastructure -# markers (private IPs, .local hosts, host paths, key/secret markers, plus any -# caller-supplied hostnames). Runs scripts/privacy-scan.sh from this repo. +# Reusable privacy scan (job-level wrapper): fails if tracked files contain +# private-infrastructure markers. Thin wrapper around the privacy-scan composite +# action — use this when you want a standalone job; use the action directly +# (roleme/workflows/privacy-scan@) to run it as a step inside an existing job. # -# Callers delegate here and pass their own private hostnames via extra-patterns -# (newline-separated extended-regexps). Those patterns stay in the caller's -# (private) repo and run in the caller's (private) Actions context — they are -# NOT hardcoded in this public repo: +# Callers pass their own private hostnames via extra-patterns (newline-separated +# extended-regexps). Those patterns stay in the caller's (private) repo and run +# in the caller's Actions context — never hardcoded in this public repo: # # jobs: # privacy-scan: @@ -31,19 +31,16 @@ jobs: privacy-scan: runs-on: ubuntu-latest steps: - # The caller's own code is checked out (default), but the scan SCRIPT must - # come from this workflows repo. Fetch it explicitly so the rules cannot - # be tampered with by the calling repo's working tree. - name: Checkout caller repo uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: persist-credentials: false - - name: Fetch scan script from workflows repo - # job.workflow_repository + job.workflow_sha resolve to THIS reusable - # workflow's repo at the exact commit the caller pinned — so the scan - # rules cannot be swapped by the calling repo's working tree, and a - # caller pinned to an older SHA gets that SHA's script (not main). + # Fetch the composite action (which carries the scan script) from THIS + # repo at the pinned commit, so the rules cannot be swapped by the + # caller's working tree. uses: cannot take an expression ref, so we + # check the action dir out by job.workflow_sha and invoke its script. + - name: Fetch scan tooling from workflows repo uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: repository: ${{ job.workflow_repository }} @@ -56,4 +53,4 @@ jobs: # env and quote it so it is never spliced into the command line. env: EXTRA_PATTERNS: ${{ inputs.extra-patterns }} - run: bash .privacy-scan-tools/scripts/privacy-scan.sh + run: bash .privacy-scan-tools/privacy-scan/privacy-scan.sh diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 0c62be7..0cabe8b 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -16,7 +16,7 @@ - id: privacy-scan name: privacy scan (private-infra markers) description: Fail the commit if tracked files contain private-infrastructure markers. - entry: scripts/privacy-scan.sh + entry: privacy-scan/privacy-scan.sh language: script pass_filenames: false always_run: true diff --git a/komodo-deploy/action.yml b/komodo-deploy/action.yml new file mode 100644 index 0000000..4265f0d --- /dev/null +++ b/komodo-deploy/action.yml @@ -0,0 +1,44 @@ +# Composite action: trigger a Komodo stack deploy by calling its per-stack +# GitHub listener, HMAC-signing the body with the stack's webhook secret. Drop +# it in as a STEP after a build/push: +# +# - uses: roleme/workflows/komodo-deploy@ +# with: +# host: ${{ vars.KOMODO_HOST }} +# stack: my-stack +# webhook-secret: ${{ secrets.KOMODO_WEBHOOK_SECRET }} +# +# No host is hardcoded here (public repo) — the caller supplies host/stack/secret. +name: komodo-deploy +description: Trigger an instant Komodo stack deploy via its HMAC-signed webhook listener. + +inputs: + host: + description: Komodo host (e.g. komodo.example.com), no scheme + required: true + stack: + description: Komodo stack name + required: true + webhook-secret: + description: The stack's webhook_secret used to HMAC-sign the request + required: true + +runs: + using: composite + steps: + - name: Trigger Komodo deploy + shell: bash + # All values come from action inputs (trusted caller config / secrets), + # passed via quoted env so they are never spliced into the command line. + env: + KOMODO_HOST: ${{ inputs.host }} + KOMODO_STACK: ${{ inputs.stack }} + KOMODO_WEBHOOK_SECRET: ${{ inputs.webhook-secret }} + run: | + BODY='{"ref":"refs/heads/main"}' + SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$KOMODO_WEBHOOK_SECRET" | awk '{print $2}')" + curl -fsSL -X POST \ + "https://${KOMODO_HOST}/listener/github/stack/${KOMODO_STACK}/deploy" \ + -H "Content-Type: application/json" \ + -H "X-Hub-Signature-256: $SIG" \ + --data "$BODY" diff --git a/privacy-scan/action.yml b/privacy-scan/action.yml new file mode 100644 index 0000000..ae2dcde --- /dev/null +++ b/privacy-scan/action.yml @@ -0,0 +1,32 @@ +# Composite action: run the privacy scan as a STEP inside any job, e.g. at the +# end of a lint job, without spinning up a separate job. Same rules as the +# privacy-scan reusable workflow (both run scripts/privacy-scan.sh). +# +# - uses: roleme/workflows/privacy-scan@ +# with: +# extra-patterns: | +# example-private-host\.example +# +# Private hostnames are passed by the caller via extra-patterns and never +# hardcoded in this public repo. +name: privacy-scan +description: Fail if tracked files contain private-infrastructure markers. + +inputs: + extra-patterns: + description: Newline-separated extended-regexps of extra strings to flag (e.g. private hostnames) + required: false + default: "" + +runs: + using: composite + steps: + - name: Run privacy scan + shell: bash + # extra-patterns is action input (trusted caller config); pass via quoted + # env so it is never spliced into the command line. ${{ github.action_path }} + # points at this action's checked-out dir, so the script is always the one + # shipped with the pinned action ref — not the caller's tree. + env: + EXTRA_PATTERNS: ${{ inputs.extra-patterns }} + run: bash "${{ github.action_path }}/privacy-scan.sh" diff --git a/scripts/privacy-scan.sh b/privacy-scan/privacy-scan.sh similarity index 100% rename from scripts/privacy-scan.sh rename to privacy-scan/privacy-scan.sh