Skip to content

test(auth): pin the repository-less org check, gone-user comment skip, non-RequestError and half-formed root OWNERS reads, and the OWNERS path in role errors - #579

Closed
hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-auth-guards
Closed

hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-auth-guards

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Test Improvement

A Stryker probe of src/utils/auth.ts (npx stryker run --mutate src/utils/auth.ts on #572's harness, main @ e3119ad, Stryker 10.0.0 / Vitest 5.0.4, 8 workers, 10 m 38 s) left 22 of 273 mutants alive. Eleven flip a guard the suite reaches but never distinguishes from its mutation. This PR adds one test file that kills all eleven; re-running the probe with it reports 7 survived / 258 killed / 8 timeout (97.44 %).

Files / cluster claimed: __tests__/utils/authGuards.test.ts (new). No src/, dist/ or existing-test change. Disjoint from every held PR on this module: #553 drives getErrorDetails' object folds (auth.ts:15-17) through the bundle; #571 edits __tests__/utils/auth.test.ts; #575/#564/#569 are owners.ts. Follows the same pattern as #575 (ownersGuards.test.ts) and #578 (tideGuards.test.ts).

Mutants pinned (span → test)

auth.ts span Mutation Test
43:51-46:6 if (repository === undefined) { … } → {} TypeError caught as "unexpected error" instead of the quiet early return refuses a payload without a repository quietly, without a warning annotation
129:11 e.user?.login → e.user.login a null user aborts the scan and warns instead of being skipped skips a comment whose user is gone and keeps scanning
444:9 typeof e === 'object' && e && 'status' in e — 5 mutants (true × 3, || × 2) 'status' in 'string' / null.status throw a TypeError instead of the OWNERS lookup error reports a string / null rejection of the contents read as an OWNERS lookup error (vi.spyOn(octokit.repos, 'getContent').mockRejectedValueOnce, the same precedent auth.test.ts uses for checkMembershipForUser)
454:7 content === undefined || !encoding → && content without encoding is decoded as utf8 instead of rejected rejects a contents response that carries content but no encoding
454:7 content === undefined → false encoding without content reaches Buffer.from(undefined) rejects a contents response that carries an encoding but no content
358:30 / 421:30 parseOwners('OWNERS', …) → '' the role error loses its OWNERS at OWNERS: prefix names the root OWNERS file when a role is not a list (assertRootOwner) and … when the trusted policy falls through to a malformed file (rootOwnersIncludes via policyAllows)

Reviewed survivors, not pinned (7)

  • 379, 434, 445, 459 — core.debug string literals; the same class test(mutation): add a bounded Stryker harness for the merge-decision code #572's docs table excludes.
  • 417:7, 417:20, 417:24 — the contents === '' short-circuit of rootOwnersIncludes. Equivalent: parseOwners('OWNERS', '') yields empty role lists (contents.trim() === '' ? {}), ownersInclude then calls expandGroups with an empty list, which returns an empty set without any request, so the result is false either way with no observable difference.

I have not edited docs/contributing.md's survivor table because that file is #572's claimed ground; this list is the record until #572 lands.

Validation

  • npx vitest run __tests__/utils/authGuards.test.ts → 8 passed
  • npx eslint __tests__/utils/authGuards.test.ts → clean
  • Stryker on auth.ts before: 246 killed / 5 timeout / 22 survived (91.94 %); after: 258 / 8 / 7 (97.44 %)
  • Unit coverage on main (npm run test:coverage, 167 files / 2330 tests) is already 99.92 % stmts / 99.35 % branches for this module; the remaining auth.ts:220 is the phantom branch docs/contributing.md documents. This PR adds assertion strength, not line coverage.

Related Issue

Refs #554 — ticks a slice of the "Strengthen assertions and the test harness" section (reviewed mutation survivors on the authorization module); the tracker's CI-enforcement, release-delivery and routing sections stay open and are owned elsewhere.


Filed by quality agent (hold-gated mode). Human review required.

— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88 requested_by=@mrbobbytables

…skip, the non-RequestError and half-formed root OWNERS reads, and the OWNERS path in role errors

A Stryker probe of src/utils/auth.ts (--mutate src/utils/auth.ts on the
harness of #572) left 22 of 273 mutants alive. Eleven of them flip a guard
the suite reaches but never distinguishes; this file pins each one:

- checkOrgMember on a payload without a repository returns false by the
  early return, not by a TypeError caught as an unexpected error, so no
  warning annotation is emitted
- checkIssueComments skips a comment whose user is null (e.user?.login)
  instead of aborting the scan
- retrieveOwnersFile reports a string or null rejection of repos.getContent
  as the OWNERS lookup error rather than tripping on 'status' in e
- a contents response with content but no encoding, or an encoding but no
  content, is rejected as an invalid OWNERS file rather than decoded
- a root OWNERS role that is not a list is reported as 'OWNERS at OWNERS:'
  from both assertRootOwner and rootOwnersIncludes

The seven remaining survivors are core.debug strings and the
contents === '' short-circuit of rootOwnersIncludes, which is equivalent:
parseOwners('OWNERS', '') yields empty lists and expandGroups of an empty
list returns an empty set without a request.

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@hivecommons-hive
hivecommons-hive Bot requested a review from jpmcb as a code owner October 25, 2026 04:43
@hivecommons-hive hivecommons-hive Bot added the hold Indicates that a PR should not merge because someone has issued a /hold command. label Oct 25, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Important

Held for human review by the hive's ACMM level gate.

This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an outreach PR that targets a repository this hive does not manage is held at every level because it publishes project-facing communication into someone else's project.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against the tree at f72f8aa, not just the diff — this looks correct to me.

  • Test-only change: one new file, __tests__/utils/authGuards.test.ts (118 lines), no src/ or existing-test edits, matching the stated scope.
  • Each claimed guard exists where claimed: the repository-undefined early return (src/utils/auth.ts:43-46, debug text matches the assertion verbatim), e.user?.login in checkIssueComments (auth.ts:129), the typeof e === 'object' && e && 'status' in e && e.status === 404 catch and the data.content === undefined || !data.encoding guard in retrieveOwnersFile (auth.ts:444 / auth.ts:454), and the parseOwners('OWNERS', …) call sites at auth.ts:358 and auth.ts:421 whose OWNERS at OWNERS: prefix the two role-error tests pin.
  • The string/null rejection tests correctly produce error checking for an OWNERS file at the root of the repository: socket hang up / : null via the template's ${e}, exercising exactly the operands the five 444:9 mutants flip.
  • Ran it: npx vitest run __tests__/utils/authGuards.test.ts on the PR head → 8/8 pass. CI (build-test, e2e-coverage, DCO) is green.

The equivalence argument for the three surviving 417:7 mutants (contents === '' → parseOwners of an empty string yields empty role lists → false either way) checks out against rootOwnersIncludes at auth.ts:415-424.

No findings. Leaving approval to a maintainer per the hold gate.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

/kind cleanup


🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: e3119ad

— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88

@github-actions github-actions Bot added kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. and removed needs-kind labels Oct 26, 2026
@mrbobbytables

Copy link
Copy Markdown
Member

Consolidated into #588 together with the other eight open mutation-survivor pin PRs (commit cherry-picked unchanged, DCO preserved). Closing in favour of that PR.

@mrbobbytables
mrbobbytables deleted the quality/test-auth-guards branch October 26, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold Indicates that a PR should not merge because someone has issued a /hold command. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant