Skip to content

refactor: move domain check into small helper util#1000

Merged
steveiliop56 merged 7 commits into
mainfrom
fix/domain-checks
Jul 14, 2026
Merged

refactor: move domain check into small helper util#1000
steveiliop56 merged 7 commits into
mainfrom
fix/domain-checks

Conversation

@steveiliop56

@steveiliop56 steveiliop56 commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes
    • Strengthened OAuth redirect URI validation with strict hostname equivalence, optional scheme/port enforcement, safer subdomain handling, and improved support for internationalized hostnames.
    • Updated static access-control domain matching to rely on validated domain equivalence and more robust subdomain/name fallback behavior.
  • New Features
    • Added a reusable domain validation utility that normalizes hostnames (including IDNA) and can optionally enforce scheme and port rules.
  • Tests
    • Added comprehensive test coverage for hostname normalization and domain/URL validation edge cases.
  • Chores
    • Ensured container builds include shared pkg code in both dev and distribution images.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 78fbb6ed-7af2-4fb6-be60-b88ad71f9851

📥 Commits

Reviewing files that changed from the base of the PR and between 8f81309 and edb2829.

📒 Files selected for processing (3)
  • Dockerfile
  • Dockerfile.dev
  • Dockerfile.distroless

📝 Walkthrough

Walkthrough

Adds a reusable domain validator for URL, hostname, scheme, port, and IDNA handling. OAuth redirect checks and static ACL lookup now use it, with updated subdomain fallback behavior and comprehensive validator tests.

Changes

Domain validation and consumers

Layer / File(s) Summary
Domain validator contract and behavior
pkg/validators/domain_validator.go, pkg/validators/domain_validator_test.go, Dockerfile, Dockerfile.dev, Dockerfile.distroless
Adds configurable URL validation, hostname normalization, effective-port handling, safe-hostname extraction, table-driven tests, and copies pkg into container build contexts.
OAuth redirect validation
internal/controller/oauth_controller.go, internal/controller/oauth_controller_test.go
Uses DomainValidator for redirect checks and retains cookie-domain suffix handling for enabled subdomains.
Static ACL domain lookup
internal/service/access_controls_service.go
Validates configured app domains and replaces split-based fallback matching with an app-name prefix check.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OAuthController
  participant DomainValidator
  participant RuntimeConfig
  OAuthController->>RuntimeConfig: read AppURL and CookieDomain
  OAuthController->>DomainValidator: validate AppURL and redirectURI
  DomainValidator-->>OAuthController: validation result
  OAuthController->>DomainValidator: derive safe redirect hostname
  DomainValidator-->>OAuthController: normalized hostname
Loading

Possibly related PRs

Suggested reviewers: scottmckendry

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: domain checks were refactored into a small helper utility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/domain-checks

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

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

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.63780% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/service/access_controls_service.go 62.50% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🧹 Nitpick comments (2)
internal/service/access_controls_service.go (1)

54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer an explicit local copy instead of &<range-variable>.

config is the loop variable from for app, config := range service.config.Apps; returning/storing &config directly works on modern Go but the project has previously preferred an explicit copy (result := config; ... &result) for clarity.

Based on learnings, "prefer the explicit local copy pattern (e.g., result := config; return &result) rather than returning &<range-variable> directly... the project prefers the explicit copy for clarity."

Also applies to: 58-58

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/access_controls_service.go` at line 54, In the config lookup
loop within the access-control service, avoid returning pointers to the range
variable config directly. Create an explicit local copy before returning or
storing the pointer at both referenced locations, preserving the existing
behavior while following the project’s copy-then-address pattern.

Source: Learnings

internal/controller/oauth_controller.go (1)

326-326: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Validate(expected, actual) args are reversed vs. the access-control usage.

Here expected is the untrusted redirectURI and actual is the trusted controller.runtime.AppURL; access_controls_service.go's v.Validate(config.Config.Domain, domain) puts the trusted value first. It doesn't change the boolean outcome, but produces confusing error text (e.g. "expected port 8080, got 443" instead of the intuitive direction) when debugging redirect-safety failures.

♻️ Proposed fix
-	err = v.Validate(redirectURI, controller.runtime.AppURL)
+	err = v.Validate(controller.runtime.AppURL, redirectURI)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/oauth_controller.go` at line 326, Swap the arguments to
Validate in the OAuth redirect-safety check so the trusted
controller.runtime.AppURL is passed as expected and the untrusted redirectURI as
actual, matching the access-control usage and correcting validation error
direction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/service/access_controls_service.go`:
- Line 56: Update the app-name subdomain fallback in the access-control
validation flow to compare normalized lowercase host and app values, matching
the behavior of Validate via formatHostname. Preserve the existing prefix
boundary using app+"." so mixed-case hosts such as FOO.example.com match the
configured app correctly.
- Around line 39-63: Update lookupStaticACLs so validation errors for individual
configured domains are treated as non-matches rather than returned, allowing
iteration to continue and valid apps to match regardless of map order; also make
the app-name fallback comparison case-insensitive when checking the domain
prefix against app+".". Preserve direct domain matches and return nameMatch only
after all apps are evaluated.

In `@pkg/validators/domain_validator_test.go`:
- Around line 249-253: Update the “Non matching hostnames should fail” test case
in the Validate test table to provide an errorFunc assertion for the expected
validation error, so it does not fall through to require.NoError when expected
and actual hostnames differ.

In `@pkg/validators/domain_validator.go`:
- Around line 99-147: Introduce exported sentinel or typed errors in
DomainValidator.Validate/getURL for invalid input, scheme mismatch, port
mismatch, and hostname mismatch, wrapping them while preserving useful details.
In internal/controller/oauth_controller.go lines 334-338, replace error-message
prefix checks with errors.Is/errors.As against the new errors; in
internal/service/access_controls_service.go line 49, recognize only the
hostname-mismatch error and treat other validation errors as failures.

---

Nitpick comments:
In `@internal/controller/oauth_controller.go`:
- Line 326: Swap the arguments to Validate in the OAuth redirect-safety check so
the trusted controller.runtime.AppURL is passed as expected and the untrusted
redirectURI as actual, matching the access-control usage and correcting
validation error direction.

In `@internal/service/access_controls_service.go`:
- Line 54: In the config lookup loop within the access-control service, avoid
returning pointers to the range variable config directly. Create an explicit
local copy before returning or storing the pointer at both referenced locations,
preserving the existing behavior while following the project’s copy-then-address
pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 224f3f3f-683d-45f3-a89d-f7cf8da78283

📥 Commits

Reviewing files that changed from the base of the PR and between b62bb2d and 0c1cc98.

📒 Files selected for processing (6)
  • internal/controller/oauth_controller.go
  • internal/controller/oauth_controller_test.go
  • internal/service/access_controls_service.go
  • internal/service/access_controls_service_test.go
  • pkg/validators/domain_validator.go
  • pkg/validators/domain_validator_test.go

Comment thread internal/service/access_controls_service.go Outdated
Comment thread internal/service/access_controls_service.go Outdated
Comment thread pkg/validators/domain_validator_test.go
Comment thread pkg/validators/domain_validator.go
Comment thread pkg/validators/domain_validator.go Outdated

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
internal/service/access_controls_service.go (1)

50-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer explicit local copy when taking the address of a loop variable.

Based on learnings, when returning or storing a pointer to a for range loop value, prefer the explicit local copy pattern (e.g., cfg := config; return &cfg) rather than taking the address of the range variable directly. This avoids confusion regarding loop-variable capture semantics.

  • internal/service/access_controls_service.go#L50-L50: create a local copy of config before returning its address.
  • internal/service/access_controls_service.go#L57-L57: create a local copy of config before assigning its address to nameMatch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/access_controls_service.go` at line 50, In
internal/service/access_controls_service.go at lines 50-50 and 57-57, update the
loop handling to copy each range variable into an explicit local before taking
its address: return the local copy at the first site and assign the local copy’s
address to nameMatch at the second. Use the existing config value without
changing matching behavior.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/service/access_controls_service.go`:
- Line 50: In internal/service/access_controls_service.go at lines 50-50 and
57-57, update the loop handling to copy each range variable into an explicit
local before taking its address: return the local copy at the first site and
assign the local copy’s address to nameMatch at the second. Use the existing
config value without changing matching behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 05bf647f-d5cb-49a7-96ed-43e864fb0103

📥 Commits

Reviewing files that changed from the base of the PR and between 25b434a and db1d423.

📒 Files selected for processing (4)
  • internal/controller/oauth_controller.go
  • internal/service/access_controls_service.go
  • pkg/validators/domain_validator.go
  • pkg/validators/domain_validator_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/validators/domain_validator_test.go
  • pkg/validators/domain_validator.go
  • internal/controller/oauth_controller.go

Rycochet
Rycochet previously approved these changes Jul 14, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 14, 2026
@steveiliop56

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@steveiliop56 steveiliop56 merged commit e75605b into main Jul 14, 2026
5 checks passed
@steveiliop56 steveiliop56 deleted the fix/domain-checks branch July 14, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants