fix(ui): keep the UI security audit green on the Atlas branch

Three findings scripts/security-ui.sh raised on this branch, none new to
the merge:

- The analytics pattern matched the English word "plausible" in the
  wiki text, and `\s` inside an ERE bracket is a literal backslash and
  's', which cut every localhost URL at its first 's' and then failed
  the allowlist. Same two regex fixes as on the stacked branch
  (plausible.io; [:space:]).
- graph-ui/src/lib/rationale.ts carried a literal GitHub URL in a doc
  comment, and its test built forge links from a literal GitHub base.
  The audit forbids external URLs anywhere in the UI source, tests
  included; the comment now describes the shape, and the test composes
  the same links from a loopback base (the composition is
  host-agnostic).

Audit passes; rationale tests 5 passed.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel
2026-09-06 03:05:40 +02:00
parent da7235ab39
commit a44732b6f8
3 changed files with 10 additions and 8 deletions
+5 -3
View File
@@ -35,12 +35,14 @@ describe("linkifyRefs", () => {
describe("forge URLs", () => {
it("builds commit and issue/PR URLs from the remote base", () => {
const remote = "https://github.com/DeusData/codebase-memory-mcp";
/* A loopback base: the composition is host-agnostic, and the UI
* security audit forbids literal external URLs in this tree. */
const remote = "http://localhost:9749/DeusData/codebase-memory-mcp";
expect(commitUrl(remote, "617a4b14")).toBe(
"https://github.com/DeusData/codebase-memory-mcp/commit/617a4b14",
"http://localhost:9749/DeusData/codebase-memory-mcp/commit/617a4b14",
);
expect(refUrl(remote, 123)).toBe(
"https://github.com/DeusData/codebase-memory-mcp/issues/123",
"http://localhost:9749/DeusData/codebase-memory-mcp/issues/123",
);
});
});
+3 -3
View File
@@ -13,9 +13,9 @@ export interface SymbolCommit {
export interface SymbolHistoryPayload {
max_commits: number;
/* Normalized https forge base (e.g. "https://github.com/owner/repo");
* absent when the repo has no usable remote — then hashes render as
* plain text and #refs stay unlinked. */
/* Normalized https forge base (scheme, host, owner and repository, no
* trailing slash); absent when the repo has no usable remote — then
* hashes render as plain text and #refs stay unlinked. */
remote_url?: string;
available: boolean;
/* Newest first, at most max_commits; absent on the unavailable paths. */
+2 -2
View File
@@ -51,7 +51,7 @@ else
if find "$UI_DIR" -type f \( -name '*.js' -o -name '*.ts' -o -name '*.tsx' -o -name '*.css' \) -exec grep -lE 'https?://' {} \; 2>/dev/null | head -20 > "$SEC_TMPDIR/urls"; then
while IFS= read -r file; do
relfile="${file#"$ROOT/"}"
grep -onE 'https?://[^\s"'"'"')]+' "$file" 2>/dev/null | while IFS=: read -r lineno url; do
grep -onE 'https?://[^[:space:]"'"'"')]+' "$file" 2>/dev/null | while IFS=: read -r lineno url; do
case "$url" in
http://localhost*|http://127.0.0.1*|https://localhost*|https://127.0.0.1*)
;; # OK — local dev/runtime
@@ -85,7 +85,7 @@ else
# A3: No tracking/analytics
echo " Checking for tracking/analytics..."
TRACKING='google-analytics|gtag|mixpanel|segment\.com|hotjar|sentry\.io|plausible|posthog'
TRACKING='google-analytics|gtag|mixpanel|segment\.com|hotjar|sentry\.io|plausible\.io|posthog'
if find "$UI_DIR" -type f \( -name '*.js' -o -name '*.ts' -o -name '*.tsx' -o -name '*.html' \) \
-exec grep -lE "$TRACKING" {} \; 2>/dev/null > "$SEC_TMPDIR/track"; then
while IFS= read -r file; do