sentinelayer-cli 0.32.3 → 0.32.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentinelayer-cli",
3
- "version": "0.32.3",
3
+ "version": "0.32.5",
4
4
  "description": "Scaffold Sentinelayer spec/prompt/guide artifacts with secure browser auth and token bootstrap.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -29,7 +29,41 @@ const SENSITIVE_COMMAND_PATHS = new Set([
29
29
  "session.kill",
30
30
  "session.listen",
31
31
  "session.provision-emails",
32
+ "daemon.control.stop",
33
+ "omargate.investor-dd",
34
+ // Token-handling (same class as auth.*): writes the live SentinelLayer token into a
35
+ // caller-specified GitHub repo's secrets — a token-misplacement/exfil vector via the bridge.
36
+ "scan.setup-secrets",
37
+ // Bulk session-content exfil (same rationale that blocks config.*): full transcript dumps
38
+ // can carry arbitrary sensitive content that output-redaction does not mask. `session read`
39
+ // (normal recent-message reads) stays available for legitimate agent use.
40
+ "session.export",
41
+ "session.download",
42
+ "review.show",
43
+ "review.export",
44
+ // Identity/state mutation (same class as session.kill): create/revoke/kill AIdenIDs +
45
+ // provision emails (cost + side effects) should not be driven by an untrusted LLM via the bridge.
46
+ "ai.identity.provision",
47
+ "ai.identity.revoke",
48
+ "ai.identity.kill-all",
49
+ "ai.identity.create-child",
50
+ "ai.identity.revoke-children",
51
+ "ai.provision-email",
52
+ // Inbound AIdenID extraction surfaces can expose OTPs, action links, or raw events.
53
+ "ai.identity.events",
54
+ "ai.identity.latest",
55
+ "ai.identity.wait-for-otp",
32
56
  ]);
57
+
58
+ // Whole governance sub-trees under ai.identity (domain/target/site/legal-hold) are live
59
+ // identity-governance mutations (create/verify/freeze/etc.); block the entire prefix so the
60
+ // bridge stays complete + future-proof as new leaves are added. Operators use the direct CLI.
61
+ const SENSITIVE_COMMAND_PREFIXES = [
62
+ "ai.identity.domain.",
63
+ "ai.identity.target.",
64
+ "ai.identity.site.",
65
+ "ai.identity.legal-hold.",
66
+ ];
33
67
  const REDACTION_MARKER = "[REDACTED]";
34
68
 
35
69
  function normalizeString(value) {
@@ -129,6 +163,9 @@ function blockedReasonForCommandPath(commandPathKey) {
129
163
  if (SENSITIVE_COMMAND_PATHS.has(commandPathKey)) {
130
164
  return "blocked_sensitive_cli_command";
131
165
  }
166
+ if (SENSITIVE_COMMAND_PREFIXES.some((prefix) => commandPathKey.startsWith(prefix))) {
167
+ return "blocked_sensitive_cli_command";
168
+ }
132
169
  return "";
133
170
  }
134
171
 
@@ -164,7 +201,17 @@ function validateCliOptionSpecs(optionSpecs = []) {
164
201
 
165
202
  function validateBridgeToolDefinition(tool = {}) {
166
203
  const metadata = tool.metadata || {};
167
- return validateCliPathSegments(metadata.cliPath) || validateCliOptionSpecs(metadata.options);
204
+ const shapeError = validateCliPathSegments(metadata.cliPath) || validateCliOptionSpecs(metadata.options);
205
+ if (shapeError) return shapeError;
206
+ if (metadata.generated_from !== "commander" || metadata.execution !== "bridge") {
207
+ return "untrusted_cli_bridge_definition";
208
+ }
209
+ const commandPathKey = metadata.cliPath.map(normalizeString).filter(Boolean).join(".");
210
+ const namePathKey = registryToolNameToCliPath(tool.name).join(".");
211
+ if (namePathKey && namePathKey !== commandPathKey) {
212
+ return "cli_path_name_mismatch";
213
+ }
214
+ return "";
168
215
  }
169
216
 
170
217
  function isAllowedInputValue(value) {
@@ -124,7 +124,7 @@ function hostedRollupToJson(rollup, fallbackLabel = "") {
124
124
  const hasCustomerCost = Boolean(bag.hasCustomerCost ?? bag.has_customer_cost ?? bag.customerCostUsd != null ?? bag.customer_cost_usd != null);
125
125
  return {
126
126
  label: normalize(bag.label ?? bag.agentId ?? bag.agent_id ?? bag.action ?? fallbackLabel) || "unknown",
127
- entries: nonNegativeInt(bag.entries ?? bag.count),
127
+ entries: nonNegativeInt(bag.entries ?? bag.entryCount ?? bag.entry_count ?? bag.count ?? bag.interactions),
128
128
  inputTokens: nonNegativeInt(bag.inputTokens ?? bag.input_tokens),
129
129
  outputTokens: nonNegativeInt(bag.outputTokens ?? bag.output_tokens),
130
130
  totalTokens: nonNegativeInt(bag.totalTokens ?? bag.total_tokens),
@@ -249,11 +249,24 @@ export function buildSessionUsageReportFromLedgerPayload({
249
249
  ? embedded
250
250
  : root;
251
251
  const entries = sourceArray(source.entries).map(hostedEntryToJson);
252
- const totals = hostedRollupToJson(object(source.totals), "session");
253
- const priceBookVersions = sourceArray(source.priceBooks || source.price_books || source.priceBookVersions || source.price_book_versions)
252
+ const sourceTotals = object(source.totals);
253
+ const totals = hostedRollupToJson(sourceTotals, "session");
254
+ const priceBookVersions = sourceArray(
255
+ source.priceBooks ||
256
+ source.price_books ||
257
+ source.priceBookVersions ||
258
+ source.price_book_versions ||
259
+ sourceTotals.priceBooks ||
260
+ sourceTotals.price_books ||
261
+ sourceTotals.priceBookVersions ||
262
+ sourceTotals.price_book_versions,
263
+ )
254
264
  .map(normalize)
255
265
  .filter(Boolean)
256
266
  .sort();
267
+ const resolvedPriceBookVersions = priceBookVersions.length
268
+ ? priceBookVersions
269
+ : [...new Set(entries.map((entry) => normalize(entry.priceBookVersion)).filter(Boolean))].sort();
257
270
  const limit = clampRecentLimit(recentLimit);
258
271
  return {
259
272
  schema: SESSION_USAGE_REPORT_SCHEMA,
@@ -268,12 +281,28 @@ export function buildSessionUsageReportFromLedgerPayload({
268
281
  providerCostUsd: totals.providerCostUsd,
269
282
  customerCostUsd: totals.customerCostUsd,
270
283
  unpriced: totals.unpriced,
271
- priceBookVersions,
284
+ priceBookVersions: resolvedPriceBookVersions,
272
285
  },
273
- perAgent: sourceArray(source.agents || source.perAgent || source.per_agent || source.agentsById || source.agents_by_id)
286
+ perAgent: sourceArray(
287
+ source.agents ||
288
+ source.perAgent ||
289
+ source.per_agent ||
290
+ source.byAgent ||
291
+ source.by_agent ||
292
+ source.agentsById ||
293
+ source.agents_by_id,
294
+ )
274
295
  .map((rollup) => hostedRollupToJson(rollup))
275
296
  .sort((a, b) => b.providerCostUsd - a.providerCostUsd || b.totalTokens - a.totalTokens || a.label.localeCompare(b.label)),
276
- perAction: sourceArray(source.actions || source.perAction || source.per_action || source.actionsById || source.actions_by_id)
297
+ perAction: sourceArray(
298
+ source.actions ||
299
+ source.perAction ||
300
+ source.per_action ||
301
+ source.byAction ||
302
+ source.by_action ||
303
+ source.actionsById ||
304
+ source.actions_by_id,
305
+ )
277
306
  .map((rollup) => hostedRollupToJson(rollup))
278
307
  .sort((a, b) => b.providerCostUsd - a.providerCostUsd || b.totalTokens - a.totalTokens || a.label.localeCompare(b.label)),
279
308
  recentEntries: recentReportEntries(entries, limit),