{"id":50851716,"url":"https://github.com/meblabs/security-workflow","last_synced_at":"2026-06-14T14:02:44.467Z","repository":{"id":361213202,"uuid":"1253258195","full_name":"meblabs/security-workflow","owner":"meblabs","description":"Reusable GitHub Actions workflow for the MEBlabs open-source security gate.","archived":false,"fork":false,"pushed_at":"2026-06-11T18:54:57.000Z","size":89,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T20:20:03.694Z","etag":null,"topics":["github-actions","security"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meblabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T09:37:39.000Z","updated_at":"2026-06-11T18:54:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/meblabs/security-workflow","commit_stats":null,"previous_names":["meblabs/security-workflow"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/meblabs/security-workflow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meblabs%2Fsecurity-workflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meblabs%2Fsecurity-workflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meblabs%2Fsecurity-workflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meblabs%2Fsecurity-workflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meblabs","download_url":"https://codeload.github.com/meblabs/security-workflow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meblabs%2Fsecurity-workflow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34324002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-actions","security"],"created_at":"2026-06-14T14:02:43.580Z","updated_at":"2026-06-14T14:02:44.459Z","avatar_url":"https://github.com/meblabs.png","language":"Shell","funding_links":["https://github.com/sponsors/meblabs"],"categories":[],"sub_categories":[],"readme":"# MEBlabs Security Workflow\n\n[![quality](https://github.com/meblabs/security-workflow/actions/workflows/quality.yml/badge.svg)](https://github.com/meblabs/security-workflow/actions/workflows/quality.yml)\n![type](https://img.shields.io/badge/github-Reusable%20Workflow-purple?logo=github)\n[![](https://img.shields.io/static/v1?label=MEBlabs\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86)](https://github.com/sponsors/meblabs)\n\nReusable GitHub Actions workflow for the MEBlabs open-source security gate.\n\nThis repository is designed to be used after [meblabs/npm-pull-request-action](https://github.com/meblabs/npm-pull-request-action), but it is independent from that composite action. The npm quality action remains responsible for checkout, Node setup, `npm ci`, Prettier, lockfile audit remediation, ESLint, Jest, and downstream coordination outputs. This workflow only runs security checks against the exact ref passed by the caller.\n\n## Coverage\n\nThe workflow currently covers:\n\n- Semgrep CE SAST.\n- Gitleaks OSS secret scanning.\n- Trivy filesystem SCA for OS and library vulnerabilities.\n- Trivy config scanning for IaC, Dockerfile, and workflow misconfiguration.\n- `cfn-lint` for AWS SAM and CloudFormation templates.\n- `zizmor` for GitHub Actions workflow and action security.\n- Optional Docker image build and Trivy image vulnerability scan.\n- Filesystem and Docker image CycloneDX SBOM generation.\n- Dependency license report.\n- One consolidated pull request security summary with failure details.\n- `security-reports` artifact upload.\n- Final security gate after all reports are collected.\n\n## Security Checks\n\nThe workflow checks out the caller repository at the exact `ref` provided by the caller before running any scanner. It does not run `npm ci`, does not modify caller files, and does not commit changes. Scanner failures are collected first; the job fails only at the final security gate.\n\n### Semgrep CE SAST\n\nSemgrep runs on every invocation and performs static application security testing on source files. It uses the Docker image configured by `semgrep-version` and the rulesets configured by `security-config`.\n\nBy default `security-config` is `auto`, so Semgrep chooses relevant community rules based on the repository contents. Callers can pass a space-separated ruleset list such as `p/javascript p/typescript p/owasp-top-ten`.\n\nThe `security-severity-threshold` input controls which Semgrep severities are considered blocking:\n\n- `low` or `info` includes INFO, WARNING, and ERROR.\n- `medium` or `warning` includes WARNING and ERROR.\n- `high`, `error`, or `critical` includes ERROR only.\n\nThe workflow writes `security-reports/semgrep.sarif`. If Semgrep fails on a pull request, the workflow posts SARIF findings using the bot `token`. Semgrep is a blocking check.\n\n### Gitleaks Secret Scanning\n\nGitleaks runs on every invocation and scans for committed secrets such as API keys, tokens, private keys, credentials, and high-confidence secret patterns.\n\nThe workflow intentionally scans only files tracked by git. It creates a temporary archive from `git ls-files` and scans that isolated directory. This avoids false positives from generated files, local caches, scanner output, dependency folders, and other untracked working-directory content.\n\nThe workflow writes `security-reports/gitleaks.sarif` with redacted findings. If Gitleaks fails on a pull request, the workflow posts SARIF findings using the bot `token`. Gitleaks is a blocking check.\n\n### Trivy Filesystem SCA\n\nTrivy filesystem SCA runs on every invocation and scans dependency and OS package metadata present in the repository. It checks manifests and lockfiles without installing dependencies, so it avoids duplicating the npm quality gate.\n\nThe scan uses:\n\n- `scanners: vuln`\n- `vuln-type: os,library`\n- `ignore-unfixed: true`\n- severities from `security-vulnerability-severities`, defaulting to `HIGH,CRITICAL`\n- skipped directories from `security-skip-dirs`\n\nThe workflow writes `security-reports/trivy-fs.sarif`. If Trivy finds blocking vulnerabilities on a pull request, the workflow posts SARIF findings using the bot `token`. Trivy filesystem SCA is a blocking check.\n\n### Trivy Config And IaC Misconfiguration\n\nTrivy config scan runs on every invocation and checks infrastructure and configuration files for misconfigurations. This includes supported IaC formats, Dockerfiles, Kubernetes manifests, Terraform files, CloudFormation/SAM files, and GitHub Actions workflow files when Trivy recognizes them.\n\nThe scan uses severities from `security-vulnerability-severities`, skips directories from `security-skip-dirs`, and writes `security-reports/trivy-config.sarif`.\n\nThis check is broad and always runs. Dedicated `cfn-lint` and `zizmor` checks still run separately when their specific target files exist. Trivy config scan is a blocking check.\n\n### cfn-lint SAM And CloudFormation Validation\n\n`cfn-lint` runs only when the repository contains `template.yaml` or `template.yml` outside skipped dependency and git directories.\n\nIt validates AWS SAM and CloudFormation templates for structural errors, invalid resource properties, unsupported values, and template issues that CloudFormation would reject or warn about. The workflow installs `cfn-lint[sarif]` in a temporary Python virtual environment and runs it with `--non-zero-exit-code error`.\n\nThe workflow writes textual output to `security-reports/cfn-lint.txt` and includes the first 200 lines in the GitHub Step Summary. `cfn-lint` is a blocking check only when templates are detected; otherwise it is reported as `NA`.\n\n### zizmor GitHub Actions Security\n\n`zizmor` runs only when the repository contains GitHub Actions workflow or action files:\n\n- `.github/workflows/*.yml`\n- `.github/workflows/*.yaml`\n- `action.yml`\n- `action.yaml`\n\nIt scans workflow and action definitions for security issues such as unsafe permissions, risky trigger patterns, script injection surfaces, untrusted checkout/use patterns, and other GitHub Actions hardening findings.\n\nWhen `github-token` is available, the workflow passes it as `GH_TOKEN` so `zizmor` can perform API-backed checks. Otherwise it can run in offline mode, but in this workflow `github-token` is required by the reusable workflow contract.\n\nBy default, the workflow runs `zizmor` with a generated config that relaxes `unpinned-uses` for common trusted action namespaces:\n\n```yml\nrules:\n  unpinned-uses:\n    config:\n      policies:\n        meblabs/*: ref-pin\n        actions/*: ref-pin\n        aws-actions/*: ref-pin\n```\n\nSet `zizmor-config` in the reusable workflow, or pass `--zizmor-config PATH` locally, to replace this built-in config with a repository-specific `zizmor.yml`.\n\nThe workflow writes `security-reports/zizmor.txt` and includes the first 200 lines in the GitHub Step Summary. Exit code `3` is treated as reportable findings rather than a blocking failure according to the current operational policy. `zizmor` is a blocking check only when workflow/action files are detected; otherwise it is reported as `NA`.\n\n### Docker Image Build\n\nThe Docker image build runs only when the configured `dockerfile-path` exists, defaulting to `Dockerfile`.\n\nThe workflow builds a local image using:\n\n- `dockerfile-path`\n- `docker-build-context`\n- optional newline-separated `docker-build-args`\n- local tag `${{ inputs.docker-image-name }}:${{ github.sha }}`\n\nThe resulting image reference is written to `security-reports/docker-image-ref.txt`. The build is a blocking check when the configured Dockerfile exists. If no configured Dockerfile exists, Docker image build and image scanning are reported as `NA`.\n\n### Trivy Docker Image Vulnerability Scan\n\nTrivy image scan runs only when the configured Dockerfile exists and the Docker image build succeeds.\n\nIt scans the locally built image for OS and library vulnerabilities using the same severity threshold as filesystem SCA. The scan uses `ignore-unfixed: true` and writes `security-reports/trivy-image.sarif`.\n\nIf Trivy finds blocking image vulnerabilities on a pull request, the workflow posts SARIF findings using the bot `token`. Trivy Docker image scan is a blocking check only when image build applies and succeeds.\n\n### Trivy License Report\n\nThe license report runs on every invocation and uses Trivy's license scanner over the repository filesystem.\n\nIt records dependency license information in `security-reports/trivy-license.txt`. This output is informational and does not fail the final security gate.\n\n### Filesystem SBOM\n\nThe filesystem SBOM runs on every invocation and uses Trivy to generate a CycloneDX SBOM for repository dependencies and detected components.\n\nThe workflow writes `security-reports/sbom-fs.cdx.json`. SBOM generation is informational and does not fail the final security gate.\n\n### Docker Image SBOM\n\nThe Docker image SBOM runs only when the configured Dockerfile exists and the Docker image build succeeds.\n\nIt generates a CycloneDX SBOM for the locally built image and writes `security-reports/sbom-image.cdx.json`. Docker image SBOM generation is informational and does not fail the final security gate.\n\n### Pull Request Reporting\n\nWhen the workflow runs on a pull request, it publishes one consolidated summary comment using the bot `token`. The comment is marked with `\u003c!-- meblabs-security-workflow:summary --\u003e`.\n\nThe consolidated comment includes the check table and expandable details for scanner failures. SARIF-producing scanners are summarized from their SARIF files, including rule, level, source location, message, and help link where available. `cfn-lint` and `zizmor` text output is also included in expandable sections.\n\nThe consolidated comment is idempotent: the workflow updates the previous marked comment instead of creating a new one on every run. Its table has only `Check` and `Outcome` columns. Outcomes are rendered as green `PASS`, red `FAIL`, or grey `NA` badges. `NA` means that the check was not applicable to the scanned repository, for example Docker image scanning when the configured Dockerfile does not exist.\n\nGitHub issue comments have a maximum body size. The workflow includes failure details directly in the PR comment under normal report sizes and truncates oversized sections with a note if needed. The comment links the uploaded `security-reports` artifact so the full files remain one click away.\n\n### Artifact And Step Summary\n\nThe workflow always prepares `security-reports/security-summary.md` and writes a security table to the GitHub Step Summary. The Step Summary uses the same `PASS`, `FAIL`, and `NA` outcomes as the PR comment. When `upload-artifact` is enabled, it uploads the full `security-reports` directory as the `security-reports` artifact and links it from the PR comment.\n\nArtifact upload and PR comments are non-blocking. They use `continue-on-error: true` so report publication problems do not hide scanner outcomes.\n\n## Inputs\n\n| Input | Required | Default | Description |\n|---|---:|---|---|\n| `ref` | yes | n/a | Git ref, branch, tag, or SHA to scan. The workflow checks out this ref explicitly. |\n| `node-version` | no | `22.x` | Node.js version used when npm metadata is needed. |\n| `security-config` | no | `auto` | Semgrep config/rulesets. Use `auto` or a space-separated list such as `p/javascript p/typescript p/owasp-top-ten`. |\n| `security-severity-threshold` | no | `high` | Minimum Semgrep severity that fails the gate: `low`, `medium`, or `high` and aliases `info`, `warning`, `error`, `critical`. |\n| `security-vulnerability-severities` | no | `HIGH,CRITICAL` | Comma-separated Trivy severities that fail the gate. |\n| `security-skip-dirs` | no | `node_modules,.git,.security-workflow,security-reports,coverage,dist,build,.next,.nuxt` | Directories skipped by Trivy filesystem and config scans. |\n| `semgrep-version` | no | `latest` | Semgrep Docker image tag. |\n| `trivy-version` | no | `v0.71.0` | Trivy CLI version used by the local Trivy Docker image. |\n| `gitleaks-version` | no | `v8.30.1` | Gitleaks Docker image tag. |\n| `zizmor-version` | no | `v1.25.2` | zizmor Docker image tag. |\n| `zizmor-config` | no | built-in MEBlabs policy | Optional repository-relative zizmor config file replacing the built-in policy. |\n| `dockerfile-path` | no | `Dockerfile` | Dockerfile path used for optional Docker image build and scan. |\n| `docker-build-context` | no | `.` | Docker build context used for optional Docker image build and scan. |\n| `docker-build-args` | no | empty | Optional newline-separated Docker build args in `KEY=VALUE` format. |\n| `docker-image-name` | no | `meblabs-security-scan` | Local Docker image name used for security scanning. |\n| `post-pr-comment` | no | `true` | Post or update a consolidated security summary comment on pull requests. |\n| `upload-artifact` | no | `true` | Upload security reports as a workflow artifact. |\n| `artifact-retention-days` | no | `14` | Retention days for the `security-reports` artifact. |\n\n## Tokens And Secrets\n\nThis workflow uses two reusable workflow secrets with separate responsibilities:\n\n| Purpose | Secret | Required | Recommended value |\n|---|---|---:|---|\n| Consolidated PR summary comments | `token` | yes | `${{ secrets.MEBBOT }}` |\n| Checkout and read/API-backed scanner checks such as authenticated `zizmor` runs | `github-token` | yes | `${{ secrets.GITHUB_TOKEN }}` |\n\nUse the same bot fine-grained PAT or GitHub App token used by `meblabs/npm-pull-request-action` for `token`. Use the default `GITHUB_TOKEN` for `github-token`, because checkout and read-oriented scanner API calls do not need the bot PAT.\n\n## Required Permissions\n\nThe caller should grant permissions compatible with the reusable workflow:\n\n```yml\npermissions:\n  contents: read\n  actions: read\n```\n\nThese are the caller job permissions for `GITHUB_TOKEN`. The `MEBBOT` token must also have matching repository access for the PR comment API calls it performs.\n\nMinimum recommended fine-grained PAT repository permissions for `MEBBOT` in this security workflow:\n\n| Permission | Access | Used for |\n|---|---|---|\n| Metadata | Read | Required by GitHub for repository access. |\n| Pull requests | Read and write | Read pull request metadata when needed by the bot token. |\n| Issues | Read and write | Create or update the consolidated PR summary comment, because PR conversation comments use the Issues API. |\n\nThis workflow does not need the `MEBBOT` PAT to have access to contents, actions, commit statuses, checks, discussions, merge queues, repository advisories, secrets, workflows, administration, or security events. `security-events: write` is only needed if a future version uploads SARIF into GitHub code scanning instead of only storing SARIF as artifacts and summarizing it in the PR comment.\n\n## Local Usage From An Application Repository\n\nThe same scanner and gate logic can run locally before opening a pull request. The recommended setup for an application repository is to commit only a small bootstrap script and cache this repository under a gitignored internal directory.\n\nAdd the local cache directory to the application repository `.gitignore`:\n\n```gitignore\n.security-workflow/\n```\n\nAdd a bootstrap script, for example `security-workflow.sh`:\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nVERSION=\"${SECURITY_WORKFLOW_VERSION:-v1}\"\nCACHE_ROOT=\"${SECURITY_WORKFLOW_CACHE_DIR:-.security-workflow}\"\nINSTALL_DIR=\"${CACHE_ROOT}\"\nVERSION_FILE=\"${INSTALL_DIR}/VERSION\"\nARCHIVE_URL=\"https://github.com/meblabs/security-workflow/archive/refs/tags/${VERSION}.tar.gz\"\n\nif [[ ! -x \"${INSTALL_DIR}/bin/security-workflow\" ]] || [[ ! -f \"${VERSION_FILE}\" ]] || [[ \"$(cat \"${VERSION_FILE}\")\" != \"${VERSION}\" ]]; then\n  rm -rf \"${INSTALL_DIR}\"\n  mkdir -p \"${INSTALL_DIR}\"\n\n  curl -fsSL \"${ARCHIVE_URL}\" \\\n    | tar -xz -C \"${INSTALL_DIR}\" --strip-components=1\n\n  echo \"${VERSION}\" \u003e \"${VERSION_FILE}\"\nfi\n\nexec \"${INSTALL_DIR}/bin/security-workflow\" \\\n  --repo \"$PWD\" \\\n  --ref \"${SECURITY_WORKFLOW_REF:-HEAD}\" \\\n  --reports-dir \"${CACHE_ROOT}/security-reports\" \\\n  \"$@\"\n```\n\n`--repo \"$PWD\"` can point either to a Git repository root or to a subdirectory inside a Git worktree. The scan scope remains the path passed with `--repo`.\n\nAdd an npm script:\n\n```json\n{\n  \"scripts\": {\n    \"security\": \"bash security-workflow.sh\"\n  }\n}\n```\n\nRun the local security gate:\n\n```bash\nnpm run security\n```\n\nConsole results use green `PASS`, red `FAIL`, and yellow `SKIP` labels by default. Set `NO_COLOR=1` or `SECURITY_WORKFLOW_COLOR=never` to disable colors.\n\nPass CLI options after `--`:\n\n```bash\nnpm run security -- --security-severity-threshold medium\nnpm run security -- --zizmor-config zizmor.yml\n```\n\nRun only selected local checks while iterating on a specific class of findings:\n\n```bash\nnpm run security -- --only semgrep,gitleaks\nnpm run security -- --only trivy-fs,trivy-config\nnpm run security -- --only docker\nnpm run security -- --skip docker,sbom,license\n```\n\n`--only` and `--skip` accept comma-separated check names or groups:\n\n| Selector | Runs or skips |\n|---|---|\n| `semgrep` | Semgrep SAST |\n| `gitleaks` | Gitleaks secrets |\n| `trivy-fs` | Trivy filesystem vulnerability scan |\n| `trivy-config` | Trivy IaC/config misconfiguration scan |\n| `cfn-lint` | AWS SAM/CloudFormation validation |\n| `zizmor` | GitHub Actions security scan |\n| `docker-build` | Docker image build |\n| `trivy-image` | Trivy Docker image vulnerability scan |\n| `license` | Trivy license report |\n| `sbom` | Filesystem and Docker image SBOM |\n| `docker` | Docker build, image scan, and image SBOM |\n| `trivy` | All Trivy-backed checks and reports |\n| `all` | Every local check |\n\nWhen a check is excluded by `--only` or `--skip`, it is reported as `NA` and does not fail the local gate. GitHub Actions does not pass these options, so pull requests still run the full security gate.\n\nUse the same tag locally and in GitHub Actions. For example, if the pull request workflow uses:\n\n```yml\nuses: meblabs/security-workflow/.github/workflows/security.yml@v1\n```\n\nthen local runs should use:\n\n```bash\nSECURITY_WORKFLOW_VERSION=v1 npm run security\n```\n\nThe local CLI writes reports inside the gitignored cache directory:\n\n```text\n.security-workflow/security-reports/\n```\n\nThis does not affect the GitHub Action. The reusable workflow does not pass `--reports-dir`, so it keeps using the default `security-reports/` path required by artifact upload and PR comments.\n\nLocal requirements are `git`, `docker`, `curl`, and `tar`. `node` generates the SARIF findings overview, and `jq` normalizes SARIF metadata when available. `python3` is required only when `cfn-lint` applies because the repository contains SAM or CloudFormation templates.\n\nIn GitHub Actions, the reusable workflow checks out its own CLI scripts from the same repository and ref used by the caller's `uses: meblabs/security-workflow/.github/workflows/security.yml@...` line. No extra input is needed to keep the workflow YAML and local CLI scripts aligned.\n\n## Usage Standalone\n\n```yml\nname: Security\n\non:\n  pull_request:\n    branches: [release, staging, dev]\n\njobs:\n  security:\n    name: Security Gate\n    uses: meblabs/security-workflow/.github/workflows/security.yml@v1\n    permissions:\n      contents: read\n      actions: read\n    with:\n      ref: ${{ needs.quality.outputs.current-head-sha }}\n      repository: ${{ github.repository }}\n      pr-number: ${{ github.event.pull_request.number }}\n      head-ref: ${{ github.head_ref }}\n    secrets:\n      token: ${{ secrets.MEBBOT }}\n      github-token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n## Usage With `meblabs/npm-pull-request-action`\n\nUse the quality action first. Invoke this security workflow only when the quality action did not modify formatting or audit lockfiles, and pass the `current-head-sha` output as `ref`.\n\n```yml\nname: PullRequest\n\non:\n  pull_request:\n    branches: [release, staging, dev]\n\njobs:\n  quality:\n    name: Quality Gate\n    runs-on: ubuntu-latest\n    timeout-minutes: 20\n    permissions:\n      checks: write\n      pull-requests: write\n      contents: write\n      issues: write\n    outputs:\n      prettier-changed: ${{ steps.quality.outputs.prettier-changed }}\n      audit-changed: ${{ steps.quality.outputs.audit-changed }}\n      current-head-sha: ${{ steps.quality.outputs.current-head-sha }}\n    steps:\n      - id: quality\n        name: NPM pull request quality gate\n        uses: meblabs/npm-pull-request-action@v4\n        with:\n          token: ${{ secrets.MEBBOT }}\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          node-version: 22.x\n          prettier: true\n          eslint: true\n          audit: true\n          audit-level: high\n          test: true\n\n  security:\n    name: Security Gate\n    needs: quality\n    if: |\n      needs.quality.outputs.prettier-changed != 'true' \u0026\u0026\n      needs.quality.outputs.audit-changed != 'true'\n    uses: meblabs/security-workflow/.github/workflows/security.yml@v1\n    permissions:\n      contents: read\n      actions: read\n    with:\n      ref: ${{ needs.quality.outputs.current-head-sha }}\n      repository: ${{ github.repository }}\n      pr-number: ${{ github.event.pull_request.number }}\n      head-ref: ${{ github.head_ref }}\n    secrets:\n      token: ${{ secrets.MEBBOT }}\n      github-token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n## Reports And Artifacts\n\nThe workflow creates `security-reports/security-summary.md` on every run. When enabled, it uploads the whole `security-reports` directory as the `security-reports` artifact.\n\nTypical files include:\n\n- `security-summary.md`\n- `semgrep.sarif`\n- `gitleaks.sarif`\n- `trivy-fs.sarif`\n- `trivy-config.sarif`\n- `trivy-image.sarif`\n- `trivy-license.txt`\n- `sbom-fs.cdx.json`\n- `sbom-image.cdx.json`\n- `cfn-lint.txt`\n- `zizmor.txt`\n- `zizmor.yml`\n- `docker-image-ref.txt`\n\nThe GitHub Step Summary receives the same security table as the artifact summary. On pull requests, the workflow updates a single consolidated PR comment marked with:\n\n```text\n\u003c!-- meblabs-security-workflow:summary --\u003e\n```\n\nScanner details are included in that single consolidated comment. SARIF files are parsed into `security-reports/sarif-findings-summary.md`, and text reports such as `cfn-lint.txt` and `zizmor.txt` are attached as expandable sections.\n\n## Failure Policy\n\nBlocking checks run with `continue-on-error: true` so every scanner can finish and publish reports. The job fails only in the final `Fail security gate if blocking checks failed` step when an applicable blocking check failed, was cancelled, was skipped unexpectedly, or produced an unknown outcome.\n\nBlocking checks:\n\n- Semgrep SAST.\n- Gitleaks secrets.\n- Trivy filesystem SCA.\n- Trivy IaC/config scan.\n- `cfn-lint`, only when `template.yaml` or `template.yml` files exist.\n- `zizmor`, only when GitHub workflow or action files exist.\n- Docker image build, only when the configured Dockerfile exists.\n- Trivy Docker image scan, only when the configured Dockerfile exists and the image build succeeds.\n\nNon-blocking outputs:\n\n- Trivy license report.\n- Filesystem SBOM.\n- Docker image SBOM.\n- PR comments and artifact upload.\n\nMissing optional targets are reported as `NA`, not as failures.\n\n## Troubleshooting\n\nIf the workflow scans the wrong commit, check the caller's `ref` input. With `meblabs/npm-pull-request-action`, pass `needs.quality.outputs.current-head-sha` and run this workflow only when `prettier-changed` and `audit-changed` are not `true`.\n\nIf PR comments are missing, verify that `token` is passed from `${{ secrets.MEBBOT }}` and that the bot PAT has Pull requests read/write and Issues read/write. Reusable workflows called from non-PR events do not post PR comments.\n\nIf using a fine-grained PAT, the current broad permission set with read access to metadata and secrets plus read/write access to actions, code, commit statuses, discussions, issues, merge queues, pull requests, repository advisories, security events, and workflows is sufficient for this workflow. It is broader than needed. For this workflow alone, reduce `MEBBOT` to Metadata read, Pull requests read/write, and Issues read/write.\n\nIf Docker scanning is skipped, confirm that `dockerfile-path` points to an existing file in the scanned ref. The image scan only runs after a successful local Docker build.\n\nIf `cfn-lint` is skipped, confirm the templates are named `template.yaml` or `template.yml`. Other CloudFormation filenames are still covered by Trivy config scanning, but they do not trigger the dedicated `cfn-lint` step.\n\nIf `zizmor` is skipped, confirm the repository contains `.github/workflows/*.yml`, `.github/workflows/*.yaml`, `action.yml`, or `action.yaml`.\n\nIf a scanner reports findings but later steps still run, that is expected. The workflow collects all reports first and applies the final gate at the end.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeblabs%2Fsecurity-workflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeblabs%2Fsecurity-workflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeblabs%2Fsecurity-workflow/lists"}