Skip to content

Commit cc267a6

Browse files
feat: Rust rewrite with cross-compilation and npm distribution (#30)
* feat: add cross-compilation, npm distribution, and release workflows - Add release.yml workflow triggered by v* tags: builds 5 targets (darwin-arm64, darwin-x64, linux-x64-musl, linux-arm64, win32-x64), creates GitHub Release, publishes npm platform packages - Add ci.yml workflow for PRs/pushes: cargo clippy + cargo test - Add npm/ directory with esbuild-style optionalDependencies pattern (root wrapper + 5 platform packages with os/cpu fields) - Add scripts/version-sync.sh to propagate versions across Cargo.toml and all npm package.json files - Update publish.yml to bump version, sync, and push tag to trigger release pipeline - Add rust-toolchain.toml pinning stable channel - Update .gitignore for Rust target/ and npm platform binaries Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: pin all GitHub Actions to full commit SHAs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add explicit toolchain input for pinned rust-toolchain action When dtolnay/rust-toolchain is pinned to a SHA instead of a branch name, the toolchain version can't be inferred from the ref and must be passed explicitly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: consolidate npm distribution into single package with bundled binaries Delete all TypeScript source, configs, and platform-specific npm packages. The single @socketsecurity/socket-patch package now ships all 5 platform binaries (~20MB total) instead of using optionalDependencies with 6 packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Windows support for Python crawler and CI test matrix Resolve runtime gaps on Windows: use find_python_command() to discover python3/python/py, add USERPROFILE fallback for home dir, gate Unix-only paths and add Windows Python install locations (APPDATA, LOCALAPPDATA, Program Files), and add Windows uv tools path. CI now runs tests on both ubuntu-latest and windows-latest. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add cargo publish, install script, clippy fixes, and expanded tests Add crates.io publishing to release workflow, a one-line install script, and README installation docs. Fix UTF-8 truncation bug in API client, apply clippy suggestions (is_some_and, strip_prefix, div_ceil, derive Default), and add comprehensive tests across API, package_json, and blob_fetcher modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: fix Windows CI test failures for telemetry and Python crawler Use home_dir_string() helper (which checks USERPROFILE on Windows) in the sanitize_error_message test instead of only checking HOME. Use platform-appropriate venv directory layout in test_crawl_all_python. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: merge telemetry env-var tests to prevent parallel race condition The two tests (test_is_telemetry_disabled_default and test_is_telemetry_disabled_when_set) mutated shared env vars and raced when run in parallel on Windows CI. Merge them into a single test that saves/restores the original values. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add e2e tests for npm and PyPI patch lifecycles Add full end-to-end tests that exercise the CLI against the public Socket API: - npm: minimist@1.2.2 patch (CVE-2021-44906, prototype pollution) - PyPI: pydantic-ai@0.0.36 patch (CVE-2026-25580, SSRF) Each test covers the complete lifecycle: get → list → rollback → apply → remove, plus a dry-run test per ecosystem. Tests are gated with #[ignore] and run in CI via a dedicated e2e job on ubuntu and macos. Also fixes a bug where patches with no beforeHash (new files added by a patch) were silently dropped from the manifest. The apply and rollback engines now handle empty beforeHash correctly: - apply: creates new files, skips beforeHash verification - rollback: deletes patch-created files instead of restoring from blob - get: includes files in manifest even when beforeHash is absent Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: use crates.io trusted publishing via OIDC instead of static token Replace CRATES_IO_TOKEN secret with rust-lang/crates-io-auth-action, which exchanges a GitHub OIDC token for a short-lived crates.io publish token. This eliminates the need to manage long-lived API secrets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7f464f4 commit cc267a6

File tree

119 files changed

+14855
-15811
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+14855
-15811
lines changed

.github/workflows/ci.yml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
test:
13+
strategy:
14+
matrix:
15+
os: [ubuntu-latest, windows-latest]
16+
runs-on: ${{ matrix.os }}
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
20+
21+
- name: Install Rust
22+
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
23+
with:
24+
toolchain: stable
25+
components: clippy
26+
27+
- name: Cache cargo
28+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
29+
with:
30+
path: |
31+
~/.cargo/registry
32+
~/.cargo/git
33+
target
34+
key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
35+
restore-keys: ${{ matrix.os }}-cargo-
36+
37+
- name: Run clippy
38+
run: cargo clippy --workspace -- -D warnings
39+
40+
- name: Run tests
41+
run: cargo test --workspace
42+
43+
e2e:
44+
needs: test
45+
strategy:
46+
fail-fast: false
47+
matrix:
48+
include:
49+
- os: ubuntu-latest
50+
suite: e2e_npm
51+
- os: ubuntu-latest
52+
suite: e2e_pypi
53+
- os: macos-latest
54+
suite: e2e_npm
55+
- os: macos-latest
56+
suite: e2e_pypi
57+
runs-on: ${{ matrix.os }}
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
61+
62+
- name: Install Rust
63+
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
64+
with:
65+
toolchain: stable
66+
67+
- name: Cache cargo
68+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
69+
with:
70+
path: |
71+
~/.cargo/registry
72+
~/.cargo/git
73+
target
74+
key: ${{ matrix.os }}-cargo-e2e-${{ hashFiles('**/Cargo.lock') }}
75+
restore-keys: ${{ matrix.os }}-cargo-e2e-
76+
77+
- name: Setup Node.js
78+
if: matrix.suite == 'e2e_npm'
79+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
80+
with:
81+
node-version: 20
82+
83+
- name: Setup Python
84+
if: matrix.suite == 'e2e_pypi'
85+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
86+
with:
87+
python-version: "3.12"
88+
89+
- name: Run e2e tests
90+
run: cargo test -p socket-patch-cli --test ${{ matrix.suite }} -- --ignored

.github/workflows/publish.yml

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: 📦 Publish
1+
name: Publish
22

33
on:
44
workflow_dispatch:
@@ -11,29 +11,13 @@ on:
1111
- patch
1212
- minor
1313
- major
14-
dist-tag:
15-
description: 'npm dist-tag (latest, next, beta, canary, backport, etc.)'
16-
required: false
17-
default: 'latest'
18-
type: string
19-
debug:
20-
description: 'Enable debug output'
21-
required: false
22-
default: '0'
23-
type: choice
24-
options:
25-
- '0'
26-
- '1'
2714

2815
permissions:
2916
contents: write
30-
id-token: write
3117

3218
jobs:
33-
bump-version:
19+
bump-and-tag:
3420
runs-on: ubuntu-latest
35-
outputs:
36-
new-tag: ${{ steps.bump.outputs.new-tag }}
3721
steps:
3822
- name: Checkout
3923
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -48,23 +32,20 @@ jobs:
4832
git config user.name "github-actions[bot]"
4933
git config user.email "github-actions[bot]@users.noreply.github.com"
5034
51-
- name: Bump version
52-
id: bump
35+
- name: Bump version and sync
5336
run: |
54-
npm version ${{ inputs.version-bump }} -m "v%s"
55-
echo "new-tag=$(git describe --tags --abbrev=0)" >> "$GITHUB_OUTPUT"
56-
57-
- name: Push changes
37+
CURRENT=$(node -p "require('./npm/socket-patch/package.json').version")
38+
VERSION=$(node -e "
39+
const [major, minor, patch] = '$CURRENT'.split('.').map(Number);
40+
const bump = '${{ inputs.version-bump }}';
41+
if (bump === 'major') console.log((major+1)+'.0.0');
42+
else if (bump === 'minor') console.log(major+'.'+(minor+1)+'.0');
43+
else console.log(major+'.'+minor+'.'+(patch+1));
44+
")
45+
bash scripts/version-sync.sh "$VERSION"
46+
git add Cargo.toml npm/
47+
git commit -m "v$VERSION"
48+
git tag "v$VERSION"
49+
50+
- name: Push changes and tag
5851
run: git push && git push --tags
59-
60-
publish:
61-
needs: bump-version
62-
uses: SocketDev/socket-registry/.github/workflows/provenance.yml@main
63-
with:
64-
debug: ${{ inputs.debug }}
65-
dist-tag: ${{ inputs.dist-tag }}
66-
package-name: '@socketsecurity/socket-patch'
67-
publish-script: 'publish:ci'
68-
ref: ${{ needs.bump-version.outputs.new-tag }}
69-
setup-script: 'pnpm run build'
70-
use-trusted-publishing: true

.github/workflows/release.yml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
id-token: write
11+
12+
jobs:
13+
build:
14+
strategy:
15+
matrix:
16+
include:
17+
- target: aarch64-apple-darwin
18+
runner: macos-14
19+
archive: tar.gz
20+
build-tool: cargo
21+
- target: x86_64-apple-darwin
22+
runner: macos-13
23+
archive: tar.gz
24+
build-tool: cargo
25+
- target: x86_64-unknown-linux-musl
26+
runner: ubuntu-latest
27+
archive: tar.gz
28+
build-tool: cross
29+
- target: aarch64-unknown-linux-gnu
30+
runner: ubuntu-latest
31+
archive: tar.gz
32+
build-tool: cross
33+
- target: x86_64-pc-windows-msvc
34+
runner: windows-latest
35+
archive: zip
36+
build-tool: cargo
37+
runs-on: ${{ matrix.runner }}
38+
steps:
39+
- name: Checkout
40+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
41+
42+
- name: Install Rust
43+
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
44+
with:
45+
toolchain: stable
46+
targets: ${{ matrix.target }}
47+
48+
- name: Install cross
49+
if: matrix.build-tool == 'cross'
50+
run: cargo install cross --git https://github.com/cross-rs/cross
51+
52+
- name: Build (cargo)
53+
if: matrix.build-tool == 'cargo'
54+
run: cargo build --release --target ${{ matrix.target }}
55+
56+
- name: Build (cross)
57+
if: matrix.build-tool == 'cross'
58+
run: cross build --release --target ${{ matrix.target }}
59+
60+
- name: Package (unix)
61+
if: matrix.archive == 'tar.gz'
62+
run: |
63+
cd target/${{ matrix.target }}/release
64+
tar czf ../../../socket-patch-${{ matrix.target }}.tar.gz socket-patch
65+
cd ../../..
66+
67+
- name: Package (windows)
68+
if: matrix.archive == 'zip'
69+
shell: pwsh
70+
run: |
71+
Compress-Archive -Path "target/${{ matrix.target }}/release/socket-patch.exe" -DestinationPath "socket-patch-${{ matrix.target }}.zip"
72+
73+
- name: Upload artifact (tar.gz)
74+
if: matrix.archive == 'tar.gz'
75+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
76+
with:
77+
name: socket-patch-${{ matrix.target }}
78+
path: socket-patch-${{ matrix.target }}.tar.gz
79+
80+
- name: Upload artifact (zip)
81+
if: matrix.archive == 'zip'
82+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
83+
with:
84+
name: socket-patch-${{ matrix.target }}
85+
path: socket-patch-${{ matrix.target }}.zip
86+
87+
github-release:
88+
needs: build
89+
runs-on: ubuntu-latest
90+
steps:
91+
- name: Download all artifacts
92+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
93+
with:
94+
path: artifacts
95+
merge-multiple: true
96+
97+
- name: Create GitHub Release
98+
env:
99+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
100+
run: |
101+
TAG="${GITHUB_REF_NAME}"
102+
gh release create "$TAG" \
103+
--repo "$GITHUB_REPOSITORY" \
104+
--generate-notes \
105+
artifacts/*
106+
107+
cargo-publish:
108+
needs: build
109+
runs-on: ubuntu-latest
110+
permissions:
111+
contents: read
112+
id-token: write
113+
steps:
114+
- name: Checkout
115+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
116+
117+
- name: Install Rust
118+
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
119+
with:
120+
toolchain: stable
121+
122+
- name: Authenticate with crates.io
123+
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3
124+
125+
- name: Publish socket-patch-core
126+
run: cargo publish -p socket-patch-core
127+
128+
- name: Wait for crates.io index update
129+
run: sleep 30
130+
131+
- name: Publish socket-patch-cli
132+
run: cargo publish -p socket-patch-cli
133+
134+
npm-publish:
135+
needs: build
136+
runs-on: ubuntu-latest
137+
steps:
138+
- name: Checkout
139+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
140+
141+
- name: Download all artifacts
142+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
143+
with:
144+
path: artifacts
145+
merge-multiple: true
146+
147+
- name: Setup Node.js
148+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
149+
with:
150+
node-version: '20'
151+
registry-url: 'https://registry.npmjs.org'
152+
153+
- name: Extract version and sync
154+
run: |
155+
VERSION="${GITHUB_REF_NAME#v}"
156+
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
157+
bash scripts/version-sync.sh "$VERSION"
158+
159+
- name: Stage binaries
160+
run: |
161+
mkdir -p npm/socket-patch/bin
162+
tar xzf artifacts/socket-patch-aarch64-apple-darwin.tar.gz -C npm/socket-patch/bin/
163+
mv npm/socket-patch/bin/socket-patch npm/socket-patch/bin/socket-patch-darwin-arm64
164+
tar xzf artifacts/socket-patch-x86_64-apple-darwin.tar.gz -C npm/socket-patch/bin/
165+
mv npm/socket-patch/bin/socket-patch npm/socket-patch/bin/socket-patch-darwin-x64
166+
tar xzf artifacts/socket-patch-x86_64-unknown-linux-musl.tar.gz -C npm/socket-patch/bin/
167+
mv npm/socket-patch/bin/socket-patch npm/socket-patch/bin/socket-patch-linux-x64
168+
tar xzf artifacts/socket-patch-aarch64-unknown-linux-gnu.tar.gz -C npm/socket-patch/bin/
169+
mv npm/socket-patch/bin/socket-patch npm/socket-patch/bin/socket-patch-linux-arm64
170+
cd npm/socket-patch/bin
171+
unzip ../../../artifacts/socket-patch-x86_64-pc-windows-msvc.zip
172+
mv socket-patch.exe socket-patch-win32-x64.exe
173+
174+
- name: Publish package
175+
env:
176+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
177+
run: npm publish npm/socket-patch --provenance --access public

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,9 @@ dist
137137
# Vite logs files
138138
vite.config.js.timestamp-*
139139
vite.config.ts.timestamp-*
140+
141+
# Rust
142+
target/
143+
144+
# npm binaries (populated at publish time)
145+
npm/socket-patch/bin/socket-patch-*

.npmignore

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)