From 42b5cf887faaa77ceba1c09ac8b52e1d5f29b368 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sun, 11 Oct 2026 16:08:19 +0200 Subject: [PATCH] fix(scripts): allow the files.ts upload XHR in check-phase10 hygiene - network rule exempts only the line-anchored upload XHR in admin/src/api/files.ts - api-listing rule exempts only the exact path admin/src/api/files.ts - self-test plants an XHR elsewhere and an extra admin/src/api file --- scripts/check-phase10.sh | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/check-phase10.sh b/scripts/check-phase10.sh index bd4bfea..d158519 100755 --- a/scripts/check-phase10.sh +++ b/scripts/check-phase10.sh @@ -224,7 +224,9 @@ run_self_test() { done # The hygiene stage passes on a scratch copy of the tree and fails once a - # raw-HTML directive, a direct fetch or an app name is planted in it. + # raw-HTML directive, a direct fetch, an XMLHttpRequest outside the files.ts + # upload, an app name, a browser-storage call or an extra admin/src/api file + # is planted in it. local scratch scratch="$(mktemp -d)" trap 'rm -rf "$scratch"' RETURN @@ -240,8 +242,8 @@ run_self_test() { # Each plant is imported by a scratch test, so only its own rule can fire; # the refusal must name that rule. local plant want out - for plant in vhtml fetch appname storage; do - rm -rf "$scratch/admin/src/__plant" "$scratch/admin/tests/__plant.test.ts" + for plant in vhtml fetch appname storage xhr apifile; do + rm -rf "$scratch/admin/src/__plant" "$scratch/admin/tests/__plant.test.ts" "$scratch/admin/src/api/__plant.ts" mkdir -p "$scratch/admin/src/__plant" case "$plant" in vhtml) @@ -261,6 +263,15 @@ run_self_test() { printf 'export const keep = (v: string) => localStorage.setItem("token", v)\n' >"$scratch/admin/src/__plant/plant.ts" want="browser storage" ;; + xhr) + printf 'export const open = () => new XMLHttpRequest()\n' >"$scratch/admin/src/__plant/plant.ts" + want="direct fetch" + ;; + apifile) + printf 'export {}\n' >"$scratch/admin/src/api/__plant.ts" + printf "import '../src/api/__plant'\n" >"$scratch/admin/tests/__plant.test.ts" + want="unexpected files in admin/src/api" + ;; esac [[ -f "$scratch/admin/tests/__plant.test.ts" ]] || printf "import '../src/__plant/plant'\n" >"$scratch/admin/tests/__plant.test.ts" @@ -357,11 +368,14 @@ hygiene_checks() { grep -vE '^admin/src/components/form/fields/MarkdownField\.vue:[0-9]+:[[:space:]]*v-html="sanitizedHtml"[[:space:]]*$' || true)" [[ -z "$hits" ]] || fail "raw-HTML directive in admin/src: $hits" # All HTTP goes through the typed openapi-fetch client. + # Uploads in admin/src/api/files.ts use XMLHttpRequest because only XHR reports upload progress (12.2-04); that XHR sends X-Requested-With (T-12.2-32) and refreshes through client.ts; every other XHR, fetch or axios call is still refused. hits="$(cd "$tree" && grep -rnE '(^|[^A-Za-z0-9_.])fetch\(|XMLHttpRequest\(|axios' admin/src --include='*.ts' --include='*.vue' 2>/dev/null | - grep -v '^admin/src/api/client.ts:' || true)" + grep -v '^admin/src/api/client.ts:' | + grep -vE '^admin/src/api/files\.ts:[0-9]+:[[:space:]]*const request = new XMLHttpRequest\(\)[[:space:]]*$' || true)" [[ -z "$hits" ]] || fail "direct fetch outside admin/src/api/client.ts: $hits" - # admin/src/api holds the generated schema, the client and aliases only. - hits="$(cd "$tree" && find admin/src/api -type f ! -name schema.d.ts ! -name client.ts ! -name types.ts 2>/dev/null || true)" + # admin/src/api holds the generated schema, the client, the aliases and the + # FileRoutes adapters (files.ts, 12.2-04) only. + hits="$(cd "$tree" && find admin/src/api -type f ! -name schema.d.ts ! -name client.ts ! -name types.ts ! -path admin/src/api/files.ts 2>/dev/null || true)" [[ -z "$hits" ]] || fail "unexpected files in admin/src/api: $hits" hits="$(cd "$tree" && grep -nE '\binterface\b|=\s*\{|:\s*\{' admin/src/api/types.ts 2>/dev/null || true)" [[ -z "$hits" ]] || fail "admin/src/api/types.ts declares a shape instead of aliasing the generated schema: $hits"