Skip to content

Commit f56ec58

Browse files
committed
Merge branch 'main' into lelia/update-purl-endpoint-support
# Conflicts: # CHANGELOG.md # pyproject.toml # socketsecurity/__init__.py
2 parents b0af1ae + 0d19e64 commit f56ec58

32 files changed

Lines changed: 1494 additions & 219 deletions

.github/workflows/e2e-test.yml

Lines changed: 57 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: E2E Test
1+
name: E2E Tests
22

33
on:
44
push:
@@ -10,93 +10,58 @@ permissions:
1010
contents: read
1111

1212
jobs:
13-
e2e-scan:
14-
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
15-
runs-on: ubuntu-latest
16-
steps:
17-
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
18-
with:
19-
fetch-depth: 0
20-
persist-credentials: false
21-
22-
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
23-
with:
24-
python-version: '3.12'
25-
26-
- name: Install CLI from local repo
27-
run: |
28-
python -m pip install --upgrade pip
29-
pip install .
30-
31-
- name: Run Socket CLI scan
32-
env:
33-
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
34-
run: |
35-
set -o pipefail
36-
socketcli \
37-
--target-path tests/e2e/fixtures/simple-npm \
38-
--disable-blocking \
39-
--enable-debug \
40-
2>&1 | tee /tmp/scan-output.log
41-
42-
- name: Verify scan produced a report
43-
run: |
44-
if grep -q "Full scan report URL: https://socket.dev/" /tmp/scan-output.log; then
45-
echo "PASS: Full scan report URL found"
46-
grep "Full scan report URL:" /tmp/scan-output.log
47-
elif grep -q "Diff Url: https://socket.dev/" /tmp/scan-output.log; then
48-
echo "PASS: Diff URL found"
49-
grep "Diff Url:" /tmp/scan-output.log
50-
else
51-
echo "FAIL: No report URL found in scan output"
52-
cat /tmp/scan-output.log
53-
exit 1
54-
fi
55-
56-
e2e-sarif:
57-
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
58-
runs-on: ubuntu-latest
59-
steps:
60-
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
61-
with:
62-
fetch-depth: 0
63-
persist-credentials: false
64-
65-
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
66-
with:
67-
python-version: '3.12'
68-
69-
- name: Install CLI from local repo
70-
run: |
71-
python -m pip install --upgrade pip
72-
pip install .
73-
74-
- name: Run Socket CLI scan with --sarif-file
75-
env:
76-
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
77-
run: |
78-
set -o pipefail
79-
socketcli \
80-
--target-path tests/e2e/fixtures/simple-npm \
81-
--sarif-file /tmp/results.sarif \
82-
--disable-blocking \
83-
2>&1 | tee /tmp/sarif-output.log
84-
85-
- name: Verify SARIF file is valid
86-
run: |
87-
python3 -c "
88-
import json, sys
89-
with open('/tmp/results.sarif') as f:
90-
data = json.load(f)
91-
assert data['version'] == '2.1.0', f'Invalid version: {data[\"version\"]}'
92-
assert '\$schema' in data, 'Missing \$schema'
93-
count = len(data['runs'][0]['results'])
94-
print(f'PASS: Valid SARIF 2.1.0 with {count} result(s)')
95-
"
96-
97-
e2e-reachability:
13+
e2e:
9814
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
9915
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
include:
20+
- name: scan
21+
args: >-
22+
--target-path tests/e2e/fixtures/simple-npm
23+
--disable-blocking
24+
--enable-debug
25+
validate: tests/e2e/validate-scan.sh
26+
27+
- name: sarif
28+
args: >-
29+
--target-path tests/e2e/fixtures/simple-npm
30+
--sarif-file /tmp/results.sarif
31+
--disable-blocking
32+
validate: tests/e2e/validate-sarif.sh
33+
34+
- name: reachability
35+
args: >-
36+
--target-path tests/e2e/fixtures/simple-npm
37+
--reach
38+
--disable-blocking
39+
--enable-debug
40+
validate: tests/e2e/validate-reachability.sh
41+
setup-node: "true"
42+
43+
- name: gitlab
44+
args: >-
45+
--target-path tests/e2e/fixtures/simple-npm
46+
--enable-gitlab-security
47+
--disable-blocking
48+
validate: tests/e2e/validate-gitlab.sh
49+
50+
- name: json
51+
args: >-
52+
--target-path tests/e2e/fixtures/simple-npm
53+
--enable-json
54+
--disable-blocking
55+
validate: tests/e2e/validate-json.sh
56+
57+
- name: pypi
58+
args: >-
59+
--target-path tests/e2e/fixtures/simple-pypi
60+
--disable-blocking
61+
--enable-debug
62+
validate: tests/e2e/validate-scan.sh
63+
64+
name: e2e-${{ matrix.name }}
10065
steps:
10166
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
10267
with:
@@ -108,6 +73,7 @@ jobs:
10873
python-version: '3.12'
10974

11075
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
76+
if: matrix.setup-node == 'true'
11177
with:
11278
node-version: '20'
11379

@@ -117,85 +83,17 @@ jobs:
11783
pip install .
11884
11985
- name: Install uv
86+
if: matrix.setup-node == 'true'
12087
run: pip install uv
12188

122-
- name: Run Socket CLI with reachability
89+
- name: Run Socket CLI
12390
env:
12491
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
12592
run: |
12693
set -o pipefail
127-
socketcli \
128-
--target-path tests/e2e/fixtures/simple-npm \
129-
--reach \
130-
--disable-blocking \
131-
--enable-debug \
132-
2>&1 | tee /tmp/reach-output.log
133-
134-
- name: Verify reachability analysis completed
135-
run: |
136-
if grep -q "Reachability analysis completed successfully" /tmp/reach-output.log; then
137-
echo "PASS: Reachability analysis completed"
138-
grep "Reachability analysis completed successfully" /tmp/reach-output.log
139-
grep "Results written to:" /tmp/reach-output.log || true
140-
else
141-
echo "FAIL: Reachability analysis did not complete successfully"
142-
cat /tmp/reach-output.log
143-
exit 1
144-
fi
145-
146-
- name: Verify scan produced a report
147-
run: |
148-
if grep -q "Full scan report URL: https://socket.dev/" /tmp/reach-output.log; then
149-
echo "PASS: Full scan report URL found"
150-
grep "Full scan report URL:" /tmp/reach-output.log
151-
elif grep -q "Diff Url: https://socket.dev/" /tmp/reach-output.log; then
152-
echo "PASS: Diff URL found"
153-
grep "Diff Url:" /tmp/reach-output.log
154-
else
155-
echo "FAIL: No report URL found in scan output"
156-
cat /tmp/reach-output.log
157-
exit 1
158-
fi
94+
socketcli ${{ matrix.args }} 2>&1 | tee /tmp/e2e-output.log
15995
160-
- name: Run scan with --sarif-file (all results)
96+
- name: Validate results
16197
env:
16298
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
163-
run: |
164-
socketcli \
165-
--target-path tests/e2e/fixtures/simple-npm \
166-
--reach \
167-
--sarif-file /tmp/sarif-all.sarif \
168-
--sarif-scope full \
169-
--sarif-reachability all \
170-
--disable-blocking \
171-
2>/dev/null
172-
173-
- name: Run scan with --sarif-file --sarif-reachability reachable (filtered results)
174-
env:
175-
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
176-
run: |
177-
socketcli \
178-
--target-path tests/e2e/fixtures/simple-npm \
179-
--reach \
180-
--sarif-file /tmp/sarif-reachable.sarif \
181-
--sarif-scope full \
182-
--sarif-reachability reachable \
183-
--disable-blocking \
184-
2>/dev/null
185-
186-
- name: Verify reachable-only results are a subset of all results
187-
run: |
188-
test -f /tmp/sarif-all.sarif
189-
test -f /tmp/sarif-reachable.sarif
190-
python3 -c "
191-
import json
192-
with open('/tmp/sarif-all.sarif') as f:
193-
all_data = json.load(f)
194-
with open('/tmp/sarif-reachable.sarif') as f:
195-
reach_data = json.load(f)
196-
all_count = len(all_data['runs'][0]['results'])
197-
reach_count = len(reach_data['runs'][0]['results'])
198-
print(f'All results: {all_count}, Reachable-only results: {reach_count}')
199-
assert reach_count <= all_count, f'FAIL: reachable ({reach_count}) > all ({all_count})'
200-
print('PASS: Reachable-only results is a subset of all results')
201-
"
99+
run: bash ${{ matrix.validate }}

.github/workflows/version-check.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ on:
44
types: [opened, synchronize, ready_for_review]
55
paths:
66
- 'socketsecurity/**'
7-
- 'setup.py'
87
- 'pyproject.toml'
8+
- 'uv.lock'
99

1010
permissions:
1111
contents: read
@@ -46,6 +46,18 @@ jobs:
4646
print(f'✅ Version properly incremented from {main_ver} to {pr_ver}')
4747
"
4848
49+
- name: Require uv.lock update when pyproject changes
50+
run: |
51+
CHANGED_FILES="$(git diff --name-only origin/main...HEAD)"
52+
53+
if echo "$CHANGED_FILES" | grep -qx 'pyproject.toml'; then
54+
if ! echo "$CHANGED_FILES" | grep -qx 'uv.lock'; then
55+
echo "❌ pyproject.toml changed, but uv.lock was not updated."
56+
echo "Run 'uv lock' and commit uv.lock with the version bump."
57+
exit 1
58+
fi
59+
fi
60+
4961
- name: Manage PR Comment
5062
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
5163
if: always() && github.event.pull_request.head.repo.full_name == github.repository

.hooks/sync_version.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
INIT_FILE = pathlib.Path("socketsecurity/__init__.py")
1010
PYPROJECT_FILE = pathlib.Path("pyproject.toml")
11+
UV_LOCK_FILE = pathlib.Path("uv.lock")
1112

1213
VERSION_PATTERN = re.compile(r"__version__\s*=\s*['\"]([^'\"]+)['\"]")
1314
PYPROJECT_PATTERN = re.compile(r'^version\s*=\s*".*"$', re.MULTILINE)
@@ -72,6 +73,21 @@ def inject_version(version: str):
7273
new_pyproject = re.sub(r"(\[project\])", rf"\1\nversion = \"{version}\"", pyproject)
7374
PYPROJECT_FILE.write_text(new_pyproject)
7475

76+
77+
def run_uv_lock() -> bool:
78+
before = UV_LOCK_FILE.read_bytes() if UV_LOCK_FILE.exists() else b""
79+
try:
80+
subprocess.run(["uv", "lock"], check=True, text=True)
81+
except FileNotFoundError:
82+
print("❌ `uv` is required but was not found in PATH.")
83+
sys.exit(1)
84+
except subprocess.CalledProcessError:
85+
print("❌ `uv lock` failed. Please run it manually and fix any errors.")
86+
sys.exit(1)
87+
88+
after = UV_LOCK_FILE.read_bytes() if UV_LOCK_FILE.exists() else b""
89+
return before != after
90+
7591
def main():
7692
dev_mode = "--dev" in sys.argv
7793
current_version = read_version_from_init(INIT_FILE)
@@ -84,15 +100,24 @@ def main():
84100
base_version = current_version.split(".dev")[0] if ".dev" in current_version else current_version
85101
new_version = find_next_available_dev_version(base_version)
86102
inject_version(new_version)
87-
print("⚠️ Version was unchanged — auto-bumped. Please git add + commit again.")
103+
uv_lock_changed = run_uv_lock()
104+
lock_hint = " and uv.lock" if uv_lock_changed else ""
105+
print(f"⚠️ Version was unchanged — auto-bumped. Please git add{lock_hint} + commit again.")
88106
sys.exit(0)
89107
else:
90108
new_version = bump_patch_version(current_version)
91109
inject_version(new_version)
92-
print("⚠️ Version was unchanged — auto-bumped. Please git add + commit again.")
110+
uv_lock_changed = run_uv_lock()
111+
lock_hint = " and uv.lock" if uv_lock_changed else ""
112+
print(f"⚠️ Version was unchanged — auto-bumped. Please git add{lock_hint} + commit again.")
93113
sys.exit(1)
94114
else:
95-
print("✅ Version already bumped — proceeding.")
115+
uv_lock_changed = run_uv_lock()
116+
if uv_lock_changed:
117+
print("⚠️ Version already bumped, but uv.lock was out of date and has been updated. Please git add uv.lock + commit again.")
118+
sys.exit(1)
119+
120+
print("✅ Version already bumped and uv.lock is up to date — proceeding.")
96121
sys.exit(0)
97122

98123
if __name__ == "__main__":

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Changelog
22

3-
## [Unreleased]
3+
## 2.2.90
44

55
- Migrated license enrichment PURL lookup to the org-scoped endpoint (`POST /v0/orgs/{slug}/purl`) from the deprecated global endpoint (`POST /v0/purl`).
66

7+
## 2.2.83
8+
9+
- Fixed branch detection in detached-HEAD CI checkouts. When `git name-rev --name-only HEAD` returned an output with a suffix operator (e.g. `remotes/origin/master~1`, `master^0`), the `~N`/`^N` was previously passed through as the branch name and rejected by the Socket API as an invalid Git ref. The suffix is now stripped before the prefix split, producing the bare branch name.
10+
711
## 2.2.80
812

913
- Hardened GitHub Actions workflows.

0 commit comments

Comments
 (0)