From 0834f6797e3df6accade1c3c656d4518bac7b7a8 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 1 Jun 2026 13:01:48 +0200 Subject: [PATCH 1/5] Add zizmor GitHub Actions security scanning Introduce zizmor CI, policy config (hash-pin third-party actions; ref-pin actions/* and elastic/*), and remediations so workflows pass local audit cleanly. Co-Authored-By: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor --- .github/actions/bootstrap/action.yml | 2 +- .github/dependabot.yml | 4 +++ .../build-link-index-updater-lambda.yml | 5 ++++ .github/workflows/ci.yml | 14 +++++++++- .github/workflows/create-major-tag.yml | 2 ++ .github/workflows/docs-preview-local.yml | 7 +++-- .github/workflows/license.yml | 4 ++- .github/workflows/prerelease.yml | 14 +++++++--- .github/workflows/release.yml | 15 ++++++---- .github/workflows/required-labels.yml | 2 ++ .github/workflows/smoke-test.yml | 7 ++++- .github/workflows/updatecli.yml | 2 ++ .github/workflows/zizmor.yml | 28 +++++++++++++++++++ .github/zizmor.yml | 22 +++++++++++++++ actions/update-link-index/action.yml | 3 +- 15 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/zizmor.yml create mode 100644 .github/zizmor.yml diff --git a/.github/actions/bootstrap/action.yml b/.github/actions/bootstrap/action.yml index e4ac144f71..c2ad549dd0 100644 --- a/.github/actions/bootstrap/action.yml +++ b/.github/actions/bootstrap/action.yml @@ -34,7 +34,7 @@ runs: - id: dotnet shell: bash - run: | + run: | # zizmor: ignore[github-env] dotnet tool restore REPO_VERSION=$(dotnet minver -t=v -p=canary.0 -v=e -m=0.1) echo "Version Number: ${REPO_VERSION}" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a66900d8ab..be7624674b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,8 @@ updates: time: '08:00' labels: - chore + cooldown: + default-days: 7 - package-ecosystem: npm directories: - '**/*' @@ -47,3 +49,5 @@ updates: - 'System.IO.Abstractions.*' labels: - chore + cooldown: + default-days: 7 diff --git a/.github/workflows/build-link-index-updater-lambda.yml b/.github/workflows/build-link-index-updater-lambda.yml index 6da541085f..e2008b0a85 100644 --- a/.github/workflows/build-link-index-updater-lambda.yml +++ b/.github/workflows/build-link-index-updater-lambda.yml @@ -12,15 +12,20 @@ on: type: string default: ${{ github.ref }} +permissions: {} + jobs: build: runs-on: ubuntu-latest + permissions: + contents: read env: BINARY_PATH: .artifacts/docs-lambda-index-publisher/release_linux-x64/bootstrap steps: - uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} + persist-credentials: false - name: Amazon Linux 2023 build run: | docker build . -t publish-links-index:latest -f src/infra/docs-lambda-index-publisher/lambda.DockerFile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1ba91c792..abc7e57fd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap @@ -41,6 +43,8 @@ jobs: MSBuildNoWarn: IDE0032 steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap @@ -74,6 +78,8 @@ jobs: working-directory: src/Elastic.Documentation.Site steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - uses: actions/setup-node@v6 with: @@ -122,6 +128,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap @@ -141,6 +149,8 @@ jobs: - windows-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: 'Windows only, set TEMP to the same drive' if: ${{ matrix.os == 'windows-latest' }} # temporary waiting for https://github.com/parcel-bundler/parcel/pull/10095 to fix @@ -192,6 +202,8 @@ jobs: id-token: write steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap @@ -201,7 +213,7 @@ jobs: run: dotnet workload install aspire - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4 with: role-to-assume: arn:aws:iam::197730964718:role/elastic-docs-v3-integration-tests aws-region: us-east-1 diff --git a/.github/workflows/create-major-tag.yml b/.github/workflows/create-major-tag.yml index 424e80b00a..7400aff56e 100644 --- a/.github/workflows/create-major-tag.yml +++ b/.github/workflows/create-major-tag.yml @@ -16,6 +16,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Get major version run: | MAJOR_VERSION=$(echo "${GITHUB_REF#refs/tags/}" | awk -F. '{print $1}') diff --git a/.github/workflows/docs-preview-local.yml b/.github/workflows/docs-preview-local.yml index 764adb6b51..4294c99a08 100644 --- a/.github/workflows/docs-preview-local.yml +++ b/.github/workflows/docs-preview-local.yml @@ -50,7 +50,7 @@ jobs: - name: Match for PR events debug if: github.event_name == 'pull_request' run: | - echo "ref=${{ github.base_ref }}" + echo "ref=${GITHUB_BASE_REF}" echo "repo=${{ github.repository }}" - name: Match for push events @@ -63,7 +63,7 @@ jobs: - name: Match for push events debug if: github.event_name == 'push' run: | - echo "ref=${{ github.ref_name }}" + echo "ref=${GITHUB_REF_NAME}" echo "repo=${{ github.repository }}" - name: Debug outputs @@ -96,6 +96,7 @@ jobs: uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha || github.ref }} + persist-credentials: false - name: Get changed files if: contains(fromJSON('["push", "pull_request"]'), github.event_name) @@ -110,7 +111,7 @@ jobs: - name: Get modified file detail if: github.event_name == 'pull_request' id: check-modified-file-detail - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + uses: actions/github-script@v8 env: IGNORE_PATTERNS: | .github/** diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml index 8b3391d500..0ae71ac315 100644 --- a/.github/workflows/license.yml +++ b/.github/workflows/license.yml @@ -12,7 +12,9 @@ jobs: steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check license headers run: | - ./.github/check-license-headers.sh \ No newline at end of file + ./.github/check-license-headers.sh diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 39fe134ec2..56244eeb4f 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -5,14 +5,13 @@ on: branches: - main -permissions: - contents: read - packages: write +permissions: {} jobs: deploy: runs-on: ubuntu-latest permissions: + contents: read pages: write id-token: write outputs: @@ -29,6 +28,8 @@ jobs: - id: repo-basename run: 'echo "value=`basename ${{ github.repository }}`" >> $GITHUB_OUTPUT' - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Setup Pages id: pages uses: actions/configure-pages@v6.0.0 @@ -47,19 +48,24 @@ jobs: build: runs-on: ubuntu-latest + permissions: + contents: read + packages: write outputs: full-version: ${{ steps.bootstrap.outputs.full-version }} major-version: ${{ steps.bootstrap.outputs.major-version }} steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap uses: ./.github/actions/bootstrap - name: Login to GitHub Container Registry - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcf964e14a..e30be45732 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,10 +3,8 @@ name: Release on: workflow_dispatch: -permissions: - contents: read - packages: write - +permissions: {} + concurrency: group: release-drafter @@ -22,7 +20,7 @@ jobs: steps: - name: Verify branch run: | - if [[ "${{ github.ref }}" != refs/heads/main ]]; then + if [[ "${GITHUB_REF}" != refs/heads/main ]]; then echo "This workflow is only allowed to run on the main branch." exit 1 fi @@ -47,6 +45,9 @@ jobs: needs: - release-drafter runs-on: ubuntu-latest + permissions: + contents: read + packages: write outputs: full-version: ${{ steps.bootstrap.outputs.full-version }} major-version: ${{ steps.bootstrap.outputs.major-version }} @@ -55,12 +56,13 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ needs.release-drafter.outputs.tag_name }} + persist-credentials: false - name: Bootstrap Action Workspace id: bootstrap uses: ./.github/actions/bootstrap - name: Login to GitHub Container Registry - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -185,6 +187,7 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ needs.release-drafter.outputs.tag_name }} + persist-credentials: false - name: 'Windows only, set TEMP to the same drive' if: ${{ matrix.os == 'windows-latest' }} # temporary waiting for https://github.com/parcel-bundler/parcel/pull/10095 to fix diff --git a/.github/workflows/required-labels.yml b/.github/workflows/required-labels.yml index 4e8453dba3..13c0bb56c3 100644 --- a/.github/workflows/required-labels.yml +++ b/.github/workflows/required-labels.yml @@ -19,6 +19,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Wait for PR to be ready (if just opened) if: github.event_name == 'pull_request_target' && github.event.action == 'opened' run: sleep 30 diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index 9c2ccb4247..b5c6523a04 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -27,6 +27,8 @@ jobs: steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Bootstrap Action Workspace uses: ./.github/actions/bootstrap @@ -34,6 +36,7 @@ jobs: with: repository: ${{ matrix.repository }} path: test-repo + persist-credentials: false - name: Build documentation id: docs-build @@ -41,7 +44,9 @@ jobs: dotnet run --project src/tooling/docs-builder -- --strict --path-prefix "/docs" -p test-repo - name: Verify landing-page-path output - run: test ${{ steps.docs-build.outputs.landing-page-path }} == ${{ matrix.landing-page-path-output }} + run: test ${STEPS_DOCS_BUILD_OUTPUTS_LANDING_PAGE_PATH} == ${{ matrix.landing-page-path-output }} + env: + STEPS_DOCS_BUILD_OUTPUTS_LANDING_PAGE_PATH: ${{ steps.docs-build.outputs.landing-page-path }} - name: Verify link validation run: | diff --git a/.github/workflows/updatecli.yml b/.github/workflows/updatecli.yml index d39e5abd64..e4b286bcb0 100644 --- a/.github/workflows/updatecli.yml +++ b/.github/workflows/updatecli.yml @@ -17,6 +17,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Get token id: get_token diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000000..6d35621861 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,28 @@ +name: GitHub Actions Security Analysis with zizmor + +on: + push: + branches: + - main + pull_request: + +permissions: {} + +jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + advanced-security: false + annotations: true + config: .github/zizmor.yml diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000000..257eb498b9 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,22 @@ +rules: + unpinned-uses: + config: + policies: + # Official GitHub and Elastic actions may use tag/branch refs. + actions/*: ref-pin + elastic/*: ref-pin + # All other actions must be pinned to a commit SHA (implicit "*": hash-pin). + + # Intentional pull_request_target for fork PRs / label automation / preview cleanup. + dangerous-triggers: + ignore: + - assembler-preview-cleanup.yml + - docs-preview-cleanup-local.yml + - required-labels.yml + + # Low-confidence expansions in trusted workflow contexts (github.event, step outputs). + template-injection: + ignore: + - assembler-preview.yml + - docs-preview-local.yml + - release.yml diff --git a/actions/update-link-index/action.yml b/actions/update-link-index/action.yml index c1ebafe085..8761173d53 100644 --- a/actions/update-link-index/action.yml +++ b/actions/update-link-index/action.yml @@ -50,5 +50,6 @@ runs: shell: bash env: LINK_REFERENCE_FILE: ${{ inputs.link_reference_file }} + INPUTS_AWS_S3_BUCKET_NAME: ${{ inputs.aws_s3_bucket_name }} run: | - aws s3 cp --checksum-algorithm "SHA256" "${LINK_REFERENCE_FILE}" "s3://${{ inputs.aws_s3_bucket_name }}/${GITHUB_REPOSITORY}/${GITHUB_REF_NAME}/links.json" + aws s3 cp --checksum-algorithm "SHA256" "${LINK_REFERENCE_FILE}" "s3://${INPUTS_AWS_S3_BUCKET_NAME}/${GITHUB_REPOSITORY}/${GITHUB_REF_NAME}/links.json" From 335b66ae2904d33641630d534943595806b3e10f Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 1 Jun 2026 13:05:27 +0200 Subject: [PATCH 2/5] Use inline zizmor ignores for template-injection Replace file-level template-injection suppressions with per-site comments so each ignored expansion is visible in review. Co-Authored-By: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor --- .github/workflows/assembler-preview.yml | 2 +- .github/workflows/docs-preview-local.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/zizmor.yml | 7 ------- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/assembler-preview.yml b/.github/workflows/assembler-preview.yml index c0336ead42..a7b9695b0c 100644 --- a/.github/workflows/assembler-preview.yml +++ b/.github/workflows/assembler-preview.yml @@ -118,7 +118,7 @@ jobs: if: always() && steps.deployment.outputs.result uses: actions/github-script@v9 with: - script: | + script: | # zizmor: ignore[template-injection] deployment_id from prior step output await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/docs-preview-local.yml b/.github/workflows/docs-preview-local.yml index 4294c99a08..0d5197a2b1 100644 --- a/.github/workflows/docs-preview-local.yml +++ b/.github/workflows/docs-preview-local.yml @@ -67,7 +67,7 @@ jobs: echo "repo=${{ github.repository }}" - name: Debug outputs - run: | + run: | # zizmor: ignore[template-injection] debug echoes of trusted step outputs echo "content-source-match: ${{ format('{0}{1}', steps.pr-check.outputs.content-source-match, steps.push-check.outputs.content-source-match) }}" echo "content-source-next: ${{ format('{0}{1}', steps.pr-check.outputs.content-source-next, steps.push-check.outputs.content-source-next) }}" echo "content-source-current: ${{ format('{0}{1}', steps.pr-check.outputs.content-source-current, steps.push-check.outputs.content-source-current) }}" @@ -374,7 +374,7 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} LANDING_PAGE_PATH: ${{ env.PATH_PREFIX }} with: - script: | + script: | # zizmor: ignore[template-injection] deployment_id from prior step output await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e30be45732..d26d9ed1ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: - name: Create tag uses: actions/github-script@v9 with: - script: | + script: | # zizmor: ignore[template-injection] tag_name from release-drafter on main github.rest.git.createRef({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 257eb498b9..78f36f0385 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -13,10 +13,3 @@ rules: - assembler-preview-cleanup.yml - docs-preview-cleanup-local.yml - required-labels.yml - - # Low-confidence expansions in trusted workflow contexts (github.event, step outputs). - template-injection: - ignore: - - assembler-preview.yml - - docs-preview-local.yml - - release.yml From 58ab598c56f0dda1011588afb8d213da4f543cd1 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 1 Jun 2026 13:07:13 +0200 Subject: [PATCH 3/5] Set Dependabot cooldown to 14 days for all ecosystems Align github-actions and nuget with npm (reakaleek review). Co-Authored-By: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index be7624674b..e6d07e35ed 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,7 +10,7 @@ updates: labels: - chore cooldown: - default-days: 7 + default-days: 14 - package-ecosystem: npm directories: - '**/*' @@ -50,4 +50,4 @@ updates: labels: - chore cooldown: - default-days: 7 + default-days: 14 From a7caee8cb1f84d713f5b20c0778387b3d7c17460 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 1 Jun 2026 13:08:16 +0200 Subject: [PATCH 4/5] Fix tj-actions/changed-files pin to match v45.0.6 tag Correct ref-version-mismatch that caused zizmor CI to exit 13. Co-Authored-By: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor --- .github/workflows/comment-on-asciidoc-changes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/comment-on-asciidoc-changes.yml b/.github/workflows/comment-on-asciidoc-changes.yml index d58d944c36..20f1cfb220 100644 --- a/.github/workflows/comment-on-asciidoc-changes.yml +++ b/.github/workflows/comment-on-asciidoc-changes.yml @@ -22,7 +22,7 @@ jobs: # - https://github.com/tj-actions/changed-files?tab=readme-ov-file#using-githubs-api-octocat - name: Get changed files id: check-files - uses: tj-actions/changed-files@d6e91a2266cdb9d62096cebf1e8546899c6aa18f # v45.0.6 + uses: tj-actions/changed-files@a284dc1814e3fd07f2e34267fc8f81227ed29fb8 # v45.0.6 with: files: | **/*.asciidoc From 1d6c755e3df5525b94c2a09c1db929e4a1b9de81 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 1 Jun 2026 13:13:16 +0200 Subject: [PATCH 5/5] Address PR review on smoke-test and create-major-tag workflows Quote landing-page-path test operands and use POSIX '=' so empty matrix values do not break test. Restore checkout credentials for major tag push. Co-Authored-By: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor --- .github/workflows/create-major-tag.yml | 2 +- .github/workflows/smoke-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-major-tag.yml b/.github/workflows/create-major-tag.yml index 7400aff56e..0269fe9b79 100644 --- a/.github/workflows/create-major-tag.yml +++ b/.github/workflows/create-major-tag.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v6 with: - persist-credentials: false + persist-credentials: true - name: Get major version run: | MAJOR_VERSION=$(echo "${GITHUB_REF#refs/tags/}" | awk -F. '{print $1}') diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index b5c6523a04..a2b5b3ae74 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -44,7 +44,7 @@ jobs: dotnet run --project src/tooling/docs-builder -- --strict --path-prefix "/docs" -p test-repo - name: Verify landing-page-path output - run: test ${STEPS_DOCS_BUILD_OUTPUTS_LANDING_PAGE_PATH} == ${{ matrix.landing-page-path-output }} + run: test "${STEPS_DOCS_BUILD_OUTPUTS_LANDING_PAGE_PATH}" = "${{ matrix.landing-page-path-output }}" env: STEPS_DOCS_BUILD_OUTPUTS_LANDING_PAGE_PATH: ${{ steps.docs-build.outputs.landing-page-path }}