Repository navigation
Register and check rules for locking, installing and testing from uv.lock - #887
Merged
Merged
Conversation
A [[rule.exception]] can now carry match (a substring of the one command or call it allows), category, removal (the condition for removing it) and issue (the tracking issue of a dated exception). expires becomes optional. The rendered rules list shows each of them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/rules/locked_installs.py reads every workflow, composite action, shell script, Makefile, Dockerfile, Compose file and Modal image module. It reports installs that do not install the locked versions, test commands that do not run through uv run --frozen, project directories without a committed uv.lock or a PR CI uv lock --check, and the absence of a scheduled relock that covers every project and opens a pull request. Each check has bad and good proof fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.github/scripts/check-uv-locks.sh runs uv lock --check for every tracked pyproject.toml directory and reports each stale lock before failing. The PR test-integration job runs it after generating the API clients, because policyengine-apis-integ depends on the generated client by path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every uv sync and uv run in the workflows, the scripts they call, the Makefile and scripts/ now passes --frozen. Each one already ran against a committed lock that matches pyproject.toml (or, in the bundle updater, one it has just relocked and checked), so the installed versions do not change; --frozen stops uv from relocking instead of installing what the lock says. The PR test-integration job also runs check-uv-locks.sh after generating the API clients. The script tests expect the new arguments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rules/registry.toml registers sim.dependencies.lock-committed, install-from-lock, test-from-lock and scheduled-relock, enforced by the new locked-installs quality guard, with proof fixtures. Four sites are registered exceptions: the pinned ruff and shellcheck installs, the bundle updater's pinned isolated read of a new release, and the rules tool's unittest run, which has no project or lock. docs/engineering/skills/dependencies.md explains the rules and how to add an exception. A test fails if any install-capable file is not scanned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's Makefile reads the pinned ruff version with $(shell sed ...) and runs it with uv tool run ruff@$(RUFF_VERSION). The guard no longer splits commands at parentheses, skips commands whose first program only prints or edits text (echo, printf, sed, grep, awk), and accepts a name@version pin as a pinned tool. The Makefile's pinned ruff is a registered pinned-tool exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rollback test replaced uv run python with printf, so it ran the frozen command for real; the permission test looked for the old authenticated-tests command; the routing invariants accepted only the frozen prefix. The routing parser now accepts uv run with and without --frozen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…view dates Three self-review findings in the locked-installs guard: - A workflow site was reported on the first line holding its first three words, so different sites shared one line number. Run blocks are now located in file order and each command is reported on its own line. - A pinned-tool exception accepted any name@version, including @latest. A pin is now name==version or name@version where the version is a release number or a variable that holds one. - An exception with an issue but no expires was accepted. It now needs a removal condition, or both expires and issue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tching Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
marked this pull request as ready for review
October 21, 2026 22:31
anth-volk
added a commit
that referenced
this pull request
Oct 22, 2026
#887 changed the test job to run uv run --frozen pytest tests/, so the proof's recorded invocation no longer matched and the rules registry check failed after the rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 22, 2026
#887 changed the test job to run uv run --frozen pytest tests/, so the proof's recorded invocation no longer matched and the rules registry check failed after the rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 26, 2026
#887 changed the test job to run uv run --frozen pytest tests/, so the proof's recorded invocation no longer matched and the rules registry check failed after the rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #886
What this changes
Four registered rules, all enforced by the new
locked-installsquality guard (scripts/rules/locked_installs.py, standard library only), each with bad and good proof fixtures underscripts/rules/tests/fixtures/locked_installs/and atest_rule_proof_*test:sim.dependencies.lock-committedpyproject.tomldirectory commits auv.lock; apr.ymljob runsuv lock --check. New.github/scripts/check-uv-locks.shchecks every tracked project (found fromgit ls-files), intest-integrationafter the API clients are generated, becausepolicyengine-apis-integdepends on the generated client by path.sim.dependencies.install-from-lockuv sync --frozen,uv run --frozenoruv_sync(frozen=True), or a registered exception for that site.sim.dependencies.test-from-lockpytest,coverage runandpython -m unittestcommand runs throughuv run --frozen, or is a registered exception.sim.dependencies.scheduled-relockschedule:workflow relocks with upgrades, covers every project directory, and opens a PR (static check ofupdate-dependencies.yml→make update→uv lock --upgradeoverlibs/*/pyproject.toml projects/*/pyproject.toml, anddependency-update-create-pr.sh→gh pr create).[[rule.exception]]gainsmatch(one site),category,removalandissue;expiresis optional. The guard requires amatch, and either a removal condition, a tracking issue, orcategory = "pinned-tool"with an exact pin; an exception that matches no site fails as stale.TestRepository.test_every_install_capable_file_is_scannedfails if a tracked workflow, shell script, Makefile, Dockerfile, Compose file or Modal image module is not scanned.Every
uv syncanduv runin the workflows, the scripts they call, the Makefile andscripts/now passes--frozen. Each already ran against a committed lock that matchespyproject.toml(in the bundle updater, one it has just relocked and checked withuv lock --check), so the installed versions do not change;--frozenonly stops uv from relocking. The script tests expect the new arguments.Doc:
docs/engineering/skills/dependencies.md(rules and how to add an exception).Install sites
simulation-entry,simulation-executor):uv sync --frozen --no-devdeployment/docker-compose.yml:uv run --frozen --no-devapp.py,stage12_precompute_app.py,v2_app.py, gatewayapp.py:uv_sync(frozen=True)uv sync/uv run(pr.yml, pr-image-smoke.yml, simulation-deploy.reusable.yml, simulation-rollback.yml, 13.github/scripts/*.sh, Makefile,scripts/generate-clients.sh,scripts/test-integration-local.sh)--frozenadded)pr.yml:uv tool install ruff==0.15.22pr.yml:pip install "shellcheck-py==0.11.0.1"Makefile:uv tool run ruff@$(RUFF_VERSION)(version read from pr.yml's pin)update-policyengine-package.sh:uv run --isolated --no-project --with "${PACKAGE}==${LATEST}"pr.yml:python -m unittest discover -s scripts/rules/testsscripts/rulesgains apyproject.tomlanduv.lock, or a third-party dependency.Modal images
All four Modal image definitions already install packages with
uv_sync(uv_project_dir=..., frozen=True)(the executor images with--only-group modal-simulation-image, the gateway with--no-default-groups). The executor images'run_commands(policyengine bundle install ... --no-packages ...)downloads certified datasets and installs no packages.add_local_python_sourceandadd_local_dircopy repository source and static files, not packages. No Modal image definition is changed, and no Modal exception is needed. #611 is still open, but its first two steps appear done in code (--no-packages, model packages from the lock).The scheduled relock
update-dependencies.ymlrunsmake update(uv lock --upgradein all 8 project directories). Its last 10 scheduled runs (2026-10-12 to 2026-10-21) all failed at "Generate API clients", most recently witherror: Failed to parse uv.lock(acryptography50.0.1 entry with 49.0.0 wheels) on the update branch the run checks out, with uv 0.13.4. This PR does not change that failure:generate-clients.shonly gains--frozen, and the lock still has to parse.Red and green
Exception fields:
test_loadred on the new allowed-key list, green after updating it; 115/115 rule-tool tests green.Scanner:
test_locked_installsred (module missing), then green for the proof, classification and exception tests.check-uv-locks.sh:tests/test_check_uv_locks_script.py2 failed (script missing), then 2 passed.--frozenedits: the guard listed 72 unlocked install sites and 18 unlocked test commands before, 4 after (the registered exceptions). Executor script tests: 9 failed on the old arguments, then 129 passed. Entry workflow tests: 21 failed after the rebase (the rollback test'suv run pythonsubstitution, the authenticated-tests command, the routing prefix check), then 348 passed (commitExpect --frozen in the deployment and rollback workflow tests).Registration: the guard on the previous registry reported the 4 unregistered sites; green after registering.
Makefile shell functions (after rebasing onto Run Pyright in CI for every package, in its own locked environment #864): 2 new tests red (a
$(shell sed ...)reading the ruff pin was reported as an install;ruff@$(RUFF_VERSION)not accepted as a pin), green after the fix.Self-review fixes (commit
Report workflow sites on their own line and require exact pins and review dates): 4 tests red first. A second workflow site was reported on line 7 instead of 13; aruff@latestpinned-tool exception was accepted; an exception withissueand noexpireswas accepted (and the existing message test expected the old text). After the fix, 21/21 guard tests pass, and deployment-workflow sites are reported on their real lines (131, 140, 260, 296).Self-review
name@latestaccepted as an exact pinissuewithoutexpiresacceptedexpiresandissuedependencies.mdmatchcould cover several sites in one fileChecks
python -m unittest discover -s scripts/rules/tests -t .: OKpython scripts/run_quality_guards.py: rules-registry, ci-scripts, pyright-coverage, locked-installs passedpython -m scripts.rules guard --base-ref origin/main: passed; rendered views currentformat --checkandcheck .: clean.# noqacount: 211 before and after../scripts/generate-clients.sh,check-uv-locks.shpasses for all 8 projects (uv 0.12.23).Environment variables
No changed line reads a new environment variable: the changes add
--frozento existing commands and one step runningcheck-uv-locks.sh, which reads none (it usesgitanduv).simulation-deploy.reusable.yml,simulation-rollback.ymland the deployment scripts run only on pushes tomainor manual dispatch, so PR CI does not exercise their--frozenchanges; their tests underprojects/*/testsdo.Not verified
--frozenchanges have not run in GitHub Actions.subprocessare not scanned (for examplescripts/rules/pyright.pyrunsuv sync --frozen --all-extras, which is locked).🤖 Generated with Claude Code