diff --git a/lib/job-summary.js b/lib/job-summary.js index 67b226b2f..564465922 100644 --- a/lib/job-summary.js +++ b/lib/job-summary.js @@ -38,7 +38,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.JobSummary = void 0; const core = __importStar(require("@actions/core")); const semver_1 = require("semver"); -const core_1 = require("@octokit/core"); const github = __importStar(require("@actions/github")); const util_1 = require("util"); const zlib_1 = require("zlib"); @@ -107,16 +106,21 @@ class JobSummary { }); } /** - * Uploads the code scanning SARIF content to the code-scanning GitHub API. - * @param encodedSarif - The final compressed and encoded sarif content. - * @param token - GitHub token to use for the request. Has to have 'security-events: write' permission. - * @private + * Uploads a SARIF (Static Analysis Results Interchange Format) file to GitHub's code scanning API. + * This method handles the communication with GitHub's REST API to populate the code scanning tab with security analysis results. + * Supports both GitHub.com and GitHub Enterprise Server installations. + * @param encodedSarif - The SARIF content that has been compressed using gzip and encoded to base64 format. + * This encoding is required by GitHub's code-scanning/sarifs API endpoint. + * @param token - GitHub authentication token with appropriate permissions to upload SARIF files. + * Must have 'security_events: write' and 'contents: read' permissions. + * @throws Will throw an error if the HTTP response status is not in the 2xx range or if authentication fails. */ static uploadCodeScanningSarif(encodedSarif, token) { return __awaiter(this, void 0, void 0, function* () { - const octokit = new core_1.Octokit({ auth: token }); - let response; - response = yield octokit.request('POST /repos/{owner}/{repo}/code-scanning/sarifs', { + var _a, _b, _c; + const inputBaseUrl = core.getInput('ghe-base-url', { required: false }) || core.getInput('ghe_base_url', { required: false }) || ''; + const octokit = inputBaseUrl ? github.getOctokit(token, { baseUrl: inputBaseUrl }) : github.getOctokit(token); + const response = yield octokit.request('POST /repos/{owner}/{repo}/code-scanning/sarifs', { owner: github.context.repo.owner, repo: github.context.repo.repo, commit_sha: github.context.sha, @@ -124,7 +128,8 @@ class JobSummary { sarif: encodedSarif, }); if (response.status < 200 || response.status >= 300) { - throw new Error(`Failed to upload SARIF file: ` + JSON.stringify(response)); + const usedBaseUrl = ((_c = (_b = (_a = octokit.request) === null || _a === void 0 ? void 0 : _a.endpoint) === null || _b === void 0 ? void 0 : _b.DEFAULTS) === null || _c === void 0 ? void 0 : _c.baseUrl) || 'unknown'; + throw new Error(`Failed to upload SARIF file (status ${response.status}). baseUrl=${usedBaseUrl}; response=` + JSON.stringify(response)); } core.info('SARIF file uploaded successfully'); }); diff --git a/package-lock.json b/package-lock.json index b0f0b9374..1950b0c9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@jfrog/setup-jfrog-cli", - "version": "4.5.13", + "version": "4.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@jfrog/setup-jfrog-cli", - "version": "4.5.13", + "version": "4.6.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/src/job-summary.ts b/src/job-summary.ts index fe1f47efc..8206446dc 100644 --- a/src/job-summary.ts +++ b/src/job-summary.ts @@ -103,17 +103,23 @@ export class JobSummary { core.warning(`Failed populating code scanning sarif: ${error}`); } } - + /** - * Uploads the code scanning SARIF content to the code-scanning GitHub API. - * @param encodedSarif - The final compressed and encoded sarif content. - * @param token - GitHub token to use for the request. Has to have 'security-events: write' permission. - * @private + * Uploads a SARIF (Static Analysis Results Interchange Format) file to GitHub's code scanning API. + * This method handles the communication with GitHub's REST API to populate the code scanning tab with security analysis results. + * Supports both GitHub.com and GitHub Enterprise Server installations. + * @param encodedSarif - The SARIF content that has been compressed using gzip and encoded to base64 format. + * This encoding is required by GitHub's code-scanning/sarifs API endpoint. + * @param token - GitHub authentication token with appropriate permissions to upload SARIF files. + * Must have 'security_events: write' and 'contents: read' permissions. + * @throws Will throw an error if the HTTP response status is not in the 2xx range or if authentication fails. */ private static async uploadCodeScanningSarif(encodedSarif: string, token: string) { - const octokit: Octokit = new Octokit({ auth: token }); - let response: OctokitResponse | undefined; - response = await octokit.request('POST /repos/{owner}/{repo}/code-scanning/sarifs', { + const inputBaseUrl = core.getInput('ghe-base-url', { required: false }) || core.getInput('ghe_base_url', { required: false }) || ''; + + const octokit = inputBaseUrl ? github.getOctokit(token, { baseUrl: inputBaseUrl }) : github.getOctokit(token); + + const response = await octokit.request('POST /repos/{owner}/{repo}/code-scanning/sarifs', { owner: github.context.repo.owner, repo: github.context.repo.repo, commit_sha: github.context.sha, @@ -122,7 +128,8 @@ export class JobSummary { }); if (response.status < 200 || response.status >= 300) { - throw new Error(`Failed to upload SARIF file: ` + JSON.stringify(response)); + const usedBaseUrl = (octokit as any).request?.endpoint?.DEFAULTS?.baseUrl || 'unknown'; + throw new Error(`Failed to upload SARIF file (status ${response.status}). baseUrl=${usedBaseUrl}; response=` + JSON.stringify(response)); } core.info('SARIF file uploaded successfully'); diff --git a/test/job-summary.sarif.baseurl.spec.ts b/test/job-summary.sarif.baseurl.spec.ts new file mode 100644 index 000000000..f05571a3a --- /dev/null +++ b/test/job-summary.sarif.baseurl.spec.ts @@ -0,0 +1,64 @@ +/** + * test/job-summary.sarif.baseurl.spec.ts + * Checking baseUrl selection when loading SARIF on GHES. + */ + +import * as core from '@actions/core'; + +jest.mock('@actions/github', () => { + const actual = jest.requireActual('@actions/github'); + return { + ...actual, + getOctokit: jest.fn((token: string, opts?: { baseUrl?: string }) => { + const usedBaseUrl = (opts && opts.baseUrl) || process.env.__AUTO_BASE_URL__ || 'https://api.github.com'; + + const req = jest.fn(async (_route: string, _params: any) => { + (global as any).__USED_BASE_URL__ = usedBaseUrl; + return { status: 201, data: {} }; + }) as unknown as any; + + req.endpoint = { DEFAULTS: { baseUrl: usedBaseUrl } }; + + return { request: req } as any; + }), + context: { + repo: { owner: 'o', repo: 'r' }, + sha: 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef', + ref: 'refs/heads/main', + }, + }; +}); + +import { JobSummary } from '../src/job-summary'; + +describe('uploadCodeScanningSarif baseUrl selection (GHES)', () => { + beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + + jest.spyOn(core, 'getInput').mockImplementation((_name: string) => ''); + + delete process.env.__AUTO_BASE_URL__; + delete (global as any).__USED_BASE_URL__; + }); + + it('Should use explicit input ghe-base-url if given', async () => { + (core.getInput as jest.Mock).mockImplementation((name: string) => { + if (name === 'ghe-base-url') return 'https://github.enterprise.local/api/v3'; + if (name === 'ghe_base_url') return ''; + return ''; + }); + + await (JobSummary as any).uploadCodeScanningSarif('eJx4YWJj', 'ghs_token'); + + expect((global as any).__USED_BASE_URL__).toBe('https://github.enterprise.local/api/v3'); + }); + + it('Should falls back to auto GHES baseUrl via @actions/github if input is not specified', async () => { + process.env.__AUTO_BASE_URL__ = 'https://ghe.corp.local/api/v3'; + + await (JobSummary as any).uploadCodeScanningSarif('eJx4YWJj', 'ghs_token'); + + expect((global as any).__USED_BASE_URL__).toBe('https://ghe.corp.local/api/v3'); + }); +});