Skip to content

fix(repos): refuse managed path identity mismatches - #68

Merged
andrei-hasna merged 1 commit into
mainfrom
fix/67-iapp-todos-identity
Aug 7, 2026
Merged

fix(repos): refuse managed path identity mismatches#68
andrei-hasna merged 1 commit into
mainfrom
fix/67-iapp-todos-identity

Conversation

@andrei-hasna

@andrei-hasna andrei-hasna commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Closes #67

Root cause

getRepo() trusted a single exact-name row even when a canonical managed path (<owner>/internalapp/<repo>) encoded an owner/repository identity that disagreed with the indexed remote. Explicit path lookup could bypass name-resolution checks entirely.

Fix

  • derive the expected GitHub identity generically from canonical internalapp paths
  • reject mismatched managed rows while preserving ambiguity across valid candidates
  • enforce the same invariant at the public repo/show/inspect CLI boundary for explicit paths
  • leave non-managed layouts unopinionated; there is no iapp-todos special case

Evidence

Regression first:

  • mismatched managed-name lookup: expected rc=1, received rc=0 before the fix
  • mismatched explicit-path lookup: expected rc=1, received rc=0 before the boundary fix
  • valid matching control passed before and after

Current gates:

  • bun test src/cli/checkout-guard.test.ts: 19 pass, 0 fail, 131 assertions
  • bun test: 794 pass, 0 fail, 3533 assertions across 51 files
  • bun run typecheck: exit 0
  • bun run build: exit 0
  • git diff --check: exit 0
  • file-only secret scan: critical 0, high 0

Live installed-registry retry through the built candidate:

  • repos repo iapp-todos --json: rc=1, empty stdout, explicit expected github.com/hasnaxyz/iapp-todos vs indexed github.com/hasna/todos mismatch
  • matched managed control repos repo iapp-sites --json: rc=0

Population probe: 731 indexed rows examined; 20 canonical internalapp path/remote mismatches classified. Only issue #67s iapp-todos identity was independently verified against GitHub; the broader count is blast-radius evidence, not a claim that every row has been externally adjudicated.

Candidate: 9a0802ef1b993232ae07b539978fc602b489cdd9


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@andrei-hasna

Copy link
Copy Markdown
Contributor Author

Independent adversarial review: GO at exact head 9a0802ef1b993232ae07b539978fc602b489cdd9; zero reachable in-scope P0/P1 defects and no P2/P3 findings.

Reviewer evidence:

  • no iapp-todos hardcode; generic <owner>/internalapp/<repo> derivation
  • repo, show, and inspect fail closed by exact name and explicit path for the live mismatch (six rc=1 results, empty stdout)
  • matched managed iapp-sites and non-managed open-repos controls return rc=0
  • AMBIGUITY=PRESERVED, VALID_BEATS_MISMATCH=true, NON_MANAGED_UNAFFECTED=true
  • focused 57/0, full suite 794/0, typecheck and diff-check exit 0
  • exact-SHA CI Typecheck/Test/Build succeeded

Candidate remains unchanged and the worktree is clean. This executor will not merge, release, publish, or install.

Validate canonical internalapp checkout paths against their indexed GitHub remote before resolving them. Preserve ambiguity across valid candidates and fail closed for both name and explicit-path CLI lookup.

Add two-sided CLI regressions covering the mismatch and valid managed-checkout paths.

Refs #67

Agent: vitruvius
@andrei-hasna
andrei-hasna force-pushed the fix/67-iapp-todos-identity branch from 9a0802e to afe13ba Compare August 7, 2026 15:31
@andrei-hasna

Copy link
Copy Markdown
Contributor Author

Independent adversarial review: GO

Candidate: afe13ba9ccd3897fd368d2fabff90bd4991a7055
Current base: d5a37c043efb371dc9447c52aedf3ba4f79b9758
Current candidate/merge tree: d7110ff4b74b6acbbbcaf99cf62d1d422fc44311

Evidence on the exact current candidate:

  • git range-diff f6aefd278b57be5bf6120b02fe2a7c34825e6994..9a0802ef1b993232ae07b539978fc602b489cdd9 d5a37c043efb371dc9447c52aedf3ba4f79b9758..afe13ba9ccd3897fd368d2fabff90bd4991a7055 -> 1: 9a0802e = 1: afe13ba
  • git merge-tree --write-tree <base> <head> -> d7110ff4b74b6acbbbcaf99cf62d1d422fc44311; git diff --quiet <head> <merge-tree> -> rc 0
  • live candidate negative controls: exact-name and explicit-path iapp-todos lookup each returned rc 1, stdout 0 bytes, and the explicit expected github.com/hasnaxyz/iapp-todos versus indexed github.com/hasna/todos identity mismatch
  • matching managed control iapp-sites returned rc 0 with github.com/hasnaxyz/iapp-sites and a usable checkout
  • collateral controls: VALID_BEATS_MISMATCH=true, AMBIGUITY_PRESERVED=true, NON_MANAGED_UNAFFECTED=true
  • bun test src/cli/checkout-guard.test.ts: 19 pass, 0 fail, 131 assertions
  • bun test: 802 pass, 0 fail, 3567 assertions across 52 files
  • bun run typecheck: rc 0; bun run build: rc 0; git diff --check: rc 0
  • gitleaks git --log-opts=<base>..<head>: no leaks found, report length 0
  • current exact-SHA CI Typecheck, Test & Build: SUCCESS; PR remains OPEN, CLEAN, and MERGEABLE

Blocking findings: none. I found no concrete, currently reachable, in-scope P0/P1 defect material to issue #67, secrets/security, data integrity, unsafe mutation/rollback, or required compatibility gates.

@andrei-hasna
andrei-hasna merged commit bca9a9a into main Aug 7, 2026
2 checks passed
@andrei-hasna

Copy link
Copy Markdown
Contributor Author

[REVIEW] NO_GO — #68 @ 9a0802e — lens: correctness+security+gates, reviewer unresolved-account004 (1 of 1)

Scope read:

  • git log --oneline origin/main..HEAD at exact base d5a37c043efb371dc9447c52aedf3ba4f79b9758 and exact candidate 9a0802ef1b993232ae07b539978fc602b489cdd9: one commit, 9a0802e fix(repos): refuse managed path identity mismatches.
  • Full origin/main...HEAD diff for all changed files: src/cli/checkout-guard.test.ts, src/cli/index.tsx, and src/db/repos.ts.
  • Surrounding lookup and mutation callers in src/db/repos.ts, src/cli/index.tsx, src/lib/worktrees.ts, src/lib/repo-lifecycle.ts, src/lib/github.ts, and src/server/index.ts, plus PR fix(repos): refuse managed path identity mismatches #68 and issue BUG: @hasna/repos — iapp-todos target resolves to the public todos remote #67 acceptance text.

Commands and gates actually run, unpiped with stdout/stderr separated:

  • bun install — exit 0; setup only, not a gate; literal output: 496 packages installed [164.00ms].
  • bun run typecheck — exit 0; pass/fail counts not applicable; literal command output: $ tsc --noEmit; zero diagnostics.
  • bun run test — exit 0; literal summary: 794 pass, 0 fail, 3533 expect() calls, Ran 794 tests across 51 files. [100.05s].

Blocking P0/P1 findings:

  1. P1, high confidence — the supported explicit-path worktree mutation bypasses the new identity invariant (src/db/repos.ts:217-218; src/lib/worktrees.ts:350-356,665,739).
    • Reachable path: caller supplies a managed checkout path to repos worktree add <repo> / addWorktree({ repo: path })resolveRepo() calls getRepo(path) → the byPath early return skips getManagedRepoIdentityMismatch()git worktree add creates a branch/worktree from the mismatched parent.
    • Concrete impact: the issue BUG: @hasna/repos — iapp-todos target resolves to the public todos remote #67 tuple can still create a worktree from public hasna/todos while its managed path says private hasnaxyz/iapp-todos, preserving the wrong-repository mutation/data-integrity failure this PR is intended to stop.
    • Same-row reproduction on this candidate: public detail lookup correctly refused with exit 1 and printed Repository identity mismatch ... managed path requires remote 'github.com/hasnaxyz/iapp-fixture', but the index reports 'github.com/hasna/fixture'. The worktree library call then exited 0 and printed {"outcome":"CREATED","repo_path":"/home/hasna/.hasna/repos/worktrees/open-repos/pr68-review/.review-captures-68/probe/workspace/hasnaxyz/internalapp/iapp-fixture","worktree_path":"/home/hasna/.hasna/repos/worktrees/open-repos/pr68-review/.review-captures-68/probe/worktrees/iapp-fixture/mismatch-probe"}.
    • Minimal safe remedy: enforce managed identity on path-based repository resolution before any act-on-repo caller receives the row (or add the invariant to every mutation boundary), and add a regression proving addWorktree({ repo: mismatchedManagedPath }) refuses before creating a branch, directory, or lease. Re-run the affected worktree and checkout-guard lanes plus the declared typecheck/test gates because the shared resolver is cross-cutting.

Non-blocking follow-ups: none.

The GitHub PR head had already advanced beyond this reviewed SHA during the run. This verdict is intentionally scoped only to 9a0802ef1b993232ae07b539978fc602b489cdd9; it must not be treated as review coverage for a later head.

@andrei-hasna

Copy link
Copy Markdown
Contributor Author

[REVIEW] GO — #68 @ f7d4113 — lens: correctness+security+gates, reviewer unresolved-account004 (1 of 1)

Focused re-review of the one named blocker and its direct regressions only:

  • Fix commit: f7d4113361c5bb77241bf1f90fffe3cdf39a54d5 (fix(repos): enforce managed identity on direct lookup).
  • Direct path and numeric-ID getRepo() results now pass through the managed identity check before callers receive a row.
  • The worktree boundary maps that refusal to typed REPO_IDENTITY_MISMATCH.
  • Regression proves the supported explicit-path worktree path creates no branch, worktree directory, or lease.
  • Real-path retry exited 0 and printed {"result":"REFUSED","code":"REPO_IDENTITY_MISMATCH","root_entries":[],"branch":"","leases":0}.

Current-candidate validation, unpiped with stdout/stderr separated:

  • bun run typecheck — exit 0; pass/fail counts not applicable; literal output $ tsc --noEmit; zero diagnostics.
  • bun run test — exit 0; literal summary 803 pass, 0 fail, 3571 expect() calls, Ran 803 tests across 52 files. [107.19s].
  • git diff --check — exit 0.
  • Staged gitleaks before commit — exit 0; literal output no leaks found.
  • Commit-range gitleaks before push — exit 0; literal output 1 commits scanned. and no leaks found.
  • Push — exit 0; literal output afe13ba..f7d4113 HEAD -> fix/67-iapp-todos-identity.

Blocking P0/P1 findings: none remain on the named defect, implemented fix, or direct regressions.
Non-blocking follow-ups: none.

@andrei-hasna

Copy link
Copy Markdown
Contributor Author

Correction to the disposition record: PR #68 was merged at afe13ba9ccd9881b9b6d8530730fc68c142d3db8 before the reproduced P1 and initial NO_GO were posted. The managed-identity remedy therefore is not part of PR #68. The same branch now carries the rebased, patch-equivalent fix as PR #70 at c124509. Do not treat the earlier GO at f7d4113 as evidence that PR #68 merged the remedy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: @hasna/repos — iapp-todos target resolves to the public todos remote

1 participant