Skip to content
This repository was archived by the owner on Sep 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/actions/setup-ci/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ 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 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"
Expand All @@ -110,11 +110,13 @@ 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 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
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/Publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/Security-Reachability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,13 @@ 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.
# 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 uv --upgrade
run: sfw pip install socketsecurity==2.5.5 uv --upgrade
Comment thread
pr0uxx marked this conversation as resolved.

# 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
Expand All @@ -88,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
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
67 changes: 67 additions & 0 deletions scripts/update-reachability-pin.mjs
Original file line number Diff line number Diff line change
@@ -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==(?<version>\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`);
}