@gendigital/sage-openclaw 0.13.1 → 0.14.0

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.
@@ -35,6 +35,9 @@ __export(skill_upload_worker_exports, {
35
35
  module.exports = __toCommonJS(skill_upload_worker_exports);
36
36
  var import_node_path8 = require("node:path");
37
37
 
38
+ // ../core/src/audit-log.ts
39
+ var import_node_crypto2 = require("node:crypto");
40
+
38
41
  // ../core/src/config.ts
39
42
  var import_node_path2 = require("node:path");
40
43
 
@@ -4457,6 +4460,46 @@ var CONTENT_FIELD_LIMITS = Object.freeze({
4457
4460
  package_registry: 128
4458
4461
  });
4459
4462
 
4463
+ // ../core/src/detection-names.ts
4464
+ var REPORTING_ENGINE_SHORTHANDS = {
4465
+ package: "sgpk",
4466
+ amsi: "sgam",
4467
+ heuristics: "sghe",
4468
+ ml: "sgml",
4469
+ skill: "skan"
4470
+ };
4471
+ var REPORTING_DETECTION_SUFFIX = "sage";
4472
+ function formatReportingDetectionName(canonicalName, engine, optionalData = "") {
4473
+ const engineMetadata = optionalData ? `${REPORTING_ENGINE_SHORTHANDS[engine]}:${optionalData}` : REPORTING_ENGINE_SHORTHANDS[engine];
4474
+ return `${canonicalName}|${engineMetadata}|${REPORTING_DETECTION_SUFFIX}`;
4475
+ }
4476
+ var SKILL_DETECTION_NAMES = {
4477
+ HIGH: "Other:SageSuspiciousSkill-A [Susp]",
4478
+ CRITICAL: "Other:SageMaliciousSkill-A [Trj]"
4479
+ };
4480
+ function skillDetectionName(verdict) {
4481
+ return SKILL_DETECTION_NAMES[verdict.toUpperCase()];
4482
+ }
4483
+ function isSkillId(value) {
4484
+ return /^[0-9a-f]{64}$/i.test(value);
4485
+ }
4486
+ function skillReportingDetectionName(verdict, skillId) {
4487
+ const canonicalName = skillDetectionName(verdict);
4488
+ return canonicalName && isSkillId(skillId) ? formatReportingDetectionName(canonicalName, "skill", skillId.toLowerCase()) : void 0;
4489
+ }
4490
+ function buildSkillCheckSignal(skillId, analyzerVerdict, jobId) {
4491
+ const normalizedSkillId = skillId.toLowerCase();
4492
+ const normalizedVerdict = analyzerVerdict.toUpperCase();
4493
+ const detectionName = skillReportingDetectionName(normalizedVerdict, normalizedSkillId);
4494
+ if (!detectionName) return void 0;
4495
+ return {
4496
+ detection_name: detectionName,
4497
+ skill_id: normalizedSkillId,
4498
+ ...jobId ? { job_id: jobId } : {},
4499
+ analyzer_verdict: normalizedVerdict
4500
+ };
4501
+ }
4502
+
4460
4503
  // ../core/src/jsonl-log-writer.ts
4461
4504
  var import_promises2 = require("node:fs/promises");
4462
4505
  var import_node_path3 = require("node:path");
@@ -4516,19 +4559,30 @@ async function appendEntry(config, entry) {
4516
4559
  const stamped = { ...entry, schema_version: AUDIT_LOG_SCHEMA_VERSION };
4517
4560
  await appendJsonlEntry(config, stamped);
4518
4561
  }
4519
- async function logSkillVerdict(config, skillId, status, verdict, summary) {
4520
- if (!config.enabled) return;
4562
+ async function logSkillVerdict(config, skillId, status, verdict, summary, context = {}) {
4563
+ if (!config.enabled) return false;
4521
4564
  const entry = {
4522
4565
  type: "skill_verdict",
4566
+ entry_id: context.entryId ?? (0, import_node_crypto2.randomUUID)(),
4523
4567
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4524
4568
  skill_id: skillId,
4525
4569
  status
4526
4570
  };
4571
+ if (context.jobId !== void 0) entry.job_id = context.jobId;
4572
+ if (context.agentRuntime !== void 0) entry.agent_runtime = context.agentRuntime;
4527
4573
  if (verdict !== void 0) entry.verdict = verdict;
4528
4574
  if (summary !== void 0) entry.summary = summary.slice(0, MAX_SUMMARY_LEN);
4575
+ const skillSignal = status === "analyzed" && verdict !== void 0 ? buildSkillCheckSignal(skillId, verdict, context.jobId) : void 0;
4576
+ if (skillSignal) {
4577
+ entry.signals = {
4578
+ skill_checks: [skillSignal]
4579
+ };
4580
+ }
4529
4581
  try {
4530
4582
  await appendEntry(config, entry);
4583
+ return true;
4531
4584
  } catch {
4585
+ return false;
4532
4586
  }
4533
4587
  }
4534
4588
 
@@ -4537,7 +4591,7 @@ var import_node_path4 = require("node:path");
4537
4591
  var import_node_url = require("node:url");
4538
4592
  var import_meta = {};
4539
4593
  function resolveVersion() {
4540
- if (true) return "0.13.0";
4594
+ if (true) return "0.14.0";
4541
4595
  try {
4542
4596
  const pkgPath = (0, import_node_path4.join)((0, import_node_path4.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
4543
4597
  const pkg = JSON.parse(getFileContentSync(pkgPath));
@@ -4914,7 +4968,7 @@ function mergeSources(existing, incoming) {
4914
4968
  function defaultCachePath2() {
4915
4969
  return (0, import_node_path7.join)(resolvePath(SAGE_DIR), "skill_verdict_cache.json");
4916
4970
  }
4917
- async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DEFAULT_VERDICT_TTL_MS, logger = nullLogger) {
4971
+ async function loadSkillVerdictCacheInternal(cachePath, ttlMs, logger, pruneOnLoad) {
4918
4972
  let raw;
4919
4973
  try {
4920
4974
  raw = await getFileContent(cachePath);
@@ -4936,6 +4990,8 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
4936
4990
  continue;
4937
4991
  }
4938
4992
  entries[skillId] = {
4993
+ entryId: typeof entry.entry_id === "string" ? entry.entry_id : void 0,
4994
+ jobId: typeof entry.job_id === "string" ? entry.job_id : void 0,
4939
4995
  verdict: typeof entry.verdict === "string" ? entry.verdict : void 0,
4940
4996
  summary: typeof entry.summary === "string" ? entry.summary : void 0,
4941
4997
  skillName: typeof entry.skill_name === "string" ? entry.skill_name : void 0,
@@ -4944,7 +5000,7 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
4944
5000
  };
4945
5001
  }
4946
5002
  const cache = { entries };
4947
- if (pruned > 0) {
5003
+ if (pruneOnLoad && pruned > 0) {
4948
5004
  logger.debug(`Pruned ${pruned} stale verdict(s) from cache`, { cachePath });
4949
5005
  await saveSkillVerdictCache(cache, cachePath, logger);
4950
5006
  }
@@ -4954,6 +5010,9 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
4954
5010
  return { entries: {} };
4955
5011
  }
4956
5012
  }
5013
+ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DEFAULT_VERDICT_TTL_MS, logger = nullLogger) {
5014
+ return loadSkillVerdictCacheInternal(cachePath, ttlMs, logger, true);
5015
+ }
4957
5016
  async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), logger = nullLogger) {
4958
5017
  try {
4959
5018
  const data = {
@@ -4962,6 +5021,8 @@ async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), log
4962
5021
  Object.entries(cache.entries).map(([skillId, v]) => [
4963
5022
  skillId,
4964
5023
  {
5024
+ entry_id: v.entryId,
5025
+ job_id: v.jobId,
4965
5026
  verdict: v.verdict,
4966
5027
  summary: v.summary,
4967
5028
  skill_name: v.skillName,
@@ -4975,8 +5036,10 @@ async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), log
4975
5036
  )
4976
5037
  };
4977
5038
  await atomicWriteJson(cachePath, data);
5039
+ return true;
4978
5040
  } catch (e) {
4979
5041
  logger.warn(`Failed to save verdict cache to ${cachePath}`, { error: String(e) });
5042
+ return false;
4980
5043
  }
4981
5044
  }
4982
5045
  function putVerdict(cache, skillId, verdict) {
@@ -4988,6 +5051,33 @@ function putVerdict(cache, skillId, verdict) {
4988
5051
  };
4989
5052
  }
4990
5053
 
5054
+ // ../core/src/skill-verdict-record.ts
5055
+ var import_node_crypto3 = require("node:crypto");
5056
+ function recordAnalyzedSkillVerdict(cache, skillId, result, origin) {
5057
+ const entryId = (0, import_node_crypto3.randomUUID)();
5058
+ putVerdict(cache, skillId, {
5059
+ entryId,
5060
+ jobId: result.jobId,
5061
+ verdict: result.verdict,
5062
+ summary: result.summary,
5063
+ skillName: origin.skillName,
5064
+ sources: [{ agentRuntime: origin.agentRuntime, containerKey: origin.containerKey }]
5065
+ });
5066
+ const { loggingConfig } = origin;
5067
+ return {
5068
+ entryId,
5069
+ writeAuditEntry: async () => {
5070
+ if (!loggingConfig) return;
5071
+ await logSkillVerdict(loggingConfig, skillId, "analyzed", result.verdict, result.summary, {
5072
+ entryId,
5073
+ jobId: result.jobId,
5074
+ agentRuntime: origin.agentRuntime
5075
+ });
5076
+ }
5077
+ };
5078
+ }
5079
+ var SKILL_ENTRY_ID_NAMESPACE = Buffer.from("75bba79a376142a7bacbf95d791126d3", "hex");
5080
+
4991
5081
  // ../../node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
4992
5082
  var import_module = require("module");
4993
5083
  var require2 = (0, import_module.createRequire)("/");
@@ -5519,14 +5609,18 @@ async function runSkillUploadWorker(args = {}) {
5519
5609
  error: String(outcome.error)
5520
5610
  });
5521
5611
  if (loggingConfig) {
5522
- logSkillVerdict(loggingConfig, skillId, "error").catch(() => {
5612
+ logSkillVerdict(loggingConfig, skillId, "error", void 0, void 0, {
5613
+ agentRuntime: skill.agentRuntime ?? args.agentRuntime
5614
+ }).catch(() => {
5523
5615
  });
5524
5616
  }
5525
5617
  } else if (outcome.tag === "no_verdict") {
5526
5618
  retained += 1;
5527
5619
  logger.debug("Skill analysis returned no verdict; leaving pending", { skillId });
5528
5620
  if (loggingConfig) {
5529
- logSkillVerdict(loggingConfig, skillId, "no_verdict").catch(() => {
5621
+ logSkillVerdict(loggingConfig, skillId, "no_verdict", void 0, void 0, {
5622
+ agentRuntime: skill.agentRuntime ?? args.agentRuntime
5623
+ }).catch(() => {
5530
5624
  });
5531
5625
  }
5532
5626
  } else if (outcome.tag === "ok") {
@@ -5534,55 +5628,48 @@ async function runSkillUploadWorker(args = {}) {
5534
5628
  } else if (outcome.tag === "too_large" || outcome.tag === "empty") {
5535
5629
  terminal.push(skillId);
5536
5630
  if (loggingConfig) {
5537
- logSkillVerdict(loggingConfig, skillId, outcome.tag).catch(() => {
5631
+ logSkillVerdict(loggingConfig, skillId, outcome.tag, void 0, void 0, {
5632
+ agentRuntime: skill.agentRuntime ?? args.agentRuntime
5633
+ }).catch(() => {
5538
5634
  });
5539
5635
  }
5540
5636
  }
5541
5637
  }
5542
5638
  if (successes.length === 0 && terminal.length === 0) continue;
5543
5639
  const cache = await loadSkillVerdictCache(args.verdictCachePath, args.verdictTtlMs, logger);
5544
- for (const { skill, result } of successes) {
5545
- putVerdict(cache, skill.skillId, {
5546
- verdict: result.verdict,
5547
- summary: result.summary,
5640
+ const recorded = successes.map(
5641
+ ({ skill, result }) => recordAnalyzedSkillVerdict(cache, skill.skillId, result, {
5548
5642
  skillName: (0, import_node_path8.basename)(skill.folder),
5549
- sources: [
5550
- {
5551
- agentRuntime: skill.agentRuntime ?? args.agentRuntime,
5552
- containerKey: skill.containerKey
5553
- }
5554
- ]
5555
- });
5556
- }
5643
+ agentRuntime: skill.agentRuntime ?? args.agentRuntime,
5644
+ containerKey: skill.containerKey,
5645
+ loggingConfig
5646
+ })
5647
+ );
5557
5648
  for (const skillId of terminal) {
5558
5649
  putVerdict(cache, skillId, {});
5559
5650
  }
5560
- await saveSkillVerdictCache(cache, args.verdictCachePath, logger);
5651
+ const cacheSaved = await saveSkillVerdictCache(cache, args.verdictCachePath, logger);
5561
5652
  const fresh = await loadPendingMarker(args.pendingPath, logger);
5562
- for (const { skill } of successes) {
5563
- removePending(fresh, skill.skillId);
5564
- }
5565
- for (const skillId of terminal) {
5566
- removePending(fresh, skillId);
5567
- }
5568
- await savePendingMarker(fresh, args.pendingPath, logger);
5569
- analyzed += successes.length;
5570
- for (const { skill, result } of successes) {
5571
- logger.debug("Skill analyzed and cached", {
5572
- skillId: skill.skillId,
5573
- risk: result.verdict
5574
- });
5575
- if (loggingConfig) {
5576
- logSkillVerdict(
5577
- loggingConfig,
5578
- skill.skillId,
5579
- "analyzed",
5580
- result.verdict,
5581
- result.summary
5582
- ).catch(() => {
5653
+ if (cacheSaved) {
5654
+ for (const { skill } of successes) {
5655
+ removePending(fresh, skill.skillId);
5656
+ }
5657
+ for (const skillId of terminal) {
5658
+ removePending(fresh, skillId);
5659
+ }
5660
+ analyzed += successes.length;
5661
+ await Promise.all(recorded.map((entry) => entry.writeAuditEntry().catch(() => {
5662
+ })));
5663
+ for (const { skill, result } of successes) {
5664
+ logger.debug("Skill analyzed and cached", {
5665
+ skillId: skill.skillId,
5666
+ risk: result.verdict
5583
5667
  });
5584
5668
  }
5669
+ } else {
5670
+ retained += successes.length + terminal.length;
5585
5671
  }
5672
+ await savePendingMarker(fresh, args.pendingPath, logger);
5586
5673
  }
5587
5674
  return { analyzed, retained };
5588
5675
  }