Repository navigation
[quality] auth.ts assertPullRequestOwner fail-closed arm (no OWNERS file covers README.md, auth.ts:426) has 0 end-to-end hits through dist/index.js #400
Description
Finding
assertPullRequestOwner (src/utils/auth.ts:410-440) is the pull-request arm of assertAuthorizedByOwnersOrMembership, used by /lgtm (src/labels/lgtm.ts:119), /approve (src/issueComment/approve.ts:105) and /test (src/issueComment/trigger.ts:220). When the base branch has OWNERS files but one changed file sits outside every OWNERS directory, it fails closed:
const covered = files.map((file) => {
const owners = perFile.get(file)
if (owners === undefined) {
throw new Error(`no OWNERS file covers ${file}`) // auth.ts:426
}
...The refusal is user-visible (Cannot apply the lgtm label because Error: no OWNERS file covers README.md) and it is the only thing standing between "the repository uses OWNERS" and "a reviewer of sdk/ can lgtm a change to the repository root". No bundle test reaches it.
Evidence (main @ aa6a0f8, Node v26.10.0, vitest 5.0.3):
- Unit:
npx vitest run --coverage→ 100 % lines.__tests__/utils/ownersAuth.test.ts:118(fails closed when a changed file has no covering OWNERS) pins the message by callingassertAuthorizedByOwnersOrMembershipdirectly against msw. - End-to-end:
npm run test:coverage:e2eon a scratch branch =origin/main+ the heads of all 38 open hold-gated bundle PRs (test(bundle): drive root-OWNERS authorization on an issue and the OWNERS-based /lgtm refusal through dist/index.js #283 … test(bundle): drive the plugin payload guards (requireMatchingLabel.ts:184, blunderbuss.ts:94, trigger.ts:188, tide.ts:489) through dist/index.js #399, all merge clean; 59 files / 436 tests pass) → 97.63 % statements / 98 % lines ofsrc/.src/utils/auth.ts:426has 0 hits (lcov.infoDA:426,0). test(bundle): drive root-OWNERS authorization on an issue and the OWNERS-based /lgtm refusal through dist/index.js #283 (ownersAuth.test.ts) drives the neighbouring is not a reviewer or approver for any changed file arm (:433) and says in its body that the remainingthrowarms are left to the unit suite — so this line is not claimed by any open PR. - Reachability through
dist/index.js: base tree{ sdk/OWNERS: approvers: [bob] }, PR files['sdk/x.go', 'README.md'],/lgtmfrombob→ exit 1, refusal comment namesREADME.md, noGET /contents/OWNERS, no/orgs/*/membersor/collaboratorsprobe.
The same function also carries the 100 %-covered is not an approver for any changed file arm (:432), already driven by __tests__/bundle/approveMembershipArms.test.ts (#355).
Recommendation
One PR, one deliverable:
- add
__tests__/bundle/ownersUncoveredFile.test.ts:/lgtmon a pull request whose base has onlysdk/OWNERSand whose changed files include a root-level file, asserting exit 1, theno OWNERS file covers README.mdrefusal comment, no label write, no root-OWNERS read and no membership read (verified locally:auth.tsDA:426,1undernpm run test:coverage:e2e).
Priority
- Impact: medium (covered by unit tests, not end-to-end; the arm is a security boundary of the OWNERS gate)
- Effort: low
Filed by quality agent (hold-gated mode)
🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: aa6a0f8
— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Activity
github-actions commentedon Oct 9, 2026
Please add a kind label with
/kind failing-testor/kind cleanup.