Skip to content

fix(frontend): forward Remote-User zum Backend (vervollständigt PR #130)#132

Merged
strausmann merged 1 commit into
mainfrom
fix/forward-remote-user
Jun 23, 2026
Merged

fix(frontend): forward Remote-User zum Backend (vervollständigt PR #130)#132
strausmann merged 1 commit into
mainfrom
fix/forward-remote-user

Conversation

@strausmann

Copy link
Copy Markdown
Owner

Fortsetzung von PR #130

Closes #131

PR #130 hatte X-Pangolin-Token zum Forwarding hinzugefügt — externes Header-Auth funktioniert damit. Aber Browser-User mit aktiver Pangolin SSO-Session bekommen weiterhin 503 weil das Backend für den SSO-Trust-Pfad beide Header braucht:

Forwarding nur einer von beiden → 401 vom Backend → Frontend wirft 503.

Fix

1-Zeilen-Change: Remote-User zur Forwarding-Liste hinzugefügt + Docstring präzisiert.

Test

Neuer Test TestWithAuthFromForwardsRemoteUserHeader — RED ohne Fix, GREEN damit. Alle 4 Header-Forwarding-Tests grün mit Race-Detector.

--- PASS: TestWithAuthFromForwardsAPIKeyHeader (0.01s)
--- PASS: TestWithAuthFromForwardsPangolinTokenHeader (0.01s)
--- PASS: TestWithAuthFromForwardsRemoteUserHeader (0.02s)
--- PASS: TestWithAuthFromForwardsPangolinHeader (0.02s)

Test Plan

  • CI grün
  • Image-Build durch
  • Stack-Recreate auf hhdocker03
  • Browser-Smoke: https://labels.strausmann.cloud/ zeigt Dashboard
  • Cleanup-Followup: pangolin_pangolin_mgmt aus Frontend-Networks (separate Dockhand-Update, kein Repo-Change weil Compose in Dockhand-DB lebt)

…-Header)

PR #130 hatte X-Pangolin-Token zur Forwarding-Liste hinzugefuegt um Browser-
User ohne SSO-Session den Trust-Pfad zu ermoeglichen. Damit war der externe
Pangolin-Path mit Header-Auth Bypass abgedeckt — aber Browser-User MIT
aktiver Pangolin-SSO-Session bekommen weiterhin 503.

Grund: Pangolin Standard-SSO setzt Remote-User als User-Identity-Header
(sso_user_header). Das Backend erlaubt den SSO-Trust-Pfad nur wenn BEIDE
Header gesetzt sind — X-Pangolin-Token (Trust-Signal) UND Remote-User
(Identitaet). Forwarding nur eines davon → 401 → Frontend wirft 503.

Fix: Remote-User zur Forwarding-Liste in WithAuthFrom hinzugefuegt.

Test: TestWithAuthFromForwardsRemoteUserHeader prueft via httptest-Backend
dass Remote-User beim Backend ankommt. Race-Detector grün, alle 4 Header-
Forwarding-Tests passen.

Refs: PR #130 (X-Pangolin-Token), Issue #131 (vom ops-agent geoeffnet als
Followup zum unvollstaendigen PR #130)
Copilot AI review requested due to automatic review settings June 23, 2026 11:00
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Dieser Pull Request vervollständigt die Authentifizierungslogik für das Forwarding von Requests an das Backend. Da das Backend für den SSO-Trust-Pfad sowohl ein Trust-Signal als auch die Benutzeridentität benötigt, wurde der 'Remote-User'-Header in die Forwarding-Liste aufgenommen, um 401-Fehler und daraus resultierende 503-Statuscodes im Frontend zu beheben.

Highlights

  • Header Forwarding Update: Added the 'Remote-User' header to the list of headers forwarded by the HubClient to ensure proper authentication with the backend.
  • Documentation Improvement: Updated docstrings in client.go to clarify that both 'X-Pangolin-Token' and 'Remote-User' are required for successful SSO-trust path authentication.
  • Regression Testing: Implemented 'TestWithAuthFromForwardsRemoteUserHeader' to verify that the 'Remote-User' header is correctly propagated to the backend.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@strausmann strausmann merged commit 38c0cc3 into main Jun 23, 2026
12 checks passed
@strausmann strausmann deleted the fix/forward-remote-user branch June 23, 2026 11:00

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request updates the frontend API client to forward the Remote-User header alongside existing authentication headers in WithAuthFrom, ensuring compatibility with the backend's SSO-trust path. A corresponding unit test has been added to verify this behavior. The feedback suggests adding a defensive nil check for the incoming http.Request parameter to prevent potential nil-pointer dereferences.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 138 to 143
func (c *HubClient) WithAuthFrom(r *http.Request) *HubClient {
headers := make(map[string]string, 4)
for _, h := range []string{"X-Label-Hub-Key", "X-Pangolin-User", "X-Pangolin-Token", "Authorization"} {
headers := make(map[string]string, 5)
for _, h := range []string{"X-Label-Hub-Key", "X-Pangolin-User", "X-Pangolin-Token", "Remote-User", "Authorization"} {
if v := r.Header.Get(h); v != "" {
headers[h] = v
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Zur defensiven Programmierung sollte überprüft werden, ob r nil ist, um eine Nil-Pointer-Dereferenzierung (Panic) zu verhindern, falls die Methode mit einem nil-Request aufgerufen wird (z. B. in Tests oder Hintergrund-Tasks).

func (c *HubClient) WithAuthFrom(r *http.Request) *HubClient {
	if r == nil {
		return &HubClient{
			gen:         c.gen,
			hc:          c.hc,
			baseURL:     c.baseURL,
			authHeaders: nil,
		}
	}
	headers := make(map[string]string, 5)
	for _, h := range []string{"X-Label-Hub-Key", "X-Pangolin-User", "X-Pangolin-Token", "Remote-User", "Authorization"} {
		if v := r.Header.Get(h); v != "" {
			headers[h] = v
		}

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates the frontend Hub API client to forward Pangolin’s Remote-User header to the backend and adds a regression test to ensure the header is propagated correctly.

Changes:

  • Forward Remote-User in HubClient.WithAuthFrom alongside existing auth headers.
  • Update WithAuthFrom doc comment to describe Standard-SSO behavior and requirements.
  • Add a unit test verifying Remote-User forwarding to the backend.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
frontend/internal/api/client.go Extends WithAuthFrom to propagate Remote-User and updates the associated documentation.
frontend/internal/api/client_test.go Adds a test that verifies Remote-User is forwarded to backend requests.

Comment on lines +276 to +308
func TestWithAuthFromForwardsRemoteUserHeader(t *testing.T) {
t.Parallel()
var receivedUser string
now := time.Now().Format(time.RFC3339)
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/printers" {
receivedUser = r.Header.Get("Remote-User")
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode([]map[string]any{
{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "PT-P750W",
"model": "pt_series", "backend": "tcp",
"connection": map[string]any{"host": "198.51.100.10", "port": 9100},
"enabled": true, "paused": false,
"created_at": now, "updated_at": now},
})
return
}
http.NotFound(w, r)
}))
defer backend.Close()

incomingReq := httptest.NewRequest(http.MethodGet, "/", nil)
incomingReq.Header.Set("Remote-User", "strausmann")

client := api.NewHubClient(backend.URL).WithAuthFrom(incomingReq)
_, err := client.ListPrinters(context.Background())
if err != nil {
t.Fatalf("ListPrinters: %v", err)
}
if receivedUser != "strausmann" {
t.Errorf("Remote-User forwarded as %q, want %q", receivedUser, "strausmann")
}
}
Comment on lines 127 to 143
// X-Pangolin-Token is the static trust-token that a Pangolin Resource can
// inject into every upstream request via its Header-Auth configuration. The
// backend's sso_trust_header mechanism accepts it as a SSO-equivalent signal,
// which is what allows browser users without an active SSO session to still
// reach the UI.
// but only when paired with Remote-User (the user identity from Pangolin's
// standard SSO header). Forwarding only one of the two triggers a 401 — both
// must be forwarded together for browser users with active Pangolin SSO
// sessions to reach the UI.
//
// The original HubClient is not mutated; the returned copy shares the same
// underlying http.Client and gen client but adds a RequestEditorFn that
// injects the auth headers.
func (c *HubClient) WithAuthFrom(r *http.Request) *HubClient {
headers := make(map[string]string, 4)
for _, h := range []string{"X-Label-Hub-Key", "X-Pangolin-User", "X-Pangolin-Token", "Authorization"} {
headers := make(map[string]string, 5)
for _, h := range []string{"X-Label-Hub-Key", "X-Pangolin-User", "X-Pangolin-Token", "Remote-User", "Authorization"} {
if v := r.Header.Get(h); v != "" {
headers[h] = v
}
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.75%. Comparing base (5fb2038) to head (ab42f24).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #132      +/-   ##
==========================================
+ Coverage   87.71%   87.75%   +0.04%     
==========================================
  Files          94       94              
  Lines        4574     4574              
  Branches      400      400              
==========================================
+ Hits         4012     4014       +2     
+ Misses        459      457       -2     
  Partials      103      103              
Components Coverage Δ
Printer Backends (transport) 85.71% <ø> (ø)
Printer Models (drivers) 88.20% <ø> (ø)
Services 91.30% <ø> (ø)
REST API 83.31% <ø> (ø)
Pydantic Schemas 100.00% <ø> (ø)
Integration Plugins 100.00% <ø> (ø)
see 1 file with indirect coverage changes
Flag Coverage Δ
backend 87.75% <ø> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5fb2038...ab42f24. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

strausmann added a commit that referenced this pull request Jun 23, 2026
…133)

In Phase 7c hatten wir SSO und Bypass auf "read scope only" beschraenkt,
um Leak-Defense fuer den claude-automation Bypass zu haben. Konsequenz:
das HTML-Admin-UI ist via SSO nicht nutzbar, weil Admin-Routen "admin"
Scope verlangen und SSO nur "read" liefert.

Diese Aenderung trusted SSO und Bypass fuer den jeweils verlangten Scope.
Die Defense-in-Depth ist:
- SSO: Pangolin Resource Policy gated, wer ueberhaupt auf labels.* kommt.
- Bypass: Secret liegt in Vault, rotiert via Vault bei Verdacht auf Leak.
  Production-Integrationen (Hangar, Snipe-IT, Grocy) sollen API-Keys mit
  spezifischem Scope nutzen, nicht den Bypass.

Multi-Scope-System auf X-Label-Hub-Key API-Keys bleibt unveraendert:
jeder Key hat weiterhin read/print/admin Scope-Liste und per-printer ACL.

Tests:
- test_pangolin_sso_blocked_on_print_scope ersetzt durch
  test_pangolin_sso_allows_print_and_admin_scopes (parametrisiert)
- 75/75 auth + admin tests gruen, inkl. Race-Detector

ADR 0014 dokumentiert die Entscheidung inkl. der zwei verworfenen Optionen
(SSO-Admin-User-Liste in ENV; Scope-System komplett entfernen).

Refs: Issue #78 (Phase 7c original), PR #130/#132 (Header-Forwarding),
ADR 0014
strausmann added a commit that referenced this pull request Jun 23, 2026
…min-Routes) (#134)

PR #130/#132 hatten WithAuthFrom im oapi-Client um X-Pangolin-Token und
Remote-User ergänzt. forwardAuth in admin_api_keys.go ist eine zweite,
parallele Implementierung für die Admin-Routes (/admin/printers,
/admin/api-keys) die raw http.DefaultClient verwendet — die Header-Liste
dort wurde nicht mitgezogen.

Konsequenz: SSO-User konnten Read-Routes nutzen, alle Admin-Routes gaben
weiterhin 503 weil das Backend mit "missing_credentials" 401 zurück lieferte.

Fix: dieselbe Header-Liste in forwardAuth. Plus Regression-Test
TestListPrintersPage_ForwardetPangolinSSOHeaders der httptest-Server-seitig
beide Header verifiziert.

Race-Detector grün, alle 4 Frontend-Packages grün.

Refs PR #130 (X-Pangolin-Token), PR #132 (Remote-User), PR #133 (ADR 0014
Backend-Seite)
github-actions Bot pushed a commit that referenced this pull request Jun 24, 2026
## 0.11.0 (2026-06-24)

* feat(auth): Pangolin-SSO + Bypass für alle Scopes trusted (ADR 0014) (#133) ([4fe1a91](4fe1a91)), closes [#133](#133) [#78](#78) [130/#132](#132)
* feat(nav): "Drucker" Link für Admin-Drucker-Verwaltung + getrennte ActiveNav-Werte (#135) ([1e982b0](1e982b0)), closes [#135](#135) [#104](#104) [#104](#104) [#104](#104)
* fix(frontend): forward Remote-User zum Backend (Pangolin SSO-Standard-Header) (#132) ([38c0cc3](38c0cc3)), closes [#132](#132) [#130](#130) [#130](#130) [#131](#131) [#130](#130)
* fix(frontend): forward X-Pangolin-Token zum Backend (Browser-User 503-Fix) (#130) ([5fb2038](5fb2038)), closes [#130](#130)
* fix(frontend): forwardAuth ergänzt X-Pangolin-Token + Remote-User (Admin-Routes) (#134) ([af9ee28](af9ee28)), closes [#134](#134) [130/#132](#132) [#130](#130) [#132](#132) [#133](#133)
* chore(deps): bump the go-minor-and-patch group across 1 directory with 2 updates (#128) ([a72dd90](a72dd90)), closes [#128](#128)
* ci(deps): bump lewagon/wait-on-check-action in the actions-all group (#127) ([e4139ab](e4139ab)), closes [#127](#127)
* docs(api): printers.yaml weg, Drucker in DB + /admin/printers Admin-UI (#124) [DRAFT] (#125) ([41bef28](41bef28)), closes [#124](#124) [#125](#125) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#3099](https://github.com/strausmann/label-printer-hub/issues/3099) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#3099](https://github.com/strausmann/label-printer-hub/issues/3099) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [#124](#124) [compose-passthrou#Pflicht](https://github.com/compose-passthrou/issues/Pflicht)

[skip ci]
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.

fix(frontend): WithAuthFrom must also forward Remote-User header to backend

2 participants