11import { describe , expect , it } from "vitest" ;
2- import { execSync } from "node:child_process" ;
2+ import { execFileSync } from "node:child_process" ;
33import path from "node:path" ;
44
55const REPO_ROOT = path . resolve ( __dirname , "../../../.." ) ;
@@ -8,20 +8,45 @@ describe("Railway GraphQL host unification", () => {
88 it ( "no source file references backboard.railway.com (must be .app)" , ( ) => {
99 // grep across showcase/ and .github/workflows/. Use -F (literal) so
1010 // the dot in the pattern is not regex-interpreted. The test file
11- // itself contains the forbidden literal; exclude it via --glob.
12- // Also exclude two files that legitimately reference the deprecated
13- // host in documentation/negative-assertion form (no functional use):
11+ // itself contains the forbidden literal; exclude it via git pathspec
12+ // `:(exclude)` magic. Also exclude two files that legitimately
13+ // reference the deprecated host in documentation/negative-assertion
14+ // form (no functional use):
1415 // - railway-graphql.ts JSDoc explains the deprecated .com endpoint
1516 // - railway-graphql.test.ts asserts the endpoint is NOT .com
17+ // Use --untracked so a newly-added (not-yet-committed) file that
18+ // reintroduces the forbidden host still trips the guard. Use
19+ // execFileSync with an args array so REPO_ROOT is not shell-parsed.
1620 let out = "" ;
1721 try {
18- out = execSync (
19- `git -C ${ REPO_ROOT } grep -nF "backboard.railway.com" -- showcase ':(exclude)showcase/scripts/lib/__tests__/railway-graphql.scan.test.ts' ':(exclude)showcase/scripts/lib/railway-graphql.ts' ':(exclude)showcase/scripts/lib/__tests__/railway-graphql.test.ts' .github/workflows` ,
22+ out = execFileSync (
23+ "git" ,
24+ [
25+ "-C" ,
26+ REPO_ROOT ,
27+ "grep" ,
28+ "--untracked" ,
29+ "-nF" ,
30+ "backboard.railway.com" ,
31+ "--" ,
32+ "showcase" ,
33+ ":(exclude)showcase/scripts/lib/__tests__/railway-graphql.scan.test.ts" ,
34+ ":(exclude)showcase/scripts/lib/railway-graphql.ts" ,
35+ ":(exclude)showcase/scripts/lib/__tests__/railway-graphql.test.ts" ,
36+ ".github/workflows" ,
37+ ] ,
2038 { encoding : "utf-8" } ,
2139 ) ;
22- } catch {
23- // git grep exits 1 when no matches — that's the success case.
24- out = "" ;
40+ } catch ( err ) {
41+ // git grep exits 1 when no matches — that's the clean-miss success
42+ // case. Any other exit status (git missing, bad cwd, pathspec
43+ // syntax error, etc.) must fail loud rather than silently pass.
44+ const status = ( err as { status ?: number } ) . status ;
45+ if ( status === 1 ) {
46+ out = "" ;
47+ } else {
48+ throw err ;
49+ }
2550 }
2651 expect ( out ) . toBe ( "" ) ;
2752 } ) ;
0 commit comments