Skip to content

Commit 8c178a6

Browse files
committed
verify-action-build: match TS generics on @actions/http-client *Json calls
Commit 920d616 added postJson/getJson/etc. as data-parse markers but the regex required `(` directly after `Json`. The real call site in rubygems/configure-rubygems-credentials v2.0.0 is `http.postJson<IdToken>(...)` — the TypeScript generic between `Json` and `(` defeated the match, so PR #795 still showed both src/oidc/assumeRole.ts and trustedPublisher.ts as unverified downloads. Allow an optional `<...>` between `Json` and `(`, and tighten the RUBYGEMS_OIDC_EXCHANGE fixture so it mirrors the v2.0.0 source verbatim (including the generic and IdTokenSchema.parse on the result). The fixture omitting the generic was the crack the original fix slipped through.
1 parent 2b3ae66 commit 8c178a6

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

utils/tests/verify_action_build/test_security.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -864,10 +864,12 @@ def test_split_alone_exempts(self):
864864
assert _file_is_pure_data_fetch(split_fetch) is True
865865
assert _find_binary_downloads_js(split_fetch) == []
866866

867-
# The exact pattern that triggered the false positive on PR #789
867+
# The exact pattern that triggered the false positive on PR #789 / #795
868868
# (rubygems/configure-rubygems-credentials, transitively pulled in by
869869
# rubygems/release-gem): @actions/http-client postJson against an OIDC
870870
# token-exchange endpoint. The response is a credential, not a binary.
871+
# The ``<IdToken>`` generic mirrors the v2.0.0 source verbatim — earlier
872+
# versions of this fixture omitted it and quietly hid a regex hole.
871873
RUBYGEMS_OIDC_EXCHANGE = """\
872874
import * as core from '@actions/core'
873875
import {HttpClient} from '@actions/http-client'
@@ -877,8 +879,12 @@ def test_split_alone_exempts(self):
877879
const webIdentityToken = await core.getIDToken(audience)
878880
const http = new HttpClient('rubygems-oidc-action')
879881
const url = `${server}/api/v1/oidc/trusted_publisher/exchange_token`
880-
const res = await http.postJson(url, {jwt: webIdentityToken}, {})
881-
return res.result
882+
const res = await http.postJson<IdToken>(
883+
url,
884+
{jwt: webIdentityToken},
885+
{'content-type': 'application/json', accept: 'application/json'}
886+
)
887+
return IdTokenSchema.parse(res.result)
882888
}
883889
"""
884890

utils/verify_action_build/security.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,10 @@ def analyze_action_metadata(
10801080
# delJson/requestJson) auto-parse the response body as JSON. Reaching for
10811081
# these is an explicit "treat the response as structured data" signal
10821082
# — typical of OIDC/RPC token-exchange calls, not binary downloads.
1083-
re.compile(r"\.(?:get|post|put|patch|del|request)Json\s*\("),
1083+
# The optional ``<...>`` admits TypeScript generic type parameters
1084+
# (``http.postJson<IdToken>(...)``); without it the regex misses the
1085+
# exact call shape rubygems/configure-rubygems-credentials uses.
1086+
re.compile(r"\.(?:get|post|put|patch|del|request)Json(?:\s*<[^>]*>)?\s*\("),
10841087
]
10851088

10861089
# Markers indicating the response is treated as a binary or executable —

0 commit comments

Comments
 (0)