From 87cd75c9c2f1bf583ca7b92c31716aa6f6fe6ed3 Mon Sep 17 00:00:00 2001 From: Mahdi Baghbani Date: Fri, 31 Jul 2026 12:58:33 +0000 Subject: [PATCH] fix(config): make isGhes forge-aware on Gitea Signed-off-by: Mahdi Baghbani --- packages/artifact/__tests__/config.test.ts | 40 ++++++++++++++++++- .../artifact/src/internal/shared/config.ts | 14 +++++++ packages/cache/__tests__/config.test.ts | 38 ++++++++++++++++++ packages/cache/src/internal/config.ts | 21 ++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/packages/artifact/__tests__/config.test.ts b/packages/artifact/__tests__/config.test.ts index 3d14ace2b2..2bc998d711 100644 --- a/packages/artifact/__tests__/config.test.ts +++ b/packages/artifact/__tests__/config.test.ts @@ -12,6 +12,9 @@ jest.mock('os', () => { beforeEach(() => { jest.resetModules() + delete process.env['FORGEJO_ACTIONS'] + delete process.env['GITEA_ACTIONS'] + delete process.env['ACTIONS_VENDOR'] }) describe('isGhes', () => { @@ -35,10 +38,45 @@ describe('isGhes', () => { expect(config.isGhes()).toBe(false) }) - it('should return false when the request domain is specific to an enterprise', () => { + it('should return true when the request domain is specific to an enterprise (GHES)', () => { process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com' expect(config.isGhes()).toBe(true) }) + + it('should return false when FORGEJO_ACTIONS is set on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.FORGEJO_ACTIONS = 'true' + expect(config.isGhes()).toBe(false) + }) + + it('should return false when GITEA_ACTIONS is set on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.GITEA_ACTIONS = 'true' + expect(config.isGhes()).toBe(false) + }) + + it('should return false when ACTIONS_VENDOR is github on an enterprise hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com' + process.env.ACTIONS_VENDOR = 'github' + expect(config.isGhes()).toBe(false) + }) + + it('should return true when ACTIONS_VENDOR is ghes on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.ACTIONS_VENDOR = 'ghes' + expect(config.isGhes()).toBe(true) + }) + + it('should fall through to hostname when ACTIONS_VENDOR is an unknown value on an enterprise hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com' + process.env.ACTIONS_VENDOR = 'unknownvalue' + expect(config.isGhes()).toBe(true) + }) + + it('should return true for a forge hostname with no forge flags or vendor set (pre-fix behavior)', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + expect(config.isGhes()).toBe(true) + }) }) describe('uploadChunkTimeoutEnv', () => { diff --git a/packages/artifact/src/internal/shared/config.ts b/packages/artifact/src/internal/shared/config.ts index 0a275fd5ee..de5fb4775d 100644 --- a/packages/artifact/src/internal/shared/config.ts +++ b/packages/artifact/src/internal/shared/config.ts @@ -25,6 +25,20 @@ export function getResultsServiceUrl(): string { } export function isGhes(): boolean { + // Forge runners (Forgejo, Gitea) self-identify via these flags. They are not + // GitHub Enterprise Server and must not be misclassified as GHES. + if (process.env['FORGEJO_ACTIONS'] || process.env['GITEA_ACTIONS']) { + return false + } + + // Optional operator-set vendor override. No runner emits this today; it is an + // explicit escape hatch for runners that set neither forge flag. + const vendor = (process.env['ACTIONS_VENDOR'] || '').trim().toLowerCase() + if (vendor === 'github') return false + if (vendor === 'ghes') return true + // Unknown/non-empty vendors fall through to the hostname heuristic; they do + // NOT auto-disable the GHES block (avoids a typo/spoof silently unblocking). + const ghUrl = new URL( process.env['GITHUB_SERVER_URL'] || 'https://github.com' ) diff --git a/packages/cache/__tests__/config.test.ts b/packages/cache/__tests__/config.test.ts index 7582bb3251..08b6e48479 100644 --- a/packages/cache/__tests__/config.test.ts +++ b/packages/cache/__tests__/config.test.ts @@ -2,6 +2,9 @@ import * as config from '../src/internal/config' beforeEach(() => { jest.resetModules() + delete process.env['FORGEJO_ACTIONS'] + delete process.env['GITEA_ACTIONS'] + delete process.env['ACTIONS_VENDOR'] }) test('isGhes returns false for github.com', async () => { @@ -24,6 +27,41 @@ test('isGhes returns false for ghe.localhost', () => { expect(config.isGhes()).toBe(false) }) +test('isGhes returns false when FORGEJO_ACTIONS is set on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.FORGEJO_ACTIONS = 'true' + expect(config.isGhes()).toBe(false) +}) + +test('isGhes returns false when GITEA_ACTIONS is set on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.GITEA_ACTIONS = 'true' + expect(config.isGhes()).toBe(false) +}) + +test('isGhes returns false when ACTIONS_VENDOR is github on an enterprise hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com' + process.env.ACTIONS_VENDOR = 'github' + expect(config.isGhes()).toBe(false) +}) + +test('isGhes returns true when ACTIONS_VENDOR is ghes on a forge hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + process.env.ACTIONS_VENDOR = 'ghes' + expect(config.isGhes()).toBe(true) +}) + +test('isGhes falls through to hostname for unknown ACTIONS_VENDOR on an enterprise hostname', () => { + process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com' + process.env.ACTIONS_VENDOR = 'unknownvalue' + expect(config.isGhes()).toBe(true) +}) + +test('isGhes returns true for a forge hostname with no forge flags or vendor set (pre-fix behavior)', () => { + process.env.GITHUB_SERVER_URL = 'https://forge.example.com' + expect(config.isGhes()).toBe(true) +}) + describe('cache-mode helpers', () => { const original = process.env.ACTIONS_CACHE_MODE diff --git a/packages/cache/src/internal/config.ts b/packages/cache/src/internal/config.ts index 70526475a4..73f16a7961 100644 --- a/packages/cache/src/internal/config.ts +++ b/packages/cache/src/internal/config.ts @@ -1,4 +1,25 @@ +// NOTE: isGhes() here is intentionally identical to the artifact package's. +// On forges this now returns false, so getCacheServiceVersion() honors +// ACTIONS_CACHE_SERVICE_V2. Forges that set that flag without implementing +// the cache v2 CacheService Twirp (see gitea#33393) will fail until they +// implement it or stop setting the flag. The client-side 10GB cap in cache.ts +// also becomes active on forges. These are accepted tradeoffs of making the +// vendor flag authoritative. export function isGhes(): boolean { + // Forge runners (Forgejo, Gitea) self-identify via these flags. They are not + // GitHub Enterprise Server and must not be misclassified as GHES. + if (process.env['FORGEJO_ACTIONS'] || process.env['GITEA_ACTIONS']) { + return false + } + + // Optional operator-set vendor override. No runner emits this today; it is an + // explicit escape hatch for runners that set neither forge flag. + const vendor = (process.env['ACTIONS_VENDOR'] || '').trim().toLowerCase() + if (vendor === 'github') return false + if (vendor === 'ghes') return true + // Unknown/non-empty vendors fall through to the hostname heuristic; they do + // NOT auto-disable the GHES block (avoids a typo/spoof silently unblocking). + const ghUrl = new URL( process.env['GITHUB_SERVER_URL'] || 'https://github.com' )