feat(artifact): unblock v4+ on self-hosted GHES when ACTIONS_RESULTS_URL is set#2438
feat(artifact): unblock v4+ on self-hosted GHES when ACTIONS_RESULTS_URL is set#2438camjay wants to merge 1 commit into
Conversation
…URL is set
The current isGhes() check returns true for any GitHub Server URL that
isn't github.com, *.ghe.com, or *.localhost. When isGhes() returns true,
client.ts throws GHESNotSupportedError on every upload, download, and
list call - so the artifact-v4+ family is completely blocked on
self-hosted GHES instances.
This made sense at v4 launch when the artifact-storage-v2 backend was
github.com-only. GHES 3.13 added the v2 backend, and 3.16+ has full
production support, but the hostname-based gate doesn't reflect that:
it continues to throw on any GHES regardless of release.
The runtime already exposes a clean signal for whether v2 is reachable:
the runner sets ACTIONS_RESULTS_URL exactly when the storage backend is
available. The artifact client's own getResultsServiceUrl() in the same
package throws if ACTIONS_RESULTS_URL is unset, so it's already a
precondition for the upload/download/list paths to succeed. Treating
that env var as the authority on "is the v2 backend reachable here?"
unblocks GHES 3.13+ without changing behaviour anywhere else.
Compatibility:
- github.com / *.ghe.com / *.localhost: hostname check returns
isGhes()=false. No change.
- GHES <3.13 (no v2 backend, ACTIONS_RESULTS_URL unset): hostname is
GHES-shaped, env var is missing -> isGhes()=true -> existing
GHESNotSupportedError. No change.
- GHES 3.13+ (v2 backend present, ACTIONS_RESULTS_URL set): hostname
is GHES-shaped, env var IS set -> isGhes()=false -> upload /
download / list proceed normally. This is the unblock.
Tests added in packages/artifact/__tests__/config.test.ts cover both
new branches; the existing 'enterprise hostname' test is kept and now
explicitly verifies the unset-env-var case.
|
Hey @actions/artifacts-actions, @danwkennedy, @jasongin: bumping this on the back of the artifact README's own note that v4 is "not currently supported on GHES yet." GHES 3.13+ ships the v2 artifact backend; on those releases the runner already exports Related: #2439 (issue) and the older #2123 (different approach to the same problem, open since early 2026). Happy to adjust scope/tests/style. Just looking for a triage decision so we know whether to keep iterating here or pursue an ADR per CONTRIBUTING.md. |
Closes #2439
Related to #2123 (more general vendor-aware approach for non-GitHub servers; this PR addresses the narrower GHES-3.13+ case via existing runtime signals)
isGhes()inpackages/artifact/src/internal/shared/config.tscurrently throwsGHESNotSupportedErroron any GHES, regardless of release. GHES 3.13 added the artifact-storage-v2 backend that v4+ requires, but the gate is hostname-only and ignores the release.ACTIONS_RESULTS_URLis the runtime signal for v2 availability; the same package'sgetResultsServiceUrl()already requires it. This change makesisGhes()returnfalsewhen the hostname looks like GHES andACTIONS_RESULTS_URLis set.Behaviour matrix:
github.com,*.ghe.com,*.localhost: hostname check still returnsfalse. No change.ACTIONS_RESULTS_URLunset):isGhes()returnstrue, throws as before. No change.ACTIONS_RESULTS_URLset):isGhes()returnsfalse, upload/download/list proceed.Tests in
packages/artifact/__tests__/config.test.tscover both new branches. Also added abeforeEachcleanup ofGITHUB_SERVER_URLandACTIONS_RESULTS_URLinside theisGhesdescribe block; the previous setup relied onjest.resetModules()alone and could leakACTIONS_RESULTS_URLfrom sibling tests. The previously-misleadingly-titled "should return false ... is specific to an enterprise" test (which expectedtrue) is renamed to match its actual assertion.Verified on a GHES 3.19.5 instance where the v2 backend is operational but v4+ artifact actions were blocked solely by the hostname gate.
Relationship to #2123: that PR takes a more general approach with an
ACTIONS_VENDORenv var as an explicit opt-in, supporting non-GitHub vendor servers (Gitea, Forgejo, etc.) in addition to GHES. This PR is narrower: it consults an existing runtime signal (ACTIONS_RESULTS_URL) that GHES 3.13+ runners already emit, so no operator action is required and no new env-var contract is introduced. The two approaches are complementary; if both land, the check here would short-circuit before vendor detection on v2-supporting GHES.