Repository navigation
Add admin-curated trusted marks for community listings - #760
Conversation
Trust is pinned to the reviewed commit: a listing shows its Trusted badge only while trusted_commit matches pinned_commit, so an owner republish drops the effective mark until an admin re-reviews. - Migration 0059 adds trusted_commit/trusted_by_user_id/trusted_at - setCommunityListingTrusted service + audited admin-only toggle at POST /community/:listingId/trust.json - Admin-only community_set_trusted MCP capability; community_search and community_get expose the effective trusted flag - Trusted badge on /community cards and detail header; admin trust panel on the detail page
The account data guardrail requires every *_user_id column to be covered. Deleting the reviewing admin's account keeps the trust mark (the review happened) but replaces trusted_by_user_id with 'deleted-user', matching the community_bans attribution pattern.
📝 WalkthroughWalkthroughAdds commit-pinned admin trust for community listings, including database fields, service and HTTP/MCP controls, public trust indicators, admin UI state, authorization, cache updates, documentation, and automated tests. ChangesCommunity listing trust
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Admin
participant CommunityDetailRoute
participant communityTrustApiPost
participant setCommunityListingTrusted
participant community_listings
Admin->>CommunityDetailRoute: Toggle trust
CommunityDetailRoute->>communityTrustApiPost: POST trusted boolean
communityTrustApiPost->>setCommunityListingTrusted: Validate admin request
setCommunityListingTrusted->>community_listings: Store current pinned commit
community_listings-->>setCommunityListingTrusted: Updated listing
setCommunityListingTrusted-->>communityTrustApiPost: Return trusted state
communityTrustApiPost-->>CommunityDetailRoute: JSON response
CommunityDetailRoute->>CommunityDetailRoute: Reload detail frame
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
🔎 Preview deployed: https://kody-pr-760.kody-a99.workers.dev Worker: Mocks:
|
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/worker/src/app/handlers/community-trust.node.test.ts (2)
78-85: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAssert the
Consider explicitly asserting the
🛠️ Proposed fix
expect(mockModule.logAuditEvent).toHaveBeenCalledWith( expect.objectContaining({ category: 'admin', action: 'community_listing_trust', result: 'success', + email: 'admin@example.com', reason: 'listing_id=listing-1;trusted=true', }), )🤖 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 `@packages/worker/src/app/handlers/community-trust.node.test.ts` around lines 78 - 85, Update the audit event assertion in the community trust handler test to include the expected email field alongside category, action, result, and reason, verifying the actor’s identity is passed to mockModule.logAuditEvent.
101-115: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueEnsure the console mock is always restored.
If an assertion fails before
consoleError.mockRestore()is called, the mock will remain active and suppressconsole.erroroutput in subsequent tests. Consider using atry/finallyblock to guarantee restoration.🛠️ Proposed fix
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}) - mockModule.setCommunityListingTrusted.mockRejectedValue( - new Error('db timeout'), - ) - const serverError = await handler.handler( - buildTrustRequest({ trusted: false }), - ) - expect(serverError.status).toBe(500) - expect(await serverError.json()).toEqual({ - ok: false, - error: 'Unable to update trust for this listing.', - }) - expect(consoleError).toHaveBeenCalled() - consoleError.mockRestore() + try { + mockModule.setCommunityListingTrusted.mockRejectedValue( + new Error('db timeout'), + ) + const serverError = await handler.handler( + buildTrustRequest({ trusted: false }), + ) + expect(serverError.status).toBe(500) + expect(await serverError.json()).toEqual({ + ok: false, + error: 'Unable to update trust for this listing.', + }) + expect(consoleError).toHaveBeenCalled() + } finally { + consoleError.mockRestore() + }🤖 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 `@packages/worker/src/app/handlers/community-trust.node.test.ts` around lines 101 - 115, Update the test around the console.error spy and handler assertions so consoleError.mockRestore() executes in a finally block, including when any assertion or handler call fails. Preserve the existing rejection setup and response assertions while guaranteeing cleanup after the test.
🤖 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.
Nitpick comments:
In `@packages/worker/src/app/handlers/community-trust.node.test.ts`:
- Around line 78-85: Update the audit event assertion in the community trust
handler test to include the expected email field alongside category, action,
result, and reason, verifying the actor’s identity is passed to
mockModule.logAuditEvent.
- Around line 101-115: Update the test around the console.error spy and handler
assertions so consoleError.mockRestore() executes in a finally block, including
when any assertion or handler call fails. Preserve the existing rejection setup
and response assertions while guaranteeing cleanup after the test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: edb18f8b-34de-4ac0-bcbc-bb34339cbee4
📒 Files selected for processing (38)
docs/contributing/architecture/primitives.yamldocs/contributing/community-packages.mddocs/use/community-packages.mde2e/community-trust.spec.tspackages/worker/client/routes/community-detail.tsxpackages/worker/migrations/0059-community-trusted-listings.sqlpackages/worker/src/app/account-data-targets.tspackages/worker/src/app/community-data.tspackages/worker/src/app/community-detail-content.tsxpackages/worker/src/app/community-listings-content.tsxpackages/worker/src/app/community-public-types.tspackages/worker/src/app/community-public.tspackages/worker/src/app/handlers/community-detail-og-image.node.test.tspackages/worker/src/app/handlers/community-detail.frame.node.test.tspackages/worker/src/app/handlers/community-detail.tsxpackages/worker/src/app/handlers/community-icon.node.test.tspackages/worker/src/app/handlers/community-trust.node.test.tspackages/worker/src/app/handlers/community-trust.tspackages/worker/src/app/handlers/community.frame.node.test.tspackages/worker/src/app/handlers/community.node.test.tspackages/worker/src/app/loader-data.tspackages/worker/src/app/router.tspackages/worker/src/app/routes.tspackages/worker/src/app/ssr-render.node.test.tspackages/worker/src/community/community-flow-test-schema.tspackages/worker/src/community/community-flow.workers.test.tspackages/worker/src/community/community-icon.node.test.tspackages/worker/src/community/community-icon.workers.test.tspackages/worker/src/community/community-scoring.node.test.tspackages/worker/src/community/community-service.node.test.tspackages/worker/src/community/repo.tspackages/worker/src/community/service.tspackages/worker/src/community/types.tspackages/worker/src/mcp/capabilities/community/domain.tspackages/worker/src/mcp/capabilities/community/get.tspackages/worker/src/mcp/capabilities/community/search.tspackages/worker/src/mcp/capabilities/community/set-trusted.tspackages/worker/src/mcp/capabilities/community/shared.ts
What
Admins can now mark a community listing as trusted after reviewing its content. This is the foundation for one-click install (next PR) and featured onboarding listings (after that).
0059-community-trusted-listings.sqladdstrusted_commit/trusted_by_user_id/trusted_attocommunity_listings.trusted_commit = pinned_commit, so an owner republish automatically drops the badge until an admin re-reviews. No revoke bookkeeping needed on publish.setCommunityListingTrustedservice guard: delisted listings cannot be trusted.POST /community/:listingId/trust.json, surfaced as an admin panel on the listing detail page.community_set_trustedMCP capability (enforced viarequiredRole, audited via the shared admin audit helper).community_searchandcommunity_getexpose the effectivetrustedflag;/communitycards and the detail header render a Trusted badge.trusted_by_user_idtodeleted-user(matches thecommunity_banspattern); the mark itself stays valid.Testing
community-flow.workers.test.ts: trust set → visible viacommunity_get; owner republish drops the effective mark; delisted listings reject trust; non-admin callers cannot accesscommunity_set_trusted.e2e/community-trust.spec.ts): member sees no controls and gets 403 from the API; admin toggles trust from the UI; badge appears on the detail page and/communitycard; revoke removes it.System recap — extends community-listings (medium risk)
Mode: recap · Base:
main@ed6ce6ff· Head:3f71fb23Classification: extends — the community-listings primitive gains a commit-pinned admin trust mark; other touched primitives are wiring only.
Primitives touched
community-listingscommunity_set_trustedd1-app-dbrbacrequireUserWithRole('admin')guard +requiredRoleon capabilityapp-uimcp-servertrustedfield on search/get, new admin-only capabilityaccount-exportSystem map
Admin trust flows from the detail-page toggle (or the MCP capability) through the RBAC guard into the community service, which stores the reviewed commit in D1; public surfaces read the derived
trustedflag.Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).
Before / after
Invariants
Trust attribution is the only new cross-user reference (admin id on a listing row); it is anonymized on the admin's account deletion, and public surfaces expose only the boolean flag. The map's
community-listingsentry was updated in this PR.Summary by CodeRabbit
New Features
Bug Fixes
Documentation