Skip to content
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
31 changes: 31 additions & 0 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This file is machine-generated by `gh actions-lock`.
# Do not edit by hand; run `gh actions-lock` to update.
# Docs: https://gh.io/actions-lockfile
version: 'v0.0.3'
workflows:
'.github/workflows/dependency-review.yml':
- 'actions/checkout@v7.0.1'
- 'actions/dependency-review-action@v5.0.0'
- 'actions/upload-artifact@v7.0.1'
- 'advanced-security/component-detection-dependency-submission-action@v0.2.0'
dependencies:
'actions/checkout@v7.0.1':
ref: 'v7.0.1'
commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1'
Comment thread
groupthinking marked this conversation as resolved.
Resolved
owner_id: 44036562
repo_id: 197814629
'actions/dependency-review-action@v5.0.0':
ref: 'v5.0.0'
commit: 'sha1-a1d282b36b6f3519aa1f3fc636f609c47dddb294'
owner_id: 44036562
repo_id: 476372928
'actions/upload-artifact@v7.0.1':
ref: 'v7.0.1'
commit: 'sha1-043fb46d1a93c77aae656e7c1c64a875d1fc6a0a'
owner_id: 44036562
repo_id: 192625955
'advanced-security/component-detection-dependency-submission-action@v0.2.0':
ref: 'v0.2.0'
commit: 'sha1-a02aeda7a175ad4dd38a13c4d3ff2df9da8f2cf0'
owner_id: 71494179
repo_id: 604441937
11 changes: 6 additions & 5 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
timeout-minutes: 30 # Allow full-tree scan, scoped lock submissions, and base/head snapshot retry
steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v7.0.1
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
# PR runs inspect changes introduced after the shared ancestor.
Expand Down Expand Up @@ -90,6 +90,7 @@ jobs:
def is_dependency_input(path: PurePosixPath) -> bool:
# Workflow and Dependabot configuration changes are covered by
# CI tests; they do not change the installed dependency graph.
# The native Actions lockfile is an executable dependency input.
name = path.name
return (
name in exact_names
Expand All @@ -99,7 +100,7 @@ jobs:
and name.endswith((".in", ".txt"))
)
or name.endswith((".csproj", ".fsproj", ".gradle", ".gradle.kts"))
or path.as_posix() == "vendor/modules.txt"
or path.as_posix() in {"vendor/modules.txt", ".github/workflows/actions.lock"}
)

changed = sorted(path.as_posix() for path in paths if is_dependency_input(path))
Expand Down Expand Up @@ -128,7 +129,7 @@ jobs:
# bound produced base/head drift in the #2501 exact-lock canary.
env:
PipReportFileLevelTimeoutSeconds: "240"
uses: advanced-security/component-detection-dependency-submission-action@a02aeda7a175ad4dd38a13c4d3ff2df9da8f2cf0 # v0.2.0
uses: advanced-security/component-detection-dependency-submission-action@v0.2.0
with:
snapshot-sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
snapshot-ref: ${{ github.event_name == 'pull_request' && format('refs/heads/{0}', github.event.pull_request.head.ref) || github.ref }}
Expand All @@ -149,7 +150,7 @@ jobs:
if: >-
${{ github.event_name == 'pull_request' &&
steps.dependency-changes.outputs.changed == 'true' }}
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
uses: actions/dependency-review-action@v5.0.0
with:
base-ref: ${{ github.event.pull_request.base.sha }}
head-ref: ${{ github.event.pull_request.head.sha }}
Expand Down Expand Up @@ -234,7 +235,7 @@ jobs:
if: >-
${{ always() && github.event_name == 'pull_request' &&
steps.dependency-changes.outputs.changed == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v7.0.1
with:
name: dependency-review-${{ github.event.pull_request.head.sha }}-${{ github.run_attempt }}
path: dependency-review-evidence/
Expand Down
87 changes: 85 additions & 2 deletions tests/unit/test_dependency_review_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import os
import runpy
import subprocess
import sys
from pathlib import Path

import pytest
Expand All @@ -22,6 +23,88 @@ def _load_workflow() -> dict:
return workflow if "on" in workflow else {**workflow, "on": workflow[True]}


def _locked_action(uses: str) -> str:
"""Resolve the actual runner pin, not the readable tag in the YAML."""
lock = yaml.safe_load(WORKFLOW_PATH.with_name("actions.lock").read_text())
assert uses in lock["workflows"][".github/workflows/dependency-review.yml"]
pin = lock["dependencies"][uses]
owner_repo, ref = uses.rsplit("@", 1)
assert pin["ref"] == ref
assert pin["commit"].startswith("sha1-")
return f"{owner_repo}@{pin['commit'].removeprefix('sha1-')}"


@pytest.mark.parametrize(
("changed_path", "expected_changed"),
[
(".github/workflows/actions.lock", True),
("docs/actions.lock", False),
(".github/aw/actions-lock.json", False),
],
)
def test_dependency_detector_handles_lockfile_only_changes(
tmp_path: Path, changed_path: str, expected_changed: bool
) -> None:
"""Run the workflow's detector against an actual one-file Git diff."""
repo = tmp_path / "repo"
repo.mkdir()

def git(*args: str) -> str:
return subprocess.run(
[
"git",
"-c",
"user.name=Workflow test",
"-c",
"user.email=workflow-test@example.invalid",
*args,
],
cwd=repo,
check=True,
capture_output=True,
text=True,
).stdout.strip()

git("init", "--quiet")
changed_file = repo / changed_path
changed_file.parent.mkdir(parents=True, exist_ok=True)
changed_file.write_text("before\n")
git("add", ".")
git("commit", "--quiet", "-m", "baseline")
base = git("rev-parse", "HEAD")
changed_file.write_text("after\n")
git("add", ".")
git("commit", "--quiet", "-m", "update one lockfile")
head = git("rev-parse", "HEAD")

steps = _load_workflow()["jobs"]["dependency-review"]["steps"]
detection = next(step for step in steps if step.get("id") == "dependency-changes")
script = detection["run"].split("python - <<'PY'\n", 1)[1].rsplit("\nPY", 1)[0]
output = tmp_path / "output"
summary = tmp_path / "summary"
subprocess.run(
[sys.executable, "-c", script],
cwd=repo,
env={
**os.environ,
"BASE_SHA": base,
"HEAD_SHA": head,
"GITHUB_OUTPUT": str(output),
"GITHUB_STEP_SUMMARY": str(summary),
},
check=True,
capture_output=True,
text=True,
)
assert output.read_text() == (
f"changed={str(expected_changed).lower()}\ncount={int(expected_changed)}\n"
)
if expected_changed:
assert f"- `{changed_path}`" in summary.read_text()
else:
assert "No dependency inputs introduced by this PR" in summary.read_text()


def test_dependency_review_submits_pr_head_snapshot_and_retries_warnings() -> None:
workflow = _load_workflow()
triggers = workflow["on"]
Expand Down Expand Up @@ -73,7 +156,7 @@ def test_dependency_review_submits_pr_head_snapshot_and_retries_warnings() -> No
assert "steps.dependency-changes.outputs.changed == 'true'" in submission["if"]
assert "snapshot_detector" not in submission["if"]
assert not any("focused" in step["name"].lower() for step in steps)
assert submission["uses"] == (
assert _locked_action(submission["uses"]) == (
"advanced-security/component-detection-dependency-submission-action"
"@a02aeda7a175ad4dd38a13c4d3ff2df9da8f2cf0"
)
Expand Down Expand Up @@ -313,7 +396,7 @@ def test_numpy_remains_subject_to_the_unchanged_license_policy() -> None:
assert settings.get("license-check", True) is True
assert settings.get("warn-only", False) is False
assert "continue-on-error" not in review
assert review["uses"] == (
assert _locked_action(review["uses"]) == (
"actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294"
)

Expand Down
Loading