Skip to content

feat: pass the status code and the reason to the framed error page - #137

Merged
joamag merged 2 commits into
feat/proxy-unauthorized-pagefrom
feat/proxy-error-context
Nov 6, 2026
Merged

joamag merged 2 commits into
feat/proxy-unauthorized-pagefrom
feat/proxy-error-context

Conversation

@joamag

@joamag joamag commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Closes #136.

Stacked on #135, which this needs so that all four responses already build their body through build_data. Review that one first; the base will become master once it lands.

What this does

build_data and build_iframe gain an optional params argument, encoded onto the framed URL by a new _build_url helper, and each of the four responses passes its own code and reason:

<iframe src="//cdn.hive.pt/not-found?code=404&reason=No+proxy+endpoint+found"></iframe>

A page can now show the status code and the reason instead of being a fixed sheet of text, and a single configured page becomes viable again for anyone who prefers one over three, since it can branch on the code it is handed.

Details worth noting:

  • Any query string the configured URL already carries is preserved, so //cdn.hive.pt/down?v=2 becomes ?v=2&code=500&reason=...
  • The keys are sorted, so the same context always builds the very same URL and can be cached by it
  • The values are encoded, so a reason carrying spaces, quotes or angle brackets cannot break out of the attribute it sits in
  • With no params, or no url, nothing changes at all

The up-stream error does not hand over its message

The not found, the forbidden and the not authorized responses carry a fixed message, so forwarding it is harmless. The up-stream error does not: its message is the text of the back-end exception and can name internal addresses and ports.

While writing the tests I checked what actually reaches the visitor and found the message was still being put in front of them through the <title> of the wrapper page, even with a page framed. That predates this work, it is not a regression from #132, but it sits squarely in what this issue is about, so it is fixed here: when a page is framed the response hands over the status phrase for both the reason and the title. With no page framed the message is still shown, since nothing else would report the cause.

Two tests pin this, one asserting the internal address appears nowhere in the framed response, the other asserting it is still shown when nothing is framed.

Tests

  • test/servers/http.py - the parameters on the framed branch and their absence on the plain one, _build_url with no parameters, with an empty map, sorted, against a URL that already has a query string, against one ending in the separator, and the encoding of reserved characters
  • test/extra/proxy_r.py - the eight existing assertions now pin the full URL including the context, plus the two leak tests above

The eight updated assertions are the deliberate behaviour change of this PR, not a loosening: each now pins the exact URL rather than the bare one.

Verification

  • 2074 passed, 9 skipped
  • black --check clean over all 345 files
  • mypy.stubtest reports no issues in 132 modules on Python 3.14, with the stub updated (Mapping added to its imports)
  • 100% statement and branch coverage of the changed lines (16/16), measured with coverage run -m pytest and the repository .coveragerc

Follow-up, not in this PR

The pages in hivesolutions/static do not read the parameters yet, they are static HTML. Reading them is a small piece of script on those pages, worth doing once this is released.

- Encode the context of the response onto the framed URL, keeping any
  query string the configured URL already carries and sorting the keys
- Hand over the status phrase on the up-stream error, so the text of the
  back-end exception no longer reaches the page URL nor its title
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6fa9ccad-260b-43ba-a0dd-b19cc1545f8c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@joamag joamag left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

LGTM

@joamag
joamag marked this pull request as ready for review November 6, 2026 11:02
Copilot AI balanced review requested due to automatic review settings November 6, 2026 11:02

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@joamag

joamag commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T11:04:44.471745Z 3e281c2 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@joamag joamag self-assigned this Nov 6, 2026
@joamag joamag added the enhancement New feature or request label Nov 6, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e281c28d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/netius/servers/http.py Resolved
Comment thread src/netius/servers/http.py Resolved
- Move the context argument to the end of the page builders, so a call
  that passes the existing options by position keeps its behaviour
- Place the parameters before any fragment, as they belong to the query
@joamag
joamag merged commit 7cdce94 into feat/proxy-unauthorized-page Nov 6, 2026
31 checks passed
@joamag
joamag deleted the feat/proxy-error-context branch November 6, 2026 11:14
joamag added a commit that referenced this pull request Nov 6, 2026
)

* feat: pass the status code and the reason to the framed error page

- Encode the context of the response onto the framed URL, keeping any
  query string the configured URL already carries and sorting the keys
- Hand over the status phrase on the up-stream error, so the text of the
  back-end exception no longer reaches the page URL nor its title

* fix: keep the builder signatures and the fragment intact

- Move the context argument to the end of the page builders, so a call
  that passes the existing options by position keeps its behaviour
- Place the parameters before any fragment, as they belong to the query
joamag added a commit that referenced this pull request Nov 6, 2026
* feat: serve a configured page on the not authorized response

- Add a not authorized URL map, settable per service by a consul tag,
  falling back to the error one so a single page may still cover both
- Keep the status and the challenge header untouched, so the user agent
  still asks for the credentials and only the body is replaced

* feat: pass the status code and the reason to the framed error page (#137)

* feat: pass the status code and the reason to the framed error page

- Encode the context of the response onto the framed URL, keeping any
  query string the configured URL already carries and sorting the keys
- Hand over the status phrase on the up-stream error, so the text of the
  back-end exception no longer reaches the page URL nor its title

* fix: keep the builder signatures and the fragment intact

- Move the context argument to the end of the page builders, so a call
  that passes the existing options by position keeps its behaviour
- Place the parameters before any fragment, as they belong to the query

* docs: describe the error pages and correct the changelog

- List the not found and the not authorized tags beside the error one,
  with the context parameters and the caveat of framing a page that the
  credentials of the request do not reach
- Say what the not authorized entry actually changes, the plain body was
  the one answered before and the error page is now framed by default
- Encode a quote in the framed URL, it would end the attribute early

* fix: escape the ampersand of the framed URL

- An ampersand opens a character reference in an attribute, so a query
  string carrying one was read as another URL by the browser

* fix: keep the pages named in the environment across the consul polls

- The cleanup of a rebuild dropped the entries of a host that consul
  manages, so a page named in the environment lasted until poll two
- Applies them again before the tags, which still take precedence

* docs: match the framed example and record the escaping

- The example showed the raw ampersand, the attribute carries it escaped
- Records that the pages already shipped have their URL framed as named
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants