Skip to content

Commit 227e73b

Browse files
committed
Consolidate e2e test workflows, add additional coverage
Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
1 parent abf416d commit 227e73b

File tree

8 files changed

+253
-160
lines changed

8 files changed

+253
-160
lines changed

.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 }}

tests/e2e/fixtures/simple-npm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Test fixture for reachability analysis",
55
"main": "index.js",
66
"dependencies": {
7-
"lodash": "4.17.23",
7+
"lodash": "4.18.1",
88
"express": "4.22.0",
99
"axios": "1.13.5"
1010
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
requests==2.31.0
2+
flask==3.0.0
3+
pyyaml==6.0.1

tests/e2e/validate-gitlab.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
REPORT="gl-dependency-scanning-report.json"
5+
6+
if [ ! -f "$REPORT" ]; then
7+
echo "FAIL: GitLab report not found at $REPORT"
8+
exit 1
9+
fi
10+
11+
python3 -c "
12+
import json, re, sys
13+
14+
with open('$REPORT') as f:
15+
data = json.load(f)
16+
17+
errors = []
18+
19+
# v15.0.0 required root-level keys
20+
for key in ('version', 'scan', 'vulnerabilities', 'dependency_files'):
21+
if key not in data:
22+
errors.append(f'Missing required root key: {key}')
23+
24+
if 'scan' in data:
25+
scan = data['scan']
26+
27+
# Timestamp format: YYYY-MM-DDTHH:MM:SS (no microseconds, no trailing Z)
28+
ts_pattern = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$')
29+
for field in ('start_time', 'end_time'):
30+
val = scan.get(field, '')
31+
if not ts_pattern.match(val):
32+
errors.append(f'scan.{field} \"{val}\" does not match pattern YYYY-MM-DDTHH:MM:SS')
33+
34+
if scan.get('type') != 'dependency_scanning':
35+
errors.append(f'scan.type is \"{scan.get(\"type\")}\" expected \"dependency_scanning\"')
36+
37+
analyzer_id = scan.get('analyzer', {}).get('id', '')
38+
if analyzer_id != 'socket-security':
39+
errors.append(f'scan.analyzer.id is \"{analyzer_id}\" expected \"socket-security\"')
40+
41+
scanner_id = scan.get('scanner', {}).get('id', '')
42+
if scanner_id != 'socket-cli':
43+
errors.append(f'scan.scanner.id is \"{scanner_id}\" expected \"socket-cli\"')
44+
45+
if scan.get('status') != 'success':
46+
errors.append(f'scan.status is \"{scan.get(\"status\")}\" expected \"success\"')
47+
48+
# dependency_files structure check
49+
if 'dependency_files' in data:
50+
for i, df in enumerate(data['dependency_files']):
51+
for req in ('path', 'package_manager', 'dependencies'):
52+
if req not in df:
53+
errors.append(f'dependency_files[{i}] missing required key: {req}')
54+
55+
if errors:
56+
for e in errors:
57+
print(f'FAIL: {e}')
58+
sys.exit(1)
59+
60+
vuln_count = len(data.get('vulnerabilities', []))
61+
dep_file_count = len(data.get('dependency_files', []))
62+
print(f'PASS: Valid GitLab v15.0.0 report with {vuln_count} vulnerability(ies) and {dep_file_count} dependency file(s)')
63+
"

tests/e2e/validate-json.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
LOG="/tmp/e2e-output.log"
5+
6+
python3 -c "
7+
import json, sys
8+
9+
# The JSON output is on stdout; the log may also contain stderr debug lines.
10+
# Find the first line that parses as valid JSON.
11+
found = False
12+
with open('$LOG') as f:
13+
for line in f:
14+
line = line.strip()
15+
if not line:
16+
continue
17+
try:
18+
data = json.loads(line)
19+
if isinstance(data, dict):
20+
found = True
21+
print(f'PASS: Valid JSON output with {len(data)} top-level key(s)')
22+
break
23+
except json.JSONDecodeError:
24+
continue
25+
26+
if not found:
27+
print('FAIL: No valid JSON object found in output')
28+
sys.exit(1)
29+
"

0 commit comments

Comments
 (0)