From 8c960d09baf672aba83567a9c352a1adfb7325bb Mon Sep 17 00:00:00 2001 From: pr0uxx Date: Thu, 30 Jul 2026 09:15:11 +0100 Subject: [PATCH 1/5] Pin Socket CLI version in reachability workflow Pin `socketsecurity` to `2.5.5` in `Security-Reachability.yml` to avoid transient CI failures caused by newly released `@coana-tech/cli` dependencies still inside Socket's package-age cooldown window. Added detailed maintainer guidance on when and how to safely bump the pin, including publish-date checks and rollback instructions if ETARGET/notarget errors return. --- .github/workflows/Security-Reachability.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Security-Reachability.yml b/.github/workflows/Security-Reachability.yml index f0978e6..77aade8 100644 --- a/.github/workflows/Security-Reachability.yml +++ b/.github/workflows/Security-Reachability.yml @@ -74,10 +74,27 @@ jobs: background: true run: sfw npm install -g npm - # Install the Socket CLI tool using pip and ensure it's up to date + # Install the Socket CLI tool using pip and ensure it's up to date. + # socketsecurity is pinned rather than left on --upgrade because brand-new releases can + # pull in an equally brand-new @coana-tech/cli version that is still within Socket's own + # package-age cooldown window, causing npm ETARGET failures until it ages out. Bump this + # pin manually once a release is confirmed to work. + # + # To check whether a newer socketsecurity release is safe to bump to: + # 1. Check the candidate version's publish date: https://pypi.org/project/socketsecurity/#history + # (or `pip index versions socketsecurity`). It should be at least ~24-48h old so any + # npm dependency it pulls in has had time to clear Socket's package-age cooldown. + # 2. Run `pip download --no-deps socketsecurity== -d /tmp/check && tar tzf /tmp/check/*.tar.gz` + # (or inspect the sdist/wheel metadata) to find the @coana-tech/cli version it requires, + # then confirm that version's publish date on https://www.npmjs.com/package/@coana-tech/cli + # is also old enough (again, at least ~24-48h before the date you plan to run CI). + # 3. If both dates check out, bump the pin below and watch the next scan run succeed. + # 4. If the workflow starts failing with the same ETARGET/notarget error again, it means a + # new socketsecurity release again pulled in a too-fresh @coana-tech/cli - re-pin to the + # last known-good version and retry later. - name: Install Socket CLI background: true - run: sfw pip install socketsecurity uv --upgrade + run: sfw pip install socketsecurity==2.5.5 uv --upgrade # Bring job back to sync execution by awaiting for all async jobs to finish before continuing - name: Steps - Convert Back To Synchronous Execution - Packages Updates/Setup From 090bc782f539c813cb610b7f34a6880bd37d8436 Mon Sep 17 00:00:00 2001 From: pr0uxx Date: Thu, 30 Jul 2026 09:17:40 +0100 Subject: [PATCH 2/5] Set GitHub registry only for publish step Stop configuring npm.pkg.github.com globally in CI setup by removing the Node scope/registry settings from shared workflow setup. Instead, target GitHub Packages explicitly on the GitHub publish command with `--registry`, so installs and other npm operations keep the default npmjs registry while package publication still goes to both registries as intended. --- .github/actions/setup-ci/action.yml | 2 -- .github/workflows/Build.yml | 6 +++--- .github/workflows/Publish.yml | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-ci/action.yml b/.github/actions/setup-ci/action.yml index e4a62a6..15a354f 100644 --- a/.github/actions/setup-ci/action.yml +++ b/.github/actions/setup-ci/action.yml @@ -17,8 +17,6 @@ runs: uses: actions/setup-node@v6 with: node-version: 24 - registry-url: https://npm.pkg.github.com - scope: software-hardware-integration-lab # Set up the socket firewall binary - name: Install - Socket Firewall diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 85c17d9..ec04268 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -99,7 +99,7 @@ jobs: - name: Validate Package Before Publish run: npm run validate:package - # Generate the package archive that will be attested and published to each registry. + # Generate the package archive that will be attested and published to both registries. - name: Generate NPM Package Archive id: generate-package run: echo "package-file=$(npm pack --ignore-scripts)" >> "$GITHUB_OUTPUT" @@ -110,11 +110,11 @@ jobs: with: subject-path: ${{ steps.generate-package.outputs.package-file }} - # Publish the attested package archive to GitHub Packages for internal distribution. + # Publish the attested package to GitHub Packages without changing the npmjs install registry. - name: Upload Package to GitHub Packages Registry env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm publish ${{ steps.generate-package.outputs.package-file }} --tag ${{ needs.Metadata.outputs.channel }} --ignore-scripts + run: npm publish ${{ steps.generate-package.outputs.package-file }} --registry=https://npm.pkg.github.com --tag ${{ needs.Metadata.outputs.channel }} --ignore-scripts # Upload the attested npm package archive for the publish workflow to consume. - name: Upload NPM Package Archive Artifact diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml index 79270e1..6640695 100644 --- a/.github/workflows/Publish.yml +++ b/.github/workflows/Publish.yml @@ -51,7 +51,6 @@ jobs: background: true with: node-version: 24 - scope: software-hardware-integration-lab # Download the compiled server binary - name: Download Artifact From Build Job From 5dabb4a8849767e5b3c96ad4d9607244865973da Mon Sep 17 00:00:00 2001 From: pr0uxx Date: Thu, 30 Jul 2026 09:51:43 +0100 Subject: [PATCH 3/5] Automate Socket reachability pin updates Add a new `update-reachability-pin` script that fetches PyPI release metadata for `socketsecurity`, selects the latest non-yanked stable version at least 24 hours old, and updates the pinned version in `Security-Reachability.yml`. `validate:package` now runs this updater first, while a new `validate:package:skip-reachability` command preserves CI behavior by avoiding workflow file edits during build validation. The Build workflow was updated to use the skip variant, and the reachability workflow comments now document the automated pinning approach. --- .github/workflows/Build.yml | 2 +- .github/workflows/Security-Reachability.yml | 20 +----- package.json | 4 +- scripts/update-reachability-pin.mjs | 67 +++++++++++++++++++++ 4 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 scripts/update-reachability-pin.mjs diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index ec04268..4f3a4f7 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -97,7 +97,7 @@ jobs: # Validate package integrity before publishing (tests, coverage, and production build). - name: Validate Package Before Publish - run: npm run validate:package + run: npm run validate:package:skip-reachability # Generate the package archive that will be attested and published to both registries. - name: Generate NPM Package Archive diff --git a/.github/workflows/Security-Reachability.yml b/.github/workflows/Security-Reachability.yml index 77aade8..5ed37b9 100644 --- a/.github/workflows/Security-Reachability.yml +++ b/.github/workflows/Security-Reachability.yml @@ -75,23 +75,9 @@ jobs: run: sfw npm install -g npm # Install the Socket CLI tool using pip and ensure it's up to date. - # socketsecurity is pinned rather than left on --upgrade because brand-new releases can - # pull in an equally brand-new @coana-tech/cli version that is still within Socket's own - # package-age cooldown window, causing npm ETARGET failures until it ages out. Bump this - # pin manually once a release is confirmed to work. - # - # To check whether a newer socketsecurity release is safe to bump to: - # 1. Check the candidate version's publish date: https://pypi.org/project/socketsecurity/#history - # (or `pip index versions socketsecurity`). It should be at least ~24-48h old so any - # npm dependency it pulls in has had time to clear Socket's package-age cooldown. - # 2. Run `pip download --no-deps socketsecurity== -d /tmp/check && tar tzf /tmp/check/*.tar.gz` - # (or inspect the sdist/wheel metadata) to find the @coana-tech/cli version it requires, - # then confirm that version's publish date on https://www.npmjs.com/package/@coana-tech/cli - # is also old enough (again, at least ~24-48h before the date you plan to run CI). - # 3. If both dates check out, bump the pin below and watch the next scan run succeed. - # 4. If the workflow starts failing with the same ETARGET/notarget error again, it means a - # new socketsecurity release again pulled in a too-fresh @coana-tech/cli - re-pin to the - # last known-good version and retry later. + # The local validate:package command maintains this pin using the latest non-yanked stable + # release that has been available on PyPI for at least 24 hours. CI runs the corresponding + # validate:package:skip-reachability command so workflow validation does not modify its checkout. - name: Install Socket CLI background: true run: sfw pip install socketsecurity==2.5.5 uv --upgrade diff --git a/package.json b/package.json index 569e616..4c7cb40 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "test": "npm run build:coverage && vitest run", "test:watch": "vitest", "coverage": "npm run build:coverage && vitest run --coverage", - "validate:package": "npm run lint && npm run coverage && npm run build:prod && node ./scripts/validate-package.mjs", + "validate:package": "npm run update:reachability-pin && npm run validate:package:skip-reachability", + "validate:package:skip-reachability": "npm run lint && npm run coverage && npm run build:prod && node ./scripts/validate-package.mjs", + "update:reachability-pin": "node ./scripts/update-reachability-pin.mjs", "prepack": "npm run validate:package", "postinstall": "ts-patch install -s" }, diff --git a/scripts/update-reachability-pin.mjs b/scripts/update-reachability-pin.mjs new file mode 100644 index 0000000..a2b1913 --- /dev/null +++ b/scripts/update-reachability-pin.mjs @@ -0,0 +1,67 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +const PYPI_URL = 'https://pypi.org/pypi/socketsecurity/json'; +const RELEASE_AGE_MILLISECONDS = 24 * 60 * 60 * 1000; +const workflowPath = fileURLToPath(new URL('../.github/workflows/Security-Reachability.yml', import.meta.url)); +const versionPattern = /^\d+(?:\.\d+)*$/u; +const pinPattern = /socketsecurity==(?\d+(?:\.\d+)*)/gu; + +const compareVersions = (left, right) => { + const leftParts = left.split('.').map(Number); + const rightParts = right.split('.').map(Number); + const partCount = Math.max(leftParts.length, rightParts.length); + + for (let index = 0; index < partCount; index += 1) { + const difference = (leftParts[index] ?? 0) - (rightParts[index] ?? 0); + + if (difference !== 0) { + return difference; + } + } + + return 0; +}; + +const response = await fetch(PYPI_URL); + +if (!response.ok) { + throw new Error(`Unable to retrieve socketsecurity releases from PyPI: ${ response.status } ${ response.statusText }`); +} + +const { releases } = await response.json(); +const cutoffTime = Date.now() - RELEASE_AGE_MILLISECONDS; +const eligibleRelease = Object.entries(releases) + .filter(([version, files]) => versionPattern.test(version) && Array.isArray(files) && files.length > 0 && files.every((file) => !file.yanked)) + .map(([version, files]) => { + const mostRecentUpload = Math.max(...files.map((file) => Date.parse(file.upload_time_iso_8601))); + + return { + 'mostRecentUpload': mostRecentUpload, + 'version': version + }; + }) + .filter(({ mostRecentUpload }) => Number.isFinite(mostRecentUpload) && mostRecentUpload <= cutoffTime) + .sort((left, right) => compareVersions(right.version, left.version))[0]; + +if (!eligibleRelease) { + throw new Error('PyPI did not return a non-yanked stable socketsecurity release at least 24 hours old.'); +} + +const workflow = await readFile(workflowPath, 'utf8'); +const pins = [...workflow.matchAll(pinPattern)]; + +if (pins.length !== 1) { + throw new Error(`Expected exactly one socketsecurity pin in ${ workflowPath }, found ${ pins.length }.`); +} + +const currentVersion = pins[0].groups.version; + +if (currentVersion === eligibleRelease.version) { + process.stdout.write(`Reachability pin is current: socketsecurity==${ currentVersion }\n`); +} else { + const updatedWorkflow = workflow.replace(pinPattern, `socketsecurity==${ eligibleRelease.version }`); + + await writeFile(workflowPath, updatedWorkflow); + process.stdout.write(`Updated reachability pin: socketsecurity==${ currentVersion } -> socketsecurity==${ eligibleRelease.version }\n`); +} From 7369a83104c34b0e1895678b8188d8e205bb7c3d Mon Sep 17 00:00:00 2001 From: pr0uxx Date: Thu, 30 Jul 2026 09:55:13 +0100 Subject: [PATCH 4/5] Set npm auth token before GitHub publish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the Build workflow’s GitHub Packages publish step to explicitly configure `//npm.pkg.github.com/:_authToken` from `NODE_AUTH_TOKEN` before running `npm publish`. This makes authentication explicit and avoids publish failures when npm does not automatically pick up the token from environment alone. --- .github/workflows/Build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 4f3a4f7..9c2b22e 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -114,7 +114,9 @@ jobs: - name: Upload Package to GitHub Packages Registry env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm publish ${{ steps.generate-package.outputs.package-file }} --registry=https://npm.pkg.github.com --tag ${{ needs.Metadata.outputs.channel }} --ignore-scripts + run: | + npm config set //npm.pkg.github.com/:_authToken "$NODE_AUTH_TOKEN" + npm publish ${{ steps.generate-package.outputs.package-file }} --registry=https://npm.pkg.github.com --tag ${{ needs.Metadata.outputs.channel }} --ignore-scripts # Upload the attested npm package archive for the publish workflow to consume. - name: Upload NPM Package Archive Artifact From f0058cd7585c007000b901859c033652b9e3d2a9 Mon Sep 17 00:00:00 2001 From: pr0uxx Date: Thu, 30 Jul 2026 09:57:16 +0100 Subject: [PATCH 5/5] Update Security-Reachability.yml --- .github/workflows/Security-Reachability.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Security-Reachability.yml b/.github/workflows/Security-Reachability.yml index 5ed37b9..76fa353 100644 --- a/.github/workflows/Security-Reachability.yml +++ b/.github/workflows/Security-Reachability.yml @@ -91,4 +91,4 @@ jobs: env: SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_REACHABILITY }} GH_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: socketcli --target-path $GITHUB_WORKSPACE --scm github --reach + run: socketcli --target-path $GITHUB_WORKSPACE --scm github --pr-number ${{ github.event.pull_request.number || 0 }} --reach