Skip to content

Existence-hiding 404 across ALL agent-registry routes (issue #2106, reported by hognek) - #2356

Merged
jaylfc merged 5 commits into
devfrom
exec/tsk-vzkbao
Aug 11, 2026
Merged

jaylfc merged 5 commits into
devfrom
exec/tsk-vzkbao

Conversation

@jaylfc

@jaylfc jaylfc commented Aug 10, 2026

Copy link
Copy Markdown
Owner

CARD TITLE (intent, not commit subject): Existence-hiding 404 across ALL agent-registry routes (issue #2106, reported by hognek)

Autonomous build of board card tsk-vzkbao.

Convert create_scope_request, approve_scope_request, and deny_scope_request
to return the same 404 response for both non-existent canonical_ids and
authenticated non-owners, matching the pattern already used by
GET /api/agents/registry/{id}.

Server-side logs distinguish 403-not-owner from 404-unknown; only the
response is uniform.

Updated existing tests asserting 403 to assert 404, and added red-first
identical-response tests for each converted route.

Timing: non-owner path performs the same work as before (registry lookup
plus authz check); no new fast path on the not-found side.

Files:
tests/test_agent_scope_requests.py | 125 +++++++++++++++++++++++++++++-
tinyagentos/routes/agent_auth_requests.py | 32 +++++---
2 files changed, 144 insertions(+), 13 deletions(-)

Summary by CodeRabbit

  • Bug Fixes

    • Unauthorized scope-request actions now return 404 instead of 403, preventing agent existence disclosure.
    • Create, approve, and deny operations consistently match the status and response body for unauthorized and nonexistent agents.
    • Registry updates, deletions, token rotations, and organization changes now return consistent 404 responses to unauthorized callers.
    • Unknown or inactive agents follow the same secure response behavior.
  • Documentation

    • Documented resource-existence hiding across owner-gated registry routes.

Red-first evidence (lead-run at merge ref)

All 7 new identical-response tests executed at the merge ref origin/dev (5910eb1), before the change:

FAILED tests/test_agent_scope_requests.py::test_create_scope_request_non_owner_and_nonexistent_identical
FAILED tests/test_agent_scope_requests.py::test_approve_scope_request_non_owner_and_nonexistent_identical
FAILED tests/test_agent_scope_requests.py::test_deny_scope_request_non_owner_and_nonexistent_identical
FAILED tests/test_agent_registry.py::TestRegistryWriteExistenceHiding::test_patch_non_owner_and_nonexistent_identical
FAILED tests/test_agent_registry.py::TestRegistryWriteExistenceHiding::test_delete_non_owner_and_nonexistent_identical
FAILED tests/test_agent_registry.py::TestRegistryWriteExistenceHiding::test_rotate_tokens_non_owner_and_nonexistent_identical
FAILED tests/test_agent_registry.py::TestRegistryWriteExistenceHiding::test_org_put_non_owner_and_nonexistent_identical
7 failed, 20 deselected in 17.72s

Timing statement (card point 4)

No obviously faster branch was introduced on the not-found side. Every touched route performs the same single store.get(canonical_id) (or registry lookup) on both branches; the non-owner branch additionally does one in-memory id comparison before returning the identical response. Constant-time behaviour is not claimed.

Convert create_scope_request, approve_scope_request, and deny_scope_request
to return the same 404 response for both non-existent canonical_ids and
authenticated non-owners, matching the pattern already used by
GET /api/agents/registry/{id}.

Server-side logs distinguish 403-not-owner from 404-unknown; only the
response is uniform.

Updated existing tests asserting 403 to assert 404, and added red-first
identical-response tests for each converted route.

Timing: non-owner path performs the same work as before (registry lookup
plus authz check); no new fast path on the not-found side.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jaylfc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c627cbe0-c9b8-48b1-b7bd-9570e4fbd5fb

📥 Commits

Reviewing files that changed from the base of the PR and between c3401ae and e44e721.

📒 Files selected for processing (9)
  • changelog.d/2356-registry-existence-hiding.md
  • docs/agent-coordination.md
  • tests/test_agent_registry.py
  • tests/test_agent_scope_requests.py
  • tests/test_registry_governance_lifecycle.py
  • tests/test_routes_agent_org.py
  • tests/test_token_rotation.py
  • tinyagentos/routes/agent_auth_requests.py
  • tinyagentos/routes/agent_registry.py
📝 Walkthrough

Walkthrough

Scope-request and agent-registry mutation routes now return 404 for unauthorized access. The routes log rejected and unavailable-agent requests. Tests verify identical responses for unauthorized and nonexistent agent IDs.

Changes

Agent existence hiding

Layer / File(s) Summary
Scope-request authorization
tinyagentos/routes/agent_auth_requests.py
Creation, approval, and denial return 404 for unauthorized, unknown, and inactive agents. Rejected access is logged.
Registry mutation authorization
tinyagentos/routes/agent_registry.py
Patch, revoke, token rotation, and organization updates use inline ownership checks and return 404 for unauthorized non-admin users.
Existence-hiding validation and documentation
tests/test_agent_scope_requests.py, tests/test_agent_registry.py, tests/test_registry_governance_lifecycle.py, tests/test_routes_agent_org.py, tests/test_token_rotation.py, docs/agent-coordination.md, changelog.d/2356-registry-existence-hiding.md
Tests compare unauthorized and nonexistent responses across routes. Documentation and the changelog describe the 404 behavior and admin-only 403 behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

  • jaylfc/taOS#2208: Modifies agent registry token-rotation authorization and 404 behavior.
  • jaylfc/taOS#2279: Modifies agent_auth_requests.py and overlaps with scope authorization, but changes valid scopes rather than authorization behavior.

Suggested reviewers: hognek

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: consistent 404 existence-hiding behavior across agent-registry routes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch exec/tsk-vzkbao

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_agent_scope_requests.py`:
- Around line 633-639: Update tests/test_agent_scope_requests.py lines 633-639,
673-679, and 712-717 so each nonexistent create, approve, and deny request is
issued through carol_client, then compare resp_owner.content with
resp_nonexistent.content instead of normalized JSON responses while preserving
the existing 404 assertions.

In `@tinyagentos/routes/agent_auth_requests.py`:
- Around line 1197-1205: Update the deny-route record guard in the surrounding
scope-request handler to also reject records whose status is not active by
checking record.get("status") != "active". Preserve the existing 404 detail and
ownership-check behavior for missing or inactive agents.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ead8e52d-6bfe-4370-b6a3-3dfe20f201b6

📥 Commits

Reviewing files that changed from the base of the PR and between c3401ae and 2b1ffb3.

📒 Files selected for processing (2)
  • tests/test_agent_scope_requests.py
  • tinyagentos/routes/agent_auth_requests.py

Comment thread tests/test_agent_scope_requests.py Outdated
Comment on lines 1197 to 1205
if record is None:
logger.info("scope request deny 404-unknown for %s", canonical_id)
raise HTTPException(status_code=404, detail="agent not found")
if not (user.is_admin or user.user_id == record["user_id"]):
logger.info(
"scope request deny 403-not-owner for %s by %s",
canonical_id, user.user_id,
)
raise HTTPException(status_code=404, detail="agent not found")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject inactive agents on the deny route.

Line 1197 rejects only missing records. An inactive record can reach store.set_decision, while the create and approve routes reject inactive records. Include record.get("status") != "active" in this guard and keep the same 404 response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/agent_auth_requests.py` around lines 1197 - 1205, Update
the deny-route record guard in the surrounding scope-request handler to also
reject records whose status is not active by checking record.get("status") !=
"active". Preserve the existing 404 detail and ownership-check behavior for
missing or inactive agents.

@@ -1189,8 +1195,14 @@ async def deny_scope_request(
registry = _get_registry_store(request)
record = await registry.get(canonical_id)
if record is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: deny_scope_request is missing the record.get("status") != "active" guard that approve_scope_request now has at line 1071, breaking the uniform 404 existence-hiding contract for this route.

approve_scope_request correctly returns 404 for inactive agents:

if record is None or record.get("status") != "active":
    raise HTTPException(status_code=404, ...)

deny_scope_request only checks if record is None — an inactive agent record bypasses this guard and falls through to the owner check, allowing the owning user to successfully deny a scope request for an inactive agent. This directly contradicts the PR's stated goal of a uniform 404 across all agent-registry scope-request routes (see create_scope_request line 986, which already guards both conditions).

Suggested fix — mirror the active-status check from approve_scope_request:

Suggested change
if record is None:
if record is None or record.get("status") != "active":
logger.info("scope request deny 404-unknown for %s", canonical_id)
raise HTTPException(status_code=404, detail="agent not found or not active")

A companion test (analogous to the three new red-first tests) should cover the deny + inactive-agent case.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • tests/test_agent_scope_requests.py - new inactive-token existence-hiding test
  • tinyagentos/routes/agent_auth_requests.py - 404 uniform-response updates in create/approve/deny scope-request routes
Previous Review Summaries (4 snapshots, latest commit 999f7ab)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 999f7ab)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • tests/test_agent_registry.py - previous warnings resolved (.content comparisons)
  • tests/test_agent_scope_requests.py - previous warnings resolved (carol_client + .content comparisons)
  • tinyagentos/routes/agent_registry.py - previous logging suggestion addressed (8 logger.info calls added)

Previous review (commit 74ba0d2)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
WARNING 3
Issue Details (click to expand)

WARNING

File Line Issue
tinyagentos/routes/agent_auth_requests.py 1197 deny_scope_request missing record.get("status") != "active" guard — allows deny on inactive agents while approve_scope_request returns 404, breaking uniform existence-hiding across scope-request routes
tests/test_agent_scope_requests.py 639 .json() comparison does not verify byte-identical response bodies; nonexistent request sent through unauthenticated client instead of carol_client
tests/test_agent_registry.py 873 .json() comparison does not verify byte-identical response bodies as test docstring requires
Files Reviewed (5 files)
  • tinyagentos/routes/agent_auth_requests.py - 1 issue (unchanged from previous review)
  • tests/test_agent_scope_requests.py - 1 issue (unchanged from previous review)
  • tests/test_agent_registry.py - 1 issue (unchanged from previous review)
  • docs/agent-coordination.md - no issues
  • tests/test_registry_governance_lifecycle.py - no new issues
  • tests/test_routes_agent_org.py - no new issues
  • tests/test_token_rotation.py - no new issues
  • tinyagentos/routes/agent_registry.py - no new issues

Fix these issues in Kilo Cloud

Previous review (commit 0b632eb)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
WARNING 3
Issue Details (click to expand)

WARNING

File Line Issue
tinyagentos/routes/agent_auth_requests.py 1197 deny_scope_request missing record.get("status") != "active" guard — allows deny on inactive agents while approve_scope_request returns 404, breaking uniform existence-hiding across scope-request routes
tests/test_agent_scope_requests.py 639 .json() comparison does not verify byte-identical response bodies; nonexistent request sent through unauthenticated client instead of carol_client
tests/test_agent_registry.py 873 .json() comparison does not verify byte-identical response bodies as test docstring requires
Files Reviewed (3 files)
  • tinyagentos/routes/agent_auth_requests.py - 1 issue
  • tests/test_agent_scope_requests.py - 1 issue
  • tests/test_agent_registry.py - 1 issue

Fix these issues in Kilo Cloud

Previous review (commit 2b1ffb3)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
WARNING 1
Issue Details (click to expand)

WARNING

File Line Issue
tinyagentos/routes/agent_auth_requests.py 1197 deny_scope_request missing record.get("status") != "active" guard — allows deny on inactive agents while approve_scope_request returns 404, breaking uniform existence-hiding across all scope-request routes
Files Reviewed (2 files)
  • tinyagentos/routes/agent_auth_requests.py - 1 issue
  • tests/test_agent_scope_requests.py

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 97.7K · Output: 21.3K · Cached: 279.8K

@jaylfc

jaylfc commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

nemotron-super review

VERDICT: Log messages incorrectly state 403 when raising 404 for non-owner cases

  • tinyagentos/routes/agent_auth_requests.py:951 (log message in _authorize_scope_request_creation function says 403-not-owner but raises 404)
  • tinyagentos/routes/agent_auth_requests.py:983 (log message in approve_scope_request function says 403-not-owner but raises 404)
  • tinyagentos/routes/agent_auth_requests.py:1189 (log message in deny_scope_request function says 403-not-owner but raises 404)

Automated first-pass review by the nemotron-super lane. The lead still reviews before merge.

…e routes

Sweep of the same class the scope-request routes fixed: PATCH, DELETE,
rotate-tokens, and org PUT all returned 404-if-missing then 403-if-not-owner,
disclosing id existence to any authenticated non-owner. All four now return
the not-found response for non-owners, using the exact idiom of the GET
route this file already documents as the reference implementation.

Lifecycle routes (_transition) and the consent approve/deny routes check
admin BEFORE any lookup, so they respond uniformly already and are unchanged.

Byte-identical tests (status + body, non-owner vs nonexistent) for all four
routes with a real non-admin user; PATCH test proven red against the old
require_owner_or_admin behaviour. The import that check left orphaned is
removed. Changelog fragment added for doc-gate.
@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Lead review (tsk-vzkbao, issue #2106). The lane's fix is correct and well-tested: the three scope-request routes now return the not-found response for authenticated non-owners, the true cause is logged server-side, and the byte-identical comparison tests (status + body, non-owner vs nonexistent) are exactly the right assertion shape. The consent approve/deny routes the issue also listed turn out not to leak: both check user.is_admin before any lookup, so a non-admin gets the same 403 whether the request id exists or not.

Pushed 0b632eb completing the class the issue's own goal statement names ("make every agent-registry route existence-hiding"): four owner-gated write routes in routes/agent_registry.py still had the 404-then-403 pattern — PATCH, DELETE (revoke), rotate-tokens, and PUT /api/agents/{id}/org. All four now use the same idiom as the GET route the issue cites as the reference implementation. Byte-identical tests added for each with a real non-admin user (and side-effect checks that the record was not modified/revoked); the PATCH test was proven red against the old require_owner_or_admin behaviour before restoring. The orphaned import is removed, and the doc-gate changelog fragment is in. 73 tests across both files pass locally.

Merging via the gate once checks are green on the new head.

Comment thread tests/test_agent_registry.py Outdated
"/api/agents/registry/does-not-exist", json={"display_name": "Stolen"}
)
assert resp_owned.status_code == resp_missing.status_code == 404
assert resp_owned.json() == resp_missing.json()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: .json() does not verify byte-identical responses

The test docstring asserts byte-identical responses (status + body), but resp_owned.json() == resp_missing.json() compares normalized JSON objects — whitespace, key ordering, and trailing-newline differences in the raw response body are silently ignored. Use resp_owned.content == resp_missing.content to enforce the contract the docstring promises.

Suggested change
assert resp_owned.json() == resp_missing.json()
assert resp_owned.content == resp_missing.content

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread tests/test_agent_registry.py Outdated
"/api/agents/registry/does-not-exist/rotate-tokens"
)
assert resp_owned.status_code == resp_missing.status_code == 404
assert resp_owned.json() == resp_missing.json()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: .json() does not verify byte-identical responses

Same issue as test_patch_non_owner_and_nonexistent_identical at line 873. resp_owned.json() == resp_missing.json() compares normalized JSON objects, not raw response bodies. Use resp_owned.content == resp_missing.content to enforce the byte-identical contract.

Suggested change
assert resp_owned.json() == resp_missing.json()
assert resp_owned.content == resp_missing.content

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

…04, document contract

The class sweep changed four write routes but missed four pre-existing tests
asserting the old 403 in OTHER files (caught by CI shards): two rotate-tokens
tests, the lifecycle PATCH non-owner test, and the org PUT non-owner test.
All now assert the not-found 404 with docstrings explaining why.

docs/agent-coordination.md gains the existence-hiding contract for the whole
owner-gated registry surface (doc-gate agent-manual rule), including the
warning that a 404 no longer proves nonexistence.
@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
tests/test_agent_scope_requests.py (1)

633-639: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Test raw responses with the same caller.

.json() normalizes response bodies and does not verify byte identity. In the scope-request tests, the missing-record request also uses client instead of carol_client. Send both requests through the same non-owner client and compare .content.

  • tests/test_agent_scope_requests.py#L633-L639: use carol_client for the missing create request and compare .content.
  • tests/test_agent_scope_requests.py#L673-L679: use carol_client for the missing approve request and compare .content.
  • tests/test_agent_scope_requests.py#L712-L717: use carol_client for the missing deny request and compare .content.
  • tests/test_agent_registry.py#L872-L876: compare PATCH response .content.
  • tests/test_agent_registry.py#L883-L888: compare DELETE response .content.
  • tests/test_agent_registry.py#L901-L902: compare token-rotation response .content.
  • tests/test_agent_registry.py#L915-L916: compare organization-update response .content.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_agent_scope_requests.py` around lines 633 - 639, The scope-request
tests at tests/test_agent_scope_requests.py lines 633-639, 673-679, and 712-717
must send missing-record requests through carol_client and compare raw
response.content rather than normalized JSON. In tests/test_agent_registry.py
lines 872-876, 883-888, 901-902, and 915-916, replace response JSON comparisons
with response.content comparisons for the PATCH, DELETE, token-rotation, and
organization-update checks.
tinyagentos/routes/agent_auth_requests.py (1)

1197-1205: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject inactive agents on the deny route.

Line 1197 accepts an inactive record. Its owner can then deny a scope request, while the create and approve routes return 404. Include record.get("status") != "active" in this guard and preserve the same 404 response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/agent_auth_requests.py` around lines 1197 - 1205, Update
the record validation guard after the lookup in the deny route to also reject
records whose status is not active, using record.get("status") != "active"
alongside the existing missing-record and ownership checks. Preserve the current
404 response and logging behavior for inactive agents.
🧹 Nitpick comments (1)
tinyagentos/routes/agent_auth_requests.py (1)

968-971: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the diagnostic status label with the HTTP response.

These paths return HTTP 404 but log 403-not-owner. Use 404-not-owner, or remove the status code from the event name.

  • tinyagentos/routes/agent_auth_requests.py#L968-L971: update the create-route non-owner log label.
  • tinyagentos/routes/agent_auth_requests.py#L1075-L1078: update the approve-route non-owner log label.
  • tinyagentos/routes/agent_auth_requests.py#L1201-L1204: update the deny-route non-owner log label.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tinyagentos/routes/agent_auth_requests.py` around lines 968 - 971, Update the
non-owner diagnostic labels in the create, approve, and deny routes of
tinyagentos/routes/agent_auth_requests.py at lines 968-971, 1075-1078, and
1201-1204 to use 404-not-owner, matching their HTTP responses, or remove the
status code from all three event names consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/routes/agent_registry.py`:
- Around line 618-623: In tinyagentos/routes/agent_registry.py, add distinct
diagnostic logs immediately before the uniform 404 responses for unknown records
and non-owner access in the PATCH route (618-623), revoke route (672-677),
token-rotation route (781-786), and organization-update route (845-850).
Preserve the existing response behavior while clearly identifying which outcome
occurred at each site.

---

Duplicate comments:
In `@tests/test_agent_scope_requests.py`:
- Around line 633-639: The scope-request tests at
tests/test_agent_scope_requests.py lines 633-639, 673-679, and 712-717 must send
missing-record requests through carol_client and compare raw response.content
rather than normalized JSON. In tests/test_agent_registry.py lines 872-876,
883-888, 901-902, and 915-916, replace response JSON comparisons with
response.content comparisons for the PATCH, DELETE, token-rotation, and
organization-update checks.

In `@tinyagentos/routes/agent_auth_requests.py`:
- Around line 1197-1205: Update the record validation guard after the lookup in
the deny route to also reject records whose status is not active, using
record.get("status") != "active" alongside the existing missing-record and
ownership checks. Preserve the current 404 response and logging behavior for
inactive agents.

---

Nitpick comments:
In `@tinyagentos/routes/agent_auth_requests.py`:
- Around line 968-971: Update the non-owner diagnostic labels in the create,
approve, and deny routes of tinyagentos/routes/agent_auth_requests.py at lines
968-971, 1075-1078, and 1201-1204 to use 404-not-owner, matching their HTTP
responses, or remove the status code from all three event names consistently.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 890a4ed8-8c18-4284-a769-701c8eda4a65

📥 Commits

Reviewing files that changed from the base of the PR and between c3401ae and 74ba0d2.

📒 Files selected for processing (9)
  • changelog.d/2356-registry-existence-hiding.md
  • docs/agent-coordination.md
  • tests/test_agent_registry.py
  • tests/test_agent_scope_requests.py
  • tests/test_registry_governance_lifecycle.py
  • tests/test_routes_agent_org.py
  • tests/test_token_rotation.py
  • tinyagentos/routes/agent_auth_requests.py
  • tinyagentos/routes/agent_registry.py

Comment thread tinyagentos/routes/agent_registry.py
…es, route logs

Folds the Kilo + CodeRabbit findings on the identical-response tests:
.json() compares normalized objects so it cannot back the byte-identical
claim; all seven tests now compare resp.content. The three scope-request
tests also send their nonexistent probe from the SAME non-owner client
instead of the admin fixture, since the contract under test is what one
unprivileged caller can distinguish. The four registry write routes gain
the same unknown-vs-not-owner server-side logs the scope-request routes
already emit.
@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Bot findings adjudicated (999f7ab):

Folded — both bots' byte-identity point was right: .json() compares normalized objects and cannot back the "byte-identical" claim, so all seven identical-response tests now compare resp.content. CodeRabbit's same-caller point was also right: the three scope-request tests sent their nonexistent probe from the admin fixture client; they now use the same non-owner client, since the contract under test is what one unprivileged caller can distinguish. The four registry write routes also gained the unknown-vs-not-owner server-side logs the scope-request routes already emit (CodeRabbit's consistency point).

Not folded, with reasoning — "reject inactive agents on the deny route": the deny route's None-only check predates this PR and is semantically deliberate, not an oversight. Create and approve gate on status == "active" because both can mint or add grants, which must never happen for a suspended agent. Deny writes only a refusal and grants nothing, and blocking it for inactive agents would leave pending scope requests un-cleanable exactly when an agent gets suspended. The 404 detail on deny ("agent not found", no "or not active") matches its actual check, so no message lies. Changing this would be a behavior change outside the card's existence-hiding scope; if the asymmetry should close, that's its own card.

@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/routes/agent_auth_requests.py`:
- Around line 968-971: Rename every non-owner diagnostic label from
403-not-owner to 404-not-owner in tinyagentos/routes/agent_auth_requests.py at
lines 968-971, 1075-1078, and 1201-1204, and in
tinyagentos/routes/agent_registry.py at lines 624, 680, 791, and 857, covering
the create, approve, deny, PATCH, revoke, token-rotation, and
organization-update logs.
- Around line 962-965: Update create_scope_request to validate the Authorization
bearer credentials before calling registry.get(canonical_id), preserving the
existing 401/403 behavior for malformed and inactive tokens. Store and reuse the
resolved identity from check_agent_identity for the canonical_id ownership
check, and add response-pair tests covering malformed and inactive bearer tokens
against known and unknown targets.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 51e55af7-a87f-4c19-92c2-a18e9dac2d5e

📥 Commits

Reviewing files that changed from the base of the PR and between c3401ae and 999f7ab.

📒 Files selected for processing (9)
  • changelog.d/2356-registry-existence-hiding.md
  • docs/agent-coordination.md
  • tests/test_agent_registry.py
  • tests/test_agent_scope_requests.py
  • tests/test_registry_governance_lifecycle.py
  • tests/test_routes_agent_org.py
  • tests/test_token_rotation.py
  • tinyagentos/routes/agent_auth_requests.py
  • tinyagentos/routes/agent_registry.py

Comment thread tinyagentos/routes/agent_auth_requests.py
Comment thread tinyagentos/routes/agent_auth_requests.py
…reate

check_agent_identity raises 401 (malformed token) or 403 (inactive agent)
in-route, but create_scope_request 404s on an unknown target BEFORE auth
runs, so a caller holding a bad token could distinguish existing targets
(401/403) from nonexistent ones (404). The authorize helper now converts
those raises into the uniform 404, logging the true cause server-side.

Regression test: a suspended agent's validly signed token gets
byte-identical 404s for an existing and a nonexistent target; proven red
against the unguarded call. Also renames the create/approve/deny log
labels from 403-not-owner to 404-not-owner to match what the routes
actually return (CodeRabbit findings, both folded).
@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

CodeRabbit round 2, both folded in the new head: the Major was real — a malformed/inactive bearer token got 401/403 on an existing target but 404 on an unknown one (the not-found check runs before auth), an existence oracle through the credential-error path. _authorize_scope_request_creation now converts check_agent_identity raises into the uniform 404 with the true cause logged; regression test added (suspended agent's valid-signature token, byte-identical responses) and proven red against the unguarded call. Log labels renamed 403-not-owner → 404-not-owner to match the actual responses.

@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 10 minutes.

@jaylfc

jaylfc commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Merging with the CodeRabbit status on e44e721 explicitly adjudicated, not trusted: its 'pass' there is the rate-limited fake green (description 'Review rate limited', never ran, retriggered twice with a 10-minute wait each). It is not being counted as a review. What is counted: CodeRabbit's two REAL reviews on 74ba0d2 and 999f7ab (every actionable finding from both rounds folded or adjudicated with reasoning above), Kilo's fresh pass on this exact head (19:36Z), green CI across the board, and the fact that the final delta consists solely of CodeRabbit's own round-2 findings implemented with a mutation-proven regression test.

@jaylfc
jaylfc merged commit e55ecfb into dev Aug 11, 2026
20 checks passed
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.

1 participant