From 67a75560920ae4cb6a6f369d504219a5ebdbc112 Mon Sep 17 00:00:00 2001 From: Sall Date: Mon, 27 Jul 2026 18:00:02 +0100 Subject: [PATCH 1/3] fix(ci): build zredis modules for CodeQL --- .github/tests/codeql-workflow.zsh | 157 ++++++++++++++++++++++++++ .github/workflows/codeql-analysis.yml | 99 ++++++++++++---- 2 files changed, 237 insertions(+), 19 deletions(-) create mode 100644 .github/tests/codeql-workflow.zsh diff --git a/.github/tests/codeql-workflow.zsh b/.github/tests/codeql-workflow.zsh new file mode 100644 index 0000000..23c8673 --- /dev/null +++ b/.github/tests/codeql-workflow.zsh @@ -0,0 +1,157 @@ +#!/usr/bin/env zsh + +# Validate the observable structure of the zredis CodeQL workflow. + +emulate -LR zsh +setopt errexit nounset pipefail + +readonly script_dir="${0:A:h}" +readonly workflow="${1:-${script_dir:h}/workflows/codeql-analysis.yml}" +readonly yq_bin="${YQ_BIN:-yq}" + +fail() { + print -u2 -r -- "FAIL: $1" + exit 1 +} + +assert_yq() { + local description="$1" + local expression="$2" + + if ! "$yq_bin" eval --exit-status "$expression" "$workflow" >/dev/null; then + fail "$description" + fi +} + +[[ -r "$workflow" ]] || fail "workflow is not readable: $workflow" +if [[ "$yq_bin" == */* ]]; then + [[ -x "$yq_bin" ]] || fail "YQ_BIN is not executable: $yq_bin" +else + command -v "$yq_bin" >/dev/null || fail "yq is not available: $yq_bin" +fi + +assert_yq \ + "expected exactly the Actions/none and C/C++/manual matrix entries" \ + '(.jobs.codeql.strategy."fail-fast" == false) and + ((.jobs.codeql.strategy.matrix.include | length) == 2) and + (([.jobs.codeql.strategy.matrix.include[] | + select(.language == "actions" and ."build-mode" == "none")] | + length) == 1) and + (([.jobs.codeql.strategy.matrix.include[] | + select(.language == "c-cpp" and ."build-mode" == "manual")] | + length) == 1)' + +assert_yq \ + "expected plain workflow and job names" \ + '.name == "CodeQL" and + .jobs.codeql.name == "CodeQL (${{ matrix.language }})"' + +assert_yq \ + "expected push, pull request, weekly schedule, and manual triggers" \ + '(.on.push.branches | length) == 1 and + .on.push.branches[0] == "main" and + (.on.pull_request.branches | length) == 1 and + .on.pull_request.branches[0] == "main" and + (.on.schedule | length) == 1 and + .on.schedule[0].cron == "15 21 * * 6" and + .on.workflow_dispatch.inputs."upload-results".type == "boolean" and + .on.workflow_dispatch.inputs."upload-results".default == false' + +assert_yq \ + "expected workflow/ref concurrency with cancellation" \ + '.concurrency.group == "codeql-${{ github.workflow }}-${{ github.ref }}" and + .concurrency."cancel-in-progress" == true' + +assert_yq \ + "expected least-privilege workflow and job permissions" \ + '(.permissions | length) == 1 and + .permissions.contents == "read" and + (.jobs.codeql.permissions | length) == 2 and + .jobs.codeql.permissions.contents == "read" and + .jobs.codeql.permissions."security-events" == "write"' + +assert_yq \ + "expected a 30-minute CodeQL timeout" \ + '.jobs.codeql."timeout-minutes" == 30' + +assert_yq \ + "expected immutable checkout and CodeQL initialization" \ + '(([.jobs.codeql.steps[] | + select(.uses == + "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1")] | + length) == 1) and + (([.jobs.codeql.steps[] | + select(.uses == + "github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81" and + .with.languages == "${{ matrix.language }}" and + .with."build-mode" == "${{ matrix.build-mode }}" and + .with.queries == "security-extended")] | + length) == 1)' + +assert_yq \ + "expected the exact C/C++ dependency installation" \ + '([.jobs.codeql.steps[] | + select(.name == "Install C/C++ dependencies" and + .if == "matrix.build-mode == '\''manual'\''" and + (.run | contains("build-essential")) and + (.run | contains("zsh")) and + (.run | contains("yodl")) and + (.run | contains("libhiredis-dev")) and + (.run | contains("libgdbm-dev")) and + (.run | contains("libncurses-dev")))] | + length) == 1' + +assert_yq \ + "expected the explicit module configure, capability, and output checks" \ + '([.jobs.codeql.steps[] | + select(.name == "Build C/C++ modules" and + .if == "matrix.build-mode == '\''manual'\''" and + ."working-directory" == "module" and + (.run | contains("./configure --enable-gdbm --without-tcsetpgrp")) and + (.run | contains("HAVE_HIREDIS_HIREDIS_H")) and + (.run | contains("HAVE_REDISCONNECT")) and + (.run | contains("HAVE_GDBM_H")) and + (.run | contains("HAVE_GDBM_OPEN")) and + (.run | contains("\nmake\n")) and + (.run | contains("name=zshell/db")) and + (.run | contains("name=zshell/zredis")) and + (.run | contains("name=zshell/zgdbm")) and + (.run | contains("Src/zshell/db.so")) and + (.run | contains("Src/zshell/zredis.so")) and + (.run | contains("Src/zshell/zgdbm.so")))] | + length) == 1' + +assert_yq \ + "expected mutually exclusive upload and non-upload analysis steps" \ + '(([.jobs.codeql.steps[] | + select(.name == "Analyze without upload" and + .uses == + "github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81" and + .if == + "github.event_name == '\''pull_request'\'' || (github.event_name == '\''workflow_dispatch'\'' && inputs.upload-results == false)" and + .with.upload == "never" and + .with.category == "/language:${{ matrix.language }}")] | + length) == 1) and + (([.jobs.codeql.steps[] | + select(.name == "Analyze and upload" and + .uses == + "github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81" and + .if == + "github.event_name == '\''push'\'' || github.event_name == '\''schedule'\'' || (github.event_name == '\''workflow_dispatch'\'' && inputs.upload-results == true)" and + .with.category == "/language:${{ matrix.language }}" and + (.with | has("upload") | not))] | + length) == 1)' + +assert_yq \ + "expected no CodeQL autobuild action" \ + '([.jobs.codeql.steps[].uses // "" | + select(test("github/codeql-action/autobuild@"))] | + length) == 0' + +assert_yq \ + "expected every action reference to use a full immutable SHA" \ + '([.jobs.codeql.steps[].uses // "" | + select(. != "" and (test("@[0-9a-f]{40}$") | not))] | + length) == 0' + +print -r -- "PASS: CodeQL workflow contract" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8b63df7..5e56376 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,35 +1,96 @@ --- -name: ๐Ÿ‘พ CodeQL +name: CodeQL on: push: - branches: [ main ] + branches: + - main pull_request: - branches: [ main ] + branches: + - main schedule: - - cron: '15 21 * * 6' + - cron: "15 21 * * 6" + workflow_dispatch: + inputs: + upload-results: + description: Upload CodeQL results + required: false + type: boolean + default: false + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: codeql: - name: ๐Ÿญ Scanning + name: CodeQL (${{ matrix.language }}) runs-on: ubuntu-latest + timeout-minutes: 30 permissions: - actions: read contents: read security-events: write + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: c-cpp + build-mode: manual steps: - - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@v6 - - name: ๐Ÿ— Initialize CodeQL - uses: github/codeql-action/init@v4 - - name: ๐Ÿ— Dependencies - run: sudo apt-get update && sudo apt-get install zsh -yq - - name: ๐Ÿ— Configure + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Initialize CodeQL + uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + queries: security-extended + + - name: Install C/C++ dependencies + if: matrix.build-mode == 'manual' run: | - CPPFLAGS="$cppf" CFLAGS="$cf${macro:+ $macro}" LDFLAGS="$ldf" ./module/configure --enable-gdbm --without-tcsetpgrp ${=cfgopts} - shell: zsh {0} - - name: ๐Ÿ— Autobuild - uses: github/codeql-action/autobuild@v4 - - name: ๐Ÿš€ Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + sudo apt-get update + sudo apt-get install --yes --no-install-recommends \ + build-essential \ + zsh \ + yodl \ + libhiredis-dev \ + libgdbm-dev \ + libncurses-dev + + - name: Build C/C++ modules + if: matrix.build-mode == 'manual' + working-directory: module + run: | + ./configure --enable-gdbm --without-tcsetpgrp + grep -Eq '^#define HAVE_HIREDIS_HIREDIS_H 1$' config.h + grep -Eq '^#define HAVE_REDISCONNECT 1$' config.h + grep -Eq '^#define HAVE_GDBM_H 1$' config.h + grep -Eq '^#define HAVE_GDBM_OPEN 1$' config.h + make + grep -Eq '^name=zshell/db .*link=dynamic' config.modules + grep -Eq '^name=zshell/zredis .*link=dynamic' config.modules + grep -Eq '^name=zshell/zgdbm .*link=dynamic' config.modules + test -s Src/zshell/db.so + test -s Src/zshell/zredis.so + test -s Src/zshell/zgdbm.so + + - name: Analyze without upload + if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.upload-results == false) + uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + with: + upload: never + category: /language:${{ matrix.language }} + + - name: Analyze and upload + if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.upload-results == true) + uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + with: + category: /language:${{ matrix.language }} From 9069c56c76610822b4188dde2398698e76d63a15 Mon Sep 17 00:00:00 2001 From: Sal <59910950+ss-o@users.noreply.github.com> Date: Tue, 28 Jul 2026 05:05:28 +0100 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sal <59910950+ss-o@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5e56376..5ba5847 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -83,7 +83,7 @@ jobs: test -s Src/zshell/zgdbm.so - name: Analyze without upload - if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.upload-results == false) + if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.upload-results != 'true') uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 with: upload: never From e0880c67d51c2de515f24d8b2bfe283dc1e66ecd Mon Sep 17 00:00:00 2001 From: Sal <59910950+ss-o@users.noreply.github.com> Date: Tue, 28 Jul 2026 05:05:37 +0100 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sal <59910950+ss-o@users.noreply.github.com> --- .github/tests/codeql-workflow.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/tests/codeql-workflow.zsh b/.github/tests/codeql-workflow.zsh index 23c8673..33c5f09 100644 --- a/.github/tests/codeql-workflow.zsh +++ b/.github/tests/codeql-workflow.zsh @@ -128,7 +128,7 @@ assert_yq \ .uses == "github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81" and .if == - "github.event_name == '\''pull_request'\'' || (github.event_name == '\''workflow_dispatch'\'' && inputs.upload-results == false)" and + "github.event_name == '\''pull_request'\'' || (github.event_name == '\''workflow_dispatch'\'' && inputs.upload-results != '\''true'\'')" and .with.upload == "never" and .with.category == "/language:${{ matrix.language }}")] | length) == 1) and