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
6 changes: 3 additions & 3 deletions .github/workflows/canvas-nodom-ladder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: actions/setup-python@v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"

Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:

- name: Upload evidence
if: always()
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: canvas-nodom-ladder-qualification
path: runs/canvas-ladder/results.json
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/paper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
# RDP workflow but did not reach this file.
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Check paper constants against benchmark artifacts
run: python paper/check_artifacts.py
- name: Install TeX
Expand Down Expand Up @@ -65,12 +65,12 @@ jobs:
timeout-minutes: 10
run: make -C paper
- name: Upload full report PDF
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: openadapt-paper
path: paper/build/main.pdf
- name: Upload workshop PDF
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: openadapt-paper-workshop
path: paper/workshop/build/main.pdf
Expand All @@ -90,7 +90,7 @@ jobs:
contents: write # create/overwrite the release asset on the stable tag
steps:
- name: Download built full report PDF
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: openadapt-paper
path: pdf
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ jobs:
--wait-seconds 2700 \
--poll-seconds 10

- name: Require dispatched head to remain current protected main
if: steps.check_skip.outputs.skip != 'true'
run: |
set -euo pipefail
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
current_main="$(git rev-parse refs/remotes/origin/main)"
if [ "$current_main" != "$GITHUB_SHA" ]; then
echo "Refusing stale release dispatch: main is $current_main, dispatched head is $GITHUB_SHA."
exit 1
fi

- name: Set up Python
if: steps.check_skip.outputs.skip != 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand Down
6 changes: 3 additions & 3 deletions public-artifacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
},
{
"path": ".github/workflows/canvas-nodom-ladder.yml",
"sha256": "29afaaa85b3284e5645111cf3493633940015ad419b8d8e6cbbc93966e20d982"
"sha256": "db5bdaf110b2d8acc15003eb5442ba9c2714a809fad3ac087cdc6ff5547e05a4"
},
{
"path": ".github/workflows/ci.yml",
Expand All @@ -109,7 +109,7 @@
},
{
"path": ".github/workflows/paper.yml",
"sha256": "6446edb96cddea116abe931611360122d8c4e3cba32e55c5ceab1f1e5209302a"
"sha256": "52e1d8d83c6d6b23be3fb99dee6d974056c465e1ba05e2a755a6a10262998307"
},
{
"path": ".github/workflows/quickstart-lifecycle.yml",
Expand All @@ -121,7 +121,7 @@
},
{
"path": ".github/workflows/release.yml",
"sha256": "20e760b316f9597b0cf8dc125574d8fdbaec86ca1bb34b6a6fb52fa86043a303"
"sha256": "7f5197dd1d7545185840a360d6dcea582d3c5eff0c916c9818b4cecc9a3dbc4d"
},
{
"path": ".github/workflows/validate-claims.yml",
Expand Down
26 changes: 25 additions & 1 deletion tests/test_release_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,22 @@ def test_release_workflow_uses_pinned_actions() -> None:
assert "# v10.6.1" in workflow


def test_all_workflows_use_pinned_actions() -> None:
"""A mutable action tag can change release or qualification code in place."""
mutable: list[str] = []
workflows_dir = ROOT / ".github/workflows"
paths = sorted((*workflows_dir.glob("*.yml"), *workflows_dir.glob("*.yaml")))
for path in paths:
workflow = path.read_text()
for match in re.finditer(
r"^\s*uses:\s+\S+@([^\s#]+)", workflow, flags=re.MULTILINE
):
if re.fullmatch(r"[0-9a-f]{40}", match.group(1)) is None:
mutable.append(f"{path.name}:{match.group(1)}")

assert mutable == []


def test_semantic_release_requires_dispatched_exact_head_production_evidence() -> None:
workflow = (ROOT / ".github/workflows/release.yml").read_text()

Expand All @@ -399,6 +415,9 @@ def test_semantic_release_requires_dispatched_exact_head_production_evidence() -
workflow.index("\n auto-release:") : workflow.index("\n manual-publish:")
]
wait_index = auto.index("- name: Wait for exact-head full-matrix qualification")
current_main_index = auto.index(
"- name: Require dispatched head to remain current protected main"
)
release_index = auto.index("- name: Python Semantic Release")

assert " push:" not in triggers
Expand All @@ -407,12 +426,17 @@ def test_semantic_release_requires_dispatched_exact_head_production_evidence() -
assert "- publish-existing-ref" in triggers
assert "inputs.operation == 'semantic-release'" in auto
assert "actions: read # inspect exact-head full-matrix CI" in auto
assert wait_index < release_index
assert wait_index < current_main_index < release_index
assert "python3 scripts/check_release_ci.py" in auto
assert '--repository "$GITHUB_REPOSITORY"' in auto
assert '--sha "$GITHUB_SHA"' in auto
assert "--wait-seconds 2700" in auto
assert "--poll-seconds 10" in auto
assert (
"git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main" in auto
)
assert 'current_main="$(git rev-parse refs/remotes/origin/main)"' in auto
assert '[ "$current_main" != "$GITHUB_SHA" ]' in auto
assert "gh api" not in auto
gate = (ROOT / "scripts/check_release_ci.py").read_text()
assert "require_production_qualification" in gate
Expand Down