Skip to content

[codex] fix preview subdomain collision#1943

Merged
riderx merged 3 commits into
mainfrom
codex/fix-preview-subdomain-collision
Apr 24, 2026
Merged

[codex] fix preview subdomain collision#1943
riderx merged 3 commits into
mainfrom
codex/fix-preview-subdomain-collision

Conversation

@riderx
Copy link
Copy Markdown
Member

@riderx riderx commented Apr 24, 2026

Summary (AI generated)

  • replace the preview . to __ hostname encoding with a reversible escaped format
  • keep legacy preview hostnames working while routing new preview links through the collision-safe format
  • add focused unit coverage for dotted vs double-underscore app IDs and legacy hostname parsing

Motivation (AI generated)

GHSA-76qq-gg2p-pwwj reports a cross-tenant preview namespace collision because com.example.app and com.example__app can collapse onto the same public preview hostname when __ is decoded back into .. This change removes that lossy canonicalization while preserving compatibility for existing preview links.

Business Impact (AI generated)

This protects preview namespace isolation between tenants, prevents one app ID from shadowing another app's preview hostname, and keeps the preview feature trustworthy for customers using app IDs with underscores.

Test Plan (AI generated)

  • bunx vitest run tests/preview-subdomain.unit.test.ts
  • bun typecheck
  • bun run lint:backend
  • bunx eslint shared/preview-subdomain.ts tests/preview-subdomain.unit.test.ts src/components/BundlePreviewFrame.vue supabase/functions/_backend/files/preview.ts
  • GitHub Actions

Generated with AI

Summary by CodeRabbit

  • New Features

    • Enhanced preview subdomain generation with improved special character encoding for app identifiers.
  • Refactor

    • Centralized preview subdomain encoding and parsing logic for consistency across the application.
  • Tests

    • Added comprehensive test coverage for preview subdomain functionality.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@riderx has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 36 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 36 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2fe723ee-dd62-4334-b838-410bc7f17ae4

📥 Commits

Reviewing files that changed from the base of the PR and between f13942d and b8f54a9.

📒 Files selected for processing (3)
  • shared/preview-subdomain.ts
  • supabase/functions/_backend/files/preview.ts
  • tests/preview-subdomain.unit.test.ts
📝 Walkthrough

Walkthrough

A new shared module is introduced to centralize preview subdomain encoding, decoding, and parsing logic. Existing components and backend services are refactored to use these utilities instead of maintaining inline implementations. The changes preserve backward compatibility with legacy subdomain formats while supporting a new standardized format.

Changes

Cohort / File(s) Summary
Preview Subdomain Utilities
shared/preview-subdomain.ts
New module providing encodePreviewAppId, buildPreviewSubdomain, decodePreviewAppId, parsePreviewSubdomain, and parsePreviewHostname functions to centralize DNS-safe subdomain handling with support for both new and legacy formats.
Component Updates
src/components/BundlePreviewFrame.vue
Refactored previewUrl generation to use centralized buildPreviewSubdomain helper instead of local encoding logic.
Backend Service Updates
supabase/functions/_backend/files/preview.ts
Updated generatePreviewUrl and subdomain parsing to delegate to shared utilities; error messages reflect new subdomain format and removed lowercase normalization of appId.
Test Suite
tests/preview-subdomain.unit.test.ts
New Vitest unit tests validating encoding, subdomain building, hostname parsing, and backward compatibility with legacy formats.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 Subdomains once scattered, now in one place,
Encoding app IDs with DNS-safe grace,
Shared utilities hop from file to file,
Legacy formats and new ones compile,
The warren of preview is organized—hippity-hop!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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
Title check ✅ Passed The title '[codex] fix preview subdomain collision' clearly summarizes the main change: fixing a security/namespace collision issue in preview subdomain handling.
Description check ✅ Passed The PR description includes a detailed Summary, Motivation, Business Impact, and Test Plan with execution status. While the template sections differ from the repo format, the description thoroughly covers the change rationale and testing performed.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-preview-subdomain-collision

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

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq Bot commented Apr 24, 2026

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing codex/fix-preview-subdomain-collision (b8f54a9) with main (633aeea)

Open in CodSpeed

@riderx riderx marked this pull request as ready for review April 24, 2026 09:47
Copy link
Copy Markdown

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

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: f13942d4c0

ℹ️ 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 shared/preview-subdomain.ts Outdated
Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (2)
shared/preview-subdomain.ts (1)

84-84: Consider using replaceAll() for clarity.

Static analysis suggests using String#replaceAll() instead of String#replace() with a global regex. This is a minor readability improvement.

♻️ Suggested change
   return {
-    appId: encodedAppId.replace(/__/g, '.'),
+    appId: encodedAppId.replaceAll('__', '.'),
     versionId,
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shared/preview-subdomain.ts` at line 84, Replace the regex-based global
replace on encodedAppId with a direct replaceAll call for clarity: in the object
where appId is assigned (appId: encodedAppId.replace(/__/g, '.'),) change to use
encodedAppId.replaceAll('__', '.') so the appId property uses String#replaceAll
on encodedAppId.
tests/preview-subdomain.unit.test.ts (1)

4-48: Good test coverage for the security fix.

The tests effectively verify:

  • Round-trip encoding/decoding with reserved characters
  • Critical: Dotted vs double-underscore app IDs produce different subdomains (the namespace collision fix)
  • Legacy hostname backward compatibility
  • Correct disambiguation when legacy app IDs contain --

Consider adding edge case tests for robustness (optional):

♻️ Suggested additional test cases
it.concurrent('returns null for malformed hostnames', () => {
  expect(parsePreviewHostname('invalid.domain.com')).toBeNull()
  expect(parsePreviewHostname('')).toBeNull()
})

it.concurrent('handles edge case version IDs', () => {
  expect(parsePreviewHostname('com-2eexample--0.preview.capgo.app')).toEqual({
    appId: 'com.example',
    versionId: 0,
  })
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/preview-subdomain.unit.test.ts` around lines 4 - 48, Tests currently
lack coverage for malformed hostnames and edge-case version IDs; add two new
concurrent tests in tests/preview-subdomain.unit.test.ts that call
parsePreviewHostname and assert null for clearly invalid inputs (e.g.,
'invalid.domain.com' and empty string) and assert correct decoding for an
edge-case versionId like 0 using a generated/known encoded hostname (reference
helpers buildPreviewSubdomain, encodePreviewAppId and parser
parsePreviewHostname to construct or validate these cases); ensure you place
them alongside the existing it.concurrent blocks and use toBeNull() for
malformed cases and toEqual({...}) for the version-id edge case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shared/preview-subdomain.ts`:
- Line 84: Replace the regex-based global replace on encodedAppId with a direct
replaceAll call for clarity: in the object where appId is assigned (appId:
encodedAppId.replace(/__/g, '.'),) change to use encodedAppId.replaceAll('__',
'.') so the appId property uses String#replaceAll on encodedAppId.

In `@tests/preview-subdomain.unit.test.ts`:
- Around line 4-48: Tests currently lack coverage for malformed hostnames and
edge-case version IDs; add two new concurrent tests in
tests/preview-subdomain.unit.test.ts that call parsePreviewHostname and assert
null for clearly invalid inputs (e.g., 'invalid.domain.com' and empty string)
and assert correct decoding for an edge-case versionId like 0 using a
generated/known encoded hostname (reference helpers buildPreviewSubdomain,
encodePreviewAppId and parser parsePreviewHostname to construct or validate
these cases); ensure you place them alongside the existing it.concurrent blocks
and use toBeNull() for malformed cases and toEqual({...}) for the version-id
edge case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ed664a50-f6f0-4b8c-abce-69e46a72d5b6

📥 Commits

Reviewing files that changed from the base of the PR and between 633aeea and f13942d.

📒 Files selected for processing (4)
  • shared/preview-subdomain.ts
  • src/components/BundlePreviewFrame.vue
  • supabase/functions/_backend/files/preview.ts
  • tests/preview-subdomain.unit.test.ts

Copy link
Copy Markdown

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

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: d22d07cc82

ℹ️ 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 shared/preview-subdomain.ts Outdated
@sonarqubecloud
Copy link
Copy Markdown

@riderx riderx merged commit c49e5c6 into main Apr 24, 2026
16 checks passed
@riderx riderx deleted the codex/fix-preview-subdomain-collision branch April 24, 2026 12:27
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