From 28c509a7ff2fb4fad1546b13d951108c6de021f6 Mon Sep 17 00:00:00 2001 From: NekoPunch Date: Fri, 28 Aug 2026 02:36:25 -0700 Subject: [PATCH] fix(scripts): encode direct entrypoint paths --- .github/workflows/ci.yml | 3 ++ scripts/build-cursor-overlay.mjs | 4 +- .../prepare-deepseek-harness-toolchain.mjs | 4 +- scripts/script-entrypoints.test.mjs | 40 +++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 scripts/script-entrypoints.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b73068e25b..2ae34ebf16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,9 @@ jobs: - name: Test AX tree audit contract run: node --test scripts/ax-tree-audit.test.mjs + - name: Test script entrypoint contracts + run: node --test scripts/script-entrypoints.test.mjs + - name: Verify ASF npm preflight policy run: npm run check:asf-npm diff --git a/scripts/build-cursor-overlay.mjs b/scripts/build-cursor-overlay.mjs index 93ff22cab3..88dcdd01ca 100644 --- a/scripts/build-cursor-overlay.mjs +++ b/scripts/build-cursor-overlay.mjs @@ -24,7 +24,7 @@ // - cursor-overlay.html: copied verbatim. import * as esbuild from 'esbuild'; import { resolve, dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { mkdir, copyFile } from 'node:fs/promises'; const here = dirname(fileURLToPath(import.meta.url)); @@ -140,7 +140,7 @@ export async function buildPermissionOverlay({ logLevel = 'info' } = {}) { } // Run directly (npm run build:overlay) or import buildCursorOverlay (dev.mjs). -if (import.meta.url === `file://${process.argv[1]}`) { +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { const dir = await buildCursorOverlay(); console.log('overlays built →', dir); } diff --git a/scripts/prepare-deepseek-harness-toolchain.mjs b/scripts/prepare-deepseek-harness-toolchain.mjs index 6ebfb763e8..fe371a8e8d 100644 --- a/scripts/prepare-deepseek-harness-toolchain.mjs +++ b/scripts/prepare-deepseek-harness-toolchain.mjs @@ -45,7 +45,7 @@ import { createReadStream } from 'node:fs'; import { mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises'; import { homedir } from 'node:os'; import { dirname, join, relative, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { promisify } from 'node:util'; const execFileAsync = promisify(execFile); @@ -218,7 +218,7 @@ async function recordFingerprint(fingerprint) { await writeFile(identityPath, next, 'utf8'); } -if (import.meta.url === `file://${process.argv[1]}`) { +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { const argv = process.argv.slice(2); const outIndex = argv.indexOf('--out'); const result = await prepareDeepSeekHarnessToolchain({ diff --git a/scripts/script-entrypoints.test.mjs b/scripts/script-entrypoints.test.mjs new file mode 100644 index 0000000000..90f3cd87f7 --- /dev/null +++ b/scripts/script-entrypoints.test.mjs @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import test from 'node:test'; + +test('direct script guards encode entrypoint paths with spaces', async () => { + const entrypointPath = join(tmpdir(), 'Maka Project', 'script.mjs'); + assert.match(pathToFileURL(entrypointPath).href, /Maka%20Project/); + assert.notEqual(pathToFileURL(entrypointPath).href, `file://${entrypointPath}`); + + for (const script of ['build-cursor-overlay.mjs', 'prepare-deepseek-harness-toolchain.mjs']) { + const source = await readFile(new URL(script, import.meta.url), 'utf8'); + assert.match( + source, + /process\.argv\[1\] && import\.meta\.url === pathToFileURL\(process\.argv\[1\]\)\.href/, + `${script} must compare encoded file URLs`, + ); + } +});