refactor: clarify namespace vs. per-publisher verification checks - #2103
Merged
Conversation
RepositoryService conflated two different questions under similarly-named
methods: whether a namespace itself is verified (has an owner) vs. whether a
specific user counts as a verified publisher for it (member of a namespace
that has an owner, or privileged). That ambiguity had already caused a real
bug and was an unnecessary dependency in a security scanner.
- Add RepositoryService.isVerified(Namespace): the namespace-only check,
delegating to the existing hasMemberships(namespace, ROLE_OWNER). Migrate
every call site that only ever cared about the namespace itself (the
namespace JSON's own verified badge in LocalRegistryService and UserAPI,
and SimilarityCheckService's verified-publisher skip) from hasMemberships
to this more descriptive method.
- Fix RelevanceService: it had its own private isVerified(ExtensionVersion)
that duplicated RepositoryService.isVerifiedPublisher(ExtensionVersion)
almost line for line, but called repositories.isVerified(...) directly
instead of isVerifiedPublisher(...) - silently dropping the privileged-user
bypass every other verified-badge call site gets. A privileged user's
extension version showed as verified everywhere except in search relevance
scoring. Removed the duplicate; search now calls the real method.
- Simplify NamespaceOwnershipCheckScanner: it checked isVerifiedPublisher
(namespace, user) using the specific publisher of the scanned version, but
self-service namespace creation only ever grants the creator CONTRIBUTOR
(never OWNER) - so a namespace can have contributors who can legitimately
publish while having no owner at all, which is exactly the squatting
scenario this scanner exists to catch. The scanner's own class doc already
described the check as namespace-level ("has an owner, not only
contributors"), so switch to isVerified(namespace) directly. This also
drops the ExtensionVersion#getPublishedWith() dependency, fixing a latent
false-positive: a null publisher (e.g. mirrored/migrated data) used to
force a threat regardless of whether the namespace was actually verified.
- Remove the now-redundant RepositoryService.isVerified(Namespace, UserData)
public overload: after the above, its only remaining caller was
isVerifiedPublisher(Namespace, UserData) itself. Keeping it exposed a
privilege-unaware shortcut that invited exactly the kind of bug just fixed
in RelevanceService. Inlined the single jOOQ delegation call directly into
isVerifiedPublisher instead.
Tests updated throughout to match (RegistryAPITest, UserAPITest, AdminAPITest,
SimilarityCheckServiceTest, DatabaseSearchServiceTest, ElasticSearchServiceTest,
NamespaceOwnershipCheckScannerTest, RepositoryServiceSmokeTest's reflective
method-coverage check).
Contributor
Author
|
These inconsistencies came up while reviewing #2065 This PR is supposed to clean them up as a preparation for merging the other. |
cstamas
approved these changes
Aug 27, 2026
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.
RepositoryServiceconflated two different questions under similarly-named methods: whether a namespace itself is verified (has an owner) vs. whether a specific user counts as a verified publisher for it (member of a namespace that has an owner, or privileged). That ambiguity had already caused a real bug and was an unnecessary dependency in a security scanner.Changes
Add
RepositoryService.isVerified(Namespace): the namespace-only check, delegating to the existinghasMemberships(namespace, ROLE_OWNER). Migrated every call site that only ever cared about the namespace itself — the namespace JSON's ownverifiedbadge inLocalRegistryServiceandUserAPI, andSimilarityCheckService's verified-publisher skip — fromhasMembershipsto this more descriptive method.Fix
RelevanceService: it had its own privateisVerified(ExtensionVersion)that duplicatedRepositoryService.isVerifiedPublisher(ExtensionVersion)almost line for line, but calledrepositories.isVerified(...)directly instead ofisVerifiedPublisher(...)— silently dropping the privileged-user bypass every other verified-badge call site gets. A privileged user's extension version showed as verified everywhere except in search relevance scoring. Removed the duplicate; search now calls the real method.Simplify
NamespaceOwnershipCheckScanner: it checkedisVerifiedPublisher(namespace, user)using the specific publisher of the scanned version, but self-service namespace creation only ever grants the creatorCONTRIBUTOR(neverOWNER) — so a namespace can have contributors who can legitimately publish while having no owner at all, which is exactly the squatting scenario this scanner exists to catch. The scanner's own class doc already described the check as namespace-level ("has an owner, not only contributors"), so it now callsisVerified(namespace)directly. This also drops theExtensionVersion#getPublishedWith()dependency, fixing a latent false-positive: a null publisher (e.g. mirrored/migrated data) used to force a threat regardless of whether the namespace was actually verified.Remove the now-redundant
RepositoryService.isVerified(Namespace, UserData)public overload: after the above, its only remaining caller wasisVerifiedPublisher(Namespace, UserData)itself. Keeping it exposed a privilege-unaware shortcut that invited exactly the kind of bug just fixed inRelevanceService. Inlined the single jOOQ delegation call directly intoisVerifiedPublisherinstead.Tests updated throughout to match:
RegistryAPITest,UserAPITest,AdminAPITest,SimilarityCheckServiceTest,DatabaseSearchServiceTest,ElasticSearchServiceTest,NamespaceOwnershipCheckScannerTest, andRepositoryServiceSmokeTest's reflective method-coverage check.🤖 Generated with Claude Code