fix(registry): gate brand.json serving on source_type to prevent enriched data misrepresentation#3529
Merged
Conversation
…ched data misrepresentation Closes #3528 https://claude.ai/code/session_01PR6QXBoh1GW1qqrnz6jEkY
This was referenced May 18, 2026
Merged
bokelley
added a commit
that referenced
this pull request
May 18, 2026
… to verified owners (#4743) * fix(brand-viewer): restore community brand serving + lock logo writes to verified owners Issue A — /brands/{domain}/brand.json silently started 404ing for hand-curated rows after #3529. Two root causes: - editDiscoveredBrand never promoted source_type when a human edited, so Brandfetch-seeded rows that AAO members curated (scope3.com, fandom.com) stayed source_type='enriched' and tripped the new gate. - The structural-shape check in #3529 demanded house/brands/agents/ brand_agent/authoritative_location at the manifest root; the AAO edit UI writes flat manifests that don't fit any of those shapes. Fix: drop the structural-shape check (the source_type gate alone keeps raw Brandfetch data out); promote enriched→community in editDiscoveredBrand; one-shot migration backfills any enriched row that already has revisions (= a human curated it). Issue B — logo uploads auto-approved instantly for any AAO member, including on brands they don't own (#3393). Brian's call: if a brand has a verified owner, only that org can write. Implemented: - Verified owner exists + caller is org member → 201 approved - Verified owner exists + caller is not in org → 403 verified_owner_required - No verified owner → community uploads queue as pending review Walks back the community half of #3393's auto-approval. Moderation queue throughput is an ops problem. 24 unit tests across 3 new files cover the brand.json gate, source_type promotion (enriched promotes, community doesn't churn, brand_json still rejected), and the full upload auth matrix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(test): drop unused PNG_HEADER constant flagged by code-quality bot Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(brand-viewer): address expert-review feedback Defense-in-depth from security + code review of #4743: - Lock Addie's upload_brand_logo MCP tool to the same write-authority gate as the HTTP route. Previously the tool hardcoded review_status='approved' and bypassed the verified-owner check, making it a parallel door past the route-level fix. Now refuses on verified-owned brands and queues as 'pending' otherwise. - Restrict enriched→community promotion in editDiscoveredBrand to actual brand-content changes from non-system editors. Previously, any edit call promoted enriched rows — including the audit-only revision the logo-upload route writes (no manifest input) and the manifest-rebuild call the logo-service makes after approval (system caller, just refreshes the logos array). Either path was a stealth route to publish raw Brandfetch data under the community label. - Mirror the rule in migration 483: only backfill enriched rows whose brand_revisions contain at least one non-system-attributed entry. Logo-upload manifest-rebuild revisions (system:logo-service) no longer trigger retroactive promotion. - Improve 403 copy on verified_owner_required: include a claim_url pointing at /brand/builder?domain=... so rejected users know how to prove ownership instead of giving up. - Add a "queued for moderator review" message to community-upload 201 responses so the uploader knows their change isn't live yet. - Replace empty catch around the audit revision write with a logger.debug call. 41 unit tests across 4 files pass (incl. new addie-upload-brand-logo-auth suite). Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3528
The
/brands/:domain/brand.jsonendpoint was serving Brandfetch-enriched entries as if they were brand-attested brand.json files. The response spread raw Brandfetch data (name,url,company,description,classification) at the root level of the response, injected a non-specnamefield, and omitted$schema— producing 40+ validation errors against the brand.json schema, which hasadditionalProperties: falseon all four variants.Changes:
source_type: onlybrand_jsonandcommunitysource types are served;enriched(Brandfetch) and any other non-attested type returns 404. Serving third-party commercial data under a brand-attested URL path is both a protocol correctness failure and a trust/consent violation.review_status !== 'pending'and a two-field structural shape check (presence ofhouse+brands,housestring,agents,brand_agent, orauthoritative_location) before being served.$schema: https://adcontextprotocol.org/schemas/v3/brand.jsonwhen the stored manifest lacks a well-formed HTTPS$schemavalue. Uses the/schemas/v3/alias (released stable schema) per playbook schema URL conventions.nameinjection —nameis not a top-level field in any brand.json variant; its presence causedadditionalProperties: falsefailures on every served document.Non-breaking justification: Consumers currently receiving invalid enriched data will now receive 404. A 404 is strictly less harmful than invalid JSON that silently fails schema validation. The A2UI theming feature (
brand-viewer.html) already has a graceful 404 fallback path and is unaffected. No schema changes.Pre-PR review:
review_statusgate,$schemaURL alias) and one nit ($schemapass-through validation), all addressed in the final diffadditionalProperties: falseon all four oneOf variants makes the rootnameinjection a spec violation; confirmed 404 for enriched is protocol-correct; confirmed/schemas/v3/is the correct alias for this released schemaSession: https://claude.ai/code/session_01PR6QXBoh1GW1qqrnz6jEkY
Generated by Claude Code