diff --git a/apps/web/src/markdown-links.test.ts b/apps/web/src/markdown-links.test.ts index 9fc29613867..e63894d707e 100644 --- a/apps/web/src/markdown-links.test.ts +++ b/apps/web/src/markdown-links.test.ts @@ -127,6 +127,13 @@ describe("resolveMarkdownFileLinkTarget", () => { it("does not treat app routes as file links", () => { expect(resolveMarkdownFileLinkTarget("/chat/settings")).toBeNull(); }); + + it("does not treat device nodes and kernel state as file links", () => { + expect(resolveMarkdownFileLinkTarget("/dev/kvm")).toBeNull(); + expect(resolveMarkdownFileLinkTarget("/dev/null")).toBeNull(); + expect(resolveMarkdownFileLinkTarget("/proc/cpuinfo")).toBeNull(); + expect(resolveMarkdownFileLinkTarget("/sys/class/net/eth0")).toBeNull(); + }); }); describe("resolveInlineCodeFileLinkMeta", () => { @@ -152,6 +159,15 @@ describe("resolveInlineCodeFileLinkMeta", () => { expect(resolveInlineCodeFileLinkMeta("/chat/settings")).toBeNull(); }); + it("ignores device nodes and kernel state", () => { + expect(resolveInlineCodeFileLinkMeta("/dev/kvm", "/Users/julius/project")).toBeNull(); + expect(resolveInlineCodeFileLinkMeta("/dev/null", "/Users/julius/project")).toBeNull(); + expect(resolveInlineCodeFileLinkMeta("/proc/cpuinfo", "/Users/julius/project")).toBeNull(); + expect( + resolveInlineCodeFileLinkMeta("/sys/class/net/eth0", "/Users/julius/project"), + ).toBeNull(); + }); + it("links windows drive paths", () => { expect(resolveInlineCodeFileLinkMeta("C:\\Users\\mike\\project\\src\\main.ts")).toMatchObject({ basename: "main.ts", diff --git a/apps/web/src/markdown-links.ts b/apps/web/src/markdown-links.ts index a6dba941b8a..0616fbc46e3 100644 --- a/apps/web/src/markdown-links.ts +++ b/apps/web/src/markdown-links.ts @@ -10,7 +10,10 @@ const RELATIVE_FILE_NAME_PATTERN = /^[A-Za-z0-9._-]+\.[A-Za-z0-9_-]+(?::\d+){0,2 const POSITION_SUFFIX_PATTERN = /:\d+(?::\d+)?$/; const POSITION_ONLY_PATTERN = /^\d+(?::\d+)?$/; // Standard OS and dev-container roots; deliberately excludes app-route-ish -// prefixes like /app/ or /chat/ so SPA routes never read as files. +// prefixes like /app/ or /chat/ so SPA routes never read as files, and roots +// holding device nodes, kernel state, or boot images rather than editable +// files. Entries under an excluded root still link when they carry a file +// extension or a :line suffix. const POSIX_FILE_ROOT_PREFIXES = [ "/Users/", "/home/", @@ -28,11 +31,6 @@ const POSIX_FILE_ROOT_PREFIXES = [ "/lib/", "/lib64/", "/srv/", - "/dev/", - "/proc/", - "/sys/", - "/run/", - "/boot/", "/media/", "/workspace/", "/workspaces/",