Skip to content

feat: gate PyPI access via distribution content guards instead of hardcoded feature check#1316

Open
CryptoRodeo wants to merge 5 commits into
pulp:mainfrom
CryptoRodeo:pulp-1993
Open

feat: gate PyPI access via distribution content guards instead of hardcoded feature check#1316
CryptoRodeo wants to merge 5 commits into
pulp:mainfrom
CryptoRodeo:pulp-1993

Conversation

@CryptoRodeo

@CryptoRodeo CryptoRodeo commented Jul 6, 2026

Copy link
Copy Markdown

DomainBasedPermission no longer hardcodes the "lightwell" domain name or the "lightwell-network" feature.

Instead, _check_pypi_safe_method_access reads the distribution's content_guard:

  • if one is configured, it delegates to guard.cast().permit(request).
  • if none, SAFE_METHOD access is open (preserving the existing default).

DomainOrg owners still bypass the guard.

This makes PyPI access control domain-name-agnostic, any distribution can be protected by attaching a content guard, with no code changes needed.

JIRA: PULP-1993

Summary by Sourcery

Gate PyPI SAFE_METHOD access for content-guarded distributions via their content guard, while preserving default-allow behavior for unguarded distributions and DomainOrg-based bypass.

Enhancements:

  • Replace hardcoded lightwell-network feature entitlement checks with distribution content-guard-driven permission checks for PyPI views.
  • Simplify DomainBasedPermission by removing lightwell-specific feature constants and helper methods in favor of a generic content guard flow.
  • Extend and update unit tests to cover content-guard-based PyPI access decisions, including DomainOrg bypass and domain-name agnostic behavior.

Tests:

  • Refactor PyPI permission tests to construct views with mock content guards and verify guard permit() usage, denial paths, and DomainOrg bypass scenarios.

Summary by Sourcery

Gate PyPI SAFE_METHOD access using distribution content guards instead of a hardcoded feature flag, while preserving default-allow behavior for unguarded distributions and DomainOrg-based bypass.

Enhancements:

  • Refactor DomainBasedPermission to consult a distribution’s content guard for PyPI SAFE_METHOD access, replacing lightwell-specific feature checks and constants with a domain-agnostic flow.
  • Improve robustness of PyPI permission handling by explicitly handling distribution resolution errors, content-guard casting failures, and unexpected permit() exceptions with fail-closed behavior and structured logging.
  • Clarify and slightly reorder URL routing imports without changing behavior.

Tests:

  • Expand unit tests for DomainBasedPermission to cover content-guard-driven PyPI access decisions, DomainOrg bypass, domain-name agnostic behavior, and error-handling/logging paths.
  • Update functional tests to exercise content-guard-based PyPI access control, including feature-entitled and non-entitled orgs, domain-owner bypass, unauthenticated access, write-operation behavior, and unaffected non-PyPI endpoints.
  • Adjust lightwell read-only group functional tests to use a content-guarded PyPI distribution within the lightwell domain.

@sourcery-ai

sourcery-ai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors DomainBasedPermission’s PyPI SAFE_METHOD access logic to use each distribution’s content_guard (with DomainOrg bypass and strict error/logging behavior) instead of a hardcoded lightwell-network feature check, and updates unit/functional tests and fixtures to match the new content-guard-driven, domain-agnostic model.

Sequence diagram for content-guard-based PyPI SAFE_METHOD access

sequenceDiagram
    actor Client
    participant PyPIView as PyPIView
    participant DomainBasedPermission as DomainBasedPermission
    participant Distribution as Distribution
    participant Guard as ContentGuard

    Client->>PyPIView: SAFE_METHOD request
    PyPIView->>DomainBasedPermission: has_permission(request, view)
    DomainBasedPermission->>DomainBasedPermission: _check_pypi_safe_method_access(request, view, domain)

    alt view is not PyPIMixin
        DomainBasedPermission-->>DomainBasedPermission: return None
    else view is PyPIMixin
        DomainBasedPermission->>PyPIView: access distribution
        alt Http404
            DomainBasedPermission-->>DomainBasedPermission: return True
        else other exception
            DomainBasedPermission->>DomainBasedPermission: log exception
            DomainBasedPermission-->>DomainBasedPermission: return False
        else distribution resolved
            PyPIView-->>DomainBasedPermission: distribution
            DomainBasedPermission->>Distribution: read content_guard
            alt no content_guard
                DomainBasedPermission-->>DomainBasedPermission: return True
            else has content_guard
                DomainBasedPermission->>DomainBasedPermission: get_decoded_identity_header(request)
                DomainBasedPermission->>DomainBasedPermission: get_org_id(decoded_header)
                DomainBasedPermission->>DomainBasedPermission: _has_domain_access(domain_pk, org_id, user)
                alt DomainOrg match
                    DomainBasedPermission->>DomainBasedPermission: log GRANTED via DomainOrg
                    DomainBasedPermission-->>DomainBasedPermission: return True
                else no DomainOrg match
                    DomainBasedPermission->>Guard: cast()
                    alt cast error
                        DomainBasedPermission->>DomainBasedPermission: log exception
                        DomainBasedPermission-->>DomainBasedPermission: return False
                    else cast ok
                        Guard-->>DomainBasedPermission: casted_guard
                        DomainBasedPermission->>Guard: permit(request)
                        alt PermissionError
                            DomainBasedPermission->>DomainBasedPermission: log DENIED via content guard
                            DomainBasedPermission-->>DomainBasedPermission: return False
                        else other exception
                            DomainBasedPermission->>DomainBasedPermission: log exception
                            DomainBasedPermission-->>DomainBasedPermission: return False
                        else permit ok
                            DomainBasedPermission->>DomainBasedPermission: log GRANTED via content guard
                            DomainBasedPermission-->>DomainBasedPermission: return True
                        end
                    end
                end
            end
        end
    end
Loading

File-Level Changes

Change Details Files
Replace hardcoded lightwell-network feature gating for PyPI SAFE_METHOD access with a content_guard-based permission check, including DomainOrg bypass and robust error handling/logging.
  • Remove LIGHTWELL_NETWORK_FEATURE constant, FeatureContentGuard usage, and _has_pypi_read_access/_has_lightwell_network_feature helpers from DomainBasedPermission.
  • Implement _check_pypi_safe_method_access to inspect view.distribution.content_guard, short-circuit with default-allow when no guard is configured, and otherwise gate access via guard.cast().permit(request).
  • Add DomainOrg-based bypass ahead of content guard evaluation, preserving owner semantics while making guard decisions domain-name-agnostic.
  • Handle distribution resolution errors by allowing Http404 to pass through, failing closed on other exceptions, and logging unexpected failures at ERROR level.
  • Fail closed and log when guard.cast() or casted_guard.permit() raise unexpected exceptions, treating PermissionError as an explicit deny from the guard and logging allow/deny decisions at INFO level.
pulp_service/pulp_service/app/authorization.py
Update unit tests for DomainBasedPermission to validate content_guard-based PyPI access behavior, DomainOrg bypass, logging, and new error paths.
  • Extend PyPI test helpers to construct mock views wired with a distribution.content_guard and to simulate distribution property exceptions and guard behaviors.
  • Remove tests and mocks around lightwell-network feature checks, replacing them with tests that exercise guard-permit grants/denials, anonymous vs authenticated flows, and domain-name agnostic behavior.
  • Add logging-focused tests that assert GRANTED/DENIED messages for DomainOrg bypass and content-guard outcomes, with org_id and user included.
  • Introduce tests that cover Http404 vs unexpected distribution resolution errors, guard.cast() failures, and unexpected exceptions from permit(), asserting both fail-closed behavior and error logging.
  • Ensure readonly-group behavior for PyPI views still requires passing the content guard when no DomainOrg association exists.
pulp_service/pulp_service/tests/unit/test_domain_based_permission.py
Refactor functional tests from lightwell-specific feature gating to generic content_guard-driven PyPI permission tests, including guarded vs unguarded access patterns and fixture wiring for ServiceFeatureContentGuards.
  • Rename lightwell feature permission tests to content_guard permission tests and adjust descriptions to emphasize content-guard-driven, domain-agnostic behavior.
  • Extend PyPI distribution configuration helper to optionally create ServiceFeatureContentGuard objects, associate them with distributions, and register cleanup for guards.
  • Introduce a configure_guarded_pypi_distribution fixture that creates a domain with a FeatureContentGuard requiring LIGHTWELL_NETWORK_FEATURE on its PyPI distribution, and update tests to use this for guarded scenarios.
  • Adjust tests to assert 403/200 outcomes based on org entitlement, DomainOrg ownership, presence/absence of identity headers, and HTTP method (SAFE_METHOD vs write).
  • Add tests confirming that non-PyPI endpoints remain governed purely by DomainOrg permissions and that unguarded distributions preserve open anonymous SAFE_METHOD access and public-domain behavior.
pulp_service/pulp_service/tests/functional/test_content_guard_permission.py
Ensure the lightwell read-only group fixture creates a guarded PyPI distribution and keep group semantics limited to non-PyPI endpoints while PyPI access is governed by the distribution’s content guard.
  • Extend configure_lightwell_domain fixture to create a ServiceFeatureContentGuard requiring lightwell-network, attach it to the lightwell PyPI distribution, and register guard cleanup.
  • Keep existing behavior where LIGHTWELL_READONLY_GROUP_NAME grants read-only access only to non-PyPI endpoints, relying on the new content-guard-based path for PyPI views, and update test documentation/comments to point at the new content-guard test module.
pulp_service/pulp_service/tests/functional/test_lightwell_readonly_group_permission.py
Minor test and URL module cleanups to align with the new permission model and coding standards.
  • Update authentication functional test documentation to reference the new content-guard permission tests instead of the removed lightwell-specific feature tests.
  • Simplify test_only_owners_can_delete_domain signature by removing an unused monitor_task argument flagged by linting.
  • Reorder imports in the app URL configuration to satisfy style rules without behavior change.
pulp_service/pulp_service/tests/functional/test_authentication.py
pulp_service/pulp_service/tests/functional/test_domain_based_permissions.py
pulp_service/pulp_service/app/urls.py

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

@dkliban

dkliban commented Jul 8, 2026

Copy link
Copy Markdown
Member

Architectural Review Findings

M1. Bare except Exception on view.distribution is too broad

The try/except Exception: return None block around view.distribution swallows Http404 (distribution not found) and signals "not a PyPI view, fall through to standard DomainOrg checks." This conflates "distribution doesn't exist" with "not a PyPI view." Database timeouts or connection errors would also silently fall through rather than failing closed.

Suggestion: Catch Http404 specifically and let the view handle the 404 naturally. For unexpected exceptions, fail closed:

from django.http import Http404

try:
    distribution = view.distribution
except Http404:
    return True  # let the view raise 404 normally
except Exception:
    _logger.exception("Unexpected error resolving distribution for PyPI permission check")
    return False  # fail closed

M2. guard.cast() failure path is unhandled

guard.cast() performs a DB lookup (self._pulp_model_map[self.pulp_type].objects.get(pk=self.pk)). If the content guard subclass row has been deleted (orphaned FK, race condition with concurrent deletion), this raises ObjectDoesNotExist or KeyError — neither is caught by except PermissionError, so it would bubble up as an unhandled 500 instead of failing closed.

Suggestion: Separate the cast() call from permit() and handle each failure mode:

try:
    casted_guard = guard.cast()
except Exception:
    _logger.exception("Failed to resolve content guard type for distribution")
    return False  # fail closed

try:
    casted_guard.permit(request)
    # ... log and return True
except PermissionError:
    # ... log and return False

M3. Stale comments on LIGHTWELL_DOMAIN_NAME constant

The comment above LIGHTWELL_DOMAIN_NAME = "lightwell" still says PyPI views are gated by domain name and the lightwell-network feature. After this PR, that constant is only used for the readonly group logic. The comment should be updated to reflect this.

…dcoded feature check

DomainBasedPermission no longer hardcodes the "lightwell" domain name or
the "lightwell-network" feature.

Instead, _check_pypi_safe_method_access reads the distribution's content_guard:
if one is configured, it delegates to guard.cast().permit(request).
if none, SAFE_METHOD access is open (preserving the existing default).

DomainOrg owners still bypass the guard.

This makes PyPI access control domain-name-agnostic, any distribution can be protected by attaching a content guard, with no code changes needed.

Signed-off-by: Bryan Ramos <bramos@redhat.com>
@CryptoRodeo CryptoRodeo changed the title feat: replace hardcoded feature check with content-guard-driven permissions feat: gate PyPI access via distribution content guards instead of hardcoded feature check Jul 8, 2026
@CryptoRodeo CryptoRodeo marked this pull request as ready for review July 8, 2026 19:33

@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 found 2 issues, and left some high level feedback:

  • In the logging-focused tests you switched from any(...) to all(...) when asserting on caplog.records (e.g. assert all("GRANTED via DomainOrg" in record.message ... for record in caplog.records)), which makes them brittle if any unrelated log lines are present; consider reverting to any(...) or scoping caplog with a stricter logger/level filter to avoid false negatives.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the logging-focused tests you switched from `any(...)` to `all(...)` when asserting on `caplog.records` (e.g. `assert all("GRANTED via DomainOrg" in record.message ... for record in caplog.records)`), which makes them brittle if any unrelated log lines are present; consider reverting to `any(...)` or scoping `caplog` with a stricter logger/level filter to avoid false negatives.

## Individual Comments

### Comment 1
<location path="pulp_service/pulp_service/app/authorization.py" line_range="100-82" />
<code_context>
-        same cache/lookup mechanism as FeatureContentGuard.
-        """
-        guard = FeatureContentGuard(features=[LIGHTWELL_NETWORK_FEATURE], pulp_domain=None)
-        try:
-            return guard.check_feature(org_id)
-        except PermissionError:
-            return False
-
     def _has_lightwell_readonly_group_access(self, user):
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Wrap `casted_guard.permit(request)` in a broader exception handler to avoid unexpected 500s.

Right now only `PermissionError` from `casted_guard.permit(request)` is handled; any other exception will bubble up as a 500 instead of failing closed like the other guard/distribution paths. Consider wrapping `permit` in a broad `try/except Exception` that logs and returns `False`, with a specific `except PermissionError` for expected denials, so unexpected guard errors don’t turn into user-visible 500s.

Suggested implementation:

```python
        casted_guard = typing.cast(PulpDomainGuard, guard)
        try:
            return casted_guard.permit(request)
        except PermissionError:
            # Expected denial from the guard; fail closed
            return False
        except Exception:
            # Unexpected guard error; log and fail closed rather than raising a 500
            logger.exception("Unexpected error while evaluating guard permit", extra={"view": getattr(view, "__class__", type(view)).__name__})
            return False

```

If a `logger` is not already defined in this module, you should add at the top of `authorization.py`:

- `import logging`
- `logger = logging.getLogger(__name__)`

Also, if the actual guard type or variable names differ (e.g. `casted_guard` or `PulpDomainGuard` are named differently in your code), adjust the SEARCH/REPLACE block accordingly so it matches the existing `try/except PermissionError` around `permit(request)`.
</issue_to_address>

### Comment 2
<location path="pulp_service/pulp_service/tests/unit/test_domain_based_permission.py" line_range="285" />
<code_context>
-            assert permission.has_permission(request, view) is False
-
-        assert any("DENIED: no org_id" in record.message for record in caplog.records)
+        assert all("GRANTED via DomainOrg" in record.message and "12345" in record.message for record in caplog.records)

-    @patch("pulp_service.app.authorization.DomainBasedPermission._has_lightwell_network_feature")
</code_context>
<issue_to_address>
**suggestion (testing):** Using `all(...)` for log assertions makes the test brittle; consider `any(...)` instead.

This asserts that every log record contains both strings, which is fragile if other messages are logged on the same logger. Using `any(...)` keeps the test focused on verifying that at least one matching log entry is produced, e.g.:

```python
assert any(
    "GRANTED via DomainOrg" in record.message and "12345" in record.message
    for record in caplog.records
)
```

Please apply the same pattern to the other content-guard logging tests as well.

Suggested implementation:

```python
        assert any(
            "GRANTED via DomainOrg" in record.message and "12345" in record.message
            for record in caplog.records
        )

```

To fully apply your comment, similar changes should be made to any other tests in `test_domain_based_permission.py` that:
- Use `all(...)` on `caplog.records` to assert log contents for content-guard checks.
Those occurrences should be updated to use the same `any(...)` pattern, e.g.:

```python
assert any(
    "EXPECTED MESSAGE FRAGMENT" in record.message and "OTHER_FRAGMENT" in record.message
    for record in caplog.records
)
```

This will keep all logging-related tests focused on the existence of at least one matching log entry instead of requiring every log entry to match.
</issue_to_address>

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.

Comment thread pulp_service/pulp_service/app/authorization.py
Comment thread pulp_service/pulp_service/tests/unit/test_domain_based_permission.py Outdated
CryptoRodeo and others added 2 commits July 8, 2026 16:01
Catch unexpected exceptions from casted_guard.permit() (not just
PermissionError) to prevent 500s — log and fail closed instead.

Addresses Sourcery review comment on PR pulp#1316.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ertions

Changed 5 assertions in test_domain_based_permission.py to use any() instead
of all() for checking log records. Using all() is brittle: if any unrelated
log line is present, the assertion fails even though the expected log was
emitted. Using any() correctly asserts that at least one matching record
exists, regardless of other log lines.

Fixes review feedback from PR pulp#1316.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CryptoRodeo

Copy link
Copy Markdown
Author

@sourcery-ai review

@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 found 1 issue, and left some high level feedback:

  • In _check_pypi_safe_method_access, the log messages use the string PyPi while the rest of the code and tests refer to PyPI; consider standardizing the capitalization to avoid confusion when searching logs.
  • Some new tests (e.g. test_anonymous_no_header_with_guard_denied) describe header-driven behavior that isn’t actually encoded in the _make_content_guard helper (which unconditionally raises PermissionError when permits=False); updating the docstrings or making the helper reflect the described condition would make the tests clearer to future readers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_check_pypi_safe_method_access`, the log messages use the string `PyPi` while the rest of the code and tests refer to `PyPI`; consider standardizing the capitalization to avoid confusion when searching logs.
- Some new tests (e.g. `test_anonymous_no_header_with_guard_denied`) describe header-driven behavior that isn’t actually encoded in the `_make_content_guard` helper (which unconditionally raises `PermissionError` when `permits=False`); updating the docstrings or making the helper reflect the described condition would make the tests clearer to future readers.

## Individual Comments

### Comment 1
<location path="pulp_service/pulp_service/app/authorization.py" line_range="102-111" />
<code_context>
+
+        if user.is_authenticated and self._has_domain_access(domain_pk, org_id, user):
+            _logger.info(
+                "Content-guarded PyPi access GRANTED via DomainOrg: user=%s org_id=%s",
+                user,
+                org_id,
+            )
+            return True
+
+        try:
+            casted_guard = guard.cast()
+        except Exception:
+            _logger.exception("Failed to resolve content guard type for distribution")
+            return False
+
+        try:
+            casted_guard.permit(request)
+            _logger.info(
+                "Content-guarded PyPi access GRANTED via content guard: org_id=%s user=%s",
+                org_id,
+                user,
+            )
+            return True
+        except PermissionError:
+            _logger.info(
+                "Content-guarded PyPi access DENIED via content guard: org_id=%s user=%s",
+                org_id,
+                user,
</code_context>
<issue_to_address>
**nitpick (typo):** Minor typo/inconsistency in log message: use "PyPI" instead of "PyPi".

These log lines currently use "PyPi". Please change them to "PyPI" to match the canonical spelling and keep log search/aggregation consistent with the rest of the ecosystem.

Suggested implementation:

```python
            _logger.info(
                "Content-guarded PyPI access GRANTED via DomainOrg: user=%s org_id=%s",
                user,
                org_id,
            )

```

```python
            _logger.info(
                "Content-guarded PyPI access GRANTED via content guard: org_id=%s user=%s",
                org_id,
                user,
            )

```

```python
            _logger.info(
                "Content-guarded PyPI access DENIED via content guard: org_id=%s user=%s",
                org_id,
                user,
            )

```
</issue_to_address>

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.

Comment on lines +102 to +111
"Content-guarded PyPi access GRANTED via DomainOrg: user=%s org_id=%s",
user,
org_id,
)
return True

try:
casted_guard = guard.cast()
except Exception:
_logger.exception("Failed to resolve content guard type for distribution")

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.

nitpick (typo): Minor typo/inconsistency in log message: use "PyPI" instead of "PyPi".

These log lines currently use "PyPi". Please change them to "PyPI" to match the canonical spelling and keep log search/aggregation consistent with the rest of the ecosystem.

Suggested implementation:

            _logger.info(
                "Content-guarded PyPI access GRANTED via DomainOrg: user=%s org_id=%s",
                user,
                org_id,
            )
            _logger.info(
                "Content-guarded PyPI access GRANTED via content guard: org_id=%s user=%s",
                org_id,
                user,
            )
            _logger.info(
                "Content-guarded PyPI access DENIED via content guard: org_id=%s user=%s",
                org_id,
                user,
            )

PyPi -> PyPI

Signed-off-by: Bryan Ramos <bramos@redhat.com>
better reflects described condition.

Signed-off-by: Bryan Ramos <bramos@redhat.com>
@CryptoRodeo

Copy link
Copy Markdown
Author

@sourcery-ai review

@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 _check_pypi_safe_method_access method has grown quite complex with multiple early returns and nested error handling; consider extracting the DomainOrg bypass and content-guard resolution/permit logic into dedicated helpers to make the permission flow easier to follow and maintain.
  • In _check_pypi_safe_method_access, Http404 from view.distribution is treated as an unconditional allow for SAFE_METHODs; you may want to reconsider or clearly centralize this behavior (e.g., via a helper or explicit configuration) so that unexpected distribution lookup patterns don’t silently bypass content guards.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `_check_pypi_safe_method_access` method has grown quite complex with multiple early returns and nested error handling; consider extracting the DomainOrg bypass and content-guard resolution/permit logic into dedicated helpers to make the permission flow easier to follow and maintain.
- In `_check_pypi_safe_method_access`, `Http404` from `view.distribution` is treated as an unconditional allow for SAFE_METHODs; you may want to reconsider or clearly centralize this behavior (e.g., via a helper or explicit configuration) so that unexpected distribution lookup patterns don’t silently bypass content guards.

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.

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.

2 participants