108 lines
6.8 KiB
JavaScript
108 lines
6.8 KiB
JavaScript
#!/usr/bin/env node
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import process from "node:process";
|
|
|
|
export const MAP_PATH = "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/path-isolation-and-canonical-entry-map.json";
|
|
export const CODES = Object.freeze({ CURRENT_ALLOWED: 0, RETIRED_PATH_BLOCKED_WITH_REDIRECT: 78, ISOLATION_PATH_BLOCKED: 79, UNKNOWN_PATH_NO_GUESS: 80 });
|
|
export const CURRENT_PURPOSES = new Set(["PERSONA_RECOVERY", "CURRENT_SELECTION", "CURRENT_EXECUTION", "CANONICAL_WRITE", "SERVER_DEPLOYMENT"]);
|
|
|
|
function expandHome(value) {
|
|
return String(value || "").replace(/^~(?=\/|$)/, "/Users/bingshuolingdianyuanhe");
|
|
}
|
|
|
|
export function normal(value, cwd = process.cwd()) {
|
|
return path.resolve(cwd, expandHome(value));
|
|
}
|
|
|
|
function patternRegex(pattern) {
|
|
const escaped = expandHome(pattern).replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
return new RegExp(`^${escaped}(?:/.*)?$`);
|
|
}
|
|
|
|
function within(candidate, root) {
|
|
const target = normal(candidate), base = normal(root);
|
|
return target === base || target.startsWith(`${base}${path.sep}`);
|
|
}
|
|
|
|
export function loadMap(mapPath = MAP_PATH) {
|
|
const value = JSON.parse(fs.readFileSync(mapPath, "utf8"));
|
|
if (value?.map_id !== "PATH-ISOLATION-CANONICAL-ENTRY-001" || !value.physical_gate || !Array.isArray(value.retired_paths)) throw Error("PATH_GATE_MAP_INVALID");
|
|
return value;
|
|
}
|
|
|
|
function existingSymlinkComponent(candidate) {
|
|
let cursor = normal(candidate);
|
|
while (cursor !== path.dirname(cursor)) {
|
|
if (fs.existsSync(cursor) && fs.lstatSync(cursor).isSymbolicLink()) return cursor;
|
|
cursor = path.dirname(cursor);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function classifyPath(candidate, purpose, map = loadMap()) {
|
|
const resolved = normal(candidate);
|
|
const normalizedPurpose = String(purpose || "").toUpperCase();
|
|
if (!normalizedPurpose) return { allowed: false, code: "PURPOSE_REQUIRED", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved };
|
|
const isolationRoot = map.isolation.root;
|
|
if (within(resolved, isolationRoot)) return { allowed: false, code: "ISOLATION_PATH_BLOCKED", exit_code: CODES.ISOLATION_PATH_BLOCKED, resolved, history_root: isolationRoot };
|
|
const retired = map.retired_paths.find(item => within(resolved, item.path));
|
|
if (retired && !(retired.allowed_purposes || []).includes(normalizedPurpose)) {
|
|
return { allowed: false, code: "RETIRED_PATH_BLOCKED_WITH_REDIRECT", exit_code: CODES.RETIRED_PATH_BLOCKED_WITH_REDIRECT, resolved, retired_state: retired.state, redirect_to: retired.redirect_to, history: retired.history };
|
|
}
|
|
if (retired) return { allowed: true, code: "HISTORY_OR_BRANCH_ACCESS_ONLY", exit_code: CODES.CURRENT_ALLOWED, resolved, retired_state: retired.state, redirect_to: retired.redirect_to };
|
|
const branch = (map.host_branch_roots || []).find(pattern => patternRegex(pattern).test(resolved));
|
|
if (branch && CURRENT_PURPOSES.has(normalizedPurpose)) return { allowed: false, code: "HOST_BRANCH_BLOCKED_FOR_CURRENT_WITH_REDIRECT", exit_code: CODES.RETIRED_PATH_BLOCKED_WITH_REDIRECT, resolved, matched: branch, redirect_to: map.canonical_entries.repo_012 };
|
|
if (branch && normalizedPurpose === "BRANCH_WORK") return { allowed: true, code: "HOST_BRANCH_WORK_ALLOWED_NOT_CURRENT", exit_code: CODES.CURRENT_ALLOWED, resolved, matched: branch };
|
|
const canonical = Object.entries(map.canonical_entries).find(([, root]) => within(resolved, root));
|
|
if (canonical) {
|
|
const symlink = existingSymlinkComponent(resolved);
|
|
if (symlink) return { allowed: false, code: "CANONICAL_PATH_SYMLINK_BLOCKED", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved, symlink };
|
|
return { allowed: true, code: "CURRENT_CANONICAL_PATH", exit_code: CODES.CURRENT_ALLOWED, resolved, canonical_entry: canonical[0], canonical_root: canonical[1] };
|
|
}
|
|
const exactCurrent = Object.entries(map.current_ids || {}).find(([, value]) => within(resolved, value));
|
|
if (exactCurrent) return { allowed: true, code: "CURRENT_REGISTERED_PATH", exit_code: CODES.CURRENT_ALLOWED, resolved, current_id: exactCurrent[0] };
|
|
return { allowed: false, code: "UNKNOWN_PATH_NO_GUESS", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved };
|
|
}
|
|
|
|
export function resolveId(requested, map = loadMap()) {
|
|
const id = String(requested || "");
|
|
if (Object.hasOwn(map.current_ids || {}, id)) return { allowed: true, code: "CURRENT_ID", exit_code: 0, requested_id: id, canonical_id: id, path: map.current_ids[id] };
|
|
const retired = (map.retired_ids || []).find(item => item.id === id);
|
|
if (retired) return { allowed: false, code: "RETIRED_ID_BLOCKED_WITH_REDIRECT", exit_code: 78, requested_id: id, canonical_id: retired.redirect_to, path: map.current_ids[retired.redirect_to], retired_state: retired.state };
|
|
return { allowed: false, code: "UNKNOWN_ID_NO_GUESS", exit_code: 80, requested_id: id };
|
|
}
|
|
|
|
export function audit(map = loadMap()) {
|
|
const findings = [];
|
|
for (const [id, candidate] of Object.entries(map.current_ids || {})) {
|
|
const exists = fs.existsSync(candidate), symlink = exists && existingSymlinkComponent(candidate);
|
|
findings.push({ type: "CURRENT_ID", id, path: candidate, outcome: exists && !symlink ? "PASS" : "FAIL", error: !exists ? "CURRENT_PATH_MISSING" : (symlink ? "CURRENT_PATH_SYMLINK" : null) });
|
|
}
|
|
for (const item of map.retired_paths) {
|
|
const exists = fs.existsSync(item.path), isDirectory = exists && fs.lstatSync(item.path).isDirectory();
|
|
const historicalSelf = normal(item.history) === normal(item.path);
|
|
const blockedShape = !exists || !isDirectory || historicalSelf || (item.allowed_purposes || []).includes("HISTORY_READ");
|
|
findings.push({ type: "RETIRED_PATH", path: item.path, redirect_to: item.redirect_to, exists, is_directory: isDirectory, history: item.history, outcome: blockedShape ? "PASS" : "FAIL", error: blockedShape ? null : "RETIRED_DIRECTORY_STILL_DIRECTLY_OPENABLE" });
|
|
}
|
|
const failed = findings.filter(item => item.outcome !== "PASS");
|
|
return { schema: "guanghu.fifth-domain-path-gate-audit/v1", state: failed.length ? "PATH_GATE_AUDIT_FAIL" : "PATH_GATE_AUDIT_PASS", map_id: map.map_id, version: map.version, findings, failed_count: failed.length };
|
|
}
|
|
|
|
function valueAfter(args, flag) {
|
|
const index = args.indexOf(flag);
|
|
return index >= 0 ? args[index + 1] : undefined;
|
|
}
|
|
|
|
function emit(value) {
|
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
process.exitCode = value.exit_code ?? (value.state === "PATH_GATE_AUDIT_PASS" ? 0 : 1);
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
const [command, ...args] = process.argv.slice(2);
|
|
if (command === "guard") emit(classifyPath(valueAfter(args, "--path"), valueAfter(args, "--purpose")));
|
|
else if (command === "resolve-id") emit(resolveId(valueAfter(args, "--id")));
|
|
else if (command === "audit") emit(audit());
|
|
else { process.stderr.write("usage: fifth-domain-path-gate.mjs guard --path PATH --purpose PURPOSE | resolve-id --id ID | audit\n"); process.exitCode = 2; }
|
|
}
|