Skip to content

fix(scripts): refuse destructive --out targets and skip fork PR labelling - #409

Merged
TMHSDigital merged 1 commit into
mainfrom
fix/tooling-guards
Oct 4, 2026
Merged

TMHSDigital merged 1 commit into
mainfrom
fix/tooling-guards

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Closes #352. Closes #351.

#352: build_plugin_dist.py --out deleted any existing directory

  • New unsafe_out() check, applied before anything is touched. It refuses:

    • the repo or any of its parents;
    • any directory containing .git, even with --force;
    • a non-file target;
    • a non-empty directory unless --force is given.

    A refusal exits 2.

  • release.yml builds into a fresh $RUNNER_TEMP/plugin-dist, so it is unaffected. --check is unaffected too.

  • New tests/test_build_plugin_dist.py (6 tests), wired into Validate. The repo-root and parent cases call unsafe_out() directly, never main(), so a future guard regression can't delete the checkout running the test.

#351: Auto-label failed on every fork PR, which would block releases

  • The job runs only when head.repo.full_name == github.repository. A fork's GITHUB_TOKEN is read-only, so gh pr edit would 403, and release-gate.sh refuses a merge whose PR has a failed check.
  • The unused actions/checkout is dropped. GH_REPO is set so gh works without a checkout.
  • gh label create no longer passes --force, which reset existing labels' colour and description to grey on every run.

Evidence

Proven locally (Python 3.13, Windows):

  • python tests/test_build_plugin_dist.py -v: 6/6 OK.
  • python scripts/build_plugin_dist.py --check: plugin dist: 67 files, 0.27 MB ok.
  • Falsified: in a scratch copy of the script with the guard call replaced by reason = None, three tests fail (test_refuses_non_empty_dir_without_force, test_refuses_git_checkout_even_with_force, test_force_replaces_previous_build).
  • Both workflow files parse as YAML.

By inspection only: the fork if: cannot be exercised without a fork PR. This PR's own label run (same-repo) should still apply labels, which is the observable check.

🤖 Generated with Claude Code

…ling

build_plugin_dist.py --out rmtree'd any existing directory with no
prompt; `--out .` would have wiped the checkout. It now refuses the repo,
any parent of it, any git checkout, and a non-empty directory unless
--force is given. Release builds into a fresh $RUNNER_TEMP path and is
unaffected. tests/test_build_plugin_dist.py covers each refusal and runs
in Validate; the repo-root cases test unsafe_out() directly so a guard
regression cannot delete the checkout under test.

label-sync's gh pr edit 403s on every fork PR (a fork's token is
read-only), and release-gate.sh refuses to release a merge whose PR has
a failed check, so the first outside contribution would have blocked
releases. The job now skips forks, drops its unused checkout, and no
longer passes --force to gh label create, which reset existing labels'
colour and description on every run.

Closes #352
Closes #351

Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TMHSDigital

Copy link
Copy Markdown
Owner Author

CI evidence before merge: all checks pass ( 13 pass ). Blender Smoke on PR head: Blender 5.2.2 LTS / Blender 4.5.14 LTS. Summaries (happy path; falsifiers) per leg: 143 passed, 1 skipped, 0 failed;142 passed, 0 skipped, 0 failed;141 passed, 3 skipped, 0 failed;136 passed, 6 skipped, 0 failed;

@TMHSDigital
TMHSDigital merged commit e5f7938 into main Oct 4, 2026
13 checks passed
@TMHSDigital
TMHSDigital deleted the fix/tooling-guards branch October 4, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

1 participant