Skip to content

Add admin-curated trusted marks for community listings - #760

Merged
kody-bot merged 3 commits into
mainfrom
cursor/community-trusted-listings-d4a5
Jul 16, 2026
Merged

kody-bot merged 3 commits into
mainfrom
cursor/community-trusted-listings-d4a5

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 16, 2026 •

Copy link
Copy Markdown
Member

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).

  • New migration 0059-community-trusted-listings.sql adds trusted_commit / trusted_by_user_id / trusted_at to community_listings.
  • Trust is pinned to the reviewed commit: a listing is effectively trusted only while trusted_commit = pinned_commit, so an owner republish automatically drops the badge until an admin re-reviews. No revoke bookkeeping needed on publish.
  • setCommunityListingTrusted service guard: delisted listings cannot be trusted.
  • Admin-only, audited HTTP toggle at POST /community/:listingId/trust.json, surfaced as an admin panel on the listing detail page.
  • Admin-only community_set_trusted MCP capability (enforced via requiredRole, audited via the shared admin audit helper).
  • community_search and community_get expose the effective trusted flag; /community cards and the detail header render a Trusted badge.
  • Account deletion of the reviewing admin anonymizes trusted_by_user_id to deleted-user (matches the community_bans pattern); the mark itself stays valid.

Testing

  • Extended the real-D1 community-flow.workers.test.ts: trust set → visible via community_get; owner republish drops the effective mark; delisted listings reject trust; non-admin callers cannot access community_set_trusted.
  • New handler unit test for the HTTP toggle (403 non-admin, 400 invalid body, audit event, error mapping).
  • New Playwright e2e (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 /community card; revoke removes it.
  • Account deletion/export guardrail tests now cover the new column.
System recap — extends community-listings (medium risk)

Mode: recap · Base: main @ ed6ce6ff · Head: 3f71fb23

Classification: extends — the community-listings primitive gains a commit-pinned admin trust mark; other touched primitives are wiring only.

Primitives touched

Primitive Group Impact
community-listings assistant extends — trust columns, service, badge UI, community_set_trusted
d1-app-db storage extends — migration 0059 adds three nullable columns
rbac auth composes — requireUserWithRole('admin') guard + requiredRole on capability
app-ui surfaces composes — trust toggle panel and Trusted badges
mcp-server surfaces composes — trusted field on search/get, new admin-only capability
account-export storage composes — new column registered in the shared account data targets

System 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 trusted flag.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	appUi["app-ui<br/>Browser app"]:::touched
	mcpServer["mcp-server<br/>MCP endpoint"]:::touched
	rbac["rbac<br/>Role-based access control"]:::touched
	communityListings["community-listings<br/>Community package listings"]:::extended
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	accountExport["account-export<br/>Account data export"]:::touched
	appUi -->|"POST /community/:listingId/trust.json"| rbac
	mcpServer -->|"community_set_trusted (requiredRole: admin)"| rbac
	rbac -->|"setCommunityListingTrusted"| communityListings
	communityListings -->|"trusted_commit / trusted_by / trusted_at columns"| d1AppDb
	appUi -->|"Trusted badge on /community + detail"| communityListings
	accountExport -->|"anonymize trusted_by_user_id on deletion"| d1AppDb
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

community_listings: + trusted_commit TEXT, + trusted_by_user_id TEXT, + trusted_at TEXT
effective trusted = trusted_commit IS NOT NULL AND trusted_commit = pinned_commit

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-listings entry was updated in this PR.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Admins can mark community listings as trusted for their exact pinned commit.
    • Trusted badges now appear on community listing cards and detail pages.
    • Added admin-only controls and capability to set or revoke trust.
    • Community search and detail results now show trusted status.
  • Bug Fixes

    • Trust is automatically removed when a listing’s pinned commit changes.
    • Delisted listings cannot be marked as trusted.
  • Documentation

    • Added guidance describing trusted listings, review requirements, and available capabilities.

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.
@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds 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.

Changes

Community listing trust

Layer / File(s) Summary
Trust storage and listing records
packages/worker/migrations/0059-community-trusted-listings.sql, packages/worker/src/community/*, packages/worker/src/app/account-data-targets.ts, packages/worker/src/community/*test.ts, packages/worker/src/app/handlers/*test.ts
Community listings gain nullable trust metadata, effective trust is derived when trusted_commit matches pinned_commit, and trust updates clear or set reviewer metadata.
Trust service and HTTP route
packages/worker/src/community/service.ts, packages/worker/src/app/handlers/community-trust.*, packages/worker/src/app/routes.ts, packages/worker/src/app/router.ts, packages/worker/src/app/community-data.ts, packages/worker/src/app/loader-data.ts, packages/worker/src/community/community-flow.workers.test.ts
An admin-only trust service and POST endpoint set or revoke trust, reject delisted listings, audit successful requests, and expose admin state through loader data.
MCP trust capability
packages/worker/src/mcp/capabilities/community/*
community_set_trusted is added as an audited admin-only capability, while community_search and community_get expose validated trust fields.
Trust UI and documentation
packages/worker/client/routes/community-detail.tsx, packages/worker/src/app/community-*content.tsx, docs/*, e2e/community-trust.spec.ts
Admins can toggle trust from the detail page, trusted badges render on detail and index views, and documentation and end-to-end coverage describe the commit-pinned behavior.

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
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: admin-curated trusted marks for community listings.
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 cursor/community-trusted-listings-d4a5

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.

@kody-bot
kody-bot marked this pull request as ready for review July 16, 2026 15:37
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-760.kody-a99.workers.dev

Worker: kody-pr-760
D1: kody-pr-760-db
KV: kody-pr-760-oauth-kv

Mocks:

@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.

🧹 Nitpick comments (2)
packages/worker/src/app/handlers/community-trust.node.test.ts (2)

78-85: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Assert the email field in the audit log event.

Consider explicitly asserting the email field to guarantee that the actor's identity is correctly captured and passed to the audit logging service.

🛠️ 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 value

Ensure the console mock is always restored.

If an assertion fails before consoleError.mockRestore() is called, the mock will remain active and suppress console.error output in subsequent tests. Consider using a try/finally block 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

📥 Commits

Reviewing files that changed from the base of the PR and between ed6ce6f and 3f71fb2.

📒 Files selected for processing (38)
  • docs/contributing/architecture/primitives.yaml
  • docs/contributing/community-packages.md
  • docs/use/community-packages.md
  • e2e/community-trust.spec.ts
  • packages/worker/client/routes/community-detail.tsx
  • packages/worker/migrations/0059-community-trusted-listings.sql
  • packages/worker/src/app/account-data-targets.ts
  • packages/worker/src/app/community-data.ts
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/community-listings-content.tsx
  • packages/worker/src/app/community-public-types.ts
  • packages/worker/src/app/community-public.ts
  • packages/worker/src/app/handlers/community-detail-og-image.node.test.ts
  • packages/worker/src/app/handlers/community-detail.frame.node.test.ts
  • packages/worker/src/app/handlers/community-detail.tsx
  • packages/worker/src/app/handlers/community-icon.node.test.ts
  • packages/worker/src/app/handlers/community-trust.node.test.ts
  • packages/worker/src/app/handlers/community-trust.ts
  • packages/worker/src/app/handlers/community.frame.node.test.ts
  • packages/worker/src/app/handlers/community.node.test.ts
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/app/ssr-render.node.test.ts
  • packages/worker/src/community/community-flow-test-schema.ts
  • packages/worker/src/community/community-flow.workers.test.ts
  • packages/worker/src/community/community-icon.node.test.ts
  • packages/worker/src/community/community-icon.workers.test.ts
  • packages/worker/src/community/community-scoring.node.test.ts
  • packages/worker/src/community/community-service.node.test.ts
  • packages/worker/src/community/repo.ts
  • packages/worker/src/community/service.ts
  • packages/worker/src/community/types.ts
  • packages/worker/src/mcp/capabilities/community/domain.ts
  • packages/worker/src/mcp/capabilities/community/get.ts
  • packages/worker/src/mcp/capabilities/community/search.ts
  • packages/worker/src/mcp/capabilities/community/set-trusted.ts
  • packages/worker/src/mcp/capabilities/community/shared.ts

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.

3 participants