Skip to content

Fix hardcoded docs and host URLs#527

Merged
juanmrad merged 2 commits into
mainfrom
fix-163-370-consolidate-coop-urls
May 20, 2026
Merged

Fix hardcoded docs and host URLs#527
juanmrad merged 2 commits into
mainfrom
fix-163-370-consolidate-coop-urls

Conversation

@juanmrad
Copy link
Copy Markdown
Member

@juanmrad juanmrad commented May 20, 2026

Fixes #163, fixes #370.

Context & Requests for Reviewers

Centralize HOST_URL and DOCS_URL in client/src/lib/config.ts (sourced from VITE_UI_URL and VITE_DOCS_URL) and replace literal getcoop.com / docs.getcoop.com references throughout the client. Also drop the dead Cove SaaS domains from server/utils/url.ts default blocklist and stop falling back to content.getcoop.com in the iframe content proxy.

Summary by CodeRabbit

  • New Features

    • Added environment variables to configure app and docs base URLs and a centralized URL configuration.
  • Improvements

    • Replaced hardcoded URLs across UI (links, code samples, invites, password resets, SSO) with configured values.
    • Clarified content-proxy defaults and dev-mode behavior.
  • Tests

    • Expanded URL validation tests and refined loopback/blocked-hostname handling.

Review Change Stack

Centralize HOST_URL and DOCS_URL in client/src/lib/config.ts (sourced from
VITE_UI_URL and VITE_DOCS_URL) and replace literal getcoop.com /
docs.getcoop.com references throughout the client. Also drop the dead Cove
SaaS domains from server/utils/url.ts's default blocklist and stop falling
back to content.getcoop.com in the iframe content proxy.

Fixes #163, fixes #370.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR consolidates hardcoded domain URLs (https://getcoop.com, https://docs.getcoop.com) scattered throughout the codebase into centralized, environment-configurable constants. A new config.ts module exports HOST_URL and DOCS_URL with environment variable overrides and fallbacks, which client components import instead of constructing URLs inline. Server-side URL validation logic is simplified.

Changes

Centralized URL Configuration Refactoring

Layer / File(s) Summary
Centralized URL Configuration System
client/src/lib/config.ts, client/.env.example, .env.githubci
New config module exports HOST_URL (from VITE_UI_URL env or window.location.origin) and DOCS_URL (from VITE_DOCS_URL env or default docs site) as documented environment variables; CI env points UI_URL to localhost.
Client Component Updates – URL Migrations
client/src/webpages/dashboard/actions/ActionForm.tsx, client/src/webpages/dashboard/mrt/ManualReviewAppealSettings.tsx, client/src/webpages/dashboard/item_types/itemTypeCodeSampleUtils.ts, client/src/webpages/dashboard/mrt/ManualReviewRecentDecisions.tsx, client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx, client/src/webpages/settings/ManageUsers.tsx, client/src/webpages/settings/ManageUsersInviteUserSection.tsx, client/src/webpages/settings/SSOSettings.tsx
Import HOST_URL and DOCS_URL from config module and replace hardcoded URLs in documentation links (ActionForm, ManualReviewAppealSettings), generated API code samples (Curl, Python, Node, PHP), CSV export links (ManualReviewRecentDecisions), password reset URLs (ManageUsers), invite signup URLs (ManageUsersInviteUserSection), SAML callback and entity ID URLs (SSOSettings), and content proxy initialization (IframeContentDisplayComponent).
Server URL Validation Refactoring
server/utils/url.ts, server/utils/url.test.ts
defaultBlockedHostnames() inlines loopback conditional logic and returns only ['localhost', '127.0.0.1'] when ALLOW_USER_INPUT_LOCALHOST_URIS is not set; test suite reorganized to explicitly verify loopback gating by default, localhost allow-listing when override is enabled, and caller-provided blockedHostnames options are honored.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

documentation

Suggested reviewers

  • vinaysrao1
  • cassidyjames
  • dom-notion

"I hopped through code with careful paws,\
Replaced hard strings with configurable laws,\
Docs and hosts now follow the plan,\
Local dev and CI both understand,\
A rabbit cheers for tidy URLs! 🐇"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% 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 'Fix hardcoded docs and host URLs' clearly and concisely summarizes the main objective of centralizing and removing hardcoded URL references throughout the codebase.
Description check ✅ Passed The PR description adequately covers the context and key changes, including references to the linked issues (#163 and #370) and a concise summary of the implementation approach.
Linked Issues check ✅ Passed All coding requirements from linked issues are met: #163 requirements to replace hardcoded docs.getcoop.com references with centralized DOCS_URL are fully implemented across multiple files; #370 requirements to remove dead Cove SaaS domains and stop falling back to content.getcoop.com are addressed in server/utils/url.ts and IframeContentDisplayComponent.tsx.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing hardcoded URLs as specified in linked issues #163 and #370; no out-of-scope modifications are present.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-163-370-consolidate-coop-urls

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

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.

Actionable comments posted: 2

🤖 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 `@client/src/lib/config.ts`:
- Around line 19-30: HOST_URL and DOCS_URL currently use the nullish coalescing
operator (??) which does not treat empty strings as missing; update the
resolution logic for import.meta.env.VITE_UI_URL and
import.meta.env.VITE_DOCS_URL so empty values also fall back (e.g. treat value
as falsy by using a trimmed-string check or logical OR) — change the expressions
that compute HOST_URL and DOCS_URL to check/import.meta.env.VITE_* variables,
trim and test for non-empty before using them, otherwise use
window.location.origin for HOST_URL and the default docs URL for DOCS_URL.

In
`@client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx`:
- Around line 17-18: The code currently sets contentProxyUrl =
import.meta.env.VITE_CONTENT_PROXY_URL ?? 'http://localhost:4000', which
hard-falls back to localhost in non-dev builds; change this so the localhost
default is only used in development (e.g. check import.meta.env.MODE ===
'development' or similar) and otherwise leave contentProxyUrl undefined or
fail-fast when VITE_CONTENT_PROXY_URL is missing, and update any consumers of
contentProxyUrl (the iframe/message handling code that reads contentProxyUrl) to
handle the undefined case (show error, disable iframe, or throw a clear
configuration error) so production/staging won't accidentally point at
localhost.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 23510352-1ed1-4b4c-ac65-e3ded099a8cb

📥 Commits

Reviewing files that changed from the base of the PR and between 09fe5f0 and f6c568a.

📒 Files selected for processing (13)
  • .env.githubci
  • client/.env.example
  • client/src/lib/config.ts
  • client/src/webpages/dashboard/actions/ActionForm.tsx
  • client/src/webpages/dashboard/item_types/itemTypeCodeSampleUtils.ts
  • client/src/webpages/dashboard/mrt/ManualReviewAppealSettings.tsx
  • client/src/webpages/dashboard/mrt/ManualReviewRecentDecisions.tsx
  • client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx
  • client/src/webpages/settings/ManageUsers.tsx
  • client/src/webpages/settings/ManageUsersInviteUserSection.tsx
  • client/src/webpages/settings/SSOSettings.tsx
  • server/utils/url.test.ts
  • server/utils/url.ts

Comment thread client/src/lib/config.ts
Comment on lines +19 to +30
export const HOST_URL: string =
import.meta.env.VITE_UI_URL ?? window.location.origin;

/**
* Base URL of the published Coop documentation site.
*
* Configure with `VITE_DOCS_URL` at build time to point at a fork's or
* mirror's docs. Defaults to the official mdBook site published from this
* repository's `docs/` folder.
*/
export const DOCS_URL: string =
import.meta.env.VITE_DOCS_URL ?? 'https://roostorg.github.io/coop/latest';
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 20, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle empty env values when resolving base URLs.

On Line 20 and Line 30, ?? won’t fall back if VITE_UI_URL/VITE_DOCS_URL are set to '' (empty string), which can generate broken docs links and relative host links.

Suggested fix
-export const HOST_URL: string =
-  import.meta.env.VITE_UI_URL ?? window.location.origin;
+export const HOST_URL: string =
+  import.meta.env.VITE_UI_URL?.trim() || window.location.origin;
@@
-export const DOCS_URL: string =
-  import.meta.env.VITE_DOCS_URL ?? 'https://roostorg.github.io/coop/latest';
+export const DOCS_URL: string =
+  import.meta.env.VITE_DOCS_URL?.trim() ||
+  'https://roostorg.github.io/coop/latest';
🤖 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 `@client/src/lib/config.ts` around lines 19 - 30, HOST_URL and DOCS_URL
currently use the nullish coalescing operator (??) which does not treat empty
strings as missing; update the resolution logic for import.meta.env.VITE_UI_URL
and import.meta.env.VITE_DOCS_URL so empty values also fall back (e.g. treat
value as falsy by using a trimmed-string check or logical OR) — change the
expressions that compute HOST_URL and DOCS_URL to check/import.meta.env.VITE_*
variables, trim and test for non-empty before using them, otherwise use
window.location.origin for HOST_URL and the default docs URL for DOCS_URL.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

our linter does not like || having ?? is ok.

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.

@juanmrad, understood — I'll withdraw the || suggestion. The ?? pattern is fine for this use case; empty-string env vars are an unusual misconfiguration and the current code is clear. Thanks for the context!

(๑˃ᴗ˂)ﻌﻌﻌ♡


✏️ Learnings added
Learnt from: juanmrad
Repo: roostorg/coop PR: 527
File: client/src/lib/config.ts:19-31
Timestamp: 2026-05-20T03:51:03.594Z
Learning: In the `roostorg/coop` repository, the ESLint (or equivalent) linter is configured to disallow the logical OR (`||`) operator in favour of the nullish coalescing operator (`??`). Do not suggest replacing `??` with `||` for fallback expressions in this codebase.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

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.

Actionable comments posted: 1

🤖 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
`@client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx`:
- Around line 18-19: The environment variable parsing for contentProxyUrl allows
empty or whitespace-only values because it uses
import.meta.env.VITE_CONTENT_PROXY_URL?.trim() ?? fallback; change the logic
that sets contentProxyUrl to treat an empty string (after trim) as missing by
using a truthy check (e.g., const contentProxyUrl =
(import.meta.env.VITE_CONTENT_PROXY_URL || '').trim() || (import.meta.env.DEV ?
'http://localhost:4000' : window.location.origin)); then update any code relying
on contentProxyUrl (the message event handler that checks event.origin and the
postMessage calls that use contentProxyUrl as the target origin) to use the
sanitized contentProxyUrl so origin validation and postMessage target origins
are never an empty string.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b0621e0-3584-4d6f-b71d-cf1465cfb1c5

📥 Commits

Reviewing files that changed from the base of the PR and between f6c568a and a5087e3.

📒 Files selected for processing (3)
  • client/.env.example
  • client/src/lib/config.ts
  • client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx

Comment on lines +18 to +19
import.meta.env.VITE_CONTENT_PROXY_URL?.trim() ??
(import.meta.env.DEV ? 'http://localhost:4000' : window.location.origin);
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In JavaScript/TypeScript, does value?.trim() ?? fallbackusefallbackwhenvalue is an empty string or whitespace-only string?

💡 Result:

No, the expression value?.trim?? fallback does not use the fallback when value is an empty string or a whitespace-only string [1][2][3]. The nullish coalescing operator (??) only triggers its right-hand side (the fallback) when the left-hand side is null or undefined [1][4][5]. Because an empty string ("") and a whitespace-only string (" ") are valid string values—not null or undefined—the expression will return the result of the trim operation instead of the fallback [1][2][3]. Specifically: - If value is "", value?.trim evaluates to "", and the expression returns "" [1][5]. - If value is " ", value?.trim evaluates to "", and the expression returns "" [6]. - If value is null or undefined, value?.trim evaluates to undefined, and the expression returns the fallback [1][7]. If your goal is to treat empty or whitespace-only strings as "missing" and use the fallback in those cases, you must handle that logic explicitly, for example: const result = (value?.trim || null)?? fallback; // Or more simply: const result = (!value?.trim)? fallback: value.trim; [8][3]

Citations:


🏁 Script executed:

# Check if file exists and read the relevant section
if [ -f "client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx" ]; then
  echo "File exists. Reading lines 10-25:"
  sed -n '10,25p' "client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx"
else
  echo "File not found at specified path"
fi

Repository: roostorg/coop

Length of output: 675


🏁 Script executed:

# Search for other uses of VITE_CONTENT_PROXY_URL in codebase
rg "VITE_CONTENT_PROXY_URL" --type ts --type tsx

Repository: roostorg/coop

Length of output: 85


🏁 Script executed:

# Search for contentProxyUrl usage to see how it's used (especially postMessage)
rg "contentProxyUrl" --type ts --type tsx -A 3

Repository: roostorg/coop

Length of output: 85


🏁 Script executed:

# Search for VITE_CONTENT_PROXY_URL without type flag
rg "VITE_CONTENT_PROXY_URL"

Repository: roostorg/coop

Length of output: 197


🏁 Script executed:

# Search for contentProxyUrl usage (especially postMessage and origin checks)
rg "contentProxyUrl" -A 3 -B 1

Repository: roostorg/coop

Length of output: 4112


🏁 Script executed:

# Read the entire file to see all usages and context
cat -n "client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx" | head -100

Repository: roostorg/coop

Length of output: 3757


Handle empty VITE_CONTENT_PROXY_URL before fallback.

At line 18-19, ?.trim() ?? ... won't fall back when the env var is '' or whitespace-only. The nullish coalescing operator (??) only triggers on null or undefined, not empty strings, so contentProxyUrl can become an empty string. This breaks origin validation in the message handler (line 53) where event.origin !== "" always rejects incoming messages, and invalidates the postMessage target origin at lines 77 and 93.

Suggested fix
-  const contentProxyUrl =
-    import.meta.env.VITE_CONTENT_PROXY_URL?.trim() ??
-    (import.meta.env.DEV ? 'http://localhost:4000' : window.location.origin);
+  const configuredContentProxyUrl =
+    import.meta.env.VITE_CONTENT_PROXY_URL?.trim();
+  const contentProxyUrl =
+    configuredContentProxyUrl?.length
+      ? configuredContentProxyUrl
+      : import.meta.env.DEV
+        ? 'http://localhost:4000'
+        : window.location.origin;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import.meta.env.VITE_CONTENT_PROXY_URL?.trim() ??
(import.meta.env.DEV ? 'http://localhost:4000' : window.location.origin);
const configuredContentProxyUrl =
import.meta.env.VITE_CONTENT_PROXY_URL?.trim();
const contentProxyUrl =
configuredContentProxyUrl?.length
? configuredContentProxyUrl
: import.meta.env.DEV
? 'http://localhost:4000'
: window.location.origin;
🤖 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
`@client/src/webpages/dashboard/mrt/manual_review_job/IframeContentDisplayComponent.tsx`
around lines 18 - 19, The environment variable parsing for contentProxyUrl
allows empty or whitespace-only values because it uses
import.meta.env.VITE_CONTENT_PROXY_URL?.trim() ?? fallback; change the logic
that sets contentProxyUrl to treat an empty string (after trim) as missing by
using a truthy check (e.g., const contentProxyUrl =
(import.meta.env.VITE_CONTENT_PROXY_URL || '').trim() || (import.meta.env.DEV ?
'http://localhost:4000' : window.location.origin)); then update any code relying
on contentProxyUrl (the message event handler that checks event.origin and the
postMessage calls that use contentProxyUrl as the target origin) to use the
sanitized contentProxyUrl so origin validation and postMessage target origins
are never an empty string.

@juanmrad juanmrad merged commit 95bb2d5 into main May 20, 2026
14 checks passed
@juanmrad juanmrad deleted the fix-163-370-consolidate-coop-urls branch May 20, 2026 22:35
@cassidyjames cassidyjames added the SaaS remnant Related to Coop's past as a closed-source SaaS startup (Cove) label May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

SaaS remnant Related to Coop's past as a closed-source SaaS startup (Cove)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nonexistent Coop URLs hardcoded Replace documentation links and redirect to coop

3 participants