chore(ci): add frontend boundary tripwire script
Grep-based tripwire flagging multi-type includeItemTypes literals in the Svelte frontend — the machine-detectable signature of the item-type taxonomy leaking into presentation. Wire it into the Gitea build-and-test workflow and a check:boundary package script. Motivated by docs/specs/scoped-search-boundary.md.
This commit is contained in:
@@ -49,6 +49,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
bun install
|
bun install
|
||||||
|
|
||||||
|
# Tripwire for domain-taxonomy leaks into the presentation layer (a
|
||||||
|
# multi-type includeItemTypes query defining a category in the frontend).
|
||||||
|
# See scripts/check-frontend-boundary.sh and
|
||||||
|
# docs/specs/scoped-search-boundary.md.
|
||||||
|
- name: Check frontend/backend boundary
|
||||||
|
run: bash scripts/check-frontend-boundary.sh
|
||||||
|
|
||||||
- name: Run frontend tests
|
- name: Run frontend tests
|
||||||
run: |
|
run: |
|
||||||
bunx svelte-kit sync
|
bunx svelte-kit sync
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"test:e2e:dev": "wdio run ./wdio.conf.ts --watch",
|
"test:e2e:dev": "wdio run ./wdio.conf.ts --watch",
|
||||||
"test:all": "./scripts/test-all.sh",
|
"test:all": "./scripts/test-all.sh",
|
||||||
"test:rust": "./scripts/test-rust.sh",
|
"test:rust": "./scripts/test-rust.sh",
|
||||||
|
"check:boundary": "bash scripts/check-frontend-boundary.sh",
|
||||||
"android:build": "./scripts/build-android.sh",
|
"android:build": "./scripts/build-android.sh",
|
||||||
"android:build:release": "./scripts/build-android.sh release",
|
"android:build:release": "./scripts/build-android.sh release",
|
||||||
"android:build:clean": "rm -rf node_modules/.vite dist .svelte-kit .next build target src-tauri/target && bun install && bun run build",
|
"android:build:clean": "rm -rf node_modules/.vite dist .svelte-kit .next build target src-tauri/target && bun install && bun run build",
|
||||||
|
|||||||
Executable
+85
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Boundary tripwire: flag domain-taxonomy leaks in the Svelte frontend.
|
||||||
|
#
|
||||||
|
# The project rule (CLAUDE.md, docs/architecture/02-svelte-frontend.md) is that
|
||||||
|
# the frontend is presentation-only and the Rust backend owns domain logic —
|
||||||
|
# including Jellyfin's item-type *taxonomy* (what the category "Music" means as a
|
||||||
|
# set of item types). See docs/specs/scoped-search-boundary.md for the incident
|
||||||
|
# that motivated this check.
|
||||||
|
#
|
||||||
|
# ⚠️ This is a TRIPWIRE, NOT A PROOF. A grep cannot distinguish taxonomy-as-policy
|
||||||
|
# (a leak) from taxonomy-as-display (legitimate: "is this a music card?"). It
|
||||||
|
# targets the one machine-detectable signature of the leak class — a *query* that
|
||||||
|
# names a multi-type category — and defers everything subtler to the human
|
||||||
|
# spec-review checklist (docs/specs/SPEC-REVIEW-CHECKLIST.md). A clean run here
|
||||||
|
# does not mean the boundary is respected; it means the crudest violation isn't
|
||||||
|
# present.
|
||||||
|
#
|
||||||
|
# What it flags: an `includeItemTypes: [ ... , ... ]` array literal with two or
|
||||||
|
# more types — i.e. the frontend deciding that a *category* maps to a *set* of
|
||||||
|
# Jellyfin types, which is domain knowledge the backend should own. Single-type
|
||||||
|
# query arrays (`includeItemTypes: ["Movie"]`) are a page saying "I show movies"
|
||||||
|
# and are allowed. Type *inspection* (`item.type === "Audio"`) is display logic
|
||||||
|
# and is not matched.
|
||||||
|
#
|
||||||
|
# Escaping a genuine exception: add the file+reason to the ALLOWLIST below.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Files permitted to contain a multi-type includeItemTypes query, with the reason.
|
||||||
|
# Keep this SHORT. A growing allowlist means the boundary is eroding — that is a
|
||||||
|
# signal to push taxonomy into Rust, not to keep appending here.
|
||||||
|
ALLOWLIST=(
|
||||||
|
# "Things a person appeared in" is arguably taxonomy, but it is a fixed
|
||||||
|
# two-type filmography query with no category-configuration behind it. Tracked
|
||||||
|
# as acceptable pending any person-scope work; revisit if it grows.
|
||||||
|
"src/lib/components/library/PersonDetailView.svelte"
|
||||||
|
)
|
||||||
|
|
||||||
|
is_allowed() {
|
||||||
|
local file="$1"
|
||||||
|
for allowed in "${ALLOWLIST[@]}"; do
|
||||||
|
[[ "$file" == "$allowed" ]] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Multi-element includeItemTypes array: `includeItemTypes: [ <x> , <y> ... ]`.
|
||||||
|
# The comma inside the brackets is what makes it multi-type.
|
||||||
|
PATTERN='includeItemTypes:[[:space:]]*\[[^]]*,[^]]*\]'
|
||||||
|
|
||||||
|
echo "🔎 Checking frontend for domain-taxonomy leaks (multi-type query arrays)…"
|
||||||
|
|
||||||
|
# Collect hits, excluding tests and the allowlist.
|
||||||
|
violations=""
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
file="${line%%:*}"
|
||||||
|
case "$file" in
|
||||||
|
*.test.*) continue ;;
|
||||||
|
esac
|
||||||
|
if is_allowed "$file"; then
|
||||||
|
echo " ⏭️ allowlisted: $line"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
violations+="$line"$'\n'
|
||||||
|
done < <(grep -rInE "$PATTERN" src/ 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [[ -n "$violations" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "❌ Frontend boundary violation: a multi-type includeItemTypes query defines"
|
||||||
|
echo " a category in the presentation layer. That taxonomy belongs in Rust —"
|
||||||
|
echo " send an opaque scope and let the backend expand it to item types."
|
||||||
|
echo " See docs/specs/scoped-search-boundary.md and CLAUDE.md."
|
||||||
|
echo ""
|
||||||
|
echo "$violations" | sed 's/^/ /'
|
||||||
|
echo " If this is a genuine exception, add the file + reason to ALLOWLIST in"
|
||||||
|
echo " scripts/check-frontend-boundary.sh — but prefer moving it to Rust."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ No multi-type taxonomy queries in the frontend."
|
||||||
|
echo " (Reminder: this is a tripwire, not a proof — the spec-review checklist is"
|
||||||
|
echo " the real gate for subtler leaks.)"
|
||||||
Reference in New Issue
Block a user