Skip to content

Commit 0819738

Browse files
committed
ci(dependency-review): bundle SFW reports as artifacts
Collect each Socket Firewall smoke job's output into an sfw-artifacts/ directory and upload it (if: always(), so the report survives even when sfw BLOCKS an install): - context.txt -- provenance (mode, manifest, PR#, head SHA) - sfw-*.log -- teed firewall console output (pipefail preserves the sfw exit code so a block still fails the job) - import-smoke.log (python jobs) - sfw-report.json -- the structured firewall report, copied from $SFW_JSON_REPORT_PATH (the path socketdev/action exports); a sfw-report-missing.txt breadcrumb is written instead when no report is produced Copy rather than redirect the JSON: socketdev/action's post step reads $SFW_JSON_REPORT_PATH to render its job summary, so the report must stay at its temp path. Artifacts are named per edition+manifest to stay unique within a run. Pins actions/upload-artifact to v7.0.1. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
1 parent f9fcbd9 commit 0819738

1 file changed

Lines changed: 244 additions & 9 deletions

File tree

.github/workflows/dependency-review.yml

Lines changed: 244 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ name: dependency-review
1818
# Only Enterprise jobs declare the socket-firewall environment. Free jobs do
1919
# not touch that environment or its token.
2020
#
21-
# Pattern adapted from SocketDev/socket-basics.
21+
# Each sfw smoke job collects an sfw-artifacts/ directory (provenance context
22+
# + the firewall's console logs) and uploads it as a build artifact
23+
# (if: always(), so the report survives even when sfw BLOCKS an install --
24+
# which is exactly when you want to read it).
25+
#
26+
# Pattern adapted from SocketDev/socket-basics and SocketDev/socket-sdk-python.
2227

2328
on:
2429
pull_request:
@@ -135,6 +140,16 @@ jobs:
135140
fetch-depth: 1
136141
persist-credentials: false
137142

143+
- name: Prepare SFW artifact directory
144+
run: |
145+
mkdir -p sfw-artifacts
146+
{
147+
echo "mode=firewall-free"
148+
echo "manifest=python"
149+
echo "pr=${{ github.event.pull_request.number }}"
150+
echo "sha=${{ github.event.pull_request.head.sha }}"
151+
} > sfw-artifacts/context.txt
152+
138153
- uses: ./.github/actions/setup-sfw
139154
with:
140155
uv: "true"
@@ -151,16 +166,22 @@ jobs:
151166
# Use the runner's setup-python interpreter and forbid managed-Python
152167
# downloads. The firewall is here to vet PyPI installs, not the
153168
# interpreter/toolchain download path.
169+
#
170+
# pipefail keeps sfw's exit code through the tee so a firewall block
171+
# still fails the job; tee captures the report for the artifact upload.
154172
env:
155173
UV_PYTHON: "3.12"
156174
UV_PYTHON_DOWNLOADS: never
157-
run: sfw uv sync --locked --extra test --extra dev
175+
run: |
176+
set -o pipefail
177+
sfw uv sync --locked --extra test --extra dev 2>&1 | tee sfw-artifacts/sfw-uv-sync.log
158178
159179
- name: Import smoke test
160180
env:
161181
UV_PYTHON: "3.12"
162182
UV_PYTHON_DOWNLOADS: never
163183
run: |
184+
set -o pipefail
164185
uv run python -c "
165186
from socketsecurity.socketcli import cli, build_socket_sdk
166187
from socketsecurity.core import Core
@@ -170,7 +191,31 @@ jobs:
170191
from socketsecurity.core.git_interface import Git
171192
from socketsecurity.config import CliConfig
172193
print('import smoke OK')
173-
"
194+
" 2>&1 | tee sfw-artifacts/import-smoke.log
195+
196+
- name: Collect SFW JSON report
197+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
198+
# file) and reads it back in its post step to render the job summary, so
199+
# COPY (don't move) the report into the bundle. sfw writes it even when
200+
# it blocks an install -- always() keeps it on failures too.
201+
if: always()
202+
run: |
203+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
204+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
205+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
206+
else
207+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
208+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
209+
fi
210+
211+
- name: Upload SFW report artifact
212+
if: always()
213+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
214+
with:
215+
name: socket-firewall-free-python-${{ github.event.pull_request.number }}
216+
path: sfw-artifacts/
217+
if-no-files-found: warn
218+
retention-days: 14
174219

175220
python-sfw-smoke-enterprise:
176221
needs: inspect
@@ -186,6 +231,16 @@ jobs:
186231
fetch-depth: 1
187232
persist-credentials: false
188233

234+
- name: Prepare SFW artifact directory
235+
run: |
236+
mkdir -p sfw-artifacts
237+
{
238+
echo "mode=firewall-enterprise"
239+
echo "manifest=python"
240+
echo "pr=${{ github.event.pull_request.number }}"
241+
echo "sha=${{ github.event.pull_request.head.sha }}"
242+
} > sfw-artifacts/context.txt
243+
189244
- uses: ./.github/actions/setup-sfw
190245
with:
191246
uv: "true"
@@ -203,16 +258,22 @@ jobs:
203258
# Use the runner's setup-python interpreter and forbid managed-Python
204259
# downloads. The firewall is here to vet PyPI installs, not the
205260
# interpreter/toolchain download path.
261+
#
262+
# pipefail keeps sfw's exit code through the tee so a firewall block
263+
# still fails the job; tee captures the report for the artifact upload.
206264
env:
207265
UV_PYTHON: "3.12"
208266
UV_PYTHON_DOWNLOADS: never
209-
run: sfw uv sync --locked --extra test --extra dev
267+
run: |
268+
set -o pipefail
269+
sfw uv sync --locked --extra test --extra dev 2>&1 | tee sfw-artifacts/sfw-uv-sync.log
210270
211271
- name: Import smoke test
212272
env:
213273
UV_PYTHON: "3.12"
214274
UV_PYTHON_DOWNLOADS: never
215275
run: |
276+
set -o pipefail
216277
uv run python -c "
217278
from socketsecurity.socketcli import cli, build_socket_sdk
218279
from socketsecurity.core import Core
@@ -222,7 +283,31 @@ jobs:
222283
from socketsecurity.core.git_interface import Git
223284
from socketsecurity.config import CliConfig
224285
print('import smoke OK')
225-
"
286+
" 2>&1 | tee sfw-artifacts/import-smoke.log
287+
288+
- name: Collect SFW JSON report
289+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
290+
# file) and reads it back in its post step to render the job summary, so
291+
# COPY (don't move) the report into the bundle. sfw writes it even when
292+
# it blocks an install -- always() keeps it on failures too.
293+
if: always()
294+
run: |
295+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
296+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
297+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
298+
else
299+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
300+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
301+
fi
302+
303+
- name: Upload SFW report artifact
304+
if: always()
305+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
306+
with:
307+
name: socket-firewall-enterprise-python-${{ github.event.pull_request.number }}
308+
path: sfw-artifacts/
309+
if-no-files-found: warn
310+
retention-days: 14
226311

227312
fixture-npm-sfw-smoke-free:
228313
needs: inspect
@@ -237,14 +322,52 @@ jobs:
237322
fetch-depth: 1
238323
persist-credentials: false
239324

325+
- name: Prepare SFW artifact directory
326+
run: |
327+
mkdir -p sfw-artifacts
328+
{
329+
echo "mode=firewall-free"
330+
echo "manifest=npm"
331+
echo "pr=${{ github.event.pull_request.number }}"
332+
echo "sha=${{ github.event.pull_request.head.sha }}"
333+
} > sfw-artifacts/context.txt
334+
240335
- uses: ./.github/actions/setup-sfw
241336
with:
242337
node: "true"
243338
mode: firewall-free
244339

245340
- name: Install fixture through Socket Firewall
246341
working-directory: tests/e2e/fixtures/simple-npm
247-
run: sfw npm install --no-audit --no-fund --ignore-scripts
342+
# Tee to an absolute path under the workspace so the log lands in the
343+
# repo-root sfw-artifacts/ dir despite this step's working-directory.
344+
run: |
345+
set -o pipefail
346+
sfw npm install --no-audit --no-fund --ignore-scripts 2>&1 | tee "$GITHUB_WORKSPACE/sfw-artifacts/sfw-npm-install.log"
347+
348+
- name: Collect SFW JSON report
349+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
350+
# file) and reads it back in its post step to render the job summary, so
351+
# COPY (don't move) the report into the bundle. sfw writes it even when
352+
# it blocks an install -- always() keeps it on failures too.
353+
if: always()
354+
run: |
355+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
356+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
357+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
358+
else
359+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
360+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
361+
fi
362+
363+
- name: Upload SFW report artifact
364+
if: always()
365+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
366+
with:
367+
name: socket-firewall-free-npm-${{ github.event.pull_request.number }}
368+
path: sfw-artifacts/
369+
if-no-files-found: warn
370+
retention-days: 14
248371

249372
fixture-npm-sfw-smoke-enterprise:
250373
needs: inspect
@@ -260,6 +383,16 @@ jobs:
260383
fetch-depth: 1
261384
persist-credentials: false
262385

386+
- name: Prepare SFW artifact directory
387+
run: |
388+
mkdir -p sfw-artifacts
389+
{
390+
echo "mode=firewall-enterprise"
391+
echo "manifest=npm"
392+
echo "pr=${{ github.event.pull_request.number }}"
393+
echo "sha=${{ github.event.pull_request.head.sha }}"
394+
} > sfw-artifacts/context.txt
395+
263396
- uses: ./.github/actions/setup-sfw
264397
with:
265398
node: "true"
@@ -268,7 +401,35 @@ jobs:
268401

269402
- name: Install fixture through Socket Firewall
270403
working-directory: tests/e2e/fixtures/simple-npm
271-
run: sfw npm install --no-audit --no-fund --ignore-scripts
404+
# Tee to an absolute path under the workspace so the log lands in the
405+
# repo-root sfw-artifacts/ dir despite this step's working-directory.
406+
run: |
407+
set -o pipefail
408+
sfw npm install --no-audit --no-fund --ignore-scripts 2>&1 | tee "$GITHUB_WORKSPACE/sfw-artifacts/sfw-npm-install.log"
409+
410+
- name: Collect SFW JSON report
411+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
412+
# file) and reads it back in its post step to render the job summary, so
413+
# COPY (don't move) the report into the bundle. sfw writes it even when
414+
# it blocks an install -- always() keeps it on failures too.
415+
if: always()
416+
run: |
417+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
418+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
419+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
420+
else
421+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
422+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
423+
fi
424+
425+
- name: Upload SFW report artifact
426+
if: always()
427+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
428+
with:
429+
name: socket-firewall-enterprise-npm-${{ github.event.pull_request.number }}
430+
path: sfw-artifacts/
431+
if-no-files-found: warn
432+
retention-days: 14
272433

273434
fixture-pypi-sfw-smoke-free:
274435
needs: inspect
@@ -283,18 +444,55 @@ jobs:
283444
fetch-depth: 1
284445
persist-credentials: false
285446

447+
- name: Prepare SFW artifact directory
448+
run: |
449+
mkdir -p sfw-artifacts
450+
{
451+
echo "mode=firewall-free"
452+
echo "manifest=pypi"
453+
echo "pr=${{ github.event.pull_request.number }}"
454+
echo "sha=${{ github.event.pull_request.head.sha }}"
455+
} > sfw-artifacts/context.txt
456+
286457
- uses: ./.github/actions/setup-sfw
287458
with:
288459
python: "true"
289460
mode: firewall-free
290461

291462
- name: Install fixture through Socket Firewall
292463
working-directory: tests/e2e/fixtures/simple-pypi
464+
# Tee to an absolute path under the workspace so the log lands in the
465+
# repo-root sfw-artifacts/ dir despite this step's working-directory.
293466
run: |
467+
set -o pipefail
294468
python -m venv .venv
295469
# shellcheck disable=SC1091
296470
source .venv/bin/activate
297-
sfw pip install -r requirements.txt
471+
sfw pip install -r requirements.txt 2>&1 | tee "$GITHUB_WORKSPACE/sfw-artifacts/sfw-pip-install.log"
472+
473+
- name: Collect SFW JSON report
474+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
475+
# file) and reads it back in its post step to render the job summary, so
476+
# COPY (don't move) the report into the bundle. sfw writes it even when
477+
# it blocks an install -- always() keeps it on failures too.
478+
if: always()
479+
run: |
480+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
481+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
482+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
483+
else
484+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
485+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
486+
fi
487+
488+
- name: Upload SFW report artifact
489+
if: always()
490+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
491+
with:
492+
name: socket-firewall-free-pypi-${{ github.event.pull_request.number }}
493+
path: sfw-artifacts/
494+
if-no-files-found: warn
495+
retention-days: 14
298496

299497
fixture-pypi-sfw-smoke-enterprise:
300498
needs: inspect
@@ -310,6 +508,16 @@ jobs:
310508
fetch-depth: 1
311509
persist-credentials: false
312510

511+
- name: Prepare SFW artifact directory
512+
run: |
513+
mkdir -p sfw-artifacts
514+
{
515+
echo "mode=firewall-enterprise"
516+
echo "manifest=pypi"
517+
echo "pr=${{ github.event.pull_request.number }}"
518+
echo "sha=${{ github.event.pull_request.head.sha }}"
519+
} > sfw-artifacts/context.txt
520+
313521
- uses: ./.github/actions/setup-sfw
314522
with:
315523
python: "true"
@@ -318,11 +526,38 @@ jobs:
318526

319527
- name: Install fixture through Socket Firewall
320528
working-directory: tests/e2e/fixtures/simple-pypi
529+
# Tee to an absolute path under the workspace so the log lands in the
530+
# repo-root sfw-artifacts/ dir despite this step's working-directory.
321531
run: |
532+
set -o pipefail
322533
python -m venv .venv
323534
# shellcheck disable=SC1091
324535
source .venv/bin/activate
325-
sfw pip install -r requirements.txt
536+
sfw pip install -r requirements.txt 2>&1 | tee "$GITHUB_WORKSPACE/sfw-artifacts/sfw-pip-install.log"
537+
538+
- name: Collect SFW JSON report
539+
# socketdev/action points sfw at SFW_JSON_REPORT_PATH (a $RUNNER_TEMP
540+
# file) and reads it back in its post step to render the job summary, so
541+
# COPY (don't move) the report into the bundle. sfw writes it even when
542+
# it blocks an install -- always() keeps it on failures too.
543+
if: always()
544+
run: |
545+
if [ -n "${SFW_JSON_REPORT_PATH:-}" ] && [ -f "$SFW_JSON_REPORT_PATH" ]; then
546+
cp "$SFW_JSON_REPORT_PATH" "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report.json"
547+
echo "Collected SFW report -> sfw-artifacts/sfw-report.json"
548+
else
549+
echo "No SFW JSON report found at '${SFW_JSON_REPORT_PATH:-<unset>}'." \
550+
> "$GITHUB_WORKSPACE/sfw-artifacts/sfw-report-missing.txt"
551+
fi
552+
553+
- name: Upload SFW report artifact
554+
if: always()
555+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
556+
with:
557+
name: socket-firewall-enterprise-pypi-${{ github.event.pull_request.number }}
558+
path: sfw-artifacts/
559+
if-no-files-found: warn
560+
retention-days: 14
326561

327562
dockerfile-smoke:
328563
needs: inspect

0 commit comments

Comments
 (0)