@tuent/sentinel 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SECURITY_MODEL.md +9 -0
- package/dist/Sentinel-4QKPFHTI.js +10 -0
- package/dist/{Sentinel-xFCyXH45.d.ts → Sentinel-DT0IyGQi.d.ts} +127 -9
- package/dist/{chunk-PDWWRZXF.js → chunk-2IPSTUNH.js} +18 -7
- package/dist/chunk-B6S2PBS4.js +47 -0
- package/dist/{chunk-QIYQWOLO.js → chunk-FIEIGBYL.js} +387 -242
- package/dist/{chunk-L4R3LPJS.js → chunk-HRI2Y326.js} +119 -35
- package/dist/{chunk-GRN5P3H2.js → chunk-I2FVDDSG.js} +242 -94
- package/dist/{chunk-WLIDSTS4.js → chunk-KWZ7JKKO.js} +221 -27
- package/dist/{chunk-FWIISAZZ.js → chunk-LTBVWF5H.js} +201 -80
- package/dist/chunk-TKAKHSZ3.js +1 -0
- package/dist/cli.js +33 -35
- package/dist/gateway/index.d.ts +20 -1
- package/dist/gateway/index.js +4 -4
- package/dist/gatewayDaemon.js +38 -16
- package/dist/index.d.ts +31 -19
- package/dist/index.js +9 -8
- package/dist/logAdapter-WM43W3S7.js +7 -0
- package/dist/{mcpAdapter-R47GX2P3.js → mcpAdapter-WYAXUE7T.js} +2 -2
- package/dist/{policyLoader-KZL2U4M2.js → policyLoader-XX6BQXNB.js} +8 -4
- package/package.json +1 -1
- package/dist/Sentinel-XMSJE4DZ.js +0 -10
- package/dist/chunk-FMZWHT4M.js +0 -20
- package/dist/logAdapter-IB6ZDEV2.js +0 -7
|
@@ -3,9 +3,8 @@ import {
|
|
|
3
3
|
} from "./chunk-B5QKJHSV.js";
|
|
4
4
|
import {
|
|
5
5
|
discoverPolicy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-B6S2PBS4.js";
|
|
7
7
|
import {
|
|
8
|
-
DEFAULT_FORBIDDEN_PATTERNS,
|
|
9
8
|
FORBIDDEN_BASENAMES,
|
|
10
9
|
classifyDeny,
|
|
11
10
|
isPositionallySafeMention,
|
|
@@ -14,16 +13,18 @@ import {
|
|
|
14
13
|
scanBashCommand,
|
|
15
14
|
scanContentForForbiddenBasenames,
|
|
16
15
|
scanGlobPattern,
|
|
17
|
-
tokenizePaths
|
|
18
|
-
|
|
16
|
+
tokenizePaths,
|
|
17
|
+
unionWithDefaultForbiddenPatterns
|
|
18
|
+
} from "./chunk-FIEIGBYL.js";
|
|
19
19
|
import {
|
|
20
|
+
DEFAULT_FORBIDDEN_PATTERNS,
|
|
20
21
|
loadPolicy,
|
|
21
22
|
policyToConfig,
|
|
22
23
|
policyToRole
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-KWZ7JKKO.js";
|
|
24
25
|
|
|
25
26
|
// src/gateway/workspaceRouter.ts
|
|
26
|
-
import { resolve, dirname } from "path";
|
|
27
|
+
import { resolve, dirname, sep } from "path";
|
|
27
28
|
|
|
28
29
|
// src/mergeRoles.ts
|
|
29
30
|
function isWithinActiveHours(hour, range) {
|
|
@@ -251,15 +252,35 @@ async function resolveWorkspace(cwd, home) {
|
|
|
251
252
|
const policyPath = discoverPolicy(start, home);
|
|
252
253
|
let root = start;
|
|
253
254
|
let workspaceRole = null;
|
|
255
|
+
const warnings = [];
|
|
254
256
|
if (policyPath) {
|
|
255
257
|
const policy = await loadPolicy(policyPath);
|
|
258
|
+
const policyDir = dirname(resolve(policyPath));
|
|
259
|
+
root = policyDir;
|
|
256
260
|
const repoRoot = policyToConfig(policy).repo?.root;
|
|
257
|
-
|
|
261
|
+
if (repoRoot) {
|
|
262
|
+
const declared = resolve(policyDir, repoRoot);
|
|
263
|
+
const homeAbs = resolve(home);
|
|
264
|
+
const declaredPrefix = declared.endsWith(sep) ? declared : declared + sep;
|
|
265
|
+
const containsPolicy = policyDir === declared || policyDir.startsWith(declaredPrefix);
|
|
266
|
+
const aboveHome = declared !== homeAbs && homeAbs.startsWith(declaredPrefix);
|
|
267
|
+
if (!containsPolicy) {
|
|
268
|
+
warnings.push(
|
|
269
|
+
`repo.root "${repoRoot}" (resolves to "${declared}") does not contain the policy file "${policyPath}" \u2014 anchoring to the policy's own directory "${policyDir}" instead`
|
|
270
|
+
);
|
|
271
|
+
} else if (aboveHome) {
|
|
272
|
+
warnings.push(
|
|
273
|
+
`repo.root "${repoRoot}" (resolves to "${declared}") reaches above the home directory \u2014 anchoring to the policy's own directory "${policyDir}" instead`
|
|
274
|
+
);
|
|
275
|
+
} else {
|
|
276
|
+
root = declared;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
258
279
|
workspaceRole = policyToRole(policy);
|
|
259
280
|
}
|
|
260
281
|
return {
|
|
261
282
|
ok: true,
|
|
262
|
-
resolution: { root, agentId: deriveAgentId(root), policyPath, workspaceRole }
|
|
283
|
+
resolution: { root, agentId: deriveAgentId(root), policyPath, workspaceRole, warnings }
|
|
263
284
|
};
|
|
264
285
|
}
|
|
265
286
|
function effectiveRole(ceiling, workspaceRole) {
|
|
@@ -347,11 +368,11 @@ var TranslatorRegistry = class {
|
|
|
347
368
|
|
|
348
369
|
// src/gateway/runtimeConstructionResolvers.ts
|
|
349
370
|
var MAX_RECURSION_DEPTH = 3;
|
|
350
|
-
var INTERPRETER_RE = /\b(?:python
|
|
371
|
+
var INTERPRETER_RE = /\b(?:python|node|ruby|perl|php)[0-9.]*\s+(?:\S+\s+)*?-[cer]/;
|
|
351
372
|
var NESTED_ENCODING_RE = /chr\(\d+\)|String\.fromCharCode|\\x[0-9a-fA-F]{2}|\\[0-7]{1,3}|printf\s/;
|
|
352
373
|
var PRINTF_HEX_RE = /printf\s+['"]?[^'"]*\\x[0-9a-fA-F]{2}/;
|
|
353
374
|
var PRINTF_OCT_RE = /printf\s+['"]?[^'"]*\\[0-7]{1,3}/;
|
|
354
|
-
var B1_CONTEXT_RE = /(?:\bbase64\s+(
|
|
375
|
+
var B1_CONTEXT_RE = /(?:\bbase64\s+(?:--decode\b|-[a-zA-Z]*[dD][a-zA-Z]*\b)|\bopenssl\s+(?:enc\s+)?(?:-?base64\s+(?:-\w+\s+)*-d|-d\s+(?:-\w+\s+)*-?base64)\b)/;
|
|
355
376
|
var ECHO_E_HEX_RE = /\becho\s+(?:-\w+\s+)*-\w*e\w*\b[^|;&\n]*\\x[0-9a-fA-F]{2}/;
|
|
356
377
|
var ANSI_C_QUOTE_HEX_RE = /\$'[^']*\\x[0-9a-fA-F]{2}/;
|
|
357
378
|
var ANSI_C_QUOTE_OCT_RE = /\$'[^']*\\[0-7]{1,3}/;
|
|
@@ -786,23 +807,39 @@ function mcpVerbIsMutating(toolName) {
|
|
|
786
807
|
const tokens = seg.split(/[_-]/).filter((t) => t.length > 0);
|
|
787
808
|
return tokens.some((t) => MCP_MUTATING_VERBS.some((v) => t.startsWith(v)));
|
|
788
809
|
}
|
|
810
|
+
var MCP_MAX_DEPTH = 6;
|
|
811
|
+
var MCP_MAX_NODES = 1e3;
|
|
812
|
+
function collectMcpStrings(value, depth, state) {
|
|
813
|
+
if (state.nodes >= MCP_MAX_NODES) {
|
|
814
|
+
state.truncated = true;
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
state.nodes++;
|
|
818
|
+
if (typeof value === "string") {
|
|
819
|
+
if (value.length > 0) state.strings.push(value);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
if (value === null || typeof value !== "object") return;
|
|
823
|
+
if (depth >= MCP_MAX_DEPTH) {
|
|
824
|
+
state.truncated = true;
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
828
|
+
for (const child of children) collectMcpStrings(child, depth + 1, state);
|
|
829
|
+
}
|
|
789
830
|
function extractMcpTargets(toolName, toolInput) {
|
|
790
831
|
const targets = [toolName];
|
|
791
832
|
const keys = Object.keys(toolInput);
|
|
792
|
-
|
|
793
|
-
for (const key of keys)
|
|
794
|
-
|
|
795
|
-
if (typeof value !== "string" || value.length === 0) continue;
|
|
796
|
-
extractedStrings++;
|
|
833
|
+
const state = { strings: [], nodes: 0, truncated: false };
|
|
834
|
+
for (const key of keys) collectMcpStrings(toolInput[key], 1, state);
|
|
835
|
+
for (const value of state.strings) {
|
|
797
836
|
targets.push(value);
|
|
798
837
|
const resolved = runResolverPipeline(value);
|
|
799
|
-
for (const r of resolved)
|
|
800
|
-
targets.push(r);
|
|
801
|
-
}
|
|
838
|
+
for (const r of resolved) targets.push(r);
|
|
802
839
|
}
|
|
803
840
|
return {
|
|
804
841
|
targets,
|
|
805
|
-
unextractable: keys.length > 0 &&
|
|
842
|
+
unextractable: keys.length > 0 && (state.strings.length === 0 || state.truncated),
|
|
806
843
|
mutating: mcpVerbIsMutating(toolName)
|
|
807
844
|
};
|
|
808
845
|
}
|
|
@@ -1016,17 +1053,25 @@ var ClaudeCodeTranslator = class {
|
|
|
1016
1053
|
};
|
|
1017
1054
|
|
|
1018
1055
|
// src/gateway/grepRewriter.ts
|
|
1056
|
+
function toRelativeExclusionGlob(pattern) {
|
|
1057
|
+
return pattern.startsWith("/") ? "**" + pattern : pattern;
|
|
1058
|
+
}
|
|
1019
1059
|
function buildGrepExclusions(forbiddenPatterns) {
|
|
1020
1060
|
const flags = [];
|
|
1021
1061
|
for (const pattern of forbiddenPatterns) {
|
|
1022
|
-
flags.push("--glob", `!${pattern}`);
|
|
1062
|
+
flags.push("--glob", `!${toRelativeExclusionGlob(pattern)}`);
|
|
1023
1063
|
}
|
|
1024
1064
|
return flags;
|
|
1025
1065
|
}
|
|
1026
1066
|
function isPathItselfForbidden(searchPath, forbiddenPatterns) {
|
|
1027
1067
|
const matched = [];
|
|
1028
1068
|
for (const pattern of forbiddenPatterns) {
|
|
1029
|
-
if (matchGlobInsensitive(pattern, searchPath))
|
|
1069
|
+
if (matchGlobInsensitive(pattern, searchPath) || // A directory-glob (`…/**`, e.g. `**/.ssh/**` or `/etc/**`) does NOT match
|
|
1070
|
+
// the bare directory itself — the trailing `/.*` requires a char after the
|
|
1071
|
+
// slash, so `matchGlob('**/.ssh/**', '/home/u/.ssh')` is false. When the
|
|
1072
|
+
// SEARCH PATH *is* the forbidden directory, treat it as forbidden so it
|
|
1073
|
+
// routes to DENY (no rewrite), not MODIFY.
|
|
1074
|
+
pattern.endsWith("/**") && matchGlobInsensitive(pattern.slice(0, -3), searchPath)) {
|
|
1030
1075
|
matched.push(pattern);
|
|
1031
1076
|
}
|
|
1032
1077
|
}
|
|
@@ -1044,7 +1089,6 @@ function buildModifiedGrepInput(originalInput, exclusions) {
|
|
|
1044
1089
|
import { timingSafeEqual } from "crypto";
|
|
1045
1090
|
var DEFAULT_PORT = 7847;
|
|
1046
1091
|
var MAX_BODY_SIZE = 1024 * 1024;
|
|
1047
|
-
var GATEWAY_VERSION = "0.1.0";
|
|
1048
1092
|
function isLoopbackAddress(addr) {
|
|
1049
1093
|
if (!addr) return false;
|
|
1050
1094
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1" || addr.startsWith("127.");
|
|
@@ -1101,6 +1145,9 @@ var SentinelGateway = class {
|
|
|
1101
1145
|
releaseToken;
|
|
1102
1146
|
/** Item D (F-8): disposition for unknown (non-MCP, unrecognized) tool names. */
|
|
1103
1147
|
unknownTools;
|
|
1148
|
+
/** Daemon-staleness build identity (content hash of the launched-from entry),
|
|
1149
|
+
* reported via /health. "unknown" when not supplied by the launcher. */
|
|
1150
|
+
buildId;
|
|
1104
1151
|
server = null;
|
|
1105
1152
|
running = false;
|
|
1106
1153
|
signalHandlersInstalled = false;
|
|
@@ -1116,6 +1163,7 @@ var SentinelGateway = class {
|
|
|
1116
1163
|
this.home = options.home ?? "";
|
|
1117
1164
|
this.releaseToken = options.releaseToken ?? null;
|
|
1118
1165
|
this.unknownTools = options.unknownTools ?? "warn";
|
|
1166
|
+
this.buildId = options.buildId ?? "unknown";
|
|
1119
1167
|
const internal = options;
|
|
1120
1168
|
if (internal.registry) {
|
|
1121
1169
|
this.registry = internal.registry;
|
|
@@ -1235,7 +1283,11 @@ var SentinelGateway = class {
|
|
|
1235
1283
|
const snap = this.telemetry.getSnapshot();
|
|
1236
1284
|
this.sendJson(res, 200, {
|
|
1237
1285
|
status: "running",
|
|
1238
|
-
|
|
1286
|
+
// Daemon-staleness build identity (content hash of the launched-from
|
|
1287
|
+
// entry). Replaces the former hardcoded GATEWAY_VERSION, which had
|
|
1288
|
+
// drifted from package.json and would have mismatched spuriously.
|
|
1289
|
+
// session-start compares this to the current on-disk entry hash.
|
|
1290
|
+
buildId: this.buildId,
|
|
1239
1291
|
uptime: snap.uptime_seconds
|
|
1240
1292
|
});
|
|
1241
1293
|
return;
|
|
@@ -1401,6 +1453,9 @@ var SentinelGateway = class {
|
|
|
1401
1453
|
return { ok: false, finding };
|
|
1402
1454
|
}
|
|
1403
1455
|
const { root, agentId, workspaceRole } = resolved.resolution;
|
|
1456
|
+
for (const w of resolved.resolution.warnings) {
|
|
1457
|
+
console.warn(`[SENTINEL GATEWAY] workspace-resolution warning (${agentId}): ${w}`);
|
|
1458
|
+
}
|
|
1404
1459
|
const ceiling = this.operatorCeiling;
|
|
1405
1460
|
if (!ceiling) {
|
|
1406
1461
|
const check = {
|
|
@@ -1427,7 +1482,24 @@ var SentinelGateway = class {
|
|
|
1427
1482
|
name: agentId
|
|
1428
1483
|
});
|
|
1429
1484
|
this.sentinel.touchAgent(agentId);
|
|
1430
|
-
return { ok: true, agentId };
|
|
1485
|
+
return { ok: true, agentId, effectiveRole: merged.role };
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Forbidden-pattern list for ONE request: the gateway's construction-time
|
|
1489
|
+
* list unioned with the request's merged-role patterns (operator-ceiling ∩
|
|
1490
|
+
* workspace yaml). Without this, a workspace's custom forbid targets were
|
|
1491
|
+
* enforced by the role validator inside wrap() but never reached the
|
|
1492
|
+
* gateway's own bash-L1 / Grep layers, which checked only the static list.
|
|
1493
|
+
* Normalization is idempotent (the chokepoint globstar-prepend).
|
|
1494
|
+
*/
|
|
1495
|
+
patternsForRequest(effectiveRole2) {
|
|
1496
|
+
if (!effectiveRole2?.forbiddenTargetPatterns?.length) return this.forbiddenPatterns;
|
|
1497
|
+
return [
|
|
1498
|
+
.../* @__PURE__ */ new Set([
|
|
1499
|
+
...this.forbiddenPatterns,
|
|
1500
|
+
...effectiveRole2.forbiddenTargetPatterns.map(normalizeForbiddenPattern)
|
|
1501
|
+
])
|
|
1502
|
+
];
|
|
1431
1503
|
}
|
|
1432
1504
|
async handlePreToolUse(body, res, translator) {
|
|
1433
1505
|
let payload;
|
|
@@ -1443,6 +1515,7 @@ var SentinelGateway = class {
|
|
|
1443
1515
|
return;
|
|
1444
1516
|
}
|
|
1445
1517
|
let routingId = this.agentId;
|
|
1518
|
+
let requestForbiddenPatterns = this.forbiddenPatterns;
|
|
1446
1519
|
if (this.workspaceIsolation) {
|
|
1447
1520
|
const routed = await this.resolveBPathRouting(
|
|
1448
1521
|
event.metadata?.cwd,
|
|
@@ -1460,6 +1533,7 @@ var SentinelGateway = class {
|
|
|
1460
1533
|
}
|
|
1461
1534
|
routingId = routed.agentId;
|
|
1462
1535
|
event.agentId = routingId;
|
|
1536
|
+
requestForbiddenPatterns = this.patternsForRequest(routed.effectiveRole);
|
|
1463
1537
|
}
|
|
1464
1538
|
if (event.metadata?._unknownTool === "true") {
|
|
1465
1539
|
const unknownName = event.metadata.ccToolName ?? event.primaryTarget;
|
|
@@ -1532,7 +1606,7 @@ var SentinelGateway = class {
|
|
|
1532
1606
|
let matchedPath = null;
|
|
1533
1607
|
let matchedPattern = null;
|
|
1534
1608
|
for (const tokenPath of allTokenPaths) {
|
|
1535
|
-
for (const pattern of
|
|
1609
|
+
for (const pattern of requestForbiddenPatterns) {
|
|
1536
1610
|
if (matchGlobInsensitive(pattern, tokenPath)) {
|
|
1537
1611
|
matchedPath = tokenPath;
|
|
1538
1612
|
matchedPattern = pattern;
|
|
@@ -1548,6 +1622,7 @@ var SentinelGateway = class {
|
|
|
1548
1622
|
unparseable: anyUnparseable,
|
|
1549
1623
|
hasDangerousConstruct: anyDangerousConstruct
|
|
1550
1624
|
});
|
|
1625
|
+
const targetKey = matchedPath ?? `l2:${[...new Set(allL2Hits)].sort().join(",")}`;
|
|
1551
1626
|
const finding = {
|
|
1552
1627
|
severity: "HIGH",
|
|
1553
1628
|
kind: "actionable",
|
|
@@ -1565,7 +1640,8 @@ var SentinelGateway = class {
|
|
|
1565
1640
|
timestamp: event.timestamp,
|
|
1566
1641
|
decision: "deny",
|
|
1567
1642
|
mentionOnly,
|
|
1568
|
-
dedupKey: event.primaryTarget
|
|
1643
|
+
dedupKey: event.primaryTarget,
|
|
1644
|
+
targetKey
|
|
1569
1645
|
};
|
|
1570
1646
|
await this.sentinel.handleGatewayDeny(routingId, finding);
|
|
1571
1647
|
this.telemetry.recordToolCall(event.action, "pre", "blocked", 0);
|
|
@@ -1592,7 +1668,9 @@ var SentinelGateway = class {
|
|
|
1592
1668
|
decision: "deny",
|
|
1593
1669
|
// A resolved path-glob hit is a file target — never a mention.
|
|
1594
1670
|
mentionOnly: false,
|
|
1595
|
-
dedupKey: event.primaryTarget
|
|
1671
|
+
dedupKey: event.primaryTarget,
|
|
1672
|
+
// F-5a: the resolved forbidden path IS the target identity here.
|
|
1673
|
+
targetKey: matchedPath
|
|
1596
1674
|
};
|
|
1597
1675
|
await this.sentinel.handleGatewayDeny(routingId, finding);
|
|
1598
1676
|
this.telemetry.recordToolCall(event.action, "pre", "blocked", 0);
|
|
@@ -1710,7 +1788,7 @@ var SentinelGateway = class {
|
|
|
1710
1788
|
if (ccToolName === "Grep") {
|
|
1711
1789
|
const toolInput = parsedPayload.tool_input ?? {};
|
|
1712
1790
|
const searchPath = typeof toolInput.path === "string" && toolInput.path.length > 0 ? toolInput.path : parsedPayload.cwd ?? ".";
|
|
1713
|
-
const pathCheck = isPathItselfForbidden(searchPath,
|
|
1791
|
+
const pathCheck = isPathItselfForbidden(searchPath, requestForbiddenPatterns);
|
|
1714
1792
|
if (pathCheck.forbidden) {
|
|
1715
1793
|
const finding2 = {
|
|
1716
1794
|
severity: "HIGH",
|
|
@@ -1735,7 +1813,7 @@ var SentinelGateway = class {
|
|
|
1735
1813
|
this.sendJson(res, 200, response);
|
|
1736
1814
|
return;
|
|
1737
1815
|
}
|
|
1738
|
-
const exclusions = buildGrepExclusions(
|
|
1816
|
+
const exclusions = buildGrepExclusions(requestForbiddenPatterns);
|
|
1739
1817
|
const updatedInput = buildModifiedGrepInput(toolInput, exclusions);
|
|
1740
1818
|
const finding = {
|
|
1741
1819
|
severity: "MEDIUM",
|
|
@@ -1758,7 +1836,7 @@ var SentinelGateway = class {
|
|
|
1758
1836
|
await this.sentinel.logFinding(routingId, finding);
|
|
1759
1837
|
this.telemetry.recordToolCall(event.action, "pre", "allowed", 0);
|
|
1760
1838
|
const ccTranslator = translator;
|
|
1761
|
-
const excludedPatterns =
|
|
1839
|
+
const excludedPatterns = requestForbiddenPatterns.join(", ");
|
|
1762
1840
|
const additionalContext = `Sentinel: this Grep search was modified to exclude forbidden paths. Excluded patterns: ${excludedPatterns}. To search specific forbidden files, use Read with explicit approval.`;
|
|
1763
1841
|
if (typeof ccTranslator.formatPreToolUseModifyResponse === "function") {
|
|
1764
1842
|
const response = ccTranslator.formatPreToolUseModifyResponse({
|
|
@@ -2022,13 +2100,14 @@ var SentinelGateway = class {
|
|
|
2022
2100
|
};
|
|
2023
2101
|
async function runGatewayDaemon({
|
|
2024
2102
|
policyPath,
|
|
2025
|
-
port = DEFAULT_PORT
|
|
2103
|
+
port = DEFAULT_PORT,
|
|
2104
|
+
buildId
|
|
2026
2105
|
}) {
|
|
2027
|
-
const { Sentinel: SentinelClass } = await import("./Sentinel-
|
|
2106
|
+
const { Sentinel: SentinelClass } = await import("./Sentinel-4QKPFHTI.js");
|
|
2028
2107
|
const { writePidFile, writeReleaseToken } = await import("./pidManager-DOGVN6ZT.js");
|
|
2029
2108
|
const { homedir } = await import("os");
|
|
2030
2109
|
const { randomBytes } = await import("crypto");
|
|
2031
|
-
const { loadPolicy: loadPolicy2, policyToRole: policyToRole2, policyToConfig: policyToConfig2 } = await import("./policyLoader-
|
|
2110
|
+
const { loadPolicy: loadPolicy2, policyToRole: policyToRole2, policyToConfig: policyToConfig2 } = await import("./policyLoader-XX6BQXNB.js");
|
|
2032
2111
|
const sentinel = await SentinelClass.fromPolicy(policyPath);
|
|
2033
2112
|
const baseline = await sentinel.computeBaseline("claude-code");
|
|
2034
2113
|
sentinel.setBaseline("claude-code", baseline);
|
|
@@ -2046,7 +2125,12 @@ async function runGatewayDaemon({
|
|
|
2046
2125
|
home: homedir(),
|
|
2047
2126
|
releaseToken,
|
|
2048
2127
|
unknownTools: operatorConfig.enforcement?.unknownTools,
|
|
2049
|
-
allowUnknownTools: operatorConfig.enforcement?.allowUnknownTools
|
|
2128
|
+
allowUnknownTools: operatorConfig.enforcement?.allowUnknownTools,
|
|
2129
|
+
buildId,
|
|
2130
|
+
// The operator policy's custom forbid targets must reach the gateway's own
|
|
2131
|
+
// bash-L1/Grep layers (defaults-as-floor union, same chokepoint as role
|
|
2132
|
+
// construction) — previously the gateway saw only the built-in defaults.
|
|
2133
|
+
forbiddenPatterns: unionWithDefaultForbiddenPatterns(operatorCeiling.forbiddenTargetPatterns)
|
|
2050
2134
|
});
|
|
2051
2135
|
await gateway.start();
|
|
2052
2136
|
const home = homedir();
|
|
@@ -2059,4 +2143,4 @@ export {
|
|
|
2059
2143
|
SentinelGateway,
|
|
2060
2144
|
runGatewayDaemon
|
|
2061
2145
|
};
|
|
2062
|
-
//# sourceMappingURL=chunk-
|
|
2146
|
+
//# sourceMappingURL=chunk-HRI2Y326.js.map
|