Repository navigation
v0.1.1: security hardening, benchmarks
Breaking
- The Action approves only when the base branch requires an approval and dismisses stale
approvals on push (an active branch ruleset, or classic protection the token can read).
Otherwise it logs a warning and does not approve. Add the ruleset described in
docs/github-action.md, "Required: dismiss stale approvals on push". autoApprove.requireAiReview.labelsis removed. A label is not tied to a commit and anyone with
triage access can add one, so a self-appliedai-reviewedlabel could get a PR auto-approved.
A config that still lists it, even aslabels: [], now fails to parse; list your AI reviewer's
check run underrequireAiReview.checksinstead. The Action no longer removes AI-review labels
onsynchronize.- A
paths.blockorpaths.criticallist in.opendrs.ymlnow extends the defaults instead of
replacing them. Settingblock: ["infra/**"]used to drop every default block, so a
postinstallhook inpackage.jsoncould be auto-approved. To remove a default block glob, list
it under the newpaths.unblock, exactly as written in the defaults; any other entry is a
config error that names the valid ones. If you copied the default list to delete entries from
it, move those entries topaths.unblock.paths.ignoreandpaths.testsstill replace their
defaults.
Security
- Submodule changes are never auto-approved. A moved gitlink (mode 160000) scored as a one-line
text change, so pointing a submodule at another commit could be auto-approved. The diff parser
now marks such files (ChangedFile.submodule), the gate sends them to a human, and the diff is
generated so that git config and.gitmodulesignoresettings cannot hide them.
.gitmodulesis blocked by default and by the Action's self-modification guard. - Binary detection no longer relies on git's heuristic or on the PR's own
.gitattributes. A PR
that addedtools/* diffplus an executable, or a jar with 8 KB of text in front, scored as
text and could be auto-approved. Now:- every changed file is read at the head, and one with a NUL anywhere or invalid UTF-8 is
binary, so it goes to a human; - with git 2.40 or later, attributes are read from the base commit (
--attr-source). Older git
ignores the global and system attribute files but still reads in-tree ones; **/.gitattributesis blocked by default and by the self-modification guard.
- every changed file is read at the head, and one with a NUL anywhere or invalid UTF-8 is
- The default
paths.blocknow lists files that execute code on install, build or CI: package
manifests and registry settings (npm, Yarn, pnpm, pip, setuptools), Gradle, Maven, Cargo, Go,
Bundler and Rake files, Makefiles, Dockerfiles and Compose files, and the GitLab, Jenkins,
CircleCI, Azure Pipelines and Buildkite pipelines. An.npmrcregistry change or apostinstall
hook inpackage.jsonused to score as a tiny change and could be auto-approved.opendrs init
writes the same list. Apaths.blockyou set now adds to this list (see Breaking). paths.block,paths.criticaland the Action's self-modification guard match ignoring case.
makefileand EF CoreMigrations/folders slipped past**/Makefileand**/migrations/**
and were auto-approved.- The default
paths.blockalso covers Python (requirements*.txt,conftest.py,
.pre-commit-config.yaml,tox.ini,noxfile.py), .NET (*.csproj,*.sln,
Directory.Build.*,nuget.config), CMake,.cargo/,.husky/, GNU make (GNUmakefile,
*.mk),compose.yamlanddocker-compose*.yaml, Brewfile, Vagrantfile, Procfile, Nix,
.devcontainer/,.envrc, Taskfile, justfile, Bitbucket, Drone, Travis, Cloud Build, Earthly
and Bazel files, and Rails (migrate/) and Flyway (migration/) migrations. Each of these
could be changed in a PR that was auto-approved. - Deleting tests no longer lowers risk. Deleted test lines counted as test changes, so deleting a
CSRF check together with its tests scored 0.16 and was auto-approved. Now:tests.missingcounts only added test lines;- a new signal,
tests.deleted, is 1 when a PR deletes a test file (or renames one out of
paths.tests) or deletes at least 10 more test lines than it adds. Its prior weight is 1.0; - such a PR always goes to a human, whatever its score.
- A path containing a line break could dodge every block glob, including
.github/**, because
**did not match across line breaks. Globs now match any character, and a PR whose paths contain
control characters always goes to a human. - The Action's log can no longer be fed workflow commands. A changed file named
docs/x\n::stop-commands::…\n::notice::…was printed verbatim in the decision reasons, so the
runner executed the commands. Every plain log line now shows line breaks as⏎and gets a
visible›before a leading::or a legacy##[; the Action's own::group::,::warning::,
::notice::and::error::commands still %-escape their message. - The PR comment and job summary escape untrusted text (file paths, signal summaries, policy
reasons, the auto-approval line, LLM rationale):&,<,>,|, backticks, brackets and
backslashes are escaped and line breaks removed, so a file name cannot break the table or inject
HTML or links. File names and reviewers in inline code have backticks replaced byˋ. - The Action warns when drift sampling is predictable. With
autoApprove.enabled, a
sampleRateabove 0 and nosample-salt, anyone can compute which PR numbers get sampled
(acme/app#107is,#108is not). It now logs "sampling is predictable; set sample-salt to a
secret" and repeats it in the PR comment; docs/github-action.md, "Set sample-salt", shows how.
Added
autoApprove.requireAiReview.checksentries can be{ name, app }, whereappis the slug of
the GitHub App that must have published the check run (for examplecoderabbitaior
github-actions). A check was matched by name only, and any workflow or app can publish a check
run under any name; a pinned check now ignores same-named runs from other apps. Plain names work
as before. For checks from GitHub Actions, give the reviewer job a unique name: see
docs/github-action.md, "Pin a check to the app that publishes it".
Full changelog: CHANGELOG.md