mirror of
https://github.com/astral-sh/ruff-action.git
synced 2026-09-25 07:10:39 +00:00
Use JSON for known checksums (#415)
Ports the hardening from astral-sh/setup-uv#1025 to ruff-action.\n\nThis stores generated checksums as JSON data behind a small typed TypeScript wrapper, preventing values sourced from release metadata from being mixed into generated executable code. It also updates the checksum workflow and packaged action artifacts, and adds a regression test for code-like keys and escaped checksum values.\n\nTests: npm run build, npm run check, npm test, npm run package
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
dist/** -diff linguist-generated=true
|
||||
src/download/checksum/known-checksums.json linguist-generated=true
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
id: update-known-checksums
|
||||
run:
|
||||
node dist/update-known-checksums/index.cjs
|
||||
src/download/checksum/known-checksums.ts ${{ secrets.GITHUB_TOKEN }}
|
||||
src/download/checksum/known-checksums.json ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: npm ci --ignore-scripts && npm run all
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { expect, jest, test } from "@jest/globals";
|
||||
|
||||
const mockDownloadTool = jest.fn<() => Promise<string>>();
|
||||
|
||||
jest.unstable_mockModule("@actions/tool-cache", () => ({
|
||||
downloadTool: mockDownloadTool,
|
||||
}));
|
||||
|
||||
const { updateChecksums } = await import(
|
||||
"../../../src/download/checksum/update-known-checksums"
|
||||
);
|
||||
|
||||
test("serializes checksum entries as JSON data", async () => {
|
||||
const tempDirectory = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "ruff-action-checksums-test-"),
|
||||
);
|
||||
const checksumPath = path.join(tempDirectory, "checksum");
|
||||
const outputPath = path.join(tempDirectory, "known-checksums.json");
|
||||
const checksum = 'checksum"\\value';
|
||||
const platform = 'platform"\n};\ncompromised = true;';
|
||||
const downloadUrl = `https://example.com/v1.0.0/ruff-1.0.0-${platform}.tar.gz.sha256`;
|
||||
|
||||
try {
|
||||
await fs.writeFile(checksumPath, `${checksum} ruff.tar.gz`);
|
||||
mockDownloadTool.mockResolvedValue(checksumPath);
|
||||
|
||||
await updateChecksums(outputPath, [downloadUrl]);
|
||||
|
||||
const content = await fs.readFile(outputPath, "utf8");
|
||||
expect(JSON.parse(content)).toEqual({ [`${platform}-1.0.0`]: checksum });
|
||||
expect(content.endsWith("\n")).toBe(true);
|
||||
} finally {
|
||||
await fs.rm(tempDirectory, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
+5
-2
@@ -24769,8 +24769,8 @@ var ASTRAL_MIRROR_PREFIX = "https://releases.astral.sh/github/ruff/releases/down
|
||||
var crypto3 = __toESM(require("node:crypto"), 1);
|
||||
var fs4 = __toESM(require("node:fs"), 1);
|
||||
|
||||
// src/download/checksum/known-checksums.ts
|
||||
var KNOWN_CHECKSUMS = {
|
||||
// src/download/checksum/known-checksums.json
|
||||
var known_checksums_default = {
|
||||
"aarch64-apple-darwin-0.16.5": "ed142f8656e0092828c103dd058b55b871c88e13a801cade8f860d8a9ca8943e",
|
||||
"aarch64-pc-windows-msvc-0.16.5": "30874e50be1f31626022358bbcaa80112ce1065b9297e5a9c4654f0b5a230d39",
|
||||
"aarch64-unknown-linux-gnu-0.16.5": "796079ea998dba3e455394077ba51a4c500c2402d3920580c646a0580f20370c",
|
||||
@@ -28094,6 +28094,9 @@ var KNOWN_CHECKSUMS = {
|
||||
"x86_64-unknown-linux-musl-0.0.247": "d14f59b09a83e3bdba4a54687158534f7c8ae702f8df770b8eaabf4445fb8b60"
|
||||
};
|
||||
|
||||
// src/download/checksum/known-checksums.ts
|
||||
var KNOWN_CHECKSUMS = known_checksums_default;
|
||||
|
||||
// src/download/checksum/checksum.ts
|
||||
async function validateChecksum(checkSum2, downloadPath, arch3, platform2, version2) {
|
||||
let isValid;
|
||||
|
||||
+9
-15
@@ -26771,8 +26771,8 @@ function _getGlobal(key, defaultValue) {
|
||||
return value !== void 0 ? value : defaultValue;
|
||||
}
|
||||
|
||||
// src/download/checksum/known-checksums.ts
|
||||
var KNOWN_CHECKSUMS = {
|
||||
// src/download/checksum/known-checksums.json
|
||||
var known_checksums_default = {
|
||||
"aarch64-apple-darwin-0.16.5": "ed142f8656e0092828c103dd058b55b871c88e13a801cade8f860d8a9ca8943e",
|
||||
"aarch64-pc-windows-msvc-0.16.5": "30874e50be1f31626022358bbcaa80112ce1065b9297e5a9c4654f0b5a230d39",
|
||||
"aarch64-unknown-linux-gnu-0.16.5": "796079ea998dba3e455394077ba51a4c500c2402d3920580c646a0580f20370c",
|
||||
@@ -30096,28 +30096,22 @@ var KNOWN_CHECKSUMS = {
|
||||
"x86_64-unknown-linux-musl-0.0.247": "d14f59b09a83e3bdba4a54687158534f7c8ae702f8df770b8eaabf4445fb8b60"
|
||||
};
|
||||
|
||||
// src/download/checksum/known-checksums.ts
|
||||
var KNOWN_CHECKSUMS = known_checksums_default;
|
||||
|
||||
// src/download/checksum/update-known-checksums.ts
|
||||
async function updateChecksums(filePath, downloadUrls) {
|
||||
await import_node_fs.promises.rm(filePath);
|
||||
await import_node_fs.promises.appendFile(
|
||||
filePath,
|
||||
"// AUTOGENERATED_DO_NOT_EDIT\nexport const KNOWN_CHECKSUMS: { [key: string]: string } = {\n"
|
||||
);
|
||||
let firstLine = true;
|
||||
const checksums = {};
|
||||
for (const downloadUrl of downloadUrls) {
|
||||
const key = getKey(downloadUrl);
|
||||
if (key === void 0) {
|
||||
continue;
|
||||
}
|
||||
const checksum = await getOrDownloadChecksum(key, downloadUrl);
|
||||
if (!firstLine) {
|
||||
await import_node_fs.promises.appendFile(filePath, ",\n");
|
||||
}
|
||||
await import_node_fs.promises.appendFile(filePath, ` "${key}":
|
||||
"${checksum}"`);
|
||||
firstLine = false;
|
||||
checksums[key] = checksum;
|
||||
}
|
||||
await import_node_fs.promises.appendFile(filePath, ",\n};\n");
|
||||
await import_node_fs.promises.writeFile(filePath, `${JSON.stringify(checksums, null, 2)}
|
||||
`);
|
||||
}
|
||||
function getKey(downloadUrl) {
|
||||
const parts = downloadUrl.split("/");
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
"check": "biome check --write",
|
||||
"package": "node scripts/build-dist.mjs",
|
||||
"act": "act pull_request -W .github/workflows/test.yml --container-architecture linux/amd64 -s GITHUB_TOKEN=\"$(gh auth token)\"",
|
||||
"update-known-checksums": "RUNNER_TEMP=known_checksums node dist/update-known-checksums/index.cjs src/download/checksum/known-checksums.ts \"$(gh auth token)\"",
|
||||
"update-known-checksums": "RUNNER_TEMP=known_checksums node dist/update-known-checksums/index.cjs src/download/checksum/known-checksums.json \"$(gh auth token)\"",
|
||||
"test:unit": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
|
||||
"test": "npm run build && npm run test:unit",
|
||||
"all": "npm run build && npm run check && npm run package && npm run test:unit"
|
||||
|
||||
+6644
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,25 +5,16 @@ export async function updateChecksums(
|
||||
filePath: string,
|
||||
downloadUrls: string[],
|
||||
): Promise<void> {
|
||||
await fs.rm(filePath);
|
||||
await fs.appendFile(
|
||||
filePath,
|
||||
"// AUTOGENERATED_DO_NOT_EDIT\nexport const KNOWN_CHECKSUMS: { [key: string]: string } = {\n",
|
||||
);
|
||||
let firstLine = true;
|
||||
const checksums: Record<string, string> = {};
|
||||
for (const downloadUrl of downloadUrls) {
|
||||
const key = getKey(downloadUrl);
|
||||
if (key === undefined) {
|
||||
continue;
|
||||
}
|
||||
const checksum = await getOrDownloadChecksum(key, downloadUrl);
|
||||
if (!firstLine) {
|
||||
await fs.appendFile(filePath, ",\n");
|
||||
}
|
||||
await fs.appendFile(filePath, ` "${key}":\n "${checksum}"`);
|
||||
firstLine = false;
|
||||
checksums[key] = checksum;
|
||||
}
|
||||
await fs.appendFile(filePath, ",\n};\n");
|
||||
await fs.writeFile(filePath, `${JSON.stringify(checksums, null, 2)}\n`);
|
||||
}
|
||||
|
||||
function getKey(downloadUrl: string): string | undefined {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"noImplicitAny": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"target": "ES2022"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user