Skip to content

Added logic for alias recognition to VitePress#925

Open
n-boshnakov wants to merge 3 commits intogardener:masterfrom
n-boshnakov:add-alias-recognition-vitepress
Open

Added logic for alias recognition to VitePress#925
n-boshnakov wants to merge 3 commits intogardener:masterfrom
n-boshnakov:add-alias-recognition-vitepress

Conversation

@n-boshnakov
Copy link
Copy Markdown
Contributor

@n-boshnakov n-boshnakov commented Apr 3, 2026

How to categorize this PR?

/kind documentation

What this PR does / why we need it:
This PR adds alias redirect infrastructure to the website.

Which issue(s) this PR fixes:
Fixes #926

Special notes for your reviewer:

Summary by CodeRabbit

  • New Features

    • Automatic alias redirects: pages can declare alias URLs in frontmatter; build produces static redirect pages and the dev server issues runtime redirects. Conflicting or duplicate aliases are ignored with warnings; index-style routes are normalized.
  • Refactor

    • Centralized site base path and content source configuration for consistent behavior between build and dev.

@n-boshnakov n-boshnakov requested a review from a team as a code owner April 3, 2026 12:39
@gardener-prow
Copy link
Copy Markdown

gardener-prow bot commented Apr 3, 2026

@n-boshnakov: The label(s) kind/documentation cannot be applied, because the repository doesn't have them.

Details

In response to this:

How to categorize this PR?

/kind documentation

What this PR does / why we need it:
This PR adds alias redirect infrastructure to the website.

Which issue(s) this PR fixes:
Fixes #

Special notes for your reviewer:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 3, 2026

Deploy Preview for gardener-docs ready!

Name Link
🔨 Latest commit f68d715
🔍 Latest deploy log https://app.netlify.com/projects/gardener-docs/deploys/69d6443adc7e310008141b7c
😎 Deploy Preview https://deploy-preview-925--gardener-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 67 (🟢 up 1 from production)
Accessibility: 97 (no change from production)
Best Practices: 92 (no change from production)
SEO: 98 (no change from production)
PWA: 90 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@gardener-prow
Copy link
Copy Markdown

gardener-prow bot commented Apr 3, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign jordanjordanov for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gardener-prow gardener-prow bot added do-not-merge/needs-kind Indicates a PR lacks a `kind/foo` label and requires one. cla: yes Indicates the PR's author has signed the cla-assistant.io CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Apr 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

Adds an alias-redirect feature: parses Markdown frontmatter aliases, generates static redirect HTML during build, and provides a dev-server middleware for 302 redirects. Refactors VitePress config to centralize base/srcDir, pass them to Vite config, and call redirects at buildEnd.

Changes

Cohort / File(s) Summary
VitePress config
/.vitepress/config.mts
Centralized siteBase and siteSrcDir; set base and srcDir; changed vite: getViteConfig()vite: getViteConfig(siteBase, siteSrcDir); added buildEnd(siteConfig: SiteConfig) to call generateAliasRedirects; updated imports.
Alias redirect plugin
/.vitepress/plugins/alias-redirects.ts
New plugin exporting AliasEntry, generateAliasRedirects(siteConfig) and createAliasRedirectDevPlugin(srcDir, basePath). Scans .md frontmatter for aliases, normalizes and deduplicates paths, writes static redirect HTML to outDir on build, and provides dev middleware that issues 302 redirects and invalidates cache on file changes.

Sequence Diagram(s)

sequenceDiagram
    participant MF as Markdown Files
    participant Build as VitePress Build
    participant AM as Alias Manager
    participant Dev as Dev Server
    participant FS as Output Filesystem

    rect rgba(100,150,200,0.5)
    Note over MF,AM: Parse & map aliases
    Build->>MF: Read .md from srcDir
    Build->>AM: Extract frontmatter aliases
    AM->>AM: Normalize paths & deduplicate
    end

    rect rgba(150,200,100,0.5)
    Note over Dev,AM: Dev-server redirect flow
    Dev->>AM: Incoming HTTP GET/HEAD (strip basePath)
    AM->>AM: Lookup alias map
    AM-->>Dev: 302 Location -> target path
    end

    rect rgba(200,150,100,0.5)
    Note over Build,FS: Production redirect generation
    Build->>AM: Trigger buildEnd(siteConfig)
    AM->>FS: Write static redirect HTML files to outDir
    FS-->>Build: Redirect files included in output
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hop through frontmatter, sniff each old trail,

Map them to new, then leave a little tale,
Dev server nudges, build plants the sign,
Users find home — one redirect at a time.

🚥 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
Title check ✅ Passed The title 'Added logic for alias recognition to VitePress' clearly summarizes the main change in the changeset.
Description check ✅ Passed The description includes the required template sections: PR categorization, purpose explanation, linked issue reference, and reviewer notes.
Linked Issues check ✅ Passed The PR implements alias redirect infrastructure that addresses issue #926 by enabling redirect from old URLs to current pages when aliases are defined.
Out of Scope Changes check ✅ Passed All changes are in-scope: VitePress config modifications and new alias-redirect plugin directly support the alias redirect infrastructure objective.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

🧹 Nitpick comments (1)
.vitepress/config.mts (1)

222-299: Consider adding type annotations for Vite server APIs to improve IDE support.

The dev redirect plugin logic is sound with good caching, proper cache invalidation on file changes, and correct middleware ordering (calls next() when no redirect is found, allowing other handlers to process the request). Error handling gracefully falls through to the next middleware.

The any types for server, req, and res reduce type safety. Vite and Node.js provide standard type exports that should be used:

🛠️ Optional: Add type imports for better IDE support
+import type { ViteDevServer } from 'vite'
+import type { IncomingMessage, ServerResponse } from 'node:http'

 function createAliasRedirectDevPlugin(srcDir: string, basePath: string) {
   // ...
   return {
     name: 'vitepress-aliases-dev-redirects',
     apply: 'serve',
-    configureServer(server: any) {
+    configureServer(server: ViteDevServer) {
       // ...
-      server.middlewares.use((req: any, res: any, next: () => void) => {
+      server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: () => void) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.vitepress/config.mts around lines 222 - 299, The plugin uses untyped any
for Vite server and HTTP req/res; add proper type annotations to improve IDE
support: import ViteDevServer from 'vite' and use it for the
configureServer(server) parameter in createAliasRedirectDevPlugin, and annotate
the middleware handler parameters (req, res, next) with appropriate Node types
(http.IncomingMessage / http.ServerResponse) or Connect types so IDEs can
resolve properties like url and method; update signatures for
configureServer(server: ViteDevServer) and the middleware callback inside
configureServer (and refreshOnMarkdownChange/loadAliases references remain the
same) and adjust any watcher/middleware usages to match the typed APIs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.vitepress/config.mts:
- Around line 28-45: createRedirectHtml currently embeds targetPath via
JSON.stringify directly into a <script>, which allows breaking out if targetPath
contains "</script>" (XSS). Fix by creating a script-safe string (e.g., let
safeScript = JSON.stringify(targetPath).replace(/<\/script>/gi,
'<\\/script>').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029')) and
use safeScript inside the window.location.replace(...) call while keeping the
HTML-escaped escapedTarget for the meta/link/body; update createRedirectHtml to
use this safeScript instead of JSON.stringify(targetPath).

---

Nitpick comments:
In @.vitepress/config.mts:
- Around line 222-299: The plugin uses untyped any for Vite server and HTTP
req/res; add proper type annotations to improve IDE support: import
ViteDevServer from 'vite' and use it for the configureServer(server) parameter
in createAliasRedirectDevPlugin, and annotate the middleware handler parameters
(req, res, next) with appropriate Node types (http.IncomingMessage /
http.ServerResponse) or Connect types so IDEs can resolve properties like url
and method; update signatures for configureServer(server: ViteDevServer) and the
middleware callback inside configureServer (and
refreshOnMarkdownChange/loadAliases references remain the same) and adjust any
watcher/middleware usages to match the typed APIs.
🪄 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

Run ID: a327d31b-3090-459b-9604-9d6490fc7a17

📥 Commits

Reviewing files that changed from the base of the PR and between 70d3f6e and cab8b8a.

📒 Files selected for processing (1)
  • .vitepress/config.mts

Comment thread .vitepress/config.mts 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.

Actionable comments posted: 2

♻️ Duplicate comments (1)
.vitepress/plugins/alias-redirects.ts (1)

11-21: ⚠️ Potential issue | 🔴 Critical

Make the inline redirect script safe for </script> sequences.

JSON.stringify() is not enough inside a <script> tag. If a page path or configured base ever contains </script>, the generated redirect page becomes executable markup.

🔒 Proposed fix
 const createRedirectHtml = (targetPath: string) => {
   const escapedTarget = escapeHtml(targetPath)
+  const safeScriptTarget = JSON.stringify(targetPath)
+    .replace(/</g, '\\u003c')
+    .replace(/\u2028/g, '\\u2028')
+    .replace(/\u2029/g, '\\u2029')

   return `<!doctype html>
 <html lang="en">
   <head>
     <meta charset="utf-8">
     <title>Redirecting...</title>
     <meta http-equiv="refresh" content="0; url=${escapedTarget}">
     <link rel="canonical" href="${escapedTarget}">
-    <script>window.location.replace(${JSON.stringify(targetPath)})</script>
+    <script>window.location.replace(${safeScriptTarget})</script>
   </head>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.vitepress/plugins/alias-redirects.ts around lines 11 - 21, The inline
redirect script in createRedirectHtml is unsafe because
JSON.stringify(targetPath) alone can still allow a closing "</script>" sequence
to break out of the script tag; update createRedirectHtml to sanitize the string
used inside the script by escaping any "</script>" occurrences (e.g. replace
"</script>" with "<\/script>") after JSON.stringify(targetPath) (and likewise
ensure escapedTarget used in attributes is properly HTML-escaped), so the
generated script and markup cannot be terminated by a malicious path value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.vitepress/plugins/alias-redirects.ts:
- Around line 98-107: Reject aliases containing dot-segments before joining them
into outDir: in toRedirectOutputPath, after computing normalizedAliasPath check
for any ".." path segment (e.g., normalizedAliasPath === '/..' or
normalizedAliasPath.includes('/..') or by splitting on '/' and detecting '..')
and return null (or otherwise refuse to create a redirect) if found to prevent
path traversal; apply the same validation to the other path-joining code in this
file that builds redirect output paths (the second occurrence around the other
redirect helper) so no alias can escape siteConfig.outDir.

---

Duplicate comments:
In @.vitepress/plugins/alias-redirects.ts:
- Around line 11-21: The inline redirect script in createRedirectHtml is unsafe
because JSON.stringify(targetPath) alone can still allow a closing "</script>"
sequence to break out of the script tag; update createRedirectHtml to sanitize
the string used inside the script by escaping any "</script>" occurrences (e.g.
replace "</script>" with "<\/script>") after JSON.stringify(targetPath) (and
likewise ensure escapedTarget used in attributes is properly HTML-escaped), so
the generated script and markup cannot be terminated by a malicious path value.
🪄 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

Run ID: 62231597-0a4f-477b-88b4-66e7b226caf4

📥 Commits

Reviewing files that changed from the base of the PR and between cab8b8a and c654461.

📒 Files selected for processing (2)
  • .vitepress/config.mts
  • .vitepress/plugins/alias-redirects.ts

Comment thread .vitepress/plugins/alias-redirects.ts Outdated
Comment thread .vitepress/plugins/alias-redirects.ts
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.

♻️ Duplicate comments (1)
.vitepress/plugins/alias-redirects.ts (1)

57-60: ⚠️ Potential issue | 🟠 Major

Reject . segments too.

path.join() normalizes the joined path, including . segments, so aliases like /./ or /docs/./faq/ still resolve inside outDir and can overwrite the root or a real page. The current helper only blocks ... (nodejs.org)

🛡️ Proposed fix
 function hasDotSegment(urlPath: string): boolean {
-  if (urlPath === '/..' || urlPath.includes('/../')) return true
-  return urlPath.split('/').some((segment) => segment === '..')
+  return urlPath.split('/').some((segment) => segment === '.' || segment === '..')
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.vitepress/plugins/alias-redirects.ts around lines 57 - 60, The helper
hasDotSegment currently only rejects '..' segments; update it to also reject
single-dot segments so paths containing '/./', '/.' or '/docs/./faq' are
considered invalid. Locate the hasDotSegment function and change its logic to
check segments for segment === '.' || segment === '..' (e.g., split on '/' and
test for either '.' or '..'), ensuring edge cases like a trailing '/.' or
occurrences anywhere in the path are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.vitepress/plugins/alias-redirects.ts:
- Around line 57-60: The helper hasDotSegment currently only rejects '..'
segments; update it to also reject single-dot segments so paths containing
'/./', '/.' or '/docs/./faq' are considered invalid. Locate the hasDotSegment
function and change its logic to check segments for segment === '.' || segment
=== '..' (e.g., split on '/' and test for either '.' or '..'), ensuring edge
cases like a trailing '/.' or occurrences anywhere in the path are caught.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a662704-9272-4c50-995b-1820e31a34f8

📥 Commits

Reviewing files that changed from the base of the PR and between c654461 and f68d715.

📒 Files selected for processing (1)
  • .vitepress/plugins/alias-redirects.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla: yes Indicates the PR's author has signed the cla-assistant.io CLA. do-not-merge/needs-kind Indicates a PR lacks a `kind/foo` label and requires one. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aliases do not function correctly

1 participant