From c89e805975a48a6658749e515dd1bb18aa094079 Mon Sep 17 00:00:00 2001 From: logfox-agent Date: Mon, 27 Jul 2026 22:41:05 -0400 Subject: [PATCH 1/2] fix: align cli release workflow with npm OIDC pattern Remove bogus autorel --publish-args=--provenance, match ecswatch/castellan-cli trusted publishing setup, and queue releases without cancel-in-progress. --- .github/workflows/release.yml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e607e0..b2b0437 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,12 +3,16 @@ on: push: branches: [main] workflow_dispatch: +permissions: + id-token: write # Required for npm trusted publishing (OIDC) + contents: write # Required for autorel to push release tag (and changelog) jobs: release: + name: Release runs-on: ubuntu-latest - permissions: - contents: write - id-token: write + concurrency: + group: deploy-${{ github.ref }} + cancel-in-progress: false steps: - uses: actions/checkout@v4 with: @@ -16,10 +20,11 @@ jobs: fetch-tags: true - uses: actions/setup-node@v4 with: - node-version: 24 - registry-url: https://registry.npmjs.org + node-version: '24' # npm 11+ required for trusted publishing (OIDC) + registry-url: 'https://registry.npmjs.org' + cache: 'npm' - run: npm ci - - run: npm run build - - run: npx autorel@^2 --publish-args="--provenance" + - run: npm run validate + - run: npx autorel@^2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From aee703ebd18cef0fb2da86babcf0fb457edc1b5e Mon Sep 17 00:00:00 2001 From: logfox-agent Date: Tue, 28 Jul 2026 18:32:12 -0400 Subject: [PATCH 2/2] chore: reject file: deps in package.json --- .github/workflows/ci.yml | 3 ++ package.json | 3 +- scripts/check-no-file-deps.mjs | 61 ++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 scripts/check-no-file-deps.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14fcbca..ae8a4bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,9 @@ jobs: cache: 'npm' registry-url: 'https://npm.pkg.github.com' scope: '@logfoxai' + + - name: Check package.json deps + run: node scripts/check-no-file-deps.mjs - name: Configure npm auth run: | echo "@logfoxai:registry=https://npm.pkg.github.com/" > .npmrc diff --git a/package.json b/package.json index 92aaa41..684f88d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "build": "tsc", "dev": "tsx src/index.ts", "start": "node dist/index.js", - "validate": "npm run build" + "validate": "npm run check:package-json && npm run build", + "check:package-json": "node scripts/check-no-file-deps.mjs" }, "devDependencies": { "@types/node": "^24.13.2", diff --git a/scripts/check-no-file-deps.mjs b/scripts/check-no-file-deps.mjs new file mode 100644 index 0000000..7dec517 --- /dev/null +++ b/scripts/check-no-file-deps.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env node +/** + * Fail if package.json declares file: or file:// dependency specs. + * Canonical copy: infra/ci-cd/check-no-file-deps.mjs + * Service repos ship an identical copy at scripts/check-no-file-deps.mjs for CI. + * + * Local monorepo dev uses npm link — never commit file: paths. + */ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const DEP_FIELDS = [ + "dependencies", + "devDependencies", + "optionalDependencies", + "peerDependencies", + "overrides", +]; + +const pkgPath = join(process.cwd(), "package.json"); +let pkg; +try { + pkg = JSON.parse(readFileSync(pkgPath, "utf8")); +} catch (err) { + console.error(`check-no-file-deps: failed to read ${pkgPath}: ${err.message}`); + process.exit(1); +} + +const violations = []; + +function isFileSpec(value) { + return typeof value === "string" && (value.startsWith("file:") || value.startsWith("file://")); +} + +function checkDeps(deps, path) { + if (!deps || typeof deps !== "object" || Array.isArray(deps)) { + return; + } + for (const [name, version] of Object.entries(deps)) { + if (isFileSpec(version)) { + violations.push(`${path}.${name}: ${JSON.stringify(version)}`); + } else if (version && typeof version === "object") { + checkDeps(version, `${path}.${name}`); + } + } +} + +for (const field of DEP_FIELDS) { + checkDeps(pkg[field], field); +} + +if (violations.length > 0) { + console.error("package.json must not use file: or file:// dependency specs."); + console.error("Use npm link for local development instead."); + for (const v of violations) { + console.error(` ${v}`); + } + process.exit(1); +} + +console.log("check-no-file-deps: ok");