Skip to content
This repository was archived by the owner on Aug 24, 2026. It is now read-only.

Omit run URL when GITHUB_REPOSITORY or GITHUB_RUN_ID is absent - #132

Merged
pda merged 1 commit into
buildkite:mainfrom
SirHegel:fix-github-actions-url-with-missing-env
Aug 20, 2026
Merged

Omit run URL when GITHUB_REPOSITORY or GITHUB_RUN_ID is absent#132
pda merged 1 commit into
buildkite:mainfrom
SirHegel:fix-github-actions-url-with-missing-env

Conversation

@SirHegel

Copy link
Copy Markdown
Contributor

The problem

_github_actions_env builds the run URL with an f-string over two values that _get_env can legitimately return as None:

repo = self._get_env("GITHUB_REPOSITORY")
run_id = self._get_env("GITHUB_RUN_ID")

return RunEnv(
    ...
    url=f"https://github.com/{repo}/actions/runs/{run_id}",

When either is missing, the interpolation produces the literal string None inside the URL:

https://github.com/None/actions/runs/None

That value is a non-None string, so as_json() keeps it — the filter is if v is not None — and the malformed URL is sent to the API rather than the field being omitted.

Why the other branches are unaffected

_buildkite_env and _circle_ci_env pass _get_env(...) straight through:

url=self._get_env("BUILDKITE_BUILD_URL"),

so a missing value stays None and as_json() drops the key. This change brings the GitHub Actions branch in line with them.

How it is reachable

The guard clause above only requires GITHUB_ACTION, GITHUB_RUN_NUMBER and GITHUB_RUN_ATTEMPT. Neither GITHUB_REPOSITORY nor GITHUB_RUN_ID is checked, so the branch can be entered with either unset — most plausibly through RunEnvBuilder's injected environment, which the class docstring documents as a supported use, or on a runner with a trimmed environment.

Reproduced against the current code:

>>> RunEnvBuilder({
...     "GITHUB_ACTION": "run",
...     "GITHUB_RUN_NUMBER": "12",
...     "GITHUB_RUN_ATTEMPT": "1",
... }).build().as_json()["url"]
'https://github.com/None/actions/runs/None'

The change

Build the URL only when both parts are present; otherwise leave it None and let as_json() omit it, exactly as the other two branches already do.

Tests

Added a regression test that fails on the current code with the None URL and passes with the change. Full suite: 117 passed, 1 skipped.

_github_actions_env builds the URL with an f-string over two values that
_get_env can legitimately return as None. When either is missing, the
interpolation produces the literal string 'None' inside the URL:

    https://github.com/None/actions/runs/None

That value is then a non-None string, so as_json() keeps it and sends it to
the API instead of omitting the field.

The other two CI branches do not have this problem. _buildkite_env and
_circle_ci_env pass _get_env(...) straight through, so a missing value stays
None and as_json() filters it out. This brings the GitHub Actions branch in
line with them.

The guard clause above only requires GITHUB_ACTION, GITHUB_RUN_NUMBER and
GITHUB_RUN_ATTEMPT, so reaching this code with either of the other two unset
is possible — most plausibly through RunEnvBuilder's documented injected
environment, or a runner with a trimmed environment.

Adds a regression test that fails on the current code with the 'None' URL and
passes with the change.
@pda
pda merged commit 1ef260c into buildkite:main Aug 20, 2026
2 of 3 checks passed
pda pushed a commit to buildkite/test-collector-javascript that referenced this pull request Aug 24, 2026
github_actions() builds the URL with a template literal over two environment
variables that may be undefined. Interpolating undefined yields the literal
string 'undefined', so the result is:

    https://github.com/undefined/actions/runs/undefined

That is a real string rather than undefined, so JSON.stringify keeps it and
it is sent as though it were a genuine URL.

ci_env() enters this branch on GITHUB_RUN_NUMBER alone, so the other two
variables are not guaranteed. The existing test 'uses github action
environment variables second' already exercises this exact path — it sets
only GITHUB_RUN_NUMBER — but asserts only on ci.

buildkite() and circleci() are unaffected: they assign process.env values
directly, so a missing variable stays undefined and JSON.stringify drops the
key. This brings github_actions() in line with them.

Same defect as buildkite/test-collector-python#132.

Adds a regression test that fails on the current code and passes with the
change.
pda added a commit to buildkite/bktest that referenced this pull request Aug 24, 2026
…kite/test-collector-python#132)

_github_actions_env builds the URL with an f-string over two values that
_get_env can legitimately return as None. When either is missing, the
interpolation produces the literal string 'None' inside the URL:

    https://github.com/None/actions/runs/None

That value is then a non-None string, so as_json() keeps it and sends it to
the API instead of omitting the field.

The other two CI branches do not have this problem. _buildkite_env and
_circle_ci_env pass _get_env(...) straight through, so a missing value stays
None and as_json() filters it out. This brings the GitHub Actions branch in
line with them.

The guard clause above only requires GITHUB_ACTION, GITHUB_RUN_NUMBER and
GITHUB_RUN_ATTEMPT, so reaching this code with either of the other two unset
is possible — most plausibly through RunEnvBuilder's documented injected
environment, or a runner with a trimmed environment.

Adds a regression test that fails on the current code with the 'None' URL and
passes with the change.

Co-authored-by: SirHegel <SirHegel@users.noreply.github.com>
pda pushed a commit to buildkite/bktest that referenced this pull request Aug 24, 2026
github_actions() builds the URL with a template literal over two environment
variables that may be undefined. Interpolating undefined yields the literal
string 'undefined', so the result is:

    https://github.com/undefined/actions/runs/undefined

That is a real string rather than undefined, so JSON.stringify keeps it and
it is sent as though it were a genuine URL.

ci_env() enters this branch on GITHUB_RUN_NUMBER alone, so the other two
variables are not guaranteed. The existing test 'uses github action
environment variables second' already exercises this exact path — it sets
only GITHUB_RUN_NUMBER — but asserts only on ci.

buildkite() and circleci() are unaffected: they assign process.env values
directly, so a missing variable stays undefined and JSON.stringify drops the
key. This brings github_actions() in line with them.

Same defect as buildkite/test-collector-python#132.

Adds a regression test that fails on the current code and passes with the
change.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants