fix(cli): allow docs instances on Fern-managed Cloudflare zones - #17603
fix(cli): allow docs instances on Fern-managed Cloudflare zones#17603devin-ai-integration[bot] wants to merge 1 commit into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
AI Review Summary
Adds five Fern-managed Cloudflare zones to the docs instance URL allowlist and makes domain matching label-aware. Logic is correct; only minor nits around the redundant array copy/sort per call and a subtle interaction between the new buildwithfern.dev zone and the existing subdomain rules.
- 🔵 1 suggestion(s)
To request another review, comment /ai-review on this pull request.
| const matchedDomain = [...VALID_FERN_DOMAINS] | ||
| .sort((a, b) => b.length - a.length) | ||
| .find((domain) => hostname === domain || hostname.endsWith("." + domain)); |
There was a problem hiding this comment.
🔵 suggestion
The copy + sort runs on every call. Since VALID_FERN_DOMAINS is a module constant, sort once at module scope (and note that longest-match only matters for docs.dev.buildwithfern.com vs docs.buildwithfern.com, which aren't actually suffixes of each other at a label boundary — x.docs.dev.buildwithfern.com doesn't end in .docs.buildwithfern.com. So the sort is defensive rather than required, which is fine, but hoist it):
| const matchedDomain = [...VALID_FERN_DOMAINS] | |
| .sort((a, b) => b.length - a.length) | |
| .find((domain) => hostname === domain || hostname.endsWith("." + domain)); | |
| const matchedDomain = SORTED_FERN_DOMAINS.find( | |
| (domain) => hostname === domain || hostname.endsWith("." + domain) | |
| ); |
with const SORTED_FERN_DOMAINS = [...VALID_FERN_DOMAINS].sort((a, b) => b.length - a.length); next to the constant.
Description
fern check/fern generate --docsrejects anyinstances[].urlthat doesn't end indocs.buildwithfern.comordocs.dev.buildwithfern.com, so docs sites on the other Fern-managed Cloudflare zones (e.g.adi-tests-new-pipeline.buildwithfern.dev) fail validation even though the docs publishing pipeline serves them. This adds those zones —buildwithfern.dev,fernapi.dev,ferndocs.com,ferndocs.dev,fernmcp.dev, all Fern-owned/Cloudflare-managed — to the CLI's allowlist.Matching is now label-aware instead of a bare
endsWith, so lookalikes likenotbuildwithfern.devorx.buildwithfern.dev.evil.comget the accurate "must end with one of ..." error rather than the misleading "a subdomain is required":Subdomain rules (single label, ≤62 chars, alphanumerics + hyphens) are unchanged and apply to every zone.
Changes Made
VALID_FERN_DOMAINSinpackages/cli/yaml/docs-validator/src/rules/valid-instance-url/valid-instance-url.tsgains the five Cloudflare-managed zones; existing two are kept.packages/cli/cli/changes/unreleased/.Testing
adi-tests-new-pipeline.buildwithfern.dev), plus rejection cases for unrelated domains (mycompany.buildwithfern.com,mycompany.fernapi.com), lookalikes (notbuildwithfern.dev,myferndocs.dev,x.ferndocs.com.evil.com), and apex-without-subdomain for every zone.pnpm turbo run test --filter @fern-api/docs-validator→ 226 passed;pnpm turbo run compile --filter @fern-api/docs-validator,pnpm lint:biome,pnpm format:fixclean.Link to Devin session: https://app.devin.ai/sessions/b3c4f788f19a48c58b286827f949023c
Open in Devin Desktop: https://app.devin.ai/desktop/session/b3c4f788f19a48c58b286827f949023c?variant=devin