Skip to content

Conversation

@fao89
Copy link
Member

@fao89 fao89 commented Dec 10, 2025

This enhances error reporting when external Quay.io API requests fail by checking HTTP response status before attempting JSON parsing.

Changes:

  • Add status code validation in manifest.rs before JSON deserialization
  • Add status code validation in tag.rs before JSON deserialization
  • Return clear error messages with HTTP status codes
  • Prevent confusing "JSON parsing" errors when getting HTML error pages

This improves debugging by showing actual HTTP errors (e.g., "403 Forbidden") instead of cryptic "expected value at line 1 column 1" JSON parsing failures.

Network tests now fail properly with actionable error messages when external services have authentication or permission issues.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4 noreply@anthropic.com
Signed-off-by: Fabricio Aguiar fabricio.aguiar@gmail.com

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED

This enhances error reporting when external Quay.io API requests fail by
checking HTTP response status before attempting JSON parsing.

Changes:
- Add status code validation in manifest.rs before JSON deserialization
- Add status code validation in tag.rs before JSON deserialization
- Return clear error messages with HTTP status codes
- Prevent confusing "JSON parsing" errors when getting HTML error pages

This improves debugging by showing actual HTTP errors (e.g., "403 Forbidden")
instead of cryptic "expected value at line 1 column 1" JSON parsing failures.

Network tests now fail properly with actionable error messages when external
services have authentication or permission issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Signed-off-by: Fabricio Aguiar <fabricio.aguiar@gmail.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Walkthrough

Adds runtime HTTP response status checks in Quay client functions and replaces server-side label filtering with client-side filtering in the Cincinnati metadata fetcher and corresponding tests; error paths now return or yield errors on non-successful responses, and label filtering is applied locally after fetching all labels.

Changes

Cohort / File(s) Summary
HTTP response validation (Quay client)
quay/src/v1/manifest.rs, quay/src/v1/tag.rs
Add runtime checks after HTTP requests to verify response status. Non-2xx responses now produce early errors (returns via anyhow in manifest.rs; yield/exit in tag.rs), preventing JSON parsing of failed responses. Successful paths unchanged.
Client-side label filtering (Cincinnati & tests)
cincinnati/src/plugins/internal/metadata_fetch_quay.rs, quay/tests/net/mod.rs
Replace server-side label filter with fetching all labels (None) and then locally filter entries whose keys start with the label prefix. Rename variable to all_labels and adjust test assertions/comments to reflect client-side filtering.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify consistent error construction and propagation for HTTP status checks (especially across async/streaming boundaries).
  • Confirm tests reflect the new client-side filtering behavior and that filtering logic matches expected prefix semantics.
  • Check any logging or diagnostic information remains adequate for failed HTTP responses.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 10, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fao89
Once this PR has been reviewed and has the lgtm label, please assign lalatendumohanty for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
quay/src/v1/tag.rs (1)

52-59: Status check behavior looks correct; consider adding more context and/or a helper

The early return on non-success statuses correctly prevents JSON parsing of error bodies and aligns with the PR goal. The behavior of the happy path is unchanged.

For maintainability and easier debugging, you might consider:

  • Including minimal context (e.g., repository and/or endpoint) in the error message so callers can quickly identify which request failed when multiple Quay calls are in play.
  • Extracting this status-check + error-construction pattern into a small helper on Client (or a shared function) so other HTTP callers can reuse it and stay consistent.
quay/src/v1/manifest.rs (1)

80-86: Correct HTTP error handling; consider shared helper and richer error context

The explicit status check here cleanly avoids JSON parsing on failed responses and returns a meaningful error instead, which is exactly what you want.

To improve maintainability and diagnostics further, consider:

  • Reusing a shared helper (e.g., a send_checked/check_status wrapper on Client) so get_labels and stream_tags don’t each hand-roll the same status check and message.
  • Adding a bit of context (repository/manifest reference or endpoint) to the error so it’s immediately clear which label request failed when multiple calls are in flight.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 6d3e6e3 and dbd5a80.

📒 Files selected for processing (2)
  • quay/src/v1/manifest.rs (1 hunks)
  • quay/src/v1/tag.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • quay/src/v1/tag.rs
  • quay/src/v1/manifest.rs
🧬 Code graph analysis (1)
quay/src/v1/tag.rs (1)
quay/src/v1/manifest.rs (1)
  • resp (88-88)

The Quay.io labels API returns 403 Forbidden when using filter parameters,
but works fine without filters. This change removes the server-side filtering
and implements client-side filtering instead.

Changes:
- Remove filter parameter from get_labels calls in both test and plugin code
- Add client-side filtering using starts_with() to match expected prefixes
- Tests now pass instead of failing with 403 Forbidden errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Signed-off-by: Fabricio Aguiar <fabricio.aguiar@gmail.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cincinnati/src/plugins/internal/metadata_fetch_quay.rs (1)

134-139: Consider the performance impact of client-side filtering.

Fetching all labels before filtering may transfer and process more data than necessary, especially if repositories have many labels that don't match the prefix. While this is a necessary workaround for the 403 error, consider:

  • Adding logging to track the number of labels fetched vs. filtered
  • Documenting the performance trade-off in code comments

If you'd like to add observability, consider adding a trace log:

 // Filter client-side for labels matching the expected prefix
 let quay_labels = all_labels
     .into_iter()
     .map(Into::into)
     .filter(|(key, _): &(String, String)| key.starts_with(&label_filter))
     .collect::<Vec<(String, String)>>();
+
+trace!(
+    "[{}] filtered {} labels to {} matching prefix '{}'",
+    &release_version,
+    all_labels.len(),
+    quay_labels.len(),
+    &label_filter
+);

Note: You'll need to capture all_labels.len() before consuming the iterator.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between dbd5a80 and 48173ac.

📒 Files selected for processing (2)
  • cincinnati/src/plugins/internal/metadata_fetch_quay.rs (1 hunks)
  • quay/tests/net/mod.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • cincinnati/src/plugins/internal/metadata_fetch_quay.rs
  • quay/tests/net/mod.rs
🔇 Additional comments (2)
quay/tests/net/mod.rs (2)

63-72: LGTM! Test properly validates client-side filtering.

The test correctly mirrors the production implementation by:

  • Fetching all labels without server-side filtering
  • Applying client-side filtering by prefix
  • Validating the filtered results

This ensures the workaround for the 403 error is properly tested.


74-80: LGTM! Assertion correctly updated.

The assertion properly validates the filtered labels against the expected result, ensuring only labels matching the "io.openshift.upgrades.graph" prefix are present.

Comment on lines +126 to +132
let all_labels = client
.get_labels(
repo.clone(),
manifestref.clone(),
Some(label_filter.clone()),
None, // Remove filter to avoid 403 Forbidden - filter client-side instead
)
.await?
.await?;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n -C3 'get_labels|label.*filter' --type=rust -g '!target/**'

Repository: openshift/cincinnati

Length of output: 184


🌐 Web query:

Quay.io API label filtering 403 Forbidden error

💡 Result:

Likely causes and quick checks for a 403 when filtering by labels on the Quay API

  1. Permission/scope issue (most common)
  • The API call requires repo:read (or repo:write for label changes). Ensure the token/robot account has the needed repository permissions or is a team member of the org. Test with a token that you know has repo:read. [1][2]
  1. Using the wrong account type
  • Robot accounts must be used for some automated operations (and must have read access to the repo). If using a user token, confirm the user is member of the org and has repo access. [1]
  1. Wrong endpoint/parameters or path
  • The manifest/labels endpoints include repository path and manifest digest in the path; incorrectly-formed paths or query parameters can return 403/401. Verify you’re calling the documented endpoint (e.g. GET /api/v1/repository/{repository}/manifest/{manifestref}/labels with optional filter). [2]
  1. Authentication header or token not sent
  • Confirm Authorization: Bearer is present and not being removed by proxies or client libs. Also check you’re not accidentally using a cookie/session token where an OAuth token is required. [1]
  1. Registry configuration / proxy or signature mismatch
  • If you see 403 with XML or “SignatureDoesNotMatch” in body, it can be a backend S3/signing issue or proxy that changes requests. Check registry logs and any reverse proxy in path. (Quay docs and support notes mention S3/signature and proxy issues producing 403s.) [1][3]

How to debug (quick steps)

  • Reproduce with curl (explicit header) and full verbose output:
    curl -v -H "Authorization: Bearer " "https://quay.io/api/v1/repository/namespace/name/manifest//labels?filter=keyprefix"
  • Try a token you know has repo:read to confirm permission vs token problem.
  • Check Quay server logs for the request and reason (auth/acl check or upstream storage error).
  • If using a robot, confirm it’s enabled and has read on that repo (and that you didn’t use a user token that lacks org membership). [1][2]

If you want, paste (redacted) the curl command and full response (headers + body) or the exact endpoint and token type you’re using and I’ll point to the specific cause and fix.

Sources

  • Quay docs — “I’m authorized but I’m still getting 403s” / common auth failures. [1]
  • Red Hat / Quay API guide — manifest/labels endpoints and required authorizations. [2]
  • Quay/Red Hat issues & support notes re: 403 from storage/signature problems. [3]

References
[1] Quay docs — auth failure guidance.
[2] Red Hat Quay API Guide — manifest/labels endpoints and permissions.
[3] Red Hat/Quay support notes on 403s (S3/signature/proxy).


Investigate and fix the root cause of the 403 Forbidden error instead of working around it.

The change from server-side to client-side filtering suggests an underlying authentication or permissions issue with the Quay API token/robot account. Based on Quay API documentation, 403 errors on filtered label queries typically indicate:

  • The token lacks repo:read permissions on the repository
  • The robot account or user is not properly configured
  • Incorrect API endpoint path or authentication headers

Client-side filtering is a workaround that masks the actual problem. Verify the credentials have appropriate permissions and that the API call is correctly formed before removing the server-side filter. This also has performance implications if filtering many labels.

🤖 Prompt for AI Agents
In cincinnati/src/plugins/internal/metadata_fetch_quay.rs around lines 126 to
132, stop masking a 403 by removing the server-side filter; investigate and fix
the root cause so the Quay API can accept filtered queries. Check the
credentials used by the client: verify the token/robot account has repo:read
(and other required) permissions on the target repo, confirm the robot account
is correctly provisioned, and ensure the request uses the correct Quay API
endpoint and authentication headers. Add explicit handling/logging for 403
responses to surface permission errors (include API path, token identifier, and
response body) and restore the server-side filter once permissions/endpoint/auth
are corrected to avoid client-side filtering and the associated performance
cost.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 10, 2025

@fao89: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@fao89 fao89 requested a review from PratikMahajan December 10, 2025 17:11
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