diff --git a/errors/known-unsolved/setup-node-mirror-input-ignored-when-version-in-manifest.yml b/errors/known-unsolved/setup-node-mirror-input-ignored-when-version-in-manifest.yml new file mode 100644 index 0000000..c16dd28 --- /dev/null +++ b/errors/known-unsolved/setup-node-mirror-input-ignored-when-version-in-manifest.yml @@ -0,0 +1,88 @@ +id: ku-131 +title: 'setup-node mirror input is only a download fallback — node pulled from github.com when version is found in manifest' +category: known-unsolved +severity: limitation +tags: + - setup-node + - mirror + - artifactory + - nexus + - self-hosted + - known-limitation + - node-distribution + - air-gapped +patterns: + - regex: 'Downloading node from.*github\.com|node-versions.*releases.*download' + flags: 'i' + - regex: 'Found in cache.*node|Resolved node version.*from manifest' + flags: 'i' +error_messages: + - '(no error — node is silently downloaded from github.com instead of the configured mirror URL)' + - 'Downloading node from https://github.com/actions/node-versions/releases/download/...' +root_cause: | + The `mirror` and `mirror-token` inputs in `actions/setup-node` are intended to + support authenticated artifact mirrors (e.g., JFrog Artifactory, Sonatype Nexus). + However, the action's resolution logic always consults the GitHub-hosted versions + manifest FIRST. When the requested version is found in the manifest, node is + downloaded directly from `github.com/actions/node-versions` — the mirror URL is + never used. + + The mirror is only consulted in these cases: + 1. The requested version is NOT present in the GitHub versions manifest (e.g., nightly, + RC versions, custom versions). + 2. The primary download from GitHub fails (network error, timeout). + + This means that for all stable Node.js releases (which are all in the manifest), + setup-node bypasses the configured mirror entirely. Organizations using mirrors + for security compliance, bandwidth optimization, or air-gapped environments cannot + force setup-node to use their mirror as the primary download source. + + This is by design per setup-node maintainers (confirmed in issue #1412): "The mirror + input is intended as an alternative source and is used only as a fallback when the + required version is not present in the manifest or cannot be downloaded." +fix: | + There is no supported way to force setup-node to always download from a mirror for + versions present in the GitHub manifest. The following workarounds exist: + + Option A — Block github.com at the network level (forces mirror fallback): + When the primary download fails due to network policy, setup-node falls back to + the mirror automatically. Requires network-level controls outside of GitHub Actions. + + Option B — Pre-install node in a custom runner image: + Bundle the required Node.js version into your self-hosted runner or ARC container + image; setup-node will detect the cached version and skip the download entirely. + + Option C — Use runner cache with a pre-populated tool cache: + Place node binaries in the runner's RUNNER_TOOL_CACHE directory; setup-node skips + download when the exact version is found in the tool cache. + + Track upstream: actions/setup-node#1412 — there is no current ETA for mirror-first support. +fix_code: + - language: yaml + label: 'Current behavior — mirror is configured but node still downloads from github.com' + code: | + - uses: actions/setup-node@v4 + with: + node-version: '22.20.0' + mirror: 'https://artifactory.example.com/nodejs-remote' + mirror-token: ${{ secrets.MIRROR_TOKEN }} + # NOTE: For stable versions in the manifest, this still downloads from + # github.com/actions/node-versions — the mirror is NOT used as primary source. + - language: yaml + label: 'Workaround — pre-populate runner tool cache to skip download entirely' + code: | + # On your self-hosted runner or ARC image, pre-download node binaries to: + # $RUNNER_TOOL_CACHE/node/// + # + # setup-node checks this directory first and skips network download + # if the exact version+arch is found, regardless of mirror configuration. +prevention: + - 'Do not rely on the mirror input for compliance enforcement — it is a fallback only' + - 'For true mirror-first enforcement, block outbound access to github.com at the network level' + - 'Use pre-built runner images with node bundled in RUNNER_TOOL_CACHE for air-gapped environments' + - 'Track actions/setup-node#1412 for upstream progress on mirror-as-primary support' +docs: + - url: 'https://github.com/actions/setup-node/issues/1412' + label: 'setup-node#1412 — Node distributions not pulled from authenticated mirrors' + - url: 'https://github.com/actions/setup-node#usage' + label: 'setup-node usage documentation — mirror input' diff --git a/errors/runner-environment/arc-ubuntu-slim-envsubst-command-not-found-gettext-missing.yml b/errors/runner-environment/arc-ubuntu-slim-envsubst-command-not-found-gettext-missing.yml new file mode 100644 index 0000000..80e59cb --- /dev/null +++ b/errors/runner-environment/arc-ubuntu-slim-envsubst-command-not-found-gettext-missing.yml @@ -0,0 +1,84 @@ +id: re-480 +title: 'envsubst: command not found on ARC and ubuntu-slim runners — gettext package not pre-installed' +category: runner-environment +severity: error +tags: + - arc + - ubuntu-slim + - envsubst + - gettext + - self-hosted + - container-runner + - cosign-installer +patterns: + - regex: 'envsubst: command not found' + flags: 'i' + - regex: 'line \d+: envsubst: not found|envsubst.*No such file or directory' + flags: 'i' +error_messages: + - '/home/runner/_work/_temp/0de125e0-863d-4a86-bd04-b315399dc938.sh: line 3: envsubst: command not found' + - 'envsubst: command not found' + - 'line 3: envsubst: not found' +root_cause: | + The `envsubst` binary (part of the GNU `gettext` package) substitutes environment + variable references in text templates. It is pre-installed on standard GitHub-hosted + runners (ubuntu-22.04, ubuntu-24.04) but is absent from: + + - GitHub Actions Runner Controller (ARC) container images + (`ghcr.io/actions/actions-runner`) — minimal container with no `gettext` + - `ubuntu-slim` GitHub-hosted runner — stripped Ubuntu 24.04 image that omits + many packages present in the standard ubuntu-24.04 runner + + Several popular GitHub Actions invoke `envsubst` internally during their setup + steps, including `sigstore/cosign-installer@v4`. When any such action runs on ARC + or ubuntu-slim, the step immediately fails with "command not found" even though the + workflow configuration looks correct and works on standard runners. + + The `gettext-base` Debian package (which provides `envsubst`) is a ~2 MB install + with no complex dependencies — it is straightforward to add as a pre-step. +fix: | + Install the `gettext-base` apt package as an early workflow step before any action + that requires `envsubst`. For ARC, consider building a custom runner image with + `gettext-base` pre-installed to avoid the per-job overhead. +fix_code: + - language: yaml + label: 'Add gettext-base install step before actions that use envsubst (ARC or ubuntu-slim)' + code: | + jobs: + build: + runs-on: ubuntu-slim # or your ARC runner label + steps: + - name: Install gettext-base (provides envsubst) + run: sudo apt-get install -y --no-install-recommends gettext-base + + - name: Install cosign + uses: sigstore/cosign-installer@v4 + + - name: Checkout + uses: actions/checkout@v4 + - language: yaml + label: 'Alternative — use a custom ARC base image with gettext pre-installed' + code: | + # In your ARC RunnerDeployment spec: + # spec: + # template: + # spec: + # containers: + # - name: runner + # image: your-org/custom-runner:latest # built with gettext-base + # + # Dockerfile: + # FROM ghcr.io/actions/actions-runner:latest + # RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext-base +prevention: + - 'Before using ubuntu-slim or ARC runners, audit the ubuntu-slim-Readme.md to verify all required tools are pre-installed' + - 'Add a workflow-level check step: command -v envsubst || sudo apt-get install -y gettext-base' + - 'Build custom ARC runner images with gettext-base, jq, curl, and other commonly-needed tools' + - 'File issues upstream with actions that call envsubst without checking for its presence' +docs: + - url: 'https://github.com/sigstore/cosign-installer/issues/222' + label: 'cosign-installer#222 — envsubst not found on ARC and ubuntu-slim' + - url: 'https://github.com/actions/runner-images/blob/main/images/ubuntu-slim/ubuntu-slim-Readme.md' + label: 'ubuntu-slim software manifest — check pre-installed packages' + - url: 'https://manpages.debian.org/unstable/gettext-base/envsubst.1.en.html' + label: 'envsubst man page — GNU gettext-base package' diff --git a/errors/runner-environment/ubuntu-slim-git-version-downgraded-243-instead-of-252.yml b/errors/runner-environment/ubuntu-slim-git-version-downgraded-243-instead-of-252.yml new file mode 100644 index 0000000..6f18b3d --- /dev/null +++ b/errors/runner-environment/ubuntu-slim-git-version-downgraded-243-instead-of-252.yml @@ -0,0 +1,80 @@ +id: re-481 +title: 'ubuntu-slim runner ships git 2.43.0 instead of documented 2.52+ due to missing PPA pin' +category: runner-environment +severity: warning +tags: + - ubuntu-slim + - git + - version-mismatch + - apt + - ppa + - container-runner + - regression +patterns: + - regex: 'git version 2\.43\.' + flags: 'i' + - regex: 'fatal: unknown option|error: unknown switch|unrecognized argument' + flags: 'i' +error_messages: + - 'git version 2.43.0' + - 'fatal: unknown option' + - 'error: unknown switch' +root_cause: | + The `ubuntu-slim` runner image is built from a minimal `ubuntu:24.04` Docker base. + Unlike the standard `ubuntu-24.04` GitHub-hosted runner, ubuntu-slim's git install + script does not consistently pin to the `git-core` Launchpad PPA. When the apt + resolver falls back to the Ubuntu 24.04 LTS base repository, it installs git 2.43.0 + — the LTS-pinned version in the Ubuntu focal/noble archive — rather than the 2.52+ + version distributed via the PPA and documented in the ubuntu-slim README. + + The ubuntu-slim README states git 2.52.0 is installed, but the actual installed + version since image 20260504.56.2 is 2.43.0. This regression was introduced between: + - 20260413.54.1 — git 2.53.0 (from PPA, matches README) + - 20260504.56.2 — git 2.43.0 (from Ubuntu base apt, README out of date) + + Workflows that use git features introduced between 2.44 and 2.52 fail with opaque + "unknown option" or "unknown switch" errors on ubuntu-slim, while the same workflow + succeeds on ubuntu-24.04 standard runners. As of June 2026, the issue is unresolved + and the ubuntu-slim image README is inaccurate. +fix: | + Install git explicitly from the git-core PPA as an early workflow step on ubuntu-slim. + This overrides the downgraded system git (2.43.0) with the current PPA version (2.52+). +fix_code: + - language: yaml + label: 'Upgrade git from PPA on ubuntu-slim to get 2.52+' + code: | + jobs: + build: + runs-on: ubuntu-slim + steps: + - name: Upgrade git from PPA (ubuntu-slim ships 2.43.0, not 2.52+) + run: | + sudo add-apt-repository ppa:git-core/ppa -y + sudo apt-get update -q + sudo apt-get install -y --no-install-recommends git + git --version # verify: expect 2.52+ or later + + - uses: actions/checkout@v4 + # ... rest of workflow + - language: yaml + label: 'Diagnostic — detect git version mismatch at start of workflow' + code: | + - name: Check git version + run: | + GIT_VER=$(git --version | awk '{print $3}') + echo "Git version: $GIT_VER" + # ubuntu-slim may report 2.43.0 instead of expected 2.52+ + # If you need git >= 2.44, install from PPA before using git features +prevention: + - 'Always run git --version early in ubuntu-slim workflows to detect the downgraded version' + - 'Do not assume ubuntu-slim has the same git version as ubuntu-24.04 standard runners' + - 'Pin git from git-core/ppa if your workflow uses any feature added in git 2.44 or later' + - 'Monitor actions/runner-images#14014 for the official fix to the ubuntu-slim git version' + - 'Cross-reference the ubuntu-slim README version claims against actual installed versions' +docs: + - url: 'https://github.com/actions/runner-images/issues/14014' + label: 'runner-images#14014 — ubuntu-slim git downgraded to 2.43.0' + - url: 'https://github.com/actions/runner-images/blob/main/images/ubuntu-slim/ubuntu-slim-Readme.md' + label: 'ubuntu-slim software manifest (check actual vs documented versions)' + - url: 'https://launchpad.net/~git-core/+archive/ubuntu/ppa' + label: 'git-core PPA — provides git 2.52+ for Ubuntu' diff --git a/errors/silent-failures/secret-dollar-sign-expands-in-double-quoted-shell-string.yml b/errors/silent-failures/secret-dollar-sign-expands-in-double-quoted-shell-string.yml new file mode 100644 index 0000000..db9f635 --- /dev/null +++ b/errors/silent-failures/secret-dollar-sign-expands-in-double-quoted-shell-string.yml @@ -0,0 +1,90 @@ +id: sf-216 +title: 'Secret containing $ character silently expands in double-quoted shell string, passing wrong value to command' +category: silent-failures +severity: silent-failure +tags: + - secrets + - shell-expansion + - dollar-sign + - double-quotes + - run-step + - shell-injection +patterns: + - regex: 'keystore password was incorrect|keystorepassword was incorrect' + flags: 'i' + - regex: 'password.*incorrect.*IOException|BadPaddingException|UnrecoverableKeyException' + flags: 'i' + - regex: '\$\{\{\s*secrets\.[A-Z_]+\s*\}\}' + flags: 'i' +error_messages: + - 'keytool error: java.io.IOException: keystore password was incorrect' + - 'javax.crypto.BadPaddingException: Given final block not properly padded' + - 'java.security.UnrecoverableKeyException: failed to decrypt safe contents entry' + - 'error: incorrect password' +root_cause: | + When a secret contains a `$` character and is interpolated inline via + `${{ secrets.NAME }}` inside a double-quoted shell string in a `run:` step, + Bash interprets the substring after the `$` as a shell variable name. Because + that shell variable is typically unset, it expands to an empty string, silently + truncating or mutating the secret value. The command then runs with the wrong + credential — no runner error is emitted; the failure only appears as an + authentication or decryption error from the downstream tool. + + Example: secret value `UHh&**&$k8748848923jhHH` used as: + -storepass "${{ secrets.KEYSTORE_PASSWORD }}" + becomes: + -storepass "UHh&**&" + because `$k8748848923jhHH` expands to empty string in the shell. + + The runner substitutes the literal secret value into the YAML first (replacing + `${{ secrets.KEYSTORE_PASSWORD }}`), and then Bash processes the resulting string + as a normal double-quoted argument — so any `$WORD` inside still triggers shell + variable expansion. +fix: | + Pass secrets to run steps via the `env:` block and reference them as regular + shell environment variables. This prevents the runner-substituted value from + being double-processed by the shell. + + Option A — env var pattern (recommended for any secret with special characters): + env: + KEYSTORE_PASS: ${{ secrets.KEYSTORE_PASSWORD }} + run: keytool -storepass "$KEYSTORE_PASS" + + Option B — single-quote wrap (prevents shell variable expansion): + run: keytool -storepass '${{ secrets.KEYSTORE_PASSWORD }}' + # Note: single quotes are literal in shell; ${{ ... }} is resolved by the + # runner before the shell sees the string, so this is safe. + + Option A (env var) is strongly preferred because it also protects against + glob expansion, word splitting, and other shell metacharacter issues in secrets. +fix_code: + - language: yaml + label: 'Wrong — inline double-quoted interpolation allows $-expansion on secret value' + code: | + - name: Sign release + run: | + keytool -list -v \ + -keystore release-key.jks \ + -storepass "${{ secrets.KEYSTORE_PASSWORD }}" + # PROBLEM: if KEYSTORE_PASSWORD contains $, Bash expands it silently + - language: yaml + label: 'Correct — pass secret as env var to prevent double shell expansion' + code: | + - name: Sign release + env: + KEYSTORE_PASS: ${{ secrets.KEYSTORE_PASSWORD }} + run: | + keytool -list -v \ + -keystore release-key.jks \ + -storepass "$KEYSTORE_PASS" + # SAFE: $KEYSTORE_PASS is a plain env var with no nested $ interpretation +prevention: + - 'Never interpolate secrets inline inside double-quoted shell strings — always use env: block' + - 'Audit all run: steps that use ${{ secrets.* }} inside "..." strings and migrate to env var pattern' + - 'Test secrets that contain $, !, ", \, backtick, or space characters with extra care' + - 'Use the GitHub Actions secret scanner / security review to flag direct secret interpolation in run steps' +docs: + - url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-secrets' + label: 'Security hardening for GitHub Actions — using secrets safely' + - url: 'https://github.com/actions/runner/issues/4500' + label: 'actions/runner#4500 — runner modifies secrets containing $ in double-quoted shell commands'