From b9b37ae9d3550517e9348f99f0baf4caac086758 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 05:32:11 +0000 Subject: [PATCH 1/3] Route release.yml version through env indirection; pin dev/docs deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two LOW hardening items found during a security audit: - release.yml interpolated ${{ steps.ver.outputs.version }} directly into two run: shell steps — the classic GitHub Actions shell-injection pattern. Not exploitable today (the value is constrained by changelog_extract.py's \d+\.\d+\.\d+ regex), but fragile if that regex or its input ever changes. Routed through an env: VERSION var instead, matching the pattern already used in plugin-validate.yml. - requirements-dev.txt / requirements-docs.txt left jsonschema, pytest, ruff, and mkdocs-material fully unpinned, so CI silently picks up whatever's newest on a given day. Pinned to minor-version-compatible ranges (~=X.Y). Verified: fresh install, full pytest suite, ruff, tools/validate.py against both examples, and tools/check_versions.py all still pass. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_018J1NvPtPQZd3cEt6aAbGzG --- .github/workflows/release.yml | 10 ++++++---- requirements-dev.txt | 12 +++++++++--- requirements-docs.txt | 6 +++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e8783dc..33aef82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,8 +38,9 @@ jobs: if: steps.ver.outputs.version != '' env: GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.ver.outputs.version }} run: | - if gh release view "v${{ steps.ver.outputs.version }}" >/dev/null 2>&1; then + if gh release view "v${VERSION}" >/dev/null 2>&1; then echo "exists=true" >> "$GITHUB_OUTPUT" else echo "exists=false" >> "$GITHUB_OUTPUT" @@ -49,9 +50,10 @@ jobs: if: steps.ver.outputs.version != '' && steps.check.outputs.exists == 'false' env: GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.ver.outputs.version }} run: | - python tools/changelog_extract.py "${{ steps.ver.outputs.version }}" > RELEASE_NOTES.md - gh release create "v${{ steps.ver.outputs.version }}" \ + python tools/changelog_extract.py "${VERSION}" > RELEASE_NOTES.md + gh release create "v${VERSION}" \ --target "${GITHUB_SHA}" \ - --title "v${{ steps.ver.outputs.version }}" \ + --title "v${VERSION}" \ --notes-file RELEASE_NOTES.md diff --git a/requirements-dev.txt b/requirements-dev.txt index d033c1e..219dc0e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,12 @@ # Development / CI dependencies for the feedBack plugin-spec repo. # The reference validator needs only jsonschema; pytest + ruff are for the # test and lint jobs. -jsonschema -pytest -ruff +# +# Pinned to a minor-version-compatible range (~=X.Y) rather than left +# floating: an unpinned dev dependency means CI silently picks up whatever +# the latest release is on a given day, so a breaking change upstream shows +# up as a mysterious CI failure unrelated to the PR that triggered it. +# Bump deliberately when actually adopting a newer version. +jsonschema~=4.26 +pytest~=9.1 +ruff~=0.16 diff --git a/requirements-docs.txt b/requirements-docs.txt index 9913b5e..6e86370 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,2 +1,6 @@ # Docs-site dependencies (GitHub Pages build only). See .github/workflows/pages.yml. -mkdocs-material +# +# Pinned to a minor-version-compatible range (~=X.Y) rather than left +# floating — see requirements-dev.txt for why. Bump deliberately when +# actually adopting a newer version. +mkdocs-material~=9.7 From 67977197aa07b3f6fe9fda3e6296a4cfa579e434 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 22:01:29 +0000 Subject: [PATCH 2/3] Fix ~=X.Y pins to actually lock the minor version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greptile review on this PR: PEP 440's compatible-release operator needs all three version components to lock a minor version. ~=4.26 (two components) is NOT equivalent to "4.26.x only" — it means >=4.26, ==4.* and happily permits 4.27, 4.99, anything in the 4.x line, same as leaving it unpinned in every way that actually matters here. Verified directly against packaging.specifiers.SpecifierSet: ~=4.26 accepts 4.27.0, ~=4.26.0 correctly rejects it. Rewrote all four pins with the third component (jsonschema~=4.26.0, pytest~=9.1.1, ruff~=0.16.1, mkdocs-material~=9.7.7), matching the exact versions already verified installable in the prior commit, and added a comment explaining why the third digit is load-bearing so this doesn't regress again. Verified: fresh pip install, full pytest suite (11 passed), ruff clean, tools/validate.py against both examples, tools/check_versions.py all still pass with the corrected pins. Confirmed via SpecifierSet that each pin now allows patch-level drift but rejects the next minor version. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_018J1NvPtPQZd3cEt6aAbGzG --- requirements-dev.txt | 20 +++++++++++++------- requirements-docs.txt | 9 +++++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 219dc0e..23f18a9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,11 +2,17 @@ # The reference validator needs only jsonschema; pytest + ruff are for the # test and lint jobs. # -# Pinned to a minor-version-compatible range (~=X.Y) rather than left -# floating: an unpinned dev dependency means CI silently picks up whatever -# the latest release is on a given day, so a breaking change upstream shows +# Pinned to a patch-compatible range (~=X.Y.Z, PEP 440's "compatible +# release" clause with all three components) rather than left floating: +# an unpinned dev dependency means CI silently picks up whatever the +# latest release is on a given day, so a breaking change upstream shows # up as a mysterious CI failure unrelated to the PR that triggered it. -# Bump deliberately when actually adopting a newer version. -jsonschema~=4.26 -pytest~=9.1 -ruff~=0.16 +# NOTE: ~=X.Y (two components, no patch digit) does NOT do what it looks +# like it does — ~=4.26 permits 4.27, 4.99, anything 4.*, same as leaving +# it unpinned in every way that matters here. The third component is load- +# bearing: only ~=X.Y.Z locks the minor version and allows patch-only +# drift. Bump deliberately (the X.Y.Z value itself) when actually +# adopting a newer version. +jsonschema~=4.26.0 +pytest~=9.1.1 +ruff~=0.16.1 diff --git a/requirements-docs.txt b/requirements-docs.txt index 6e86370..18d8632 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,6 +1,7 @@ # Docs-site dependencies (GitHub Pages build only). See .github/workflows/pages.yml. # -# Pinned to a minor-version-compatible range (~=X.Y) rather than left -# floating — see requirements-dev.txt for why. Bump deliberately when -# actually adopting a newer version. -mkdocs-material~=9.7 +# Pinned to a patch-compatible range (~=X.Y.Z, all three components — see +# requirements-dev.txt for why the third digit is load-bearing) rather +# than left floating. Bump deliberately when actually adopting a newer +# version. +mkdocs-material~=9.7.7 From 83f34a4515158afd1fa90a9ad4416ff4151a6939 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:42:10 +0000 Subject: [PATCH 3/3] Pin ruff in lint job via requirements-dev.txt --- .github/workflows/validate.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ee85798..8d7d0ac 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -52,8 +52,8 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" - - name: Install ruff - run: python -m pip install --upgrade ruff + - name: Install dev dependencies + run: python -m pip install --upgrade -r requirements-dev.txt - name: Lint reference tooling and tests run: python -m ruff check tools/ tests/