From bdbbce9424ff6c7801f0fb2b403b83f17d9bdcc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:59:16 +0000 Subject: [PATCH 1/7] chore(deps): bump aws-actions/configure-aws-credentials in the aws group Bumps the aws group with 1 update: [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials). Updates `aws-actions/configure-aws-credentials` from 4 to 6 - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/v4...v6) --- updated-dependencies: - dependency-name: aws-actions/configure-aws-credentials dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: aws ... Signed-off-by: dependabot[bot] --- .github/workflows/s3-upload.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/s3-upload.yml b/.github/workflows/s3-upload.yml index a9dbf679..7afdf492 100644 --- a/.github/workflows/s3-upload.yml +++ b/.github/workflows/s3-upload.yml @@ -170,7 +170,7 @@ jobs: - name: Configure AWS credentials if: steps.env.outputs.folder != '' - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ${{ inputs.aws_region }} From 557bc9a79cf881810dc8b4be6e70f5001983e207 Mon Sep 17 00:00:00 2001 From: Bedatty <79675696+bedatty@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:32:43 -0300 Subject: [PATCH 2/7] chore(refs): pin all @develop refs to v1.18.0 in workflows and v1.x.x in READMEs (#160) * chore(refs): pin all @develop refs to v1.18.0 in workflows and v1.x.x in README examples * fix(lint): quote GITHUB_OUTPUT in release-notification SC2086 --- .github/workflows/branch-cleanup.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/gptchangelog.yml | 2 +- .github/workflows/labels-sync.yml | 2 +- .github/workflows/pr-security-scan.yml | 12 ++++++------ .github/workflows/release-notification.yml | 6 +++--- .github/workflows/release.yml | 2 +- .github/workflows/typescript-build.yml | 4 ++-- .github/workflows/typescript-release.yml | 2 +- src/lint/composite-schema/README.md | 2 +- src/lint/readme-check/README.md | 2 +- src/lint/shellcheck/README.md | 2 +- src/notify/discord-release/README.md | 2 +- src/notify/pr-lint-reporter/README.md | 2 +- src/notify/slack-notify/README.md | 2 +- src/notify/slack-release/README.md | 2 +- src/security/dockerfile-checks/README.md | 2 +- src/security/pr-security-reporter/README.md | 2 +- src/security/trivy-fs-scan/README.md | 4 ++-- src/security/trivy-image-scan/README.md | 2 +- 20 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/branch-cleanup.yml b/.github/workflows/branch-cleanup.yml index 25b20639..33c07143 100644 --- a/.github/workflows/branch-cleanup.yml +++ b/.github/workflows/branch-cleanup.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@v6 - name: Run branch cleanup - uses: LerianStudio/github-actions-shared-workflows/src/config/branch-cleanup@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/branch-cleanup@v1.18.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} stale-days: ${{ inputs.stale_days }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 053569ee..e4262b90 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,7 +139,7 @@ jobs: - name: Get changed paths (monorepo) if: inputs.filter_paths != '' id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} diff --git a/.github/workflows/gptchangelog.yml b/.github/workflows/gptchangelog.yml index 7acc6177..180b8bf3 100644 --- a/.github/workflows/gptchangelog.yml +++ b/.github/workflows/gptchangelog.yml @@ -146,7 +146,7 @@ jobs: - name: Get changed paths (monorepo) if: (steps.check-tag.outputs.is_stable == 'true' || inputs.stable_releases_only == false) && inputs.filter_paths != '' id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} diff --git a/.github/workflows/labels-sync.yml b/.github/workflows/labels-sync.yml index 0b072e89..81f58623 100644 --- a/.github/workflows/labels-sync.yml +++ b/.github/workflows/labels-sync.yml @@ -44,7 +44,7 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Sync labels - uses: LerianStudio/github-actions-shared-workflows/src/config/labels-sync@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/labels-sync@v1.18.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} config: ${{ inputs.config || '.github/labels.yml' }} diff --git a/.github/workflows/pr-security-scan.yml b/.github/workflows/pr-security-scan.yml index 77910876..ca8a86ce 100644 --- a/.github/workflows/pr-security-scan.yml +++ b/.github/workflows/pr-security-scan.yml @@ -91,7 +91,7 @@ jobs: # ----------------- Detect Changes & Build Matrix ----------------- - name: Get changed paths id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} @@ -141,7 +141,7 @@ jobs: - name: Trivy Filesystem Scan id: fs-scan if: always() - uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@v1.18.0 with: scan-ref: ${{ matrix.working_dir }} app-name: ${{ env.APP_NAME }} @@ -165,7 +165,7 @@ jobs: - name: Trivy Image Scan id: image-scan if: always() && inputs.enable_docker_scan - uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-image-scan@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-image-scan@v1.18.0 with: image-ref: '${{ env.DOCKERHUB_ORG }}/${{ env.APP_NAME }}:pr-scan-${{ github.sha }}' app-name: ${{ env.APP_NAME }} @@ -175,7 +175,7 @@ jobs: - name: Dockerfile Compliance Checks id: dockerfile-checks if: always() && inputs.enable_docker_scan && inputs.enable_health_score - uses: LerianStudio/github-actions-shared-workflows/src/security/dockerfile-checks@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/dockerfile-checks@v1.18.0 with: dockerfile-path: ${{ env.DOCKERFILE_PATH }} @@ -183,7 +183,7 @@ jobs: - name: Post Security Scan Results to PR id: post-results if: always() && github.event_name == 'pull_request' - uses: LerianStudio/github-actions-shared-workflows/src/security/pr-security-reporter@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/pr-security-reporter@v1.18.0 with: github-token: ${{ secrets.MANAGE_TOKEN || secrets.GITHUB_TOKEN }} app-name: ${{ env.APP_NAME }} @@ -215,7 +215,7 @@ jobs: runs-on: ${{ inputs.runner_type }} steps: - name: Slack Notification - uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-notify@develop + uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-notify@v1.18.0 with: webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} status: ${{ needs.security_scan.result }} diff --git a/.github/workflows/release-notification.yml b/.github/workflows/release-notification.yml index dcda48d3..d025a589 100644 --- a/.github/workflows/release-notification.yml +++ b/.github/workflows/release-notification.yml @@ -138,7 +138,7 @@ jobs: exit 1 fi echo "Resolved release tag: $TAG" - echo "tag=$TAG" >> $GITHUB_OUTPUT + echo "tag=$TAG" >> "$GITHUB_OUTPUT" - name: Dry run summary if: ${{ inputs.dry_run }} @@ -162,7 +162,7 @@ jobs: - name: Discord notification if: ${{ env.DISCORD_WEBHOOK_URL != '' }} - uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@develop + uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@v1.18.0 with: webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} release-tag: ${{ steps.release.outputs.tag }} @@ -174,7 +174,7 @@ jobs: - name: Slack notification if: ${{ env.SLACK_WEBHOOK_URL != '' && inputs.slack_channel != '' }} - uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@develop + uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@v1.18.0 with: webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} channel: ${{ inputs.slack_channel }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7179f3de..d25bf101 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,7 +60,7 @@ jobs: - name: Get changed paths (monorepo) if: inputs.filter_paths != '' id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} diff --git a/.github/workflows/typescript-build.yml b/.github/workflows/typescript-build.yml index 297b98e3..0415630c 100644 --- a/.github/workflows/typescript-build.yml +++ b/.github/workflows/typescript-build.yml @@ -158,7 +158,7 @@ jobs: - name: Get changed paths (monorepo) if: inputs.components_json == '' && inputs.filter_paths != '' id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} @@ -255,7 +255,7 @@ jobs: uses: actions/checkout@v6 - name: Build and push Docker image - uses: LerianStudio/github-actions-shared-workflows/src/build/docker-build-ts@develop + uses: LerianStudio/github-actions-shared-workflows/src/build/docker-build-ts@v1.18.0 with: enable-dockerhub: ${{ inputs.enable_dockerhub }} enable-ghcr: ${{ inputs.enable_ghcr }} diff --git a/.github/workflows/typescript-release.yml b/.github/workflows/typescript-release.yml index 025c9901..e3f2877d 100644 --- a/.github/workflows/typescript-release.yml +++ b/.github/workflows/typescript-release.yml @@ -69,7 +69,7 @@ jobs: - name: Get changed paths (monorepo) if: inputs.filter_paths != '' id: changed-paths - uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@develop + uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0 with: filter-paths: ${{ inputs.filter_paths }} shared-paths: ${{ inputs.shared_paths }} diff --git a/src/lint/composite-schema/README.md b/src/lint/composite-schema/README.md index 1095b46b..a51e9baf 100644 --- a/src/lint/composite-schema/README.md +++ b/src/lint/composite-schema/README.md @@ -44,7 +44,7 @@ jobs: uses: actions/checkout@v6 - name: Composite Schema Lint - uses: LerianStudio/github-actions-shared-workflows/src/lint/composite-schema@develop + uses: LerianStudio/github-actions-shared-workflows/src/lint/composite-schema@v1.x.x with: files: "src/lint/my-check/action.yml,src/build/my-build/action.yml" ``` diff --git a/src/lint/readme-check/README.md b/src/lint/readme-check/README.md index 466c02d5..ddd57296 100644 --- a/src/lint/readme-check/README.md +++ b/src/lint/readme-check/README.md @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v6 - name: README Check - uses: LerianStudio/github-actions-shared-workflows/src/lint/readme-check@develop + uses: LerianStudio/github-actions-shared-workflows/src/lint/readme-check@v1.x.x with: files: "src/lint/my-check/action.yml,src/build/my-build/action.yml" ``` diff --git a/src/lint/shellcheck/README.md b/src/lint/shellcheck/README.md index 5f669b4a..7da71543 100644 --- a/src/lint/shellcheck/README.md +++ b/src/lint/shellcheck/README.md @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@v6 - name: Shell Check - uses: LerianStudio/github-actions-shared-workflows/src/lint/shellcheck@develop + uses: LerianStudio/github-actions-shared-workflows/src/lint/shellcheck@v1.x.x with: files: ".github/workflows/ci.yml,src/lint/my-check/action.yml" ``` diff --git a/src/notify/discord-release/README.md b/src/notify/discord-release/README.md index 566bec12..4e0551d5 100644 --- a/src/notify/discord-release/README.md +++ b/src/notify/discord-release/README.md @@ -55,7 +55,7 @@ jobs: ### Dry run (preview only) ```yaml -- uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@develop +- uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@v1.x.x with: webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} release-tag: ${{ github.event.release.tag_name }} diff --git a/src/notify/pr-lint-reporter/README.md b/src/notify/pr-lint-reporter/README.md index 25d8fc35..acf061ec 100644 --- a/src/notify/pr-lint-reporter/README.md +++ b/src/notify/pr-lint-reporter/README.md @@ -42,7 +42,7 @@ jobs: uses: actions/checkout@v6 - name: Post Lint Report - uses: LerianStudio/github-actions-shared-workflows/src/notify/pr-lint-reporter@develop + uses: LerianStudio/github-actions-shared-workflows/src/notify/pr-lint-reporter@v1.x.x with: github-token: ${{ secrets.MANAGE_TOKEN || github.token }} yamllint-result: ${{ needs.yamllint.result }} diff --git a/src/notify/slack-notify/README.md b/src/notify/slack-notify/README.md index da4a2dcb..7edd247a 100644 --- a/src/notify/slack-notify/README.md +++ b/src/notify/slack-notify/README.md @@ -35,7 +35,7 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Slack Notification - uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-notify@develop + uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-notify@v1.x.x with: webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} status: ${{ needs.build.result }} diff --git a/src/notify/slack-release/README.md b/src/notify/slack-release/README.md index b50faa1a..368328a8 100644 --- a/src/notify/slack-release/README.md +++ b/src/notify/slack-release/README.md @@ -54,7 +54,7 @@ jobs: ### Dry run (preview only) ```yaml -- uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@develop +- uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@v1.x.x with: webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} channel: "releases" diff --git a/src/security/dockerfile-checks/README.md b/src/security/dockerfile-checks/README.md index 283054e4..636fc873 100644 --- a/src/security/dockerfile-checks/README.md +++ b/src/security/dockerfile-checks/README.md @@ -41,7 +41,7 @@ jobs: - name: Dockerfile Compliance Checks id: dockerfile-checks - uses: LerianStudio/github-actions-shared-workflows/src/security/dockerfile-checks@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/dockerfile-checks@v1.x.x with: dockerfile-path: './Dockerfile' diff --git a/src/security/pr-security-reporter/README.md b/src/security/pr-security-reporter/README.md index 197fe89f..70935c0d 100644 --- a/src/security/pr-security-reporter/README.md +++ b/src/security/pr-security-reporter/README.md @@ -43,7 +43,7 @@ This composite expects the following files in the runner working directory, gene - name: Post Security Scan Results to PR id: post-results if: always() && github.event_name == 'pull_request' - uses: LerianStudio/github-actions-shared-workflows/src/security/pr-security-reporter@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/pr-security-reporter@v1.x.x with: github-token: ${{ secrets.GITHUB_TOKEN }} app-name: ${{ env.APP_NAME }} diff --git a/src/security/trivy-fs-scan/README.md b/src/security/trivy-fs-scan/README.md index 1a223366..8e0568a5 100644 --- a/src/security/trivy-fs-scan/README.md +++ b/src/security/trivy-fs-scan/README.md @@ -46,7 +46,7 @@ jobs: - name: Trivy Filesystem Scan id: fs-scan - uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@v1.x.x with: scan-ref: '.' app-name: 'my-service' @@ -56,7 +56,7 @@ jobs: ```yaml - name: Trivy Filesystem Scan - uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-fs-scan@v1.x.x with: scan-ref: ${{ matrix.working_dir }} app-name: ${{ matrix.name }} diff --git a/src/security/trivy-image-scan/README.md b/src/security/trivy-image-scan/README.md index 0d1b4a3e..3522bb14 100644 --- a/src/security/trivy-image-scan/README.md +++ b/src/security/trivy-image-scan/README.md @@ -56,7 +56,7 @@ jobs: tags: myorg/myapp:scan - name: Trivy Image Scan - uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-image-scan@develop + uses: LerianStudio/github-actions-shared-workflows/src/security/trivy-image-scan@v1.x.x with: image-ref: 'myorg/myapp:scan' app-name: 'my-service' From b6eee46d32f5766313be846436a626a6fc295a7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:45:28 -0300 Subject: [PATCH 3/7] chore(deps): bump securego/gosec in the security-scanners group (#158) Bumps the security-scanners group with 1 update: [securego/gosec](https://github.com/securego/gosec). Updates `securego/gosec` from 2.24.7 to 2.25.0 - [Release notes](https://github.com/securego/gosec/releases) - [Commits](https://github.com/securego/gosec/compare/v2.24.7...v2.25.0) --- updated-dependencies: - dependency-name: securego/gosec dependency-version: 2.25.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: security-scanners ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/go-pr-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go-pr-analysis.yml b/.github/workflows/go-pr-analysis.yml index fa00ced1..f016b67d 100644 --- a/.github/workflows/go-pr-analysis.yml +++ b/.github/workflows/go-pr-analysis.yml @@ -333,7 +333,7 @@ jobs: - name: Run Gosec for SARIF id: gosec-sarif - uses: securego/gosec@v2.24.7 + uses: securego/gosec@v2.25.0 with: args: -no-fail -fmt sarif -out gosec-${{ matrix.app.name }}.sarif ./${{ matrix.app.working_dir }}/... From 1f9c77e818f3ddfd5721e671b4ec188147b6a92e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:45:43 -0300 Subject: [PATCH 4/7] chore(deps): bump fgrosse/go-coverage-report in the go-tooling group (#141) Bumps the go-tooling group with 1 update: [fgrosse/go-coverage-report](https://github.com/fgrosse/go-coverage-report). Updates `fgrosse/go-coverage-report` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/fgrosse/go-coverage-report/releases) - [Changelog](https://github.com/fgrosse/go-coverage-report/blob/main/CHANGELOG.md) - [Commits](https://github.com/fgrosse/go-coverage-report/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: fgrosse/go-coverage-report dependency-version: 1.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-tooling ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/go-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go-ci.yml b/.github/workflows/go-ci.yml index 1ba3ad27..a88368ef 100644 --- a/.github/workflows/go-ci.yml +++ b/.github/workflows/go-ci.yml @@ -126,7 +126,7 @@ jobs: name: coverage-report - name: Go Coverage Comment - uses: fgrosse/go-coverage-report@v1.2.0 + uses: fgrosse/go-coverage-report@v1.3.0 with: coverage-artifact-name: coverage-report coverage-file-name: coverage.txt From f343096b129f1f89828450e6e7f075aaaf4c3332 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:51:03 -0300 Subject: [PATCH 5/7] chore(deps): bump actions/checkout from 4 to 6 in the actions-core group (#163) Bumps the actions-core group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4 to 6 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-core ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/s3-upload.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/s3-upload.yml b/.github/workflows/s3-upload.yml index 7afdf492..d3872bd8 100644 --- a/.github/workflows/s3-upload.yml +++ b/.github/workflows/s3-upload.yml @@ -126,7 +126,7 @@ jobs: upload: runs-on: ${{ inputs.runner_type }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Determine environment id: env From 19abf798776edef3c02aa761f1ca6d3894420dcb Mon Sep 17 00:00:00 2001 From: Bedatty <79675696+bedatty@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:45:40 -0300 Subject: [PATCH 6/7] feat(security): add CodeQL composites and integrate into pr-security-scan (#162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci(codeql): add CodeQL analysis workflow for this repository * ci(codeql): extract CodeQL steps into composites and improve workflow Extract init and analyze steps into reusable composite actions under src/security/. Remove schedule trigger (moving to future schedule-job), remove unnecessary matrix strategy, and add YAML path filters. New composites: - src/security/codeql-init — initializes CodeQL with security-extended suite - src/security/codeql-analyze — performs analysis and uploads SARIF results * refactor(codeql): use changed-workflows composite and remove push trigger Reuse existing changed-workflows composite for file detection instead of inline git diff. CodeQL analysis now only runs when action/workflow YAML files are changed in PRs. Full repo scan will move to a future schedule-job. * docs(codeql-analyze): add actions:read to permissions section Align codeql-analyze README permissions with codeql-init for consistency, since both composites are used together. * docs(codeql): document wrapped upstream actions in READMEs Add references to github/codeql-action/init and github/codeql-action/analyze in composite README descriptions for transparency. * feat(security): add CodeQL to pr-security-scan and consolidate self-codeql into self-pr-validation Add CodeQL as optional feature in pr-security-scan.yml with new inputs (enable_codeql, codeql_languages, codeql_queries). Create codeql-reporter composite that reads SARIF and posts findings as PR comments. Remove standalone self-codeql.yml and move CodeQL analysis into self-pr-validation.yml as a job alongside existing linters. * refactor(security): extract CodeQL config generation into codeql-config composite Create src/security/codeql-config composite that generates a dynamic CodeQL configuration scoped to changed paths. Supports both file lists (extracts parent dirs) and directory lists (uses as-is). Update self-pr-validation.yml and pr-security-scan.yml to use the new composite instead of inline shell scripts. * fix(security): address code injection risks and improve robustness Move ${{ }} interpolations to env: blocks in pr-security-scan.yml and codeql-config composite to prevent shell injection. Fix path-mode detection in pr-security-scan to correctly switch between dirs/files mode based on actual fallback behavior. Remove overly broad permissions from self-pr-validation.yml workflow level. Add SARIF availability detection in codeql-reporter to avoid false negatives. * fix(codeql-reporter): mark SARIF unavailable on parse errors and move outputs to env Set sarifAvailable = false when SARIF parsing fails to prevent false negatives. Move step output interpolations to env: blocks for consistency with the injection prevention pattern. * fix(codeql-reporter): separate parse errors from SARIF unavailability Track parse errors independently so a corrupt SARIF file does not suppress findings from other valid SARIF files. Only show the unavailable warning when no SARIF directory or files exist at all. * revert(pr-security-scan): remove CodeQL changes from reusable workflow Remove CodeQL integration from pr-security-scan.yml — will be added in a separate PR with proper planning for external consumers. * fix(codeql-config): use exact file paths instead of parent directories The dirname extraction was causing CodeQL to scan entire directories (e.g., all of .github/workflows/) instead of only the changed files. Now uses exact file paths in the config, ensuring CodeQL only analyzes the specific files that were modified in the PR. * fix(codeql-reporter): add PR filter to security tab link Pre-filter the Security tab URL with pr:+is:open so the link opens directly to the findings for the current PR. * fix(security): warn on partial parse errors and remove dead path-mode input Add warning in codeql-reporter when findings exist but some SARIF files failed to parse. Remove unused path-mode input and PATH_MODE env var from codeql-config (became dead code after dirname removal). --- .github/workflows/self-pr-validation.yml | 41 ++++ src/security/codeql-analyze/README.md | 43 ++++ src/security/codeql-analyze/action.yml | 20 ++ src/security/codeql-config/README.md | 45 +++++ src/security/codeql-config/action.yml | 62 ++++++ src/security/codeql-init/README.md | 61 ++++++ src/security/codeql-init/action.yml | 25 +++ src/security/codeql-reporter/README.md | 60 ++++++ src/security/codeql-reporter/action.yml | 239 +++++++++++++++++++++++ 9 files changed, 596 insertions(+) create mode 100644 src/security/codeql-analyze/README.md create mode 100644 src/security/codeql-analyze/action.yml create mode 100644 src/security/codeql-config/README.md create mode 100644 src/security/codeql-config/action.yml create mode 100644 src/security/codeql-init/README.md create mode 100644 src/security/codeql-init/action.yml create mode 100644 src/security/codeql-reporter/README.md create mode 100644 src/security/codeql-reporter/action.yml diff --git a/.github/workflows/self-pr-validation.yml b/.github/workflows/self-pr-validation.yml index c98093f3..f7ff2e48 100644 --- a/.github/workflows/self-pr-validation.yml +++ b/.github/workflows/self-pr-validation.yml @@ -176,6 +176,47 @@ jobs: with: files: ${{ needs.changed-files.outputs.composite_files }} + # ----------------- CodeQL Analysis ----------------- + codeql: + name: CodeQL Analysis + runs-on: blacksmith-4vcpu-ubuntu-2404 + needs: changed-files + if: needs.changed-files.outputs.action_files != '' + permissions: + contents: read + security-events: write + pull-requests: write + actions: read + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Generate CodeQL config for changed files + id: codeql-config + uses: ./src/security/codeql-config + with: + changed-paths: ${{ needs.changed-files.outputs.action_files }} + + - name: Initialize CodeQL + if: steps.codeql-config.outputs.skip != 'true' + uses: ./src/security/codeql-init + with: + languages: actions + config-file: ${{ steps.codeql-config.outputs.config-file }} + + - name: Perform CodeQL Analysis + if: steps.codeql-config.outputs.skip != 'true' + uses: ./src/security/codeql-analyze + with: + category: '/language:actions' + + - name: Post CodeQL Results to PR + if: always() && github.event_name == 'pull_request' && steps.codeql-config.outputs.skip != 'true' + uses: ./src/security/codeql-reporter + with: + github-token: ${{ secrets.MANAGE_TOKEN || github.token }} + languages: actions + # ----------------- Lint Report ----------------- lint-report: name: Lint Report diff --git a/src/security/codeql-analyze/README.md b/src/security/codeql-analyze/README.md new file mode 100644 index 00000000..749206b3 --- /dev/null +++ b/src/security/codeql-analyze/README.md @@ -0,0 +1,43 @@ + + + + + +
Lerian

codeql-analyze

+ +Composite action that wraps [`github/codeql-action/analyze`](https://github.com/github/codeql-action) to perform CodeQL analysis and upload SARIF results to the GitHub Security tab. Designed to be paired with [`codeql-init`](../codeql-init/). + +## Inputs + +| Input | Description | Required | Default | +|---|---|:---:|---| +| `category` | Category for SARIF results used for deduplication (e.g., `/language:actions`) | Yes | — | +| `output` | Output directory for SARIF files | No | `../results` | + +## Usage + +### Basic (paired with codeql-init) + +```yaml +steps: + - uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-init@v1.x.x + with: + languages: actions + + - name: Perform CodeQL Analysis + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-analyze@v1.x.x + with: + category: '/language:actions' +``` + +## Permissions required + +```yaml +permissions: + contents: read + security-events: write # required for SARIF upload to GitHub Security tab + actions: read # required for workflows using private repositories +``` diff --git a/src/security/codeql-analyze/action.yml b/src/security/codeql-analyze/action.yml new file mode 100644 index 00000000..ee2e7904 --- /dev/null +++ b/src/security/codeql-analyze/action.yml @@ -0,0 +1,20 @@ +name: CodeQL Analyze +description: Perform CodeQL analysis and upload SARIF results to GitHub Security tab + +inputs: + category: + description: 'Category for SARIF results used for deduplication (e.g., /language:actions)' + required: true + output: + description: 'Output directory for SARIF files' + required: false + default: '../results' + +runs: + using: composite + steps: + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: ${{ inputs.category }} + output: ${{ inputs.output }} diff --git a/src/security/codeql-config/README.md b/src/security/codeql-config/README.md new file mode 100644 index 00000000..78f11440 --- /dev/null +++ b/src/security/codeql-config/README.md @@ -0,0 +1,45 @@ + + + + + +
Lerian

codeql-config

+ +Composite action that generates a dynamic CodeQL configuration file scoped to changed paths. Ensures CodeQL analyzes only modified files in PRs instead of the entire repository. Designed to run before [`codeql-init`](../codeql-init/). + +## Inputs + +| Input | Description | Required | Default | +|---|---|:---:|---| +| `changed-paths` | Comma or newline-separated list of changed file paths | Yes | — | +| `output-file` | Path where the generated config file will be written | No | `.github/codeql-config-pr.yml` | + +## Outputs + +| Output | Description | +|---|---| +| `config-file` | Path to the generated CodeQL config file | +| `skip` | `true` if no paths were resolved and CodeQL should be skipped | + +## Usage + +### With changed-workflows (this repo) + +```yaml +- name: Generate CodeQL config + id: codeql-config + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-config@v1.x.x + with: + changed-paths: ${{ needs.changed-files.outputs.action_files }} + +- name: Initialize CodeQL + if: steps.codeql-config.outputs.skip != 'true' + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-init@v1.x.x + with: + languages: actions + config-file: ${{ steps.codeql-config.outputs.config-file }} +``` + +## Permissions required + +No special permissions needed — this composite only generates a file. diff --git a/src/security/codeql-config/action.yml b/src/security/codeql-config/action.yml new file mode 100644 index 00000000..9d0f0e1e --- /dev/null +++ b/src/security/codeql-config/action.yml @@ -0,0 +1,62 @@ +name: CodeQL Config Generator +description: Generates a dynamic CodeQL configuration file scoped to changed paths for PR-only analysis. + +inputs: + changed-paths: + description: 'Comma or newline-separated list of changed file paths or directories to scope the analysis' + required: true + output-file: + description: 'Path where the generated CodeQL config file will be written' + required: false + default: '.github/codeql-config-pr.yml' +outputs: + config-file: + description: 'Path to the generated CodeQL config file' + value: ${{ steps.generate.outputs.config-file }} + skip: + description: 'true if no paths were resolved and CodeQL should be skipped' + value: ${{ steps.generate.outputs.skip }} + +runs: + using: composite + steps: + - name: Generate CodeQL config + id: generate + shell: bash + env: + CONFIG_FILE: ${{ inputs.output-file }} + RAW_PATHS: ${{ inputs.changed-paths }} + run: | + # Normalize separators (comma or newline) to newline + PATHS=$(printf '%s' "$RAW_PATHS" | tr ',' '\n' | sed '/^[[:space:]]*$/d' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + + if [ -z "$PATHS" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "No paths provided — skipping CodeQL config generation" + exit 0 + fi + + # Remove duplicates and empty lines + PATHS=$(echo "$PATHS" | sort -u | sed '/^[[:space:]]*$/d') + + if [ -z "$PATHS" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "No paths resolved — skipping CodeQL config generation" + exit 0 + fi + + # Generate config + { + echo "paths:" + echo "$PATHS" | while IFS= read -r p; do + echo " - '$p'" + done + } > "$CONFIG_FILE" + + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "config-file=$CONFIG_FILE" >> "$GITHUB_OUTPUT" + + count=$(echo "$PATHS" | wc -l | tr -d ' ') + echo "::group::CodeQL config — $count path(s)" + cat "$CONFIG_FILE" + echo "::endgroup::" diff --git a/src/security/codeql-init/README.md b/src/security/codeql-init/README.md new file mode 100644 index 00000000..94ae1605 --- /dev/null +++ b/src/security/codeql-init/README.md @@ -0,0 +1,61 @@ + + + + + +
Lerian

codeql-init

+ +Composite action that wraps [`github/codeql-action/init`](https://github.com/github/codeql-action) to initialize CodeQL analysis for specified languages. Uses the `security-extended` query suite by default for broader coverage. Designed to be paired with [`codeql-analyze`](../codeql-analyze/). + +## Inputs + +| Input | Description | Required | Default | +|---|---|:---:|---| +| `languages` | Languages to analyze (comma-separated, e.g., `actions`, `javascript-typescript`, `go`) | Yes | — | +| `queries` | Query suite to use (`security-standard`, `security-extended`, `security-and-quality`) | No | `security-extended` | +| `config-file` | Path to CodeQL configuration file | No | — | + +## Usage + +### Basic (GitHub Actions YAML analysis) + +```yaml +jobs: + codeql: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + security-events: write + actions: read + steps: + - uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-init@v1.x.x + with: + languages: actions + + - name: Analyze + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-analyze@v1.x.x + with: + category: '/language:actions' +``` + +### Multiple languages + +```yaml +- name: Initialize CodeQL + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-init@v1.x.x + with: + languages: javascript-typescript + queries: security-and-quality +``` + +## Permissions required + +```yaml +permissions: + contents: read + security-events: write + actions: read # required for workflows using private repositories +``` diff --git a/src/security/codeql-init/action.yml b/src/security/codeql-init/action.yml new file mode 100644 index 00000000..a2442047 --- /dev/null +++ b/src/security/codeql-init/action.yml @@ -0,0 +1,25 @@ +name: CodeQL Init +description: Initialize CodeQL analysis for specified languages with configurable query suite + +inputs: + languages: + description: 'Languages to analyze (comma-separated, e.g., actions, javascript-typescript, go)' + required: true + queries: + description: 'Query suite to use (security-standard, security-extended, security-and-quality)' + required: false + default: 'security-extended' + config-file: + description: 'Path to CodeQL configuration file' + required: false + default: '' + +runs: + using: composite + steps: + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ inputs.languages }} + queries: ${{ inputs.queries }} + config-file: ${{ inputs.config-file || '' }} diff --git a/src/security/codeql-reporter/README.md b/src/security/codeql-reporter/README.md new file mode 100644 index 00000000..c0428750 --- /dev/null +++ b/src/security/codeql-reporter/README.md @@ -0,0 +1,60 @@ + + + + + +
Lerian

codeql-reporter

+ +Composite action that reads CodeQL SARIF output and posts a formatted security report as a PR comment. Uses an idempotent comment strategy (updates existing comment on re-runs). Designed to run after [`codeql-analyze`](../codeql-analyze/). + +## Inputs + +| Input | Description | Required | Default | +|---|---|:---:|---| +| `github-token` | GitHub token with `pull-requests:write` and `issues:write` permissions | Yes | — | +| `sarif-path` | Path to the CodeQL SARIF output directory | No | `../results` | +| `languages` | Comma-separated list of languages analyzed (for display) | Yes | — | +| `fail-on-findings` | Fail the step when security findings are detected (`true`/`false`) | No | `false` | + +## Outputs + +| Output | Description | +|---|---| +| `has-findings` | `true` if any CodeQL findings were detected | +| `findings-count` | Total number of CodeQL findings | + +## Usage + +### After CodeQL analysis (paired with codeql-init and codeql-analyze) + +```yaml +steps: + - uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-init@v1.x.x + with: + languages: go + + - name: Perform CodeQL Analysis + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-analyze@v1.x.x + with: + category: '/language:go' + + - name: Post CodeQL Results to PR + if: always() && github.event_name == 'pull_request' + uses: LerianStudio/github-actions-shared-workflows/src/security/codeql-reporter@v1.x.x + with: + github-token: ${{ github.token }} + languages: go +``` + +## Permissions required + +```yaml +permissions: + contents: read + security-events: write + pull-requests: write + actions: read +``` diff --git a/src/security/codeql-reporter/action.yml b/src/security/codeql-reporter/action.yml new file mode 100644 index 00000000..398041db --- /dev/null +++ b/src/security/codeql-reporter/action.yml @@ -0,0 +1,239 @@ +name: CodeQL Reporter +description: Reads CodeQL SARIF output and posts a formatted security report as a PR comment. + +inputs: + github-token: + description: GitHub token with pull-requests:write and issues:write permissions + required: true + sarif-path: + description: Path to the CodeQL SARIF output directory + required: false + default: '../results' + languages: + description: Comma-separated list of languages analyzed (for display purposes) + required: true + fail-on-findings: + description: 'Fail the step with exit code 1 when security findings are detected (true/false)' + required: false + default: 'false' + +outputs: + has-findings: + description: True if any CodeQL findings were detected + value: ${{ steps.parse-outputs.outputs.has_findings }} + findings-count: + description: Total number of CodeQL findings + value: ${{ steps.parse-outputs.outputs.findings_count }} + +runs: + using: composite + steps: + - name: Post CodeQL report to PR + id: report + uses: actions/github-script@v8 + env: + SARIF_PATH: ${{ inputs.sarif-path }} + LANGUAGES: ${{ inputs.languages }} + with: + github-token: ${{ inputs.github-token }} + result-encoding: string + script: | + const fs = require('fs'); + const path = require('path'); + + const sarifDir = process.env.SARIF_PATH; + const languages = process.env.LANGUAGES; + + let body = ''; + let hasFindings = false; + let findingsCount = 0; + let sarifAvailable = true; + let hadParseErrors = false; + + // ── Helpers ── + const SEVERITY_ICONS = { + error: '\u{1F534}', + warning: '\u{1F7E1}', + note: '\u{1F535}', + none: '\u26AA' + }; + + const SEVERITY_LABELS = { + error: 'High/Critical', + warning: 'Medium', + note: 'Low', + none: 'Info' + }; + + const SEVERITY_ORDER = { error: 0, warning: 1, note: 2, none: 3 }; + + const md = (value) => + String(value ?? '').replace(/\|/g, '\\|').replace(/\r?\n/g, ' ').replace(/`/g, '\\`'); + + const truncate = (str, max) => + str.length > max ? str.substring(0, max - 3) + '...' : str; + + // ── Read SARIF files ── + function readSarifFiles() { + const findings = []; + + if (!fs.existsSync(sarifDir)) { + sarifAvailable = false; + core.warning(`SARIF directory not found: ${sarifDir}`); + return findings; + } + + const files = fs.readdirSync(sarifDir).filter(f => f.endsWith('.sarif')); + + if (files.length === 0) { + sarifAvailable = false; + core.warning('No SARIF files found in output directory'); + return findings; + } + + for (const file of files) { + try { + const sarif = JSON.parse(fs.readFileSync(path.join(sarifDir, file), 'utf8')); + + for (const run of (sarif.runs || [])) { + const rules = new Map(); + for (const rule of (run.tool?.driver?.rules || [])) { + rules.set(rule.id, rule); + } + + for (const result of (run.results || [])) { + const rule = rules.get(result.ruleId) || {}; + const location = result.locations?.[0]?.physicalLocation; + + findings.push({ + rule: result.ruleId || 'unknown', + severity: result.level || 'warning', + message: result.message?.text || rule.shortDescription?.text || 'No description', + file: location?.artifactLocation?.uri || 'unknown', + line: location?.region?.startLine || 0, + description: rule.fullDescription?.text || rule.shortDescription?.text || '', + tags: rule.properties?.tags || [], + }); + } + } + } catch (e) { + hadParseErrors = true; + core.warning(`Failed to parse SARIF file ${file}: ${e.message}`); + } + } + + return findings; + } + + // ── Build Report ── + const findings = readSarifFiles(); + findingsCount = findings.length; + + body += `## \u{1F6E1}\uFE0F CodeQL Analysis Results\n\n`; + body += `**Languages analyzed:** \`${languages}\`\n\n`; + + if (!sarifAvailable) { + body += `\u26A0\uFE0F CodeQL did not produce readable SARIF output. Check the analysis step logs.\n\n`; + } else if (hadParseErrors && findings.length === 0) { + body += `\u26A0\uFE0F Some SARIF files could not be parsed and no findings were recovered. Check the analysis step logs.\n\n`; + } else if (findings.length === 0) { + body += `\u2705 No security issues found.\n\n`; + } else { + hasFindings = true; + + if (hadParseErrors) { + body += `\u26A0\uFE0F Some SARIF files could not be parsed. Findings below may be incomplete.\n\n`; + } + + findings.sort((a, b) => (SEVERITY_ORDER[a.severity] ?? 3) - (SEVERITY_ORDER[b.severity] ?? 3)); + + // Summary counts + const counts = {}; + for (const f of findings) { + const label = SEVERITY_LABELS[f.severity] || 'Info'; + counts[label] = (counts[label] || 0) + 1; + } + + body += `**Found ${findings.length} issue(s):** `; + body += Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(', '); + body += `\n\n`; + + // Findings table + const MAX = 30; + body += `| Severity | Rule | File | Message |\n`; + body += `|----------|------|------|----------|\n`; + + for (const f of findings.slice(0, MAX)) { + const icon = SEVERITY_ICONS[f.severity] || '\u26AA'; + const label = SEVERITY_LABELS[f.severity] || 'Info'; + const fileLink = f.line > 0 ? `\`${md(f.file)}:${f.line}\`` : `\`${md(f.file)}\``; + body += `| ${icon} ${label} | \`${md(f.rule)}\` | ${fileLink} | ${md(truncate(f.message, 80))} |\n`; + } + + if (findings.length > MAX) { + body += `\n_... and ${findings.length - MAX} more findings._\n`; + } + + body += '\n'; + } + + // ── Useful Links ── + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const securityUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/security/code-scanning?query=pr%3A${context.issue.number}+is%3Aopen`; + body += `---\n\n`; + body += `\u{1F50D} [View full scan logs](${runUrl}) | \u{1F6E1}\uFE0F [Security tab](${securityUrl})\n\n`; + + // ── Post Comment ── + const marker = ``; + body = marker + '\n' + body; + + try { + const comments = await github.paginate(github.rest.issues.listComments, { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + per_page: 100, + }); + + const existing = comments.find(c => c.body?.includes(marker)); + const params = { + owner: context.repo.owner, + repo: context.repo.repo, + body, + }; + + if (existing) { + await github.rest.issues.updateComment({ ...params, comment_id: existing.id }); + } else { + await github.rest.issues.createComment({ ...params, issue_number: context.issue.number }); + } + } catch (e) { + core.warning(`Could not post PR CodeQL comment: ${e.message}`); + } + + return JSON.stringify({ has_findings: hasFindings, findings_count: findingsCount }); + + - name: Parse outputs + id: parse-outputs + shell: bash + env: + RESULT: ${{ steps.report.outputs.result }} + run: | + HAS_FINDINGS=$(echo "$RESULT" | jq -r '.has_findings // false') + FINDINGS_COUNT=$(echo "$RESULT" | jq -r '.findings_count // 0') + echo "has_findings=$HAS_FINDINGS" >> "$GITHUB_OUTPUT" + echo "findings_count=$FINDINGS_COUNT" >> "$GITHUB_OUTPUT" + echo "Parsed outputs: has_findings=$HAS_FINDINGS, findings_count=$FINDINGS_COUNT" + + # ----------------- Security Gate ----------------- + - name: Gate - Fail on CodeQL Findings + if: inputs.fail-on-findings == 'true' + shell: bash + env: + HAS_FINDINGS: ${{ steps.parse-outputs.outputs.has_findings }} + FINDINGS_COUNT: ${{ steps.parse-outputs.outputs.findings_count }} + run: | + if [ "$HAS_FINDINGS" = "true" ]; then + echo "::error::CodeQL found $FINDINGS_COUNT security issue(s). Check the PR comment for details." + exit 1 + fi From 41c8f32f85517a4f8251ed8d68618bc1617b421d Mon Sep 17 00:00:00 2001 From: Bedatty <79675696+bedatty@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:36:39 -0300 Subject: [PATCH 7/7] feat(build): add build_context_from_working_dir for independent modules (#165) * feat(build): add build_context_from_working_dir input for independent modules Adds a new boolean input to build.yml and pr-security-scan.yml that uses the component working_dir as Docker build context instead of the repo root. This enables building tools/services with their own go.mod without conflicting with the main project dependencies. * fix(gitops): change enable_docker_login default to false GitOps updates only modify YAML files in the gitops repo and do not pull or push Docker images. Docker login is unnecessary by default and can be explicitly enabled when needed. * fix(gitops): remove trailing spaces and add cd guard for shellcheck Fix pre-existing lint issues: - Remove trailing whitespace from 17 lines - Add || exit 1 to cd commands (SC2164) --- .github/workflows/build.yml | 6 ++- .github/workflows/gitops-update.yml | 54 +++++++++++++------------- .github/workflows/pr-security-scan.yml | 6 ++- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e4262b90..77cde1d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,6 +122,10 @@ on: description: 'Force multi-platform build (amd64+arm64) even for beta/rc tags' type: boolean default: false + build_context_from_working_dir: + description: 'Use the component working_dir as Docker build context instead of build_context. Useful for independent modules (e.g., tools with their own go.mod).' + type: boolean + default: false permissions: contents: read @@ -281,7 +285,7 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v7 with: - context: ${{ inputs.build_context }} + context: ${{ inputs.build_context_from_working_dir == true && matrix.app.working_dir || inputs.build_context }} file: ${{ matrix.app.working_dir }}/${{ inputs.dockerfile_name }} platforms: ${{ needs.prepare.outputs.platforms }} push: true diff --git a/.github/workflows/gitops-update.yml b/.github/workflows/gitops-update.yml index 024a8ee8..7052345d 100644 --- a/.github/workflows/gitops-update.yml +++ b/.github/workflows/gitops-update.yml @@ -52,9 +52,9 @@ on: type: string default: 'v4.44.3' enable_docker_login: - description: 'Enable Docker Hub login to avoid rate limits' + description: 'Enable Docker Hub login to avoid rate limits. Disabled by default since GitOps updates do not require Docker registry access.' type: boolean - default: true + default: false configmap_updates: description: 'JSON object mapping artifact names to configmap keys (e.g., {"pix.tag": ".pix.configmap.VERSION"})' type: string @@ -104,7 +104,7 @@ jobs: # Determine which servers to deploy to DEPLOY_FIRMINO="${{ inputs.deploy_in_firmino }}" DEPLOY_CLOTILDE="${{ inputs.deploy_in_clotilde }}" - + echo "deploy_firmino=$DEPLOY_FIRMINO" >> "$GITHUB_OUTPUT" echo "deploy_clotilde=$DEPLOY_CLOTILDE" >> "$GITHUB_OUTPUT" echo "Deploy to Firmino: $DEPLOY_FIRMINO" @@ -144,7 +144,7 @@ jobs: shell: bash run: | set -e - cd gitops + cd gitops || exit 1 git pull origin main - name: Cleanup old artifacts (self-hosted runner safety) @@ -179,17 +179,17 @@ jobs: shell: bash run: | echo "Checking for downloaded artifacts..." - + # Check if directory exists and has files if [[ ! -d ".gitops-tags" ]]; then echo "::error::No artifacts directory found. Build job may have been skipped or failed to produce artifacts." echo "artifacts_valid=false" >> "$GITHUB_OUTPUT" exit 1 fi - + # Count actual artifact files (not directories) ARTIFACT_COUNT=$(find .gitops-tags -type f -name "*.tag" 2>/dev/null | wc -l || echo "0") - + if [[ "$ARTIFACT_COUNT" -eq 0 ]]; then echo "::error::No artifact files found in .gitops-tags/. Build job may have been skipped or failed." echo "Directory contents:" @@ -197,7 +197,7 @@ jobs: echo "artifacts_valid=false" >> "$GITHUB_OUTPUT" exit 1 fi - + echo "Found $ARTIFACT_COUNT artifact file(s):" ls -la .gitops-tags/ echo "artifacts_valid=true" >> "$GITHUB_OUTPUT" @@ -210,7 +210,7 @@ jobs: # Get app name APP_NAME="${{ steps.setup.outputs.app_name }}" - + # Determine environments to update based on tag type if [[ "${{ env.IS_BETA }}" == "true" ]]; then ENVIRONMENTS="dev" @@ -244,7 +244,7 @@ jobs: SERVERS="clotilde" fi fi - + if [[ -z "$SERVERS" ]]; then echo "No servers selected for deployment. Enable deploy_in_firmino or deploy_in_clotilde." exit 1 @@ -262,7 +262,7 @@ jobs: AVAILABLE_ARTIFACTS="${AVAILABLE_ARTIFACTS}${artifact_name} " fi done - + if [[ -z "$AVAILABLE_ARTIFACTS" ]]; then echo "No artifacts found in .gitops-tags/" echo "sync_matrix=[]" >> "$GITHUB_OUTPUT" @@ -280,10 +280,10 @@ jobs: local file="$1" local yaml_path="$2" local new_tag="$3" - + # Extract the key name from yaml path (e.g., ".image.tag" -> "tag") local key_name="${yaml_path##*.}" - + # Use sed to replace only the tag value, preserving all formatting # This handles patterns like "tag: v1.0.0" or "tag: 'v1.0.0'" or 'tag: "v1.0.0"' if grep -q "^[[:space:]]*${key_name}:" "$file"; then @@ -298,21 +298,21 @@ jobs: for SERVER in $SERVERS; do for ENV in $ENVIRONMENTS; do VALUES_FILE="gitops/environments/${SERVER}/helmfile/applications/${ENV}/${APP_NAME}/values.yaml" - + echo "" echo "Processing: $SERVER/$ENV" echo " Path: $VALUES_FILE" - + # Check if file exists if [[ ! -f "$VALUES_FILE" ]]; then echo " WARNING: Values file not found for ${SERVER}/${ENV}: ${VALUES_FILE}" MISSING_FILES="${MISSING_FILES}${SERVER}/${ENV}:${VALUES_FILE}\n" continue fi - + # Track if any changes were made to this file FILE_CHANGED=false - + # Apply mappings from inputs - only if artifact exists MAPPINGS='${{ inputs.yaml_key_mappings }}' while IFS='|' read -r artifact_key yaml_key; do @@ -334,7 +334,7 @@ jobs: fi fi done < <(echo "$MAPPINGS" | jq -r 'to_entries[] | "\(.key)|\(.value)"') - + # Apply configmap updates if configured - only if artifact exists if [[ -n "${{ inputs.configmap_updates }}" ]]; then CONFIGMAP_MAPPINGS='${{ inputs.configmap_updates }}' @@ -356,7 +356,7 @@ jobs: fi done < <(echo "$CONFIGMAP_MAPPINGS" | jq -r 'to_entries[] | "\(.key)|\(.value)"') fi - + # Only track as updated if changes were actually made if [[ "$FILE_CHANGED" == "true" ]]; then UPDATED_FILES="${UPDATED_FILES}${VALUES_FILE}\n" @@ -378,7 +378,7 @@ jobs: else echo "No files were updated" fi - + if [[ -n "$MISSING_FILES" ]]; then echo "" echo "Missing files (skipped):" @@ -388,7 +388,7 @@ jobs: # Save updated servers/envs for ArgoCD sync - only include files that actually changed if [[ -n "$UPDATED_SERVERS_ENVS" ]]; then echo -e "$UPDATED_SERVERS_ENVS" | grep -v '^$' > /tmp/updated_servers_envs.txt - + # Output sync targets as JSON array for matrix job SYNC_MATRIX=$(echo -e "$UPDATED_SERVERS_ENVS" | grep -v '^$' | while IFS=: read -r s e; do [[ -n "$s" && -n "$e" ]] && echo "{\"server\":\"$s\",\"env\":\"$e\"}" @@ -400,7 +400,7 @@ jobs: echo "sync_matrix=[]" >> "$GITHUB_OUTPUT" echo "has_sync_targets=false" >> "$GITHUB_OUTPUT" fi - + COUNT=0 if [[ -n "$UPDATED_FILES" ]]; then COUNT=$(echo -e "$UPDATED_FILES" | grep -c -v '^$' || true) @@ -410,7 +410,7 @@ jobs: - name: Show git diff shell: bash run: | - cd gitops + cd gitops || exit 1 echo "Changes to be committed:" git diff --stat echo "" @@ -432,17 +432,17 @@ jobs: - name: Commit & push (GitOps) run: | set -e - cd gitops - + cd gitops || exit 1 + # Get env label from apply_tags step ENV_LABEL="${{ steps.apply_tags.outputs.env_label }}" - + # Check if there are changes to commit if git diff --quiet; then echo "No changes to commit" exit 0 fi - + git commit -am "ci(${{ steps.setup.outputs.commit_prefix }}): update image tags ($ENV_LABEL)" || echo "No changes to commit" git push origin main diff --git a/.github/workflows/pr-security-scan.yml b/.github/workflows/pr-security-scan.yml index ca8a86ce..4679843d 100644 --- a/.github/workflows/pr-security-scan.yml +++ b/.github/workflows/pr-security-scan.yml @@ -67,6 +67,10 @@ on: description: 'Enable Docker Hub Health Score compliance checks (non-root user, CVEs, licenses)' type: boolean default: true + build_context_from_working_dir: + description: 'Use the component working_dir as Docker build context instead of repo root. Useful for independent modules (e.g., tools with their own go.mod).' + type: boolean + default: false permissions: id-token: write # Required for OIDC authentication @@ -151,7 +155,7 @@ jobs: if: always() && inputs.enable_docker_scan uses: docker/build-push-action@v7 with: - context: ${{ inputs.monorepo_type == 'type2' && matrix.working_dir == inputs.frontend_folder && inputs.frontend_folder || '.' }} + context: ${{ inputs.build_context_from_working_dir == true && matrix.working_dir || (inputs.monorepo_type == 'type2' && matrix.working_dir == inputs.frontend_folder && inputs.frontend_folder || '.') }} file: ${{ env.DOCKERFILE_PATH }} platforms: linux/amd64 load: true