@htekdev/actions-debugger 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,125 @@
1
+ id: runner-environment-024
2
+ title: "Docker Hub Pull Rate Limit — toomanyrequests in GitHub Actions"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - docker
7
+ - docker-hub
8
+ - rate-limit
9
+ - container
10
+ - pull
11
+ - authentication
12
+ patterns:
13
+ - regex: "toomanyrequests: You have reached your pull rate limit"
14
+ flags: "i"
15
+ - regex: "You have reached your unauthenticated pull rate limit"
16
+ flags: "i"
17
+ - regex: "pull rate limit reached"
18
+ flags: "i"
19
+ - regex: "ERROR: toomanyrequests"
20
+ flags: "i"
21
+ - regex: "429 Too Many Requests.*docker"
22
+ flags: "i"
23
+ error_messages:
24
+ - "toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit"
25
+ - "Error response from daemon: toomanyrequests: You have reached your unauthenticated pull rate limit."
26
+ - "pull access denied, repository does not exist or may require 'docker login'"
27
+ root_cause: |
28
+ Docker Hub enforces anonymous pull rate limits on all IP addresses. GitHub-hosted
29
+ runners share a pool of egress IPs — multiple concurrent workflow runs from different
30
+ repositories hit Docker Hub from the same IP address, exhausting the shared quota
31
+ rapidly.
32
+
33
+ **Rate limit tiers (as of 2024):**
34
+ - **Unauthenticated (anonymous):** 100 pulls per 6 hours per IP
35
+ - **Authenticated free account:** 200 pulls per 6 hours per account
36
+ - **Docker Hub Pro/Team/Business:** unlimited
37
+
38
+ Because GitHub-hosted runners use a small set of shared egress IPs, popular runners
39
+ can hit the anonymous 100-pull limit within minutes during peak hours. The error
40
+ surfaces as a hard failure when the runner attempts `docker pull` for job containers,
41
+ service containers, container actions, or explicit `docker pull` commands in steps.
42
+
43
+ Even after adding `docker/login-action`, workflows can still hit the limit if they use
44
+ actions that internally pull images (e.g., `docker/build-push-action`, `docker/bake-action`)
45
+ before the login step has executed.
46
+ fix: |
47
+ Add `docker/login-action` as the **first step** in any job that pulls from Docker Hub.
48
+ The action authenticates with Docker Hub, switching from anonymous to authenticated rate
49
+ limits (200 pulls/6 hours per account) or unlimited for Pro/Team accounts.
50
+
51
+ **Recommended approach:**
52
+ 1. Create a Docker Hub account (free tier) or use an existing one.
53
+ 2. Store credentials as repository secrets: `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN`
54
+ (use an Access Token, not your password — generate at hub.docker.com > Account Settings > Security).
55
+ 3. Add the login step before any image-pulling step.
56
+
57
+ **For self-hosted runners:** Configure a Docker Hub mirror or use GitHub Packages /
58
+ Amazon ECR / Google Artifact Registry to cache images and avoid Docker Hub entirely.
59
+ fix_code:
60
+ - language: yaml
61
+ label: "Authenticate with Docker Hub before pulling images"
62
+ code: |
63
+ jobs:
64
+ build:
65
+ runs-on: ubuntu-latest
66
+ steps:
67
+ # Login FIRST — before any step that pulls from Docker Hub
68
+ - name: Log in to Docker Hub
69
+ uses: docker/login-action@v3
70
+ with:
71
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
72
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
73
+
74
+ - uses: actions/checkout@v4
75
+
76
+ - name: Build and push
77
+ uses: docker/build-push-action@v5
78
+ with:
79
+ push: true
80
+ tags: myorg/myimage:latest
81
+ - language: yaml
82
+ label: "Authenticate for jobs using a container image"
83
+ code: |
84
+ jobs:
85
+ test:
86
+ runs-on: ubuntu-latest
87
+ container:
88
+ image: python:3.12
89
+ credentials:
90
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
91
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+ - run: python -m pytest
95
+ - language: yaml
96
+ label: "Authenticate for service containers pulling from Docker Hub"
97
+ code: |
98
+ jobs:
99
+ test:
100
+ runs-on: ubuntu-latest
101
+ services:
102
+ postgres:
103
+ image: postgres:16
104
+ credentials:
105
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
106
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
107
+ env:
108
+ POSTGRES_PASSWORD: postgres
109
+ steps:
110
+ - uses: actions/checkout@v4
111
+ prevention:
112
+ - "Store a Docker Hub access token (not password) in secrets and use docker/login-action@v3 in all jobs that pull images."
113
+ - "Place the docker/login-action step first in the job — before any action that internally pulls Docker Hub images."
114
+ - "Consider mirroring frequently-used base images to GitHub Container Registry (ghcr.io) or your cloud provider's registry to eliminate Docker Hub dependency."
115
+ - "Use Docker Hub's Automated Builds or a scheduled workflow to keep mirror images up to date."
116
+ - "For service containers and job containers, always provide `credentials:` block alongside `image:` when pulling from Docker Hub."
117
+ docs:
118
+ - url: "https://docs.docker.com/docker-hub/download-rate-limit/"
119
+ label: "Docker Hub: Download rate limit documentation"
120
+ - url: "https://github.com/docker/login-action"
121
+ label: "docker/login-action — GitHub Marketplace"
122
+ - url: "https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-docker-images"
123
+ label: "GitHub Docs: Publishing Docker images"
124
+ - url: "https://github.com/actions/runner-images/issues/1445"
125
+ label: "actions/runner-images #1445 — Did Docker Hub rate limit affect GitHub Action?"
@@ -0,0 +1,130 @@
1
+ id: runner-environment-025
2
+ title: "Service Container Network: localhost Works on Runner, Service Name Required in Container Jobs"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - service-containers
7
+ - networking
8
+ - localhost
9
+ - postgres
10
+ - mysql
11
+ - redis
12
+ - container-jobs
13
+ - docker-networking
14
+ patterns:
15
+ - regex: "Connection refused.*(?:localhost|127\\.0\\.0\\.1).*(?:5432|3306|6379|27017)"
16
+ flags: "i"
17
+ - regex: "could not connect to server.*Connection refused.*localhost"
18
+ flags: "i"
19
+ - regex: "ECONNREFUSED.*(?:5432|3306|6379|27017)"
20
+ flags: "i"
21
+ - regex: "dial tcp 127\\.0\\.0\\.1:\\d+: connect: connection refused"
22
+ flags: "i"
23
+ error_messages:
24
+ - "Error: connect ECONNREFUSED 127.0.0.1:5432"
25
+ - "could not connect to server: Connection refused (Is the server running on host \"localhost\" (127.0.0.1) and accepting TCP/IP connections on port 5432?)"
26
+ - "OperationalError: connection to server at \"localhost\" (127.0.0.1), port 5432 failed: Connection refused"
27
+ - "Error: getaddrinfo ENOTFOUND postgres"
28
+ root_cause: |
29
+ GitHub Actions service containers run as Docker containers on the runner machine.
30
+ The correct hostname to reach them depends on **how the job itself runs**:
31
+
32
+ **Scenario A — Job runs directly on the runner (no `container:` key):**
33
+ The runner process runs natively on the VM. Docker maps service container ports to the
34
+ runner's loopback interface. Services are reachable at `localhost:<mapped_port>`.
35
+ Using the service name (e.g. `postgres`) as a hostname will **fail** with ENOTFOUND.
36
+
37
+ **Scenario B — Job runs inside a container (`container:` key present):**
38
+ Both the job container and service containers are on the same Docker user-defined network.
39
+ Docker's built-in DNS resolves container names. Services are reachable by their
40
+ **service name** (e.g. `postgres`, `redis`) as the hostname, NOT `localhost`.
41
+ Using `localhost` here will produce "Connection refused" because the service port is
42
+ not bound to the job container's loopback interface.
43
+
44
+ This asymmetry is the root of most service container connectivity bugs:
45
+ developers copy a working non-containerized workflow config into a containerized job
46
+ (or vice versa) without updating the hostname.
47
+
48
+ Additionally, when using `ports:` mapping in service definitions, the runner maps the
49
+ container port to a randomly assigned host port (unless pinned with `host:container`
50
+ syntax). The `${{ job.services.postgres.ports['5432'] }}` expression returns the
51
+ actual host-side port, which may differ from 5432.
52
+ fix: |
53
+ **For jobs running directly on the runner (no `container:` key):**
54
+ Connect to services via `localhost` (or `127.0.0.1`) and the mapped port.
55
+ Use `${{ job.services.<service>.ports['<container_port>'] }}` to get the dynamic host port
56
+ when not using explicit port pinning.
57
+
58
+ **For jobs running in a container (`container:` key):**
59
+ Connect to services via the **service name** as the hostname and the container's
60
+ internal port directly. No port mapping is required — both containers share the same
61
+ Docker network and communicate directly.
62
+
63
+ Use the `options: --add-host` trick only if you need the same workflow YAML to work
64
+ in both contexts (rare — avoid this complexity).
65
+ fix_code:
66
+ - language: yaml
67
+ label: "Correct connectivity for a runner-native job (no container:)"
68
+ code: |
69
+ jobs:
70
+ test:
71
+ runs-on: ubuntu-latest
72
+ # No 'container:' key — job runs directly on the runner VM
73
+ services:
74
+ postgres:
75
+ image: postgres:16
76
+ env:
77
+ POSTGRES_PASSWORD: postgres
78
+ ports:
79
+ - 5432:5432 # pin host:container port for simplicity
80
+ options: >-
81
+ --health-cmd pg_isready
82
+ --health-interval 10s
83
+ --health-timeout 5s
84
+ --health-retries 5
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ - name: Run tests
88
+ env:
89
+ # Use localhost — runner-native job maps service ports to loopback
90
+ DATABASE_URL: postgres://postgres:postgres@localhost:5432/testdb
91
+ run: npm test
92
+ - language: yaml
93
+ label: "Correct connectivity for a containerized job (container: key present)"
94
+ code: |
95
+ jobs:
96
+ test:
97
+ runs-on: ubuntu-latest
98
+ container:
99
+ image: node:20 # Job itself runs inside a container
100
+ services:
101
+ postgres:
102
+ image: postgres:16
103
+ env:
104
+ POSTGRES_PASSWORD: postgres
105
+ # NO ports: mapping needed — containers share the Docker network
106
+ options: >-
107
+ --health-cmd pg_isready
108
+ --health-interval 10s
109
+ --health-timeout 5s
110
+ --health-retries 5
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+ - name: Run tests
114
+ env:
115
+ # Use service NAME "postgres" — Docker DNS resolves it within the network
116
+ DATABASE_URL: postgres://postgres:postgres@postgres:5432/testdb
117
+ run: npm test
118
+ prevention:
119
+ - "When your job uses `container:`, always connect to services via the service name (e.g. `postgres`, `redis`), NOT `localhost`."
120
+ - "When your job runs natively (no `container:`), always connect to services via `localhost` and the mapped host port."
121
+ - "Use `options: --health-cmd / --health-interval / --health-retries` on service containers to ensure they are ready before steps execute."
122
+ - "Avoid using `localhost` as the database hostname in connection strings — parameterize it so the same code works in both runner-native and containerized jobs."
123
+ - "If you move a job from runner-native to containerized (or vice versa), always audit all service hostnames in env variables and connection strings."
124
+ docs:
125
+ - url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/about-service-containers"
126
+ label: "GitHub Docs: About service containers"
127
+ - url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/creating-postgresql-service-containers"
128
+ label: "GitHub Docs: Creating PostgreSQL service containers"
129
+ - url: "https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/creating-redis-service-containers"
130
+ label: "GitHub Docs: Creating Redis service containers"
@@ -0,0 +1,138 @@
1
+ id: runner-environment-026
2
+ title: "ubuntu-latest Switched to Ubuntu 24.04 — Breaks Python 3.8/3.9, System Packages, OpenSSL"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - ubuntu
7
+ - ubuntu-24.04
8
+ - runner-image
9
+ - python
10
+ - openssl
11
+ - apt
12
+ - migration
13
+ - breaking-change
14
+ patterns:
15
+ - regex: "Unable to locate package python3\\.[89]"
16
+ flags: "i"
17
+ - regex: "python3\\.[89].*not found.*ubuntu.*24"
18
+ flags: "i"
19
+ - regex: "E: Package 'python3\\.[89]' has no installation candidate"
20
+ flags: "i"
21
+ - regex: "error.*openssl.*libssl1\\.1.*not available"
22
+ flags: "i"
23
+ - regex: "deadsnakes.*ppa.*focal.*not available.*noble"
24
+ flags: "i"
25
+ - regex: "ubuntu-latest.*ubuntu 24"
26
+ flags: "i"
27
+ error_messages:
28
+ - "E: Package 'python3.8' has no installation candidate"
29
+ - "E: Package 'python3.9' has no installation candidate"
30
+ - "E: Package 'libssl1.1' has no installation candidate"
31
+ - "Error: The version '3.8' with architecture 'x64' was not found for Ubuntu 24.04"
32
+ - "Error: deadsnakes/ppa does not provide Python 3.8 packages for Ubuntu Noble (24.04)"
33
+ root_cause: |
34
+ GitHub began rolling out Ubuntu 24.04 as the new target for `ubuntu-latest` on
35
+ **December 5, 2024**, completing the transition on **January 17, 2025** (tracked in
36
+ actions/runner-images #10636, 266 👍 reactions). Any workflow using `runs-on: ubuntu-latest`
37
+ without explicit version pinning now runs on Ubuntu 24.04 ("Noble Numbat") instead of 22.04.
38
+
39
+ **Key breaking changes in Ubuntu 24.04:**
40
+
41
+ 1. **Python 3.8 and 3.9 are end-of-life and not available** — not via `apt` and not via
42
+ the `deadsnakes/ppa` PPA (which only backports for supported Ubuntu releases). Workflows
43
+ that `apt-get install python3.8` or use `setup-python` with version `3.8` or `3.9` fail.
44
+
45
+ 2. **OpenSSL 1.1 removed** — Ubuntu 24.04 ships only OpenSSL 3.x. Packages and Python
46
+ versions that were compiled against OpenSSL 1.1 (`libssl1.1`) will fail to install or
47
+ run. This affects older Ruby gems, some Go binaries, and legacy pip packages.
48
+
49
+ 3. **System Python is 3.12** — the `python3` system binary points to Python 3.12, which
50
+ may break scripts that relied on the 3.10 default in 22.04.
51
+
52
+ 4. **`apt` package name changes** — some packages were renamed or split between 22.04 and
53
+ 24.04 (e.g., `python3-distutils` is gone; functionality merged into `python3`).
54
+
55
+ 5. **`/usr/bin/python` symlink absent by default** — workflows calling bare `python`
56
+ (not `python3`) fail with "python: command not found".
57
+ fix: |
58
+ **Short-term — pin to ubuntu-22.04:**
59
+ Replace `runs-on: ubuntu-latest` with `runs-on: ubuntu-22.04` to freeze the runner image
60
+ while you migrate. Note: ubuntu-22.04 will eventually reach end-of-support (~April 2027).
61
+
62
+ **Long-term — migrate to supported Python/package versions:**
63
+ - Replace Python 3.8/3.9 with Python 3.10, 3.11, or 3.12 using `actions/setup-python`.
64
+ `actions/setup-python` downloads a pre-built binary from the tool cache — it works
65
+ regardless of the runner's system Python.
66
+ - Replace `libssl1.1` dependencies by upgrading the affected package to an OpenSSL-3
67
+ compatible version, or adding a compatibility shim if available.
68
+ - Replace bare `python` calls with `python3`.
69
+
70
+ **For `deadsnakes` PPA users:** `deadsnakes/ppa` only provides Python 3.8/3.9 for
71
+ Ubuntu 20.04 (Focal) and 22.04 (Jammy) — not 24.04 (Noble). There is no supported
72
+ workaround; upgrade to a supported Python version.
73
+ fix_code:
74
+ - language: yaml
75
+ label: "Pin to ubuntu-22.04 as a short-term fix while migrating"
76
+ code: |
77
+ jobs:
78
+ test:
79
+ # Pin explicitly until Python 3.8/3.9 dependencies are upgraded
80
+ runs-on: ubuntu-22.04
81
+ steps:
82
+ - uses: actions/checkout@v4
83
+ - run: python3.9 -m pytest
84
+ - language: yaml
85
+ label: "Use actions/setup-python to install any Python version on ubuntu-latest"
86
+ code: |
87
+ jobs:
88
+ test:
89
+ runs-on: ubuntu-latest # Now 24.04
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+ - name: Set up Python
93
+ uses: actions/setup-python@v5
94
+ with:
95
+ # setup-python downloads pre-built binaries — works on any runner OS
96
+ python-version: '3.9'
97
+ - run: python --version # 3.9.x from setup-python's tool cache
98
+ - run: pip install -r requirements.txt
99
+ - language: yaml
100
+ label: "Test matrix against multiple Python versions to find breakages early"
101
+ code: |
102
+ jobs:
103
+ test:
104
+ runs-on: ubuntu-latest
105
+ strategy:
106
+ matrix:
107
+ python-version: ['3.9', '3.10', '3.11', '3.12']
108
+ steps:
109
+ - uses: actions/checkout@v4
110
+ - uses: actions/setup-python@v5
111
+ with:
112
+ python-version: ${{ matrix.python-version }}
113
+ - run: pip install -r requirements.txt && pytest
114
+ - language: yaml
115
+ label: "Fix bare 'python' command not found on Ubuntu 24.04"
116
+ code: |
117
+ steps:
118
+ - name: Ensure python symlink exists
119
+ run: |
120
+ # Ubuntu 24.04 no longer creates /usr/bin/python by default
121
+ sudo ln -sf /usr/bin/python3 /usr/bin/python
122
+ # Or: use actions/setup-python which sets up the PATH correctly
123
+ prevention:
124
+ - "Pin `runs-on: ubuntu-22.04` explicitly if your workflow depends on Python 3.8/3.9, libssl1.1, or other 22.04-specific packages."
125
+ - "Use `actions/setup-python@v5` to install a specific Python version instead of relying on `apt-get install python3.x` — it works across all Ubuntu versions."
126
+ - "When you upgrade Ubuntu runner versions, scan `apt-get install` lines in run steps for packages that may not exist in the new Ubuntu release."
127
+ - "Replace bare `python` invocations with `python3` or use `actions/setup-python` which adds an alias."
128
+ - "Test your workflows against `ubuntu-24.04` explicitly before `ubuntu-latest` changes, by running on both runner images in a matrix."
129
+ - "Subscribe to https://github.com/actions/runner-images/issues for announcements about upcoming `ubuntu-latest` image transitions."
130
+ docs:
131
+ - url: "https://github.com/actions/runner-images/issues/10636"
132
+ label: "actions/runner-images #10636 — Ubuntu-latest workflows will use Ubuntu-24.04 image"
133
+ - url: "https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md"
134
+ label: "Ubuntu 24.04 runner image — installed software reference"
135
+ - url: "https://github.com/actions/setup-python"
136
+ label: "actions/setup-python — install any Python version on any runner"
137
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
138
+ label: "GitHub Docs: Supported runners and hardware resources"
@@ -0,0 +1,112 @@
1
+ id: silent-failures-011
2
+ title: "GITHUB_OUTPUT Multiline Values Silently Truncated — Heredoc EOF Required"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - github-output
7
+ - multiline
8
+ - output
9
+ - heredoc
10
+ - truncation
11
+ - environment-files
12
+ patterns:
13
+ - regex: "echo\\s+['\"]?\\w+=.*\\$\\([^)]+\\).*>>\\s+\\$GITHUB_OUTPUT"
14
+ flags: "i"
15
+ - regex: "invalid value.*GITHUB_OUTPUT.*contains newline"
16
+ flags: "i"
17
+ - regex: "Error: Unable to process file command 'output'"
18
+ flags: "i"
19
+ - regex: "GITHUB_OUTPUT.*multiline"
20
+ flags: "i"
21
+ error_messages:
22
+ - "Error: Unable to process file command 'output' successfully."
23
+ - "Invalid format 'key=line1\\nline2' - value contains newline, use heredoc syntax"
24
+ - "Warning: Unexpected input(s) 'output', valid inputs are"
25
+ root_cause: |
26
+ The `GITHUB_OUTPUT` environment file protocol (introduced November 2022 as a replacement
27
+ for the deprecated `::set-output` command) uses a line-based key=value format that does
28
+ NOT support literal newline characters in values when using simple `echo "key=value"` syntax.
29
+
30
+ When a step sets a multiline output using the naive approach:
31
+ ```bash
32
+ echo "REPORT=$(cat report.txt)" >> $GITHUB_OUTPUT
33
+ ```
34
+ the shell expands `$(cat report.txt)` into a multiline string, which is then written as:
35
+ ```
36
+ REPORT=line1
37
+ line2
38
+ line3
39
+ ```
40
+ The runner reads the first newline as end-of-value for `REPORT`, then tries to parse `line2`
41
+ as a new key=value entry (which fails silently or errors). The downstream step reading
42
+ `${{ steps.id.outputs.REPORT }}` receives only `line1` — or an empty string if the parser
43
+ rejects the entry entirely.
44
+
45
+ This is a **silent failure** because the workflow step itself does not fail — the `echo`
46
+ command exits successfully. The broken output only surfaces downstream, often as an empty
47
+ variable or a truncated value that's hard to trace back to the output-setting step.
48
+
49
+ The same issue affects `$GITHUB_ENV` for multiline environment variable values.
50
+ fix: |
51
+ Use the **heredoc (multi-line delimiter) syntax** documented by GitHub for multiline values.
52
+ The format is:
53
+ ```
54
+ {name}<<{delimiter}
55
+ {value}
56
+ {delimiter}
57
+ ```
58
+ where `{delimiter}` is any string that does NOT appear in the value itself. `EOF` is the
59
+ conventional choice, but using a random string (e.g. `$(uuidgen)`) prevents injection
60
+ attacks if the value is untrusted.
61
+
62
+ **For `$GITHUB_ENV` multiline values:** use the identical heredoc pattern with `$GITHUB_ENV`.
63
+
64
+ **For JavaScript/TypeScript actions:** use `core.setOutput('name', value)` from
65
+ `@actions/core` — it handles serialization automatically and is not subject to this limitation.
66
+ fix_code:
67
+ - language: yaml
68
+ label: "Correct multiline GITHUB_OUTPUT using heredoc EOF syntax"
69
+ code: |
70
+ - name: Set multiline output
71
+ id: report
72
+ run: |
73
+ # WRONG: echo "REPORT=$(cat report.txt)" >> $GITHUB_OUTPUT
74
+ # Correct: heredoc syntax
75
+ echo "REPORT<<EOF" >> $GITHUB_OUTPUT
76
+ cat report.txt >> $GITHUB_OUTPUT
77
+ echo "EOF" >> $GITHUB_OUTPUT
78
+
79
+ - name: Use multiline output
80
+ run: |
81
+ echo "${{ steps.report.outputs.REPORT }}"
82
+ - language: yaml
83
+ label: "Use random delimiter to prevent injection from untrusted content"
84
+ code: |
85
+ - name: Set multiline output safely
86
+ id: data
87
+ run: |
88
+ DELIMITER=$(openssl rand -hex 16)
89
+ echo "JSON_OUTPUT<<${DELIMITER}" >> $GITHUB_OUTPUT
90
+ curl -s https://api.example.com/data >> $GITHUB_OUTPUT
91
+ echo "${DELIMITER}" >> $GITHUB_OUTPUT
92
+ - language: yaml
93
+ label: "Multiline GITHUB_ENV using heredoc (same pattern)"
94
+ code: |
95
+ - name: Set multiline environment variable
96
+ run: |
97
+ echo "CHANGELOG<<EOF" >> $GITHUB_ENV
98
+ git log --oneline -10 >> $GITHUB_ENV
99
+ echo "EOF" >> $GITHUB_ENV
100
+ prevention:
101
+ - "Never use `echo \"KEY=$(command)\" >> $GITHUB_OUTPUT` when the command output may span multiple lines."
102
+ - "Always use the heredoc EOF syntax for any output value that could contain newlines: `echo \"KEY<<EOF\" >> $GITHUB_OUTPUT && <value> >> $GITHUB_OUTPUT && echo \"EOF\" >> $GITHUB_OUTPUT`."
103
+ - "Use a random delimiter (`$(openssl rand -hex 16)`) instead of `EOF` when the value originates from untrusted input to prevent delimiter injection."
104
+ - "In JavaScript/TypeScript actions, use `@actions/core`'s `core.setOutput()` which handles serialization automatically."
105
+ - "Test multiline outputs locally with `act` or by printing `cat $GITHUB_OUTPUT` in a subsequent step to verify the full value was captured."
106
+ docs:
107
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings"
108
+ label: "GitHub Docs: Workflow commands — Multiline strings"
109
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
110
+ label: "GitHub Docs: Passing information between jobs"
111
+ - url: "https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/"
112
+ label: "GitHub Changelog: Deprecating save-state and set-output commands"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",