fix: harden frontend dependency and env hygiene
This commit is contained in:
@@ -13,6 +13,10 @@ dist-ssr
|
|||||||
coverage
|
coverage
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
|
# Local runtime configuration
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|||||||
Generated
+4
-4
@@ -18,7 +18,7 @@
|
|||||||
"react-dom": "19.2.8",
|
"react-dom": "19.2.8",
|
||||||
"react-hook-form": "7.85.0",
|
"react-hook-form": "7.85.0",
|
||||||
"react-i18next": "16.3.5",
|
"react-i18next": "16.3.5",
|
||||||
"react-router": "7.9.6",
|
"react-router": "7.18.2",
|
||||||
"zod": "3.25.76"
|
"zod": "3.25.76"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -5816,9 +5816,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.9.6",
|
"version": "7.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
|
||||||
"integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==",
|
"integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookie": "^1.0.1",
|
"cookie": "^1.0.1",
|
||||||
|
|||||||
+3
-2
@@ -17,9 +17,10 @@
|
|||||||
"openapi:generate": "openapi-typescript src/shared/api/spec/openapi.json -o src/shared/api/generated/schema.d.ts",
|
"openapi:generate": "openapi-typescript src/shared/api/spec/openapi.json -o src/shared/api/generated/schema.d.ts",
|
||||||
"openapi:sync": "node scripts/openapi-sync.mjs",
|
"openapi:sync": "node scripts/openapi-sync.mjs",
|
||||||
"openapi:check": "node scripts/openapi-check.mjs",
|
"openapi:check": "node scripts/openapi-check.mjs",
|
||||||
|
"hygiene:check": "node scripts/repository-hygiene-check.mjs",
|
||||||
"knip": "knip",
|
"knip": "knip",
|
||||||
"deps": "depcruise src --config dependency-cruiser.cjs --output-type err-long",
|
"deps": "depcruise src --config dependency-cruiser.cjs --output-type err-long",
|
||||||
"verify": "npm run openapi:check && npm run typecheck && npm run lint && npm run test:run && npm run test:coverage && npm run knip && npm run deps && npm run build",
|
"verify": "npm run openapi:check && npm run hygiene:check && npm run typecheck && npm run lint && npm run test:run && npm run test:coverage && npm run knip && npm run deps && npm run build",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
"react-dom": "19.2.8",
|
"react-dom": "19.2.8",
|
||||||
"react-hook-form": "7.85.0",
|
"react-hook-form": "7.85.0",
|
||||||
"react-i18next": "16.3.5",
|
"react-i18next": "16.3.5",
|
||||||
"react-router": "7.9.6",
|
"react-router": "7.18.2",
|
||||||
"zod": "3.25.76"
|
"zod": "3.25.76"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { dirname, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
|
||||||
|
function git(args) {
|
||||||
|
return execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIgnored(file) {
|
||||||
|
try {
|
||||||
|
execFileSync("git", ["check-ignore", "--no-index", "-q", file], {
|
||||||
|
cwd: root,
|
||||||
|
stdio: "ignore",
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.status === 1) return false;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert(condition, message) {
|
||||||
|
if (!condition) throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const trackedEnvironmentFiles = git(["ls-files", "--", ".env", ".env.*"])
|
||||||
|
.split("\n")
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
assert(
|
||||||
|
JSON.stringify(trackedEnvironmentFiles) === JSON.stringify([".env.example"]),
|
||||||
|
`Only .env.example may be tracked; found: ${trackedEnvironmentFiles.join(", ") || "none"}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const file of [".env", ".env.local", ".env.development", ".env.test"]) {
|
||||||
|
assert(isIgnored(file), `Local environment file must be ignored: ${file}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!isIgnored(".env.example"), ".env.example must remain versionable");
|
||||||
|
|
||||||
|
console.log("Frontend repository hygiene verified");
|
||||||
Reference in New Issue
Block a user