Skip to content

fix(auth): require lightwell-network feature for lightwell domain's P…#1306

Merged
YasenT merged 2 commits into
pulp:mainfrom
YasenT:fix/lightwell-feature-guard-latency
Jul 3, 2026
Merged

fix(auth): require lightwell-network feature for lightwell domain's P…#1306
YasenT merged 2 commits into
pulp:mainfrom
YasenT:fix/lightwell-feature-guard-latency

Conversation

@YasenT

@YasenT YasenT commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

DomainBasedPermission previously let any authenticated user with a valid identity header read the lightwell domain's PyPI views (simple API, package metadata), leaking proprietary package info to non-subscribers. SAFE_METHOD requests to those views now require either a DomainOrg association or the lightwell-network feature entitlement, checked against the Features Service using the same cache as FeatureContentGuard. public- domains, other domains' PyPI views, non-PyPI endpoints, and write operations are unaffected.

Summary by Sourcery

Tighten authorization for the lightwell domain’s PyPI views by requiring either a domain association or a lightwell-network feature entitlement, and reuse the FeatureContentGuard cache for this check.

Bug Fixes:

  • Prevent unauthorized, authenticated users without lightwell-network entitlement or domain association from reading the lightwell domain’s PyPI simple API and package metadata.

Enhancements:

  • Expose a reusable FeatureContentGuard.check_feature() API that shares cache entries with permit() to avoid redundant Features Service calls.

Documentation:

  • Document the special handling and constraints for the lightwell domain’s PyPI views and update test descriptions to reflect the new behavior.

Tests:

  • Add unit tests for DomainBasedPermission covering lightwell-domain PyPI feature checks, domain-org bypass behavior, and failure handling.
  • Add unit tests for FeatureContentGuard.check_feature() to validate cache usage, service-failure behavior, and cache-key consistency with permit().
  • Add functional tests exercising the lightwell-network feature gating against the real Features Service, including public and non-lightwell domain behavior and unaffected non-PyPI endpoints.

…yPI reads

DomainBasedPermission previously let any authenticated user with a valid
identity header read the lightwell domain's PyPI views (simple API, package
metadata), leaking proprietary package info to non-subscribers. SAFE_METHOD
requests to those views now require either a DomainOrg association or the
lightwell-network feature entitlement, checked against the Features Service
using the same cache as FeatureContentGuard. public- domains, other domains'
PyPI views, non-PyPI endpoints, and write operations are unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sourcery-ai

sourcery-ai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a lightwell-network feature gate for SAFE_METHOD access to the lightwell domain’s PyPI views, reusing FeatureContentGuard’s cache, and extends unit/functional tests to cover new authorization and caching behavior while keeping other domains and non-PyPI endpoints unchanged.

Sequence diagram for SAFE_METHOD access to lightwell PyPI views

sequenceDiagram
    actor User
    participant PyPIView
    participant DomainBasedPermission
    participant FeatureContentGuard
    participant FeatureContentGuardCache
    participant FeaturesService

    User->>PyPIView: HTTP GET /pypi/simple (lightwell)
    PyPIView->>DomainBasedPermission: has_permission(request, view)
    DomainBasedPermission->>DomainBasedPermission: _check_pypi_safe_method_access(request, view, domain)
    DomainBasedPermission->>DomainBasedPermission: _has_pypi_read_access(request, domain)
    DomainBasedPermission->>DomainBasedPermission: get_decoded_identity_header(request)
    DomainBasedPermission->>DomainBasedPermission: get_org_id(decoded_header_content)
    alt user has DomainOrg
        DomainBasedPermission-->>PyPIView: allow
    else no DomainOrg
        DomainBasedPermission->>DomainBasedPermission: _has_lightwell_network_feature(org_id)
        DomainBasedPermission->>FeatureContentGuard: check_feature(org_id)
        FeatureContentGuard->>FeatureContentGuardCache: _get_cached_result(cache, cache_key_digest)
        alt cache MISS
            FeatureContentGuard->>FeaturesService: _check_for_feature(org_id)
            FeaturesService-->>FeatureContentGuard: feature result
            FeatureContentGuard->>FeatureContentGuardCache: _set_cached_result(cache, cache_key_digest, account_allowed)
        else cache HIT
        end
        FeatureContentGuard-->>DomainBasedPermission: account_allowed
        alt account_allowed
            DomainBasedPermission-->>PyPIView: allow
        else not allowed
            DomainBasedPermission-->>PyPIView: deny
        end
    end
    PyPIView-->>User: HTTP response
Loading

File-Level Changes

Change Details Files
Introduce lightwell-specific PyPI SAFE_METHOD gating in DomainBasedPermission using FeatureContentGuard-based feature checks and identity header org_id.
  • Add LIGHTWELL_DOMAIN_NAME and LIGHTWELL_NETWORK_FEATURE constants and wire FeatureContentGuard into DomainBasedPermission.
  • Factor PyPI SAFE_METHOD handling into helper methods that check DomainOrg associations, parse org_id from x-rh-identity, and call a new _has_lightwell_network_feature method.
  • Restrict SAFE_METHOD bypass for public domains to names starting with public- and ensure non-lightwell PyPI SAFE_METHODs retain default-allow behavior while non-PyPI views bypass the new logic.
pulp_service/pulp_service/app/authorization.py
Expose reusable FeatureContentGuard.check_feature cache entrypoint and align permit() with it.
  • Implement check_feature(account_id) that computes the same cache key as permit(), uses FeatureContentGuardCache, and may raise PermissionError on Feature Service failures.
  • Refactor permit() to delegate cache and feature lookup to check_feature instead of duplicating cache-key logic.
pulp_service/pulp_service/app/models.py
Extend unit tests for DomainBasedPermission and FeatureContentGuard to cover lightwell feature gating and cache reuse semantics.
  • Augment DomainBasedPermission unit tests with identity header helpers and new scenarios for lightwell vs non-lightwell domains, presence/absence of org_id, DomainOrg association bypass, and fail-closed behavior when the Features Service fails.
  • Add FeatureContentGuard.check_feature tests validating cache hits/misses, behavior when the feature is absent, error propagation, and cache-key parity between permit() and check_feature().
pulp_service/pulp_service/tests/unit/test_domain_based_permission.py
pulp_service/pulp_service/tests/unit/test_feature_content_guard.py
Add functional tests and constants to verify real Features Service behavior for the lightwell-network feature on the lightwell domain’s PyPI simple API.
  • Introduce LIGHTWELL_* constants with real staging org IDs for entitled and non-entitled orgs.
  • Add functional tests that provision a literal lightwell domain with a PyPI distribution and verify 403/200 behavior for entitled vs non-entitled orgs, DomainOrg owner bypass, unauthenticated denial, unaffected non-PyPI endpoints, and unchanged behavior for non-lightwell and public- domains.
  • Clarify existing authentication functional test docstring to exclude the lightwell domain from global unauthenticated GET behavior.
pulp_service/pulp_service/tests/functional/constants.py
pulp_service/pulp_service/tests/functional/test_authentication.py
pulp_service/pulp_service/tests/functional/test_lightwell_feature_permission.py
Document bugfix in changelog.
  • Add bugfix changelog entry file describing the lightwell-network feature guard change.
CHANGES/lightwell-network-feature-guard.bugfix

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The helper for building an x-rh-identity header (_encode_identity_header / _identity_header) is duplicated across unit and functional tests; consider moving this into a shared test utility to avoid divergence in how identities are constructed.
  • The LIGHTWELL_DOMAIN_NAME constant is redefined in authorization.py, test_lightwell_feature_permission.py, and implied in comments elsewhere; importing it from a single source instead of using a string or local constant in tests would reduce the risk of subtle drift if the domain name ever changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The helper for building an x-rh-identity header (`_encode_identity_header` / `_identity_header`) is duplicated across unit and functional tests; consider moving this into a shared test utility to avoid divergence in how identities are constructed.
- The `LIGHTWELL_DOMAIN_NAME` constant is redefined in `authorization.py`, `test_lightwell_feature_permission.py`, and implied in comments elsewhere; importing it from a single source instead of using a string or local constant in tests would reduce the risk of subtle drift if the domain name ever changes.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

… test

Fixes ruff S113 violation flagged by CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@YasenT YasenT merged commit 56ea112 into pulp:main Jul 3, 2026
6 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