mirror of
https://github.com/github/codeql-action.git
synced 2026-11-03 19:49:43 +00:00
Compare commits
40 Commits
codeql-bun
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5320e3a8a | ||
|
|
875ac0c36c | ||
|
|
d0468de4ad | ||
|
|
6a39e2e9cd | ||
|
|
7c5ee8eaaf | ||
|
|
1f8cacc390 | ||
|
|
8a05ce6067 | ||
|
|
de3ece651e | ||
|
|
cc88e02cc1 | ||
|
|
7b8e4ced67 | ||
|
|
093c0af4c3 | ||
|
|
30626207b6 | ||
|
|
eb1e5bd7ab | ||
|
|
1fc58d04a4 | ||
|
|
dc4b73f464 | ||
|
|
3b22011a97 | ||
|
|
d9984814e4 | ||
|
|
0d5ac7a9b1 | ||
|
|
39528452cf | ||
|
|
9bc74b13fb | ||
|
|
c050421152 | ||
|
|
750fe8feea | ||
|
|
adfcd5ffb8 | ||
|
|
2ef3b62201 | ||
|
|
b35c6c6aae | ||
|
|
ac9f257611 | ||
|
|
fb9d45340b | ||
|
|
5c1005e0ae | ||
|
|
c29909a87f | ||
|
|
44f1c73c56 | ||
|
|
7def52843a | ||
|
|
774bc191bf | ||
|
|
dc2ed81cc7 | ||
|
|
02283e9542 | ||
|
|
86bc4448d3 | ||
|
|
9c72af5b2b | ||
|
|
929f5c0db4 | ||
|
|
a76419a632 | ||
|
|
071544a67a | ||
|
|
8bdea824e2 |
2
.github/workflows/__unsupported-macos.yml
generated
vendored
2
.github/workflows/__unsupported-macos.yml
generated
vendored
@@ -114,7 +114,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Download workflow artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
pattern: test-mode-sarif-*
|
||||
path: sarif
|
||||
|
||||
7
.github/workflows/update-bundle.yml
vendored
7
.github/workflows/update-bundle.yml
vendored
@@ -113,11 +113,12 @@ jobs:
|
||||
echo "CLI_VERSION=$cli_version" | tee -a "$GITHUB_ENV"
|
||||
echo "PR_URL=$pr_url" | tee -a "$GITHUB_ENV"
|
||||
|
||||
- name: Create changelog note
|
||||
- name: Create changenote
|
||||
run: |
|
||||
npx tsx pr-checks/bundle-changelog.ts
|
||||
|
||||
- name: Push changelog note
|
||||
- name: Push changenote
|
||||
run: |
|
||||
git commit -am "Add changelog note"
|
||||
git add unreleased-change-notes
|
||||
git commit -m "Add changenote"
|
||||
git push
|
||||
|
||||
@@ -6,6 +6,13 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.39.2 - 03 Nov 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.27.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.4). [#4284](https://github.com/github/codeql-action/pull/4284)
|
||||
- _Upcoming breaking change_: CodeQL version 2.22.3 and earlier were discontinued on 16 October 2026 alongside GitHub Enterprise Server 3.18, and will be unsupported by the next minor release of the CodeQL Action. Added a deprecation warning for customers using these versions of CodeQL. [#4266](https://github.com/github/codeql-action/pull/4266)
|
||||
- Starting with macOS 27 and Xcode 27, traced analyses are unsupported. See [this blog post for more information](https://github.blog/changelog/2026-10-19-codeql-changes-for-macos-27-xcode-27-and-swift-6-4/). The CodeQL Action will now try to identify if a workflow is about to perform a traced analysis on version 27 or above of macOS or Xcode. If so, the CodeQL Action will emit a corresponding warning that will also be visible on the [Tool Status Page](https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/manage-your-configuration/use-the-tools-status-page-for-code-scanning). This check will be rolled out following this release of the CodeQL Action. [#4221](https://github.com/github/codeql-action/pull/4221)
|
||||
- The undocumented TRAP cache cleanup feature that could be enabled using the `CODEQL_ACTION_CLEANUP_TRAP_CACHES` environment variable has been removed, as announced in the release notes for CodeQL Action 4.35.2. The `analyze` Action now warns if this environment variable is set. If you used TRAP cache cleanup to limit Actions cache usage, we recommend disabling TRAP caching by passing the `trap-caching: false` input to the `init` Action. [#4243](https://github.com/github/codeql-action/pull/4243)
|
||||
|
||||
## 4.39.1 - 21 Oct 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.27.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.3). [#4256](https://github.com/github/codeql-action/pull/4256)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"bundleVersion": "codeql-bundle-v2.27.3",
|
||||
"cliVersion": "2.27.3",
|
||||
"priorBundleVersion": "codeql-bundle-v2.27.2",
|
||||
"priorCliVersion": "2.27.2"
|
||||
"bundleVersion": "codeql-bundle-v2.27.4",
|
||||
"cliVersion": "2.27.4",
|
||||
"priorBundleVersion": "codeql-bundle-v2.27.3",
|
||||
"priorCliVersion": "2.27.3"
|
||||
}
|
||||
|
||||
612
lib/entry-points.js
generated
612
lib/entry-points.js
generated
File diff suppressed because it is too large
Load Diff
12
package-lock.json
generated
12
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.39.2",
|
||||
"version": "4.39.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codeql",
|
||||
"version": "4.39.2",
|
||||
"version": "4.39.3",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"pr-checks"
|
||||
@@ -33,7 +33,7 @@
|
||||
"js-yaml": "^5.5.0",
|
||||
"jsonschema": "1.5.0",
|
||||
"long": "^5.3.2",
|
||||
"node-forge": "^1.4.0",
|
||||
"node-forge": "^1.4.1",
|
||||
"semver": "^7.8.5",
|
||||
"undici": "^7.30.1",
|
||||
"uuid": "^14.0.3"
|
||||
@@ -8198,9 +8198,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
|
||||
"integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.1.tgz",
|
||||
"integrity": "sha512-w5/MfWaeMrpR/5ba6fZyAUTLSuE6aYz7H/3cYrqwZEmf5eQS3IaaLgJt4MBv7HglGFWmV22K8h4U18RJQmw/ow==",
|
||||
"license": "(BSD-3-Clause OR GPL-2.0)",
|
||||
"engines": {
|
||||
"node": ">= 6.13.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.39.2",
|
||||
"version": "4.39.3",
|
||||
"private": true,
|
||||
"description": "CodeQL action",
|
||||
"scripts": {
|
||||
@@ -42,7 +42,7 @@
|
||||
"js-yaml": "^5.5.0",
|
||||
"jsonschema": "1.5.0",
|
||||
"long": "^5.3.2",
|
||||
"node-forge": "^1.4.0",
|
||||
"node-forge": "^1.4.1",
|
||||
"semver": "^7.8.5",
|
||||
"undici": "^7.30.1",
|
||||
"uuid": "^14.0.3"
|
||||
|
||||
@@ -10,17 +10,13 @@ import { afterEach, beforeEach, describe, it } from "node:test";
|
||||
|
||||
import {
|
||||
CLI_VERSION_ENV_VAR,
|
||||
getChangenote,
|
||||
getCLIVersion,
|
||||
getPRNumber,
|
||||
getPRUrl,
|
||||
PR_URL_ENV_VAR,
|
||||
updateChangelog,
|
||||
} from "./bundle-changelog";
|
||||
import {
|
||||
EMPTY_CHANGELOG,
|
||||
NO_CHANGES_STR,
|
||||
UNRELEASED_PLACEHOLDER,
|
||||
} from "./changelog";
|
||||
import { isValidChangenoteContent } from "./changelog/validate";
|
||||
|
||||
let testDir: string;
|
||||
|
||||
@@ -85,58 +81,15 @@ describe("getPRNumber", async () => {
|
||||
});
|
||||
});
|
||||
|
||||
const testChangelog = `${EMPTY_CHANGELOG.trimEnd()}
|
||||
|
||||
## 4.23.7
|
||||
|
||||
- Other change
|
||||
|
||||
## 4.23.6
|
||||
|
||||
${NO_CHANGES_STR}`;
|
||||
|
||||
const expectedChangelog = `# CodeQL Action Changelog
|
||||
|
||||
## ${UNRELEASED_PLACEHOLDER}
|
||||
|
||||
- Update default CodeQL bundle version to
|
||||
|
||||
## 4.23.7
|
||||
|
||||
- Other change
|
||||
|
||||
## 4.23.6
|
||||
|
||||
${NO_CHANGES_STR}`;
|
||||
|
||||
describe("updateChangelog", async () => {
|
||||
await it("removes `NO_CHANGES_STR` if present in [UNRELEASED] section", async () => {
|
||||
const result = updateChangelog(EMPTY_CHANGELOG, "");
|
||||
assert.ok(!result.includes(NO_CHANGES_STR));
|
||||
});
|
||||
|
||||
await it("doesn't remove `NO_CHANGES_STR` if present in versioned section", async () => {
|
||||
const result = updateChangelog(
|
||||
EMPTY_CHANGELOG.replace(UNRELEASED_PLACEHOLDER, "1.2.3"),
|
||||
"",
|
||||
describe("getChangenote", async () => {
|
||||
await it("returns a note linking to the bundle release and the PR", async () => {
|
||||
assert.equal(
|
||||
getChangenote("1.2.3", testPrUrl),
|
||||
"- Update default CodeQL bundle version to [1.2.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v1.2.3). [#42](https://github.com/github/codeql-action/pulls/42)\n",
|
||||
);
|
||||
assert.ok(result.includes(NO_CHANGES_STR));
|
||||
});
|
||||
|
||||
await it("throws if there are no sections", async () => {
|
||||
assert.throws(() => {
|
||||
updateChangelog(
|
||||
"# CodeQL Action Changelog",
|
||||
"- Update default CodeQL bundle version to",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
await it("adds note at the end of the first section", async () => {
|
||||
const result = updateChangelog(
|
||||
testChangelog,
|
||||
"- Update default CodeQL bundle version to",
|
||||
);
|
||||
assert.deepEqual(result, expectedChangelog);
|
||||
await it("returns valid changenote content", async () => {
|
||||
assert.ok(isValidChangenoteContent(getChangenote("1.2.3", testPrUrl)));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
/**
|
||||
* Updates the changelog with a change note for an updated CodeQL CLI bundle.
|
||||
* Creates a changenote file for an update to the default CodeQL CLI bundle.
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
import {
|
||||
parseChangelog,
|
||||
renderChangelog,
|
||||
UNRELEASED_PLACEHOLDER,
|
||||
} from "./changelog";
|
||||
import { CHANGELOG_FILE, CLI_BUNDLE_RELEASE_URL_PREFIX } from "./config";
|
||||
import { CHANGENOTES_DIR, CLI_BUNDLE_RELEASE_URL_PREFIX } from "./config";
|
||||
import { getErrorMessage } from "./util";
|
||||
|
||||
export const CLI_VERSION_ENV_VAR = "CLI_VERSION";
|
||||
@@ -58,42 +54,19 @@ export function getPRNumber(prUrl: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates `changelog` by adding `changelogNote` to the first section.
|
||||
* Returns the contents of the changenote file for an update to the default
|
||||
* CodeQL CLI bundle.
|
||||
*
|
||||
* @param contents The existing changelog contents.
|
||||
* @param changelogNote The note to add to the first section.
|
||||
* @param cliVersion The CodeQL CLI version of the new default bundle.
|
||||
* @param prUrl The URL of the PR that updates the default bundle.
|
||||
* @throws If the PR number can't be determined from `prUrl`.
|
||||
*/
|
||||
export function updateChangelog(contents: string, changelogNote: string) {
|
||||
// If the "[UNRELEASED]" section starts with "no user facing changes", remove that line.
|
||||
contents = contents.replace(
|
||||
`## ${UNRELEASED_PLACEHOLDER}\n\nNo user facing changes.`,
|
||||
`## ${UNRELEASED_PLACEHOLDER}\n`,
|
||||
);
|
||||
export function getChangenote(cliVersion: string, prUrl: string): string {
|
||||
// The GitHub Release for the new bundle version.
|
||||
const bundleReleaseUrl = `${CLI_BUNDLE_RELEASE_URL_PREFIX}${cliVersion}`;
|
||||
|
||||
const changelog = parseChangelog(contents);
|
||||
|
||||
if (changelog.sections.length === 0) {
|
||||
throw new Error("The changelog contains no existing sections.");
|
||||
}
|
||||
|
||||
// Add the changelog note to the bottom of the first section.
|
||||
const firstSection = changelog.sections[0];
|
||||
const lastLine = firstSection.bodyLines.pop();
|
||||
|
||||
if (lastLine !== undefined && lastLine.trim() !== "") {
|
||||
// We expect the last line to be empty. If it isn't for some reason,
|
||||
// add it back.
|
||||
firstSection.bodyLines.push(lastLine);
|
||||
}
|
||||
|
||||
firstSection.bodyLines.push(changelogNote);
|
||||
|
||||
// If the last line is empty as expected, then add it back in after the new note.
|
||||
if (lastLine?.trim() === "") {
|
||||
firstSection.bodyLines.push(lastLine);
|
||||
}
|
||||
|
||||
return renderChangelog(changelog);
|
||||
const prNumber = getPRNumber(prUrl);
|
||||
return `- Update default CodeQL bundle version to [${cliVersion}](${bundleReleaseUrl}). [#${prNumber}](${prUrl})\n`;
|
||||
}
|
||||
|
||||
function main() {
|
||||
@@ -101,22 +74,19 @@ function main() {
|
||||
const cliVersion = getCLIVersion();
|
||||
const prUrl = getPRUrl();
|
||||
|
||||
// The GitHub Release for the new bundle version.
|
||||
const bundleReleaseUrl = `${CLI_BUNDLE_RELEASE_URL_PREFIX}${cliVersion}`;
|
||||
|
||||
// Get the PR number from the PR URL.
|
||||
const prNumber = getPRNumber(prUrl);
|
||||
const changelogNote = `- Update default CodeQL bundle version to [${cliVersion}](${bundleReleaseUrl}). [#${prNumber}](${prUrl})`;
|
||||
|
||||
let changelog = fs.readFileSync(CHANGELOG_FILE, "utf-8");
|
||||
|
||||
changelog = updateChangelog(changelog, changelogNote);
|
||||
|
||||
fs.writeFileSync(CHANGELOG_FILE, changelog);
|
||||
// Include the CLI version in the file name so that changenotes for
|
||||
// different bundle updates don't conflict.
|
||||
const changenotePath = path.join(
|
||||
CHANGENOTES_DIR,
|
||||
`update-bundle-${cliVersion}.md`,
|
||||
);
|
||||
fs.writeFileSync(changenotePath, getChangenote(cliVersion, prUrl));
|
||||
|
||||
return 0;
|
||||
} catch (err) {
|
||||
console.error(`Failed to bundle changelog: ${getErrorMessage(err)}`);
|
||||
console.error(
|
||||
`Failed to create changenote for bundle update: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ validationJobs:
|
||||
installNode: true
|
||||
steps:
|
||||
- name: Download workflow artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
pattern: test-mode-sarif-*
|
||||
path: sarif
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"@octokit/core": "^7.0.8",
|
||||
"@octokit/plugin-paginate-rest": ">=16.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
|
||||
"glob": "^13.0.6",
|
||||
"glob": "^14.0.3",
|
||||
"lite-matter": "^0.1.2",
|
||||
"mdast-util-from-markdown": "^2.1.0",
|
||||
"semver": "^7.8.5",
|
||||
|
||||
@@ -56,9 +56,18 @@ jobs:
|
||||
|
||||
const result = scanGeneratedWorkflows(workflowDir);
|
||||
|
||||
assert.equal(result["actions/checkout"], "v4");
|
||||
assert.equal(result["actions/setup-node"], "v5");
|
||||
assert.equal(result["actions/setup-go"], "v6");
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/checkout"],
|
||||
new Set(["v4"]),
|
||||
);
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/setup-node"],
|
||||
new Set(["v5"]),
|
||||
);
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/setup-go"],
|
||||
new Set(["v6"]),
|
||||
);
|
||||
});
|
||||
|
||||
await it("scanning workflows with version comments", () => {
|
||||
@@ -78,12 +87,18 @@ jobs:
|
||||
|
||||
const result = scanGeneratedWorkflows(workflowDir);
|
||||
|
||||
assert.equal(result["actions/checkout"], "v4");
|
||||
assert.equal(
|
||||
result["ruby/setup-ruby"],
|
||||
"44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0",
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/checkout"],
|
||||
new Set(["v4"]),
|
||||
);
|
||||
assert.deepEqual(
|
||||
result.actionVersions["ruby/setup-ruby"],
|
||||
new Set(["44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0"]),
|
||||
);
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/setup-python"],
|
||||
new Set(["v6 # Latest Python"]),
|
||||
);
|
||||
assert.equal(result["actions/setup-python"], "v6 # Latest Python");
|
||||
});
|
||||
|
||||
await it("ignores local actions", () => {
|
||||
@@ -103,9 +118,15 @@ jobs:
|
||||
|
||||
const result = scanGeneratedWorkflows(workflowDir);
|
||||
|
||||
assert.equal(result["actions/checkout"], "v4");
|
||||
assert.equal("./.github/actions/local-action" in result, false);
|
||||
assert.equal("./another-local-action" in result, false);
|
||||
assert.deepEqual(
|
||||
result.actionVersions["actions/checkout"],
|
||||
new Set(["v4"]),
|
||||
);
|
||||
assert.equal(
|
||||
"./.github/actions/local-action" in result.actionVersions,
|
||||
false,
|
||||
);
|
||||
assert.equal("./another-local-action" in result.actionVersions, false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -128,8 +149,8 @@ const steps = [
|
||||
fs.writeFileSync(syncTsPath, syncTsContent);
|
||||
|
||||
const actionVersions = {
|
||||
"actions/setup-node": "v5",
|
||||
"actions/setup-go": "v6",
|
||||
"actions/setup-node": new Set(["v5"]),
|
||||
"actions/setup-go": new Set(["v6"]),
|
||||
};
|
||||
|
||||
const result = updateSyncTs(syncTsPath, actionVersions);
|
||||
@@ -155,7 +176,7 @@ const steps = [
|
||||
fs.writeFileSync(syncTsPath, syncTsContent);
|
||||
|
||||
const actionVersions = {
|
||||
"actions/setup-node": "v5 # Latest version",
|
||||
"actions/setup-node": new Set(["v5 # Latest version"]),
|
||||
};
|
||||
|
||||
const result = updateSyncTs(syncTsPath, actionVersions);
|
||||
@@ -182,7 +203,7 @@ const steps = [
|
||||
fs.writeFileSync(syncTsPath, syncTsContent);
|
||||
|
||||
const actionVersions = {
|
||||
"actions/setup-node": "v5",
|
||||
"actions/setup-node": new Set(["v5"]),
|
||||
};
|
||||
|
||||
const result = updateSyncTs(syncTsPath, actionVersions);
|
||||
@@ -206,7 +227,9 @@ const steps = [
|
||||
fs.writeFileSync(syncTsPath, syncTsContent);
|
||||
|
||||
const actionVersions = {
|
||||
"actions/setup-node": "48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0",
|
||||
"actions/setup-node": new Set([
|
||||
"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0",
|
||||
]),
|
||||
};
|
||||
|
||||
const result = updateSyncTs(syncTsPath, actionVersions);
|
||||
@@ -244,8 +267,9 @@ steps:
|
||||
"actions/checkout": "v4",
|
||||
"actions/setup-node": "v5 # Latest",
|
||||
};
|
||||
const byWorkflow = { ["test.yml"]: actionVersions };
|
||||
|
||||
const result = updateTemplateFiles(checksDir, actionVersions);
|
||||
const result = updateTemplateFiles(checksDir, byWorkflow);
|
||||
assert.equal(result.length, 1);
|
||||
assert.ok(result.includes(templatePath));
|
||||
|
||||
@@ -269,8 +293,9 @@ steps:
|
||||
const actionVersions = {
|
||||
"ruby/setup-ruby": "55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0",
|
||||
};
|
||||
const byWorkflow = { ["test.yml"]: actionVersions };
|
||||
|
||||
const result = updateTemplateFiles(checksDir, actionVersions);
|
||||
const result = updateTemplateFiles(checksDir, byWorkflow);
|
||||
assert.equal(result.length, 1);
|
||||
|
||||
const updatedContent = fs.readFileSync(templatePath, "utf8");
|
||||
|
||||
@@ -27,16 +27,39 @@ const CHECKS_DIR = path.join(PR_CHECKS_DIR, "checks");
|
||||
const WORKFLOW_DIR = path.join(REPO_ROOT, ".github", "workflows");
|
||||
const SYNC_TS_PATH = path.join(PR_CHECKS_DIR, "sync.ts");
|
||||
|
||||
/** Type alias for action names. */
|
||||
type ActionName = string;
|
||||
|
||||
/** Type alias for action versions. May include a comment. */
|
||||
type ActionVersion = string;
|
||||
|
||||
/** Mappings of {@link ActionName}s to {@link ActionVersion}s. */
|
||||
type ActionVersions = Record<ActionName, ActionVersion>;
|
||||
|
||||
/** Mappings of workflow names to {@link ActionVersions}. */
|
||||
type ActionVersionsByWorkflow = Record<string, ActionVersions>;
|
||||
|
||||
/** The result of {@link scanGeneratedWorkflows}. */
|
||||
type ScanWorkflowResult = {
|
||||
/** A mapping of {@link ActionName}s to all encountered {@link ActionVersion}s. */
|
||||
actionVersions: Record<ActionName, Set<ActionVersion>>;
|
||||
|
||||
/** A mapping of workflow names to {@link ActionVersions}. */
|
||||
actionVersionsByWorkflow: ActionVersionsByWorkflow;
|
||||
};
|
||||
|
||||
/**
|
||||
* Scan generated workflow files to extract the latest action versions.
|
||||
*
|
||||
* @param workflowDir - Path to .github/workflows directory
|
||||
* @returns Map from action names to their latest versions (including comments)
|
||||
*
|
||||
* @returns A {@link ScanWorkflowResult} object containing information about the extracted action versions.
|
||||
*/
|
||||
export function scanGeneratedWorkflows(
|
||||
workflowDir: string,
|
||||
): Record<string, string> {
|
||||
const actionVersions: Record<string, string> = {};
|
||||
): ScanWorkflowResult {
|
||||
const actionVersionsByWorkflow: ActionVersionsByWorkflow = {};
|
||||
const actionVersions: Record<ActionName, Set<ActionVersion>> = {};
|
||||
|
||||
const generatedFiles = fs
|
||||
.readdirSync(workflowDir)
|
||||
@@ -46,6 +69,10 @@ export function scanGeneratedWorkflows(
|
||||
for (const filePath of generatedFiles) {
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
// Get the basename of the workflow and drop the leading `__` from it.
|
||||
const workflowName = path.basename(filePath).slice(2);
|
||||
actionVersionsByWorkflow[workflowName] = {};
|
||||
|
||||
// Find all action uses in the file, including potential comments
|
||||
// This pattern captures: action_name@version_with_possible_comment
|
||||
const pattern = /uses:\s+([^/\s]+\/[^@\s]+)@([^@\n]+)/g;
|
||||
@@ -57,13 +84,26 @@ export function scanGeneratedWorkflows(
|
||||
|
||||
// Only track non-local actions (those with / but not starting with ./)
|
||||
if (!actionName.startsWith("./")) {
|
||||
// Assume that version numbers are consistent (this should be the case on a Dependabot update PR)
|
||||
actionVersions[actionName] = versionWithComment;
|
||||
// Record the version of the action for this workflow.
|
||||
actionVersionsByWorkflow[workflowName][actionName] = versionWithComment;
|
||||
|
||||
// Record this version for the action so that we can write it to `sync.ts` if needed.
|
||||
// Usually we'd expect there to be exactly one version per action across all workflows,
|
||||
// but sometimes these can go out-of-sync if e.g. a workflow is added in a branch and a
|
||||
// Dependabot PR is merged in the meantime that changes the version of an action that is
|
||||
// used in the new workflow. Different versions of the same action across different
|
||||
// workflows is not fundamentally a problem, but we may need to pick one for `sync.ts`
|
||||
// so we warn there if we have multiple versions of an action.
|
||||
if (actionVersions[actionName] === undefined) {
|
||||
actionVersions[actionName] = new Set([versionWithComment]);
|
||||
} else if (!actionVersions[actionName].has(versionWithComment)) {
|
||||
actionVersions[actionName].add(versionWithComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actionVersions;
|
||||
return { actionVersions, actionVersionsByWorkflow };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +119,7 @@ export function scanGeneratedWorkflows(
|
||||
*/
|
||||
export function updateSyncTs(
|
||||
syncTsPath: string,
|
||||
actionVersions: Record<string, string>,
|
||||
actionVersions: Record<ActionName, Set<ActionVersion>>,
|
||||
): boolean {
|
||||
if (!fs.existsSync(syncTsPath)) {
|
||||
throw new Error(`Could not find ${syncTsPath}`);
|
||||
@@ -89,9 +129,18 @@ export function updateSyncTs(
|
||||
const originalContent = content;
|
||||
|
||||
// Update hardcoded action versions
|
||||
for (const [actionName, versionWithComment] of Object.entries(
|
||||
for (const [actionName, versionsWithComments] of Object.entries(
|
||||
actionVersions,
|
||||
)) {
|
||||
// We usually expect `versionsWithComments` to contain one version. If there are multiple,
|
||||
// we arbitrarily pick one and warn about it.
|
||||
const versionsWithCommentsArray = Array.from(versionsWithComments);
|
||||
const versionWithComment = versionsWithCommentsArray[0];
|
||||
if (versionsWithComments.size > 1) {
|
||||
console.warn(
|
||||
`Inconsistent versions for ${actionName}. Arbitrarily picking '${versionWithComment}'. All found: ${versionsWithCommentsArray.join(", ")}`,
|
||||
);
|
||||
}
|
||||
// Split the scanned value into the ref (e.g. a commit SHA) and the optional
|
||||
// trailing version comment (e.g. `v6.0.3`).
|
||||
const ref = versionWithComment.includes("#")
|
||||
@@ -138,12 +187,12 @@ export function updateSyncTs(
|
||||
* Update action versions in template files in pr-checks/checks/
|
||||
*
|
||||
* @param checksDir - Path to pr-checks/checks directory
|
||||
* @param actionVersions - Map of action names to versions (may include comments)
|
||||
* @param actionVersionsByWorkflow - Map of workflows to maps of action names to versions (may include comments)
|
||||
* @returns List of files that were modified
|
||||
*/
|
||||
export function updateTemplateFiles(
|
||||
checksDir: string,
|
||||
actionVersions: Record<string, string>,
|
||||
actionVersionsByWorkflow: ActionVersionsByWorkflow,
|
||||
): string[] {
|
||||
const modifiedFiles: string[] = [];
|
||||
|
||||
@@ -156,6 +205,16 @@ export function updateTemplateFiles(
|
||||
let content = fs.readFileSync(filePath, "utf8");
|
||||
const originalContent = content;
|
||||
|
||||
const workflowName = path.basename(filePath);
|
||||
const actionVersions = actionVersionsByWorkflow[workflowName];
|
||||
|
||||
if (actionVersions === undefined) {
|
||||
console.info(
|
||||
`Found no action versions for workflow template '${filePath}'.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Update action versions
|
||||
for (const [actionName, versionWithComment] of Object.entries(
|
||||
actionVersions,
|
||||
@@ -191,12 +250,15 @@ function main(): number {
|
||||
const verbose = values.verbose ?? false;
|
||||
|
||||
console.info("Scanning generated workflows for latest action versions...");
|
||||
const actionVersions = scanGeneratedWorkflows(WORKFLOW_DIR);
|
||||
const { actionVersions, actionVersionsByWorkflow } =
|
||||
scanGeneratedWorkflows(WORKFLOW_DIR);
|
||||
|
||||
if (verbose) {
|
||||
console.info("Found action versions:");
|
||||
for (const [action, version] of Object.entries(actionVersions)) {
|
||||
console.info(` ${action}@${version}`);
|
||||
for (const [action, versions] of Object.entries(actionVersions)) {
|
||||
for (const version of versions) {
|
||||
console.info(` ${action}@${version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +277,10 @@ function main(): number {
|
||||
}
|
||||
|
||||
// Update template files
|
||||
const templateModified = updateTemplateFiles(CHECKS_DIR, actionVersions);
|
||||
const templateModified = updateTemplateFiles(
|
||||
CHECKS_DIR,
|
||||
actionVersionsByWorkflow,
|
||||
);
|
||||
modifiedFiles.push(...templateModified);
|
||||
|
||||
if (modifiedFiles.length > 0) {
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
} from "./actions-util";
|
||||
import { computeAutomationID } from "./api-client";
|
||||
import { EnvVar } from "./environment";
|
||||
import { RecordingLogger, setupTests } from "./testing-utils";
|
||||
import { initializeEnvironment, withTmpDir } from "./util";
|
||||
import { getTestEnv, RecordingLogger, setupTests } from "./testing-utils";
|
||||
import { withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
@@ -227,8 +227,9 @@ test.serial(
|
||||
);
|
||||
|
||||
test.serial("initializeEnvironment", (t) => {
|
||||
initializeEnvironment("1.2.3");
|
||||
t.deepEqual(process.env[EnvVar.VERSION], "1.2.3");
|
||||
const env = getTestEnv();
|
||||
env.initialise("1.2.3");
|
||||
t.deepEqual(env.getOptional(EnvVar.VERSION), "1.2.3");
|
||||
});
|
||||
|
||||
test.serial("fixCodeQualityCategory", (t) => {
|
||||
|
||||
@@ -233,7 +233,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
|
||||
let databaseUploadResults: DatabaseUploadResult[] = [];
|
||||
|
||||
try {
|
||||
util.initializeEnvironment(actionsUtil.getActionVersion());
|
||||
action.env.initialise(actionsUtil.getActionVersion());
|
||||
|
||||
// Make inputs accessible in the `post` step, details at
|
||||
// https://github.com/github/codeql-action/issues/2553
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ProxyAgent } from "undici";
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
import { DO_NOT_RETRY_STATUSES } from "./api-client";
|
||||
import { ActionsEnvVars, RegistryProxyVars } from "./environment";
|
||||
import { ActionsEnvVars, RegistryProxyVars, getEnv } from "./environment";
|
||||
import { GITHUB_DOTCOM_API_URL, GITHUB_DOTCOM_URL } from "./github";
|
||||
import {
|
||||
callee,
|
||||
@@ -21,7 +21,7 @@ import * as util from "./util";
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
util.initializeEnvironment(actionsUtil.getActionVersion());
|
||||
getEnv().initialise(actionsUtil.getActionVersion());
|
||||
});
|
||||
|
||||
test.serial("getApiClient", async (t) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getGitHubVersion } from "./api-client";
|
||||
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
|
||||
import { getCodeQL } from "./codeql";
|
||||
import { Config, getConfig } from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { EnvVar, type Env } from "./environment";
|
||||
import { Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
checkDiskUsage,
|
||||
checkGitHubVersionInRange,
|
||||
ConfigurationError,
|
||||
initializeEnvironment,
|
||||
wrapError,
|
||||
} from "./util";
|
||||
|
||||
@@ -38,6 +37,7 @@ interface AutobuildStatusReport extends StatusReportBase {
|
||||
}
|
||||
|
||||
async function sendCompletedStatusReport(
|
||||
env: Env,
|
||||
config: Config | undefined,
|
||||
logger: Logger,
|
||||
startedAt: Date,
|
||||
@@ -45,7 +45,7 @@ async function sendCompletedStatusReport(
|
||||
failingLanguage?: string,
|
||||
cause?: Error,
|
||||
) {
|
||||
initializeEnvironment(getActionVersion());
|
||||
env.initialise(getActionVersion());
|
||||
|
||||
const status = getActionsStatus(cause, failingLanguage);
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
@@ -129,6 +129,7 @@ async function run({
|
||||
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`,
|
||||
);
|
||||
await sendCompletedStatusReport(
|
||||
env,
|
||||
config,
|
||||
logger,
|
||||
startedAt,
|
||||
@@ -141,7 +142,13 @@ async function run({
|
||||
|
||||
env.export(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
|
||||
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
||||
await sendCompletedStatusReport(
|
||||
env,
|
||||
config,
|
||||
logger,
|
||||
startedAt,
|
||||
languages ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
/** Defines the `autobuild` Action. */
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import type { Config } from "./config-utils";
|
||||
import * as defaults from "./defaults.json";
|
||||
import { DocUrl } from "./doc-url";
|
||||
import { getEnv } from "./environment";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
import { ToolsSource } from "./setup-codeql";
|
||||
import {
|
||||
@@ -38,14 +39,13 @@ import {
|
||||
} from "./testing-utils";
|
||||
import { ToolsDownloadStatusReport } from "./tools-download";
|
||||
import * as util from "./util";
|
||||
import { initializeEnvironment } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
let stubConfig: Config;
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
|
||||
stubConfig = createTestConfig({
|
||||
languages: [BuiltInLanguage.cpp],
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as path from "path";
|
||||
import * as core from "@actions/core";
|
||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||
import * as yaml from "js-yaml";
|
||||
import * as semver from "semver";
|
||||
|
||||
import {
|
||||
CommandInvocationError,
|
||||
@@ -19,6 +20,7 @@ import type { ActionConfig } from "./config/action-config";
|
||||
import { appendExtraQueryExclusions, type Config } from "./config-utils";
|
||||
import { DocUrl } from "./doc-url";
|
||||
import { EnvVar, getEnv, Env, ReadOnlyEnv } from "./environment";
|
||||
import { getErrorMessage, isDiskConfigurationError } from "./errors";
|
||||
import {
|
||||
CodeQLDefaultVersionInfo,
|
||||
Feature,
|
||||
@@ -34,7 +36,9 @@ import { ToolsDownloadStatusReport } from "./tools-download";
|
||||
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
|
||||
import { shouldEnableIndirectTracing } from "./tracer-config";
|
||||
import * as util from "./util";
|
||||
import { BuildMode, CleanupLevel, getErrorMessage } from "./util";
|
||||
import { BuildMode, CleanupLevel } from "./util";
|
||||
|
||||
export { isDiskConfigurationError } from "./errors";
|
||||
|
||||
type Options = Array<string | number | boolean>;
|
||||
|
||||
@@ -70,6 +74,11 @@ export interface CodeQL {
|
||||
* Get a string containing the semver version of the CodeQL executable.
|
||||
*/
|
||||
getVersion(): Promise<VersionInfo>;
|
||||
/**
|
||||
* Determines whether the CLI installation represented by this {@link CodeQL} instance
|
||||
* has at least the {@link requiredVersion}.
|
||||
*/
|
||||
isVersionAtLeast(requiredVersion: string): Promise<boolean>;
|
||||
/**
|
||||
* Print version information about CodeQL.
|
||||
*/
|
||||
@@ -275,26 +284,6 @@ const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-10-16";
|
||||
/** The CLI verbosity level to use for extraction in debug mode. */
|
||||
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
|
||||
|
||||
/**
|
||||
* Decides whether `e` is a disk-related error outside of our control
|
||||
* that should be classified as a `ConfigurationError`.
|
||||
*
|
||||
* @param e The error to check.
|
||||
* @returns True if the error should be treated as a `ConfigurationError` or false if not.
|
||||
*/
|
||||
export function isDiskConfigurationError(e: unknown): boolean {
|
||||
if (!(e instanceof Error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
// out of disk space
|
||||
e.message.includes("ENOSPC") ||
|
||||
// access denied
|
||||
e.message.includes("EACCES")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up CodeQL CLI access.
|
||||
*
|
||||
@@ -403,9 +392,9 @@ export function setCodeQL(codeql: Partial<CodeQL>): void {
|
||||
cachedCodeQL = createStubCodeQL(codeql);
|
||||
}
|
||||
|
||||
function resolveFunction<T>(
|
||||
function resolveFunction<K extends keyof CodeQL, T extends CodeQL[K]>(
|
||||
partialCodeql: Partial<CodeQL>,
|
||||
methodName: string,
|
||||
methodName: K,
|
||||
defaultImplementation?: T,
|
||||
): T {
|
||||
if (typeof partialCodeql[methodName] !== "function") {
|
||||
@@ -415,7 +404,7 @@ function resolveFunction<T>(
|
||||
const dummyMethod = () => {
|
||||
throw new Error(`CodeQL ${methodName} method not correctly defined`);
|
||||
};
|
||||
return dummyMethod as T;
|
||||
return dummyMethod as unknown as T;
|
||||
}
|
||||
return partialCodeql[methodName] as T;
|
||||
}
|
||||
@@ -432,6 +421,19 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
||||
getVersion: resolveFunction(partialCodeql, "getVersion", async () => ({
|
||||
version: "1.0.0",
|
||||
})),
|
||||
isVersionAtLeast: resolveFunction(
|
||||
partialCodeql,
|
||||
"isVersionAtLeast",
|
||||
async (requiredVersion) => {
|
||||
return (
|
||||
!!partialCodeql.getVersion &&
|
||||
semver.gte(
|
||||
(await partialCodeql.getVersion()).version,
|
||||
requiredVersion,
|
||||
)
|
||||
);
|
||||
},
|
||||
),
|
||||
printVersion: resolveFunction(partialCodeql, "printVersion"),
|
||||
supportsFeature: resolveFunction(
|
||||
partialCodeql,
|
||||
@@ -525,6 +527,9 @@ export async function getCodeQLForCmd(
|
||||
}
|
||||
return result;
|
||||
},
|
||||
async isVersionAtLeast(requiredVersion: string) {
|
||||
return semver.gte((await this.getVersion()).version, requiredVersion);
|
||||
},
|
||||
async printVersion() {
|
||||
// Reuse the cached version information rather than invoking the CLI again.
|
||||
core.info(JSON.stringify(await this.getVersion(), null, 2));
|
||||
@@ -1062,7 +1067,7 @@ export async function getCodeQLForCmd(
|
||||
// CodeQL object is created.
|
||||
if (
|
||||
checkVersion &&
|
||||
!(await util.codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION))
|
||||
!(await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION))
|
||||
) {
|
||||
throw new util.ConfigurationError(
|
||||
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${
|
||||
@@ -1072,7 +1077,7 @@ export async function getCodeQLForCmd(
|
||||
} else if (
|
||||
checkVersion &&
|
||||
env.getOptional(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING) !== "true" &&
|
||||
!(await util.codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION))
|
||||
!(await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION))
|
||||
) {
|
||||
const result = await codeql.getVersion();
|
||||
core.warning(
|
||||
|
||||
@@ -82,7 +82,6 @@ import {
|
||||
GitHubVersion,
|
||||
ConfigurationError,
|
||||
BuildMode,
|
||||
codeQlVersionAtLeast,
|
||||
cloneObject,
|
||||
isDefined,
|
||||
checkDiskUsage,
|
||||
@@ -654,10 +653,7 @@ async function runnerHasSufficientMemory(
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
if (
|
||||
await codeQlVersionAtLeast(
|
||||
codeql,
|
||||
CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE,
|
||||
)
|
||||
await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE)
|
||||
) {
|
||||
logger.debug(
|
||||
`Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.`,
|
||||
@@ -901,7 +897,7 @@ async function validateOverlayDatabaseMode(
|
||||
);
|
||||
return new Failure(OverlayDisabledReason.IncompatibleBuildMode);
|
||||
}
|
||||
if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) {
|
||||
if (!(await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION))) {
|
||||
logger.warning(
|
||||
`Cannot build an ${overlayDatabaseMode} database because ` +
|
||||
`the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` +
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
cleanupAndUploadDatabases,
|
||||
uploadBundledDatabase,
|
||||
} from "./database-upload";
|
||||
import { getEnv } from "./environment";
|
||||
import { Feature } from "./feature-flags";
|
||||
import * as gitUtils from "./git-utils";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
@@ -31,18 +32,12 @@ import {
|
||||
setupActionsVars,
|
||||
setupTests,
|
||||
} from "./testing-utils";
|
||||
import {
|
||||
CleanupLevel,
|
||||
GitHubVariant,
|
||||
HTTPError,
|
||||
initializeEnvironment,
|
||||
withTmpDir,
|
||||
} from "./util";
|
||||
import { CleanupLevel, GitHubVariant, HTTPError, withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
});
|
||||
|
||||
const testRepoName: RepositoryNwo = { owner: "github", repo: "example" };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"bundleVersion": "codeql-bundle-v2.27.3",
|
||||
"cliVersion": "2.27.3",
|
||||
"priorBundleVersion": "codeql-bundle-v2.27.2",
|
||||
"priorCliVersion": "2.27.2"
|
||||
"bundleVersion": "codeql-bundle-v2.27.4",
|
||||
"cliVersion": "2.27.4",
|
||||
"priorBundleVersion": "codeql-bundle-v2.27.3",
|
||||
"priorCliVersion": "2.27.3"
|
||||
}
|
||||
|
||||
@@ -397,6 +397,18 @@ export class Env extends ReadOnlyEnv {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set some initial environment variables that we can set even without
|
||||
* knowing what version of CodeQL we're running.
|
||||
*/
|
||||
public initialise(version: string) {
|
||||
this.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
this.export(EnvVar.FEATURE_SANDWICH, "false");
|
||||
this.export(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
this.export(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
this.export(EnvVar.VERSION, version);
|
||||
}
|
||||
|
||||
/** Gets a value indicating whether `set` was called at least once. */
|
||||
public hasChanged(): boolean {
|
||||
return this.changed;
|
||||
|
||||
88
src/errors/index.ts
Normal file
88
src/errors/index.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import * as json from "../json";
|
||||
|
||||
/**
|
||||
* If {@link error} is not already an instance of {@link Error}, then this function constructs
|
||||
* an {@link Error} with a string representation of {@link error} as the message.
|
||||
*/
|
||||
export function wrapError(error: unknown): Error {
|
||||
return error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriate message for the error.
|
||||
*
|
||||
* If the error is an {@link Error} instance, this returns the error message without
|
||||
* an `Error: ` prefix.
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approximates whether {@link error} is like a {@link NodeJS.ErrnoException}.
|
||||
* We only typically care about the `code` property, so that's what we check for here.
|
||||
*/
|
||||
export function isErrnoException(
|
||||
error: unknown,
|
||||
): error is NodeJS.ErrnoException {
|
||||
return (
|
||||
typeof error === "object" &&
|
||||
error !== null &&
|
||||
"code" in error &&
|
||||
typeof error.code === "string"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether `e` is a disk-related error outside of our control
|
||||
* that should be classified as a `ConfigurationError`.
|
||||
*
|
||||
* @param e The error to check.
|
||||
* @returns True if the error should be treated as a `ConfigurationError` or false if not.
|
||||
*/
|
||||
export function isDiskConfigurationError(e: unknown): boolean {
|
||||
if (!(e instanceof Error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
// out of disk space
|
||||
e.message.includes("ENOSPC") ||
|
||||
// access denied
|
||||
e.message.includes("EACCES")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error class that indicates an error that occurred due to
|
||||
* a misconfiguration of the action or the CodeQL CLI.
|
||||
*/
|
||||
export class ConfigurationError extends Error {}
|
||||
|
||||
/** Minimal representation of errors resulting from HTTP requests. */
|
||||
export class HTTPError extends Error {
|
||||
public status: number;
|
||||
|
||||
constructor(message: string, status: number) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to convert {@link arg} to a {@link HTTPError}, but returns `undefined` if
|
||||
* {@link arg} is not like a {@link HTTPError}.
|
||||
*/
|
||||
export function asHTTPError(arg: any): HTTPError | undefined {
|
||||
if (!json.isObject<any>(arg) || !json.isString(arg.message)) {
|
||||
return undefined;
|
||||
}
|
||||
if (Number.isInteger(arg.status)) {
|
||||
return new HTTPError(arg.message, arg.status as number);
|
||||
}
|
||||
// See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19
|
||||
if (Number.isInteger(arg.httpStatusCode)) {
|
||||
return new HTTPError(arg.message, arg.httpStatusCode as number);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import * as path from "path";
|
||||
import test from "ava";
|
||||
|
||||
import * as defaults from "./defaults.json";
|
||||
import { getEnv } from "./environment";
|
||||
import {
|
||||
Feature,
|
||||
featureConfig,
|
||||
@@ -26,12 +27,12 @@ import {
|
||||
setupTests,
|
||||
stubFeatureFlagApiEndpoint,
|
||||
} from "./testing-utils";
|
||||
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
|
||||
import { GitHubVariant, withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
});
|
||||
|
||||
test.serial(
|
||||
|
||||
@@ -560,7 +560,7 @@ class OfflineFeatures implements FeatureEnablement {
|
||||
// Never use this feature if the CLI version explicitly can't support it.
|
||||
const minimumVersion = config.minimumVersion;
|
||||
if (codeql && minimumVersion) {
|
||||
if (!(await util.codeQlVersionAtLeast(codeql, minimumVersion))) {
|
||||
if (!(await codeql.isVersionAtLeast(minimumVersion))) {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum ` +
|
||||
`version ${minimumVersion}.`,
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
LoggedMessage,
|
||||
setupTests,
|
||||
} from "../testing-utils";
|
||||
import { GitHubVariant, initializeEnvironment, withTmpDir } from "../util";
|
||||
import { getEnv, GitHubVariant, withTmpDir } from "../util";
|
||||
|
||||
import {
|
||||
assertAllFeaturesHaveDefaultValues,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
});
|
||||
|
||||
test("OfflineFeatures makes no API requests", async (t) => {
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import { ActionsEnvVars, type ReadOnlyEnv } from "./environment";
|
||||
import { ConfigurationError } from "./util";
|
||||
import { ConfigurationError } from "./errors";
|
||||
|
||||
export enum GitHubVariant {
|
||||
/** [GitHub.com](https://github.com) */
|
||||
DOTCOM = "GitHub.com",
|
||||
/** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */
|
||||
GHES = "GitHub Enterprise Server",
|
||||
/** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */
|
||||
GHEC_DR = "GitHub Enterprise Cloud with data residency",
|
||||
}
|
||||
|
||||
export type GitHubVersion =
|
||||
| { type: GitHubVariant.DOTCOM }
|
||||
| { type: GitHubVariant.GHEC_DR }
|
||||
| { type: GitHubVariant.GHES; version: string };
|
||||
|
||||
/** A string representing a GitHub instance address. */
|
||||
export type InstanceURL = string;
|
||||
|
||||
@@ -89,12 +89,10 @@ import {
|
||||
checkDiskUsage,
|
||||
checkForTimeout,
|
||||
checkGitHubVersionInRange,
|
||||
codeQlVersionAtLeast,
|
||||
DEFAULT_DEBUG_ARTIFACT_NAME,
|
||||
DEFAULT_DEBUG_DATABASE_NAME,
|
||||
getCodeQLMemoryLimit,
|
||||
getThreadsFlagValue,
|
||||
initializeEnvironment,
|
||||
ConfigurationError,
|
||||
wrapError,
|
||||
checkActionVersion,
|
||||
@@ -227,7 +225,7 @@ async function run(
|
||||
let toolsVersion: string;
|
||||
|
||||
try {
|
||||
initializeEnvironment(getActionVersion());
|
||||
actionState.env.initialise(getActionVersion());
|
||||
|
||||
// Make inputs accessible in the `post` step.
|
||||
persistInputs();
|
||||
@@ -685,7 +683,7 @@ async function run(
|
||||
`${EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS} is already set to '${process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]}', so the Action will not override it.`,
|
||||
);
|
||||
} else if (
|
||||
(await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION)) &&
|
||||
(await codeql.isVersionAtLeast(CODEQL_VERSION_JAR_MINIMIZATION)) &&
|
||||
config.dependencyCachingEnabled &&
|
||||
config.buildMode === BuildMode.None &&
|
||||
config.languages.includes(BuiltInLanguage.java)
|
||||
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
checkDiskUsage,
|
||||
checkForTimeout,
|
||||
checkGitHubVersionInRange,
|
||||
initializeEnvironment,
|
||||
ConfigurationError,
|
||||
wrapError,
|
||||
checkActionVersion,
|
||||
@@ -108,7 +107,7 @@ async function run(
|
||||
let toolsVersion: string;
|
||||
|
||||
try {
|
||||
initializeEnvironment(getActionVersion());
|
||||
actionState.env.initialise(getActionVersion());
|
||||
|
||||
const apiDetails = {
|
||||
auth: getRequiredInput("token"),
|
||||
|
||||
@@ -11,7 +11,13 @@ import * as sinon from "sinon";
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
import * as diagnostics from "./diagnostics";
|
||||
import { ActionsEnvVars, Env, EnvVar, ReadOnlyEnv } from "./environment";
|
||||
import {
|
||||
ActionsEnvVars,
|
||||
Env,
|
||||
EnvVar,
|
||||
getEnv,
|
||||
ReadOnlyEnv,
|
||||
} from "./environment";
|
||||
import { Feature } from "./feature-flags";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
import { getCacheRestoreKeyPrefix } from "./overlay/caching";
|
||||
@@ -37,18 +43,12 @@ import {
|
||||
setupTests,
|
||||
} from "./testing-utils";
|
||||
import * as toolsDownload from "./tools-download";
|
||||
import {
|
||||
getErrorMessage,
|
||||
GitHubVariant,
|
||||
HTTPError,
|
||||
initializeEnvironment,
|
||||
withTmpDir,
|
||||
} from "./util";
|
||||
import { getErrorMessage, GitHubVariant, HTTPError, withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
});
|
||||
|
||||
function stubDownloadAndExtract() {
|
||||
|
||||
@@ -6,7 +6,6 @@ import * as sinon from "sinon";
|
||||
import * as actionsUtil from "../actions-util";
|
||||
import { ActionsEnvVars } from "../environment";
|
||||
import { callee, getTestEnv, setupTests } from "../testing-utils";
|
||||
import { initializeEnvironment } from "../util";
|
||||
|
||||
import { getCodeQLActionRepository } from "./repository";
|
||||
|
||||
@@ -16,7 +15,7 @@ test.serial("getCodeQLActionRepository", async (t) => {
|
||||
const initialEnv = getTestEnv({
|
||||
[ActionsEnvVars.RUNNER_TEMP]: path.dirname(__dirname),
|
||||
});
|
||||
initializeEnvironment("1.2.3", initialEnv);
|
||||
initialEnv.initialise("1.2.3");
|
||||
|
||||
const target = callee(getCodeQLActionRepository)
|
||||
.withArgs()
|
||||
|
||||
@@ -2,13 +2,12 @@ import { ActionState } from "../action-common";
|
||||
import { isRunningLocalAction } from "../actions-util";
|
||||
import * as api from "../api-client";
|
||||
import { ActionsEnvVars } from "../environment";
|
||||
import { GITHUB_DOTCOM_URL } from "../github";
|
||||
import { GITHUB_DOTCOM_URL, type InstanceURL } from "../github";
|
||||
import {
|
||||
isRepositoryNwoStr,
|
||||
parseRepositoryNwo,
|
||||
type RepositoryNwoStr,
|
||||
} from "../repository";
|
||||
import { type InstanceURL } from "../util";
|
||||
|
||||
/** The NWO of the standard CodeQL Action repository. */
|
||||
export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||
|
||||
@@ -10,6 +10,7 @@ import { https } from "follow-redirects";
|
||||
import nock from "nock";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as errors from "./errors";
|
||||
import * as tar from "./tar";
|
||||
import { RecordingLogger, setupTests } from "./testing-utils";
|
||||
import { downloadAndExtract } from "./tools-download";
|
||||
@@ -163,7 +164,7 @@ test.serial(
|
||||
test.serial(
|
||||
"downloadAndExtract handles an unknown status as a non-HTTP error",
|
||||
async (t) => {
|
||||
const asHTTPError = sinon.spy(util, "asHTTPError");
|
||||
const asHTTPError = sinon.spy(errors, "asHTTPError");
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
sinon.stub(process, "platform").value("linux");
|
||||
const archivePath = path.join(tmpDir, "codeql-bundle.tar.zst");
|
||||
|
||||
@@ -10,17 +10,18 @@ import * as analyses from "./analyses";
|
||||
import { AnalysisKind, CodeQuality, CodeScanning } from "./analyses";
|
||||
import * as api from "./api-client";
|
||||
import * as diffUtils from "./diff-informed-analysis-utils";
|
||||
import { getEnv } from "./environment";
|
||||
import { Logger } from "./logging";
|
||||
import * as sarif from "./sarif";
|
||||
import { RecordingLogger, setupTests } from "./testing-utils";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import { UploadPayload } from "./upload-lib/types";
|
||||
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
|
||||
import { GitHubVariant, withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
getEnv().initialise("1.2.3");
|
||||
});
|
||||
|
||||
test.serial("validateSarifFileSchema - valid", (t) => {
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
ConfigurationError,
|
||||
checkActionVersion,
|
||||
checkDiskUsage,
|
||||
initializeEnvironment,
|
||||
shouldSkipSarifUpload,
|
||||
wrapError,
|
||||
} from "./util";
|
||||
@@ -55,11 +54,13 @@ async function sendSuccessStatusReport(
|
||||
}
|
||||
}
|
||||
|
||||
async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
async function run(action: ActionState<["Base", "Env", "Logger"]>) {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
const logger = action.logger;
|
||||
|
||||
try {
|
||||
initializeEnvironment(getActionVersion());
|
||||
action.env.initialise(getActionVersion());
|
||||
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
checkActionVersion(getActionVersion(), gitHubVersion);
|
||||
@@ -79,7 +80,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
const startingStatusReportBase = await createStatusReportBase(
|
||||
ActionName.UploadSarif,
|
||||
"starting",
|
||||
startedAt,
|
||||
action.startedAt,
|
||||
undefined,
|
||||
await checkDiskUsage(logger),
|
||||
logger,
|
||||
@@ -137,7 +138,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
// so we can't wait for that here.
|
||||
}
|
||||
await sendSuccessStatusReport(
|
||||
startedAt,
|
||||
action.startedAt,
|
||||
codeScanningResult?.statusReport || {},
|
||||
logger,
|
||||
);
|
||||
@@ -153,7 +154,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
const errorStatusReportBase = await createStatusReportBase(
|
||||
ActionName.UploadSarif,
|
||||
getActionsStatus(error),
|
||||
startedAt,
|
||||
action.startedAt,
|
||||
undefined,
|
||||
await checkDiskUsage(logger),
|
||||
logger,
|
||||
|
||||
104
src/util.ts
104
src/util.ts
@@ -20,20 +20,22 @@ import {
|
||||
getRequiredEnvParam,
|
||||
exportEnvVar,
|
||||
getEnv,
|
||||
type Env,
|
||||
type ReadOnlyEnv,
|
||||
} from "./environment";
|
||||
import * as json from "./json";
|
||||
import { Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import { ConfigurationError, getErrorMessage, wrapError } from "./errors";
|
||||
import { GitHubVariant, type GitHubVersion } from "./github";
|
||||
import type { Language } from "./languages";
|
||||
import type { Logger } from "./logging";
|
||||
|
||||
// Re-export for backwards compatibility to avoid updating a lot of imports elsewhere.
|
||||
export * from "./errors";
|
||||
export {
|
||||
getRequiredEnvParam,
|
||||
getOptionalEnvVar,
|
||||
getEnv,
|
||||
isInTestMode,
|
||||
} from "./environment";
|
||||
export { GitHubVariant, type GitHubVersion } from "./github";
|
||||
|
||||
/**
|
||||
* The name of the file containing the base database OIDs, as stored in the
|
||||
@@ -47,9 +49,6 @@ const BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json";
|
||||
*/
|
||||
const BROKEN_VERSIONS = ["0.0.0-20211207"];
|
||||
|
||||
/** A string representing a GitHub instance. */
|
||||
export type InstanceURL = string;
|
||||
|
||||
/**
|
||||
* Default name of the debugging artifact.
|
||||
*/
|
||||
@@ -470,20 +469,6 @@ const CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR =
|
||||
|
||||
let hasBeenWarnedAboutVersion = false;
|
||||
|
||||
export enum GitHubVariant {
|
||||
/** [GitHub.com](https://github.com) */
|
||||
DOTCOM = "GitHub.com",
|
||||
/** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */
|
||||
GHES = "GitHub Enterprise Server",
|
||||
/** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */
|
||||
GHEC_DR = "GitHub Enterprise Cloud with data residency",
|
||||
}
|
||||
|
||||
export type GitHubVersion =
|
||||
| { type: GitHubVariant.DOTCOM }
|
||||
| { type: GitHubVariant.GHEC_DR }
|
||||
| { type: GitHubVariant.GHES; version: string };
|
||||
|
||||
export function checkGitHubVersionInRange(
|
||||
version: GitHubVersion,
|
||||
logger: Logger,
|
||||
@@ -552,54 +537,6 @@ export function assertNever(value: never): never {
|
||||
throw new ExhaustivityCheckingError(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set some initial environment variables that we can set even without
|
||||
* knowing what version of CodeQL we're running.
|
||||
*/
|
||||
export function initializeEnvironment(version: string, env: Env = getEnv()) {
|
||||
env.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
env.export(EnvVar.FEATURE_SANDWICH, "false");
|
||||
env.export(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
env.export(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
env.export(EnvVar.VERSION, version);
|
||||
}
|
||||
|
||||
export class HTTPError extends Error {
|
||||
public status: number;
|
||||
|
||||
constructor(message: string, status: number) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error class that indicates an error that occurred due to
|
||||
* a misconfiguration of the action or the CodeQL CLI.
|
||||
*/
|
||||
export class ConfigurationError extends Error {}
|
||||
|
||||
export function asHTTPError(arg: any): HTTPError | undefined {
|
||||
if (!json.isObject<any>(arg) || !json.isString(arg.message)) {
|
||||
return undefined;
|
||||
}
|
||||
if (Number.isInteger(arg.status)) {
|
||||
return new HTTPError(arg.message, arg.status as number);
|
||||
}
|
||||
// See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19
|
||||
if (Number.isInteger(arg.httpStatusCode)) {
|
||||
return new HTTPError(arg.message, arg.httpStatusCode as number);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function codeQlVersionAtLeast(
|
||||
codeql: CodeQL,
|
||||
requiredVersion: string,
|
||||
): Promise<boolean> {
|
||||
return semver.gte((await codeql.getVersion()).version, requiredVersion);
|
||||
}
|
||||
|
||||
export function getBaseDatabaseOidsFilePath(
|
||||
config: ActionConfig<"dbLocation">,
|
||||
): string {
|
||||
@@ -886,35 +823,6 @@ export function parseMatrixInput(
|
||||
}
|
||||
}
|
||||
|
||||
export function wrapError(error: unknown): Error {
|
||||
return error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriate message for the error.
|
||||
*
|
||||
* If the error is an `Error` instance, this returns the error message without
|
||||
* an `Error: ` prefix.
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approximates whether {@link error} is like a {@link NodeJS.ErrnoException}.
|
||||
* We only typically care about the `code` property, so that's what we check for here.
|
||||
*/
|
||||
export function isErrnoException(
|
||||
error: unknown,
|
||||
): error is NodeJS.ErrnoException {
|
||||
return (
|
||||
typeof error === "object" &&
|
||||
error !== null &&
|
||||
"code" in error &&
|
||||
typeof error.code === "string"
|
||||
);
|
||||
}
|
||||
|
||||
export function prettyPrintPack(pack: Pack) {
|
||||
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${
|
||||
pack.path ? `:${pack.path}` : ""
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
- _Upcoming breaking change_: CodeQL version 2.22.3 and earlier were discontinued on 16 October 2026 alongside GitHub Enterprise Server 3.18, and will be unsupported by the next minor release of the CodeQL Action. Added a deprecation warning for customers using these versions of CodeQL. [#4266](https://github.com/github/codeql-action/pull/4266)
|
||||
@@ -1 +0,0 @@
|
||||
- Starting with macOS 27 and Xcode 27, traced analyses are unsupported. See [this blog post for more information](https://github.blog/changelog/2026-10-19-codeql-changes-for-macos-27-xcode-27-and-swift-6-4/). The CodeQL Action will now try to identify if a workflow is about to perform a traced analysis on version 27 or above of macOS or Xcode. If so, the CodeQL Action will emit a corresponding warning that will also be visible on the [Tool Status Page](https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/manage-your-configuration/use-the-tools-status-page-for-code-scanning). This check will be rolled out following this release of the CodeQL Action. [#4221](https://github.com/github/codeql-action/pull/4221)
|
||||
@@ -1 +0,0 @@
|
||||
- The undocumented TRAP cache cleanup feature that could be enabled using the `CODEQL_ACTION_CLEANUP_TRAP_CACHES` environment variable has been removed, as announced in the release notes for CodeQL Action 4.35.2. The `analyze` Action now warns if this environment variable is set. If you used TRAP cache cleanup to limit Actions cache usage, we recommend disabling TRAP caching by passing the `trap-caching: false` input to the `init` Action. [#4243](https://github.com/github/codeql-action/pull/4243)
|
||||
Reference in New Issue
Block a user