hackmyagent 0.17.8 → 0.17.9

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.
Files changed (50) hide show
  1. package/dist/.integrity-manifest.json +1 -1
  2. package/dist/arp/enforcement/kill-switch.d.ts.map +1 -1
  3. package/dist/arp/enforcement/kill-switch.js +8 -0
  4. package/dist/arp/enforcement/kill-switch.js.map +1 -1
  5. package/dist/cli.js +206 -4
  6. package/dist/cli.js.map +1 -1
  7. package/dist/hardening/scanner.d.ts +36 -0
  8. package/dist/hardening/scanner.d.ts.map +1 -1
  9. package/dist/hardening/scanner.js +120 -2
  10. package/dist/hardening/scanner.js.map +1 -1
  11. package/dist/hardening/security-check.d.ts +2 -1
  12. package/dist/hardening/security-check.d.ts.map +1 -1
  13. package/dist/nanomind-core/analyzers/capability-analyzer.d.ts +2 -1
  14. package/dist/nanomind-core/analyzers/capability-analyzer.d.ts.map +1 -1
  15. package/dist/nanomind-core/analyzers/capability-analyzer.js +44 -16
  16. package/dist/nanomind-core/analyzers/capability-analyzer.js.map +1 -1
  17. package/dist/nanomind-core/analyzers/credential-analyzer.d.ts +2 -1
  18. package/dist/nanomind-core/analyzers/credential-analyzer.d.ts.map +1 -1
  19. package/dist/nanomind-core/analyzers/credential-analyzer.js +57 -30
  20. package/dist/nanomind-core/analyzers/credential-analyzer.js.map +1 -1
  21. package/dist/nanomind-core/analyzers/governance-analyzer.d.ts +2 -1
  22. package/dist/nanomind-core/analyzers/governance-analyzer.d.ts.map +1 -1
  23. package/dist/nanomind-core/analyzers/governance-analyzer.js +7 -1
  24. package/dist/nanomind-core/analyzers/governance-analyzer.js.map +1 -1
  25. package/dist/nanomind-core/analyzers/prompt-analyzer.d.ts +2 -1
  26. package/dist/nanomind-core/analyzers/prompt-analyzer.d.ts.map +1 -1
  27. package/dist/nanomind-core/analyzers/prompt-analyzer.js +6 -1
  28. package/dist/nanomind-core/analyzers/prompt-analyzer.js.map +1 -1
  29. package/dist/nanomind-core/analyzers/scope-analyzer.d.ts +2 -1
  30. package/dist/nanomind-core/analyzers/scope-analyzer.d.ts.map +1 -1
  31. package/dist/nanomind-core/analyzers/scope-analyzer.js +6 -1
  32. package/dist/nanomind-core/analyzers/scope-analyzer.js.map +1 -1
  33. package/dist/nanomind-core/orchestrate.d.ts +2 -1
  34. package/dist/nanomind-core/orchestrate.d.ts.map +1 -1
  35. package/dist/nanomind-core/orchestrate.js +1 -1
  36. package/dist/nanomind-core/orchestrate.js.map +1 -1
  37. package/dist/nanomind-core/scanner-bridge.d.ts +2 -2
  38. package/dist/nanomind-core/scanner-bridge.d.ts.map +1 -1
  39. package/dist/nanomind-core/scanner-bridge.js +67 -12
  40. package/dist/nanomind-core/scanner-bridge.js.map +1 -1
  41. package/dist/plugins/credvault.d.ts.map +1 -1
  42. package/dist/plugins/credvault.js +16 -6
  43. package/dist/plugins/credvault.js.map +1 -1
  44. package/dist/plugins/signcrypt.d.ts.map +1 -1
  45. package/dist/plugins/signcrypt.js +11 -8
  46. package/dist/plugins/signcrypt.js.map +1 -1
  47. package/dist/plugins/skillguard.d.ts.map +1 -1
  48. package/dist/plugins/skillguard.js +12 -9
  49. package/dist/plugins/skillguard.js.map +1 -1
  50. package/package.json +1 -1
@@ -51,6 +51,36 @@ export declare function calculateSecurityScore(findings: Array<{
51
51
  score: number;
52
52
  maxScore: number;
53
53
  };
54
+ /**
55
+ * Check if a finding applies to the given project type based on the
56
+ * CHECK_PROJECT_TYPES map. Exported so CLI can filter findings after
57
+ * NanoMind merge.
58
+ */
59
+ export declare function findingAppliesTo(finding: SecurityFinding, projectType: ProjectType): boolean;
60
+ /**
61
+ * Parsed .hmaignore rules split into path patterns and check ID patterns.
62
+ * Check ID patterns start with `!` and support trailing `*` wildcards.
63
+ * Example: `!SANDBOX-*` suppresses all SANDBOX checks.
64
+ */
65
+ export interface HmaIgnoreRules {
66
+ paths: string[];
67
+ checkIds: string[];
68
+ }
69
+ /**
70
+ * Load .hmaignore patterns from a target directory. Exported so CLI
71
+ * can re-apply ignore filtering after NanoMind merge.
72
+ */
73
+ export declare function loadHmaIgnore(targetDir: string): Promise<HmaIgnoreRules>;
74
+ /**
75
+ * Check if a file path matches any .hmaignore path pattern. Exported so CLI
76
+ * can filter findings after NanoMind merge.
77
+ */
78
+ export declare function isPathIgnored(filePath: string, ignoredPaths: string[]): boolean;
79
+ /**
80
+ * Check if a checkId matches any .hmaignore check ID pattern.
81
+ * Supports exact match and trailing `*` wildcard (e.g. `SANDBOX-*`).
82
+ */
83
+ export declare function isCheckIgnored(checkId: string, ignoredChecks: string[]): boolean;
54
84
  export declare class HardeningScanner {
55
85
  private cliName;
56
86
  private static readonly BACKUP_FILES;
@@ -83,6 +113,12 @@ export declare class HardeningScanner {
83
113
  * Detect the project type based on package.json and project structure
84
114
  */
85
115
  private detectProjectType;
116
+ /**
117
+ * Detect if a package is an SDK/API client. Requires 2+ independent
118
+ * signals to avoid false positives (a random library with axios isn't
119
+ * necessarily an SDK).
120
+ */
121
+ private detectSDKPackage;
86
122
  /**
87
123
  * Check if a finding applies to the given project type
88
124
  */
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAY,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA4G3F,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6HD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG;IACrJ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAgCA;AA6GD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CA2BlC;IAEF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;OAGG;YACW,aAAa;IAwB3B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;OAGG;IACG,oBAAoB,CACxB,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,EACjB,qBAAqB,CAAC,EAAE,MAAM,EAAE,GAC/B,OAAO,CAAC,eAAe,EAAE,CAAC;IAgB7B;;OAEG;IACH,OAAO,CAAC,aAAa;IASf,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YA+ZvC,cAAc;IAwE5B;;OAEG;YACW,iBAAiB;IA+F/B;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO;YAe/D,uBAAuB;YA4GvB,aAAa;YAiDb,cAAc;YAiGd,oBAAoB;YAyDpB,gBAAgB;YAgJhB,oBAAoB;YAkFpB,gBAAgB;YA8IhB,mBAAmB;YA8EnB,iBAAiB;YA0CjB,iBAAiB;YAiEjB,wBAAwB;YA6FxB,wBAAwB;YAqExB,wBAAwB;YAyHxB,oBAAoB;YAmHpB,uBAAuB;YA4IvB,iBAAiB;YAkHjB,oBAAoB;YA0HpB,mBAAmB;YAqGnB,gBAAgB;YAwIhB,oBAAoB;YAwIpB,gBAAgB;YA6HhB,qBAAqB;YAmHrB,eAAe;IAqI7B;;OAEG;YACW,mBAAmB;IAkHjC;;OAEG;YACW,oBAAoB;IAqKlC;;OAEG;YACW,iBAAiB;IAgJ/B;;OAEG;YACW,oBAAoB;IA4IlC;;OAEG;YACW,eAAe;IAyJ7B;;OAEG;YACW,eAAe;IA2I7B;;OAEG;YACW,eAAe;IA6G7B;;OAEG;YACW,mBAAmB;IAuHjC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG;QAC3C,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB;IAID;;OAEG;YACW,YAAY;IAmE1B;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DhD;;;OAGG;YACW,cAAc;IAgD5B;;OAEG;YACW,mBAAmB;IA8qBjC;;;OAGG;YACW,kBAAkB;IAgDhC;;OAEG;YACW,sBAAsB;IAkMpC;;OAEG;YACW,sBAAsB;IA+BpC;;OAEG;YACW,oBAAoB;IAgWlC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;YACW,iBAAiB;IA8D/B;;OAEG;YACW,mBAAmB;IAsXjC;;OAEG;YACW,wBAAwB;IAqPtC;;OAEG;YACW,gBAAgB;IAoK9B;;;OAGG;YACW,eAAe;IAoD7B;;;OAGG;YACW,aAAa;IAwC3B;;;OAGG;YACW,oBAAoB;IAoKlC;;;OAGG;YACW,iBAAiB;IAiI/B;;;OAGG;YACW,kBAAkB;IAkFhC;;;OAGG;YACW,aAAa;IA0F3B;;OAEG;YACW,gBAAgB;IAiE9B;;;;OAIG;YACW,yBAAyB;IA+YvC;;;;;OAKG;YACW,qBAAqB;IAqnBnC;;;;OAIG;YACW,gBAAgB;IA2G9B;;;;OAIG;YACW,mBAAmB;IAmKjC;;;;OAIG;YACW,gBAAgB;IAkF9B;;;OAGG;YACW,iBAAiB;IA+C/B;;;;OAIG;YACW,yBAAyB;IA6FvC;;;OAGG;YACW,kBAAkB;IA8ChC;;;OAGG;YACW,mBAAmB;IA4CjC;;;OAGG;YACW,6BAA6B;IAiD3C;;;OAGG;YACW,oBAAoB;IA4ClC;;;OAGG;YACW,WAAW;IA4DzB;;;OAGG;YACW,aAAa;IAgD3B;;;OAGG;YACW,oBAAoB;IA6ClC;;;OAGG;YACW,YAAY;IAmD1B;;;OAGG;YACW,qBAAqB;IA+DnC;;;;OAIG;YACW,oBAAoB;IAyHlC;;;OAGG;YACW,iBAAiB;IA+F/B;;;OAGG;YACW,4BAA4B;IAqD1C;;;OAGG;YACW,8BAA8B;IAgE5C;;;;OAIG;YACW,qBAAqB;IAgBnC,+DAA+D;YACjD,YAAY;CA+B3B"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"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"}
@@ -39,6 +39,10 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.HardeningScanner = void 0;
41
41
  exports.calculateSecurityScore = calculateSecurityScore;
42
+ exports.findingAppliesTo = findingAppliesTo;
43
+ exports.loadHmaIgnore = loadHmaIgnore;
44
+ exports.isPathIgnored = isPathIgnored;
45
+ exports.isCheckIgnored = isCheckIgnored;
42
46
  const fs = __importStar(require("fs/promises"));
43
47
  const crypto = __importStar(require("crypto"));
44
48
  const path = __importStar(require("path"));
@@ -283,6 +287,69 @@ function calculateSecurityScore(findings) {
283
287
  : Math.round(100 * Math.exp(-weightedSum / DECAY_CONSTANT));
284
288
  return { score, maxScore: 100 };
285
289
  }
290
+ /**
291
+ * Check if a finding applies to the given project type based on the
292
+ * CHECK_PROJECT_TYPES map. Exported so CLI can filter findings after
293
+ * NanoMind merge.
294
+ */
295
+ function findingAppliesTo(finding, projectType) {
296
+ for (const [prefix, types] of Object.entries(CHECK_PROJECT_TYPES)) {
297
+ if (finding.checkId.startsWith(prefix)) {
298
+ if (types.includes('all'))
299
+ return true;
300
+ return types.includes(projectType);
301
+ }
302
+ }
303
+ return true;
304
+ }
305
+ /**
306
+ * Load .hmaignore patterns from a target directory. Exported so CLI
307
+ * can re-apply ignore filtering after NanoMind merge.
308
+ */
309
+ async function loadHmaIgnore(targetDir) {
310
+ const ignorePath = path.join(targetDir, '.hmaignore');
311
+ try {
312
+ const content = await fs.readFile(ignorePath, 'utf-8');
313
+ const lines = content
314
+ .split('\n')
315
+ .map(line => line.trim())
316
+ .filter(line => line && !line.startsWith('#'));
317
+ return {
318
+ paths: lines.filter(l => !l.startsWith('!')),
319
+ checkIds: lines.filter(l => l.startsWith('!')).map(l => l.slice(1)),
320
+ };
321
+ }
322
+ catch {
323
+ return { paths: [], checkIds: [] };
324
+ }
325
+ }
326
+ /**
327
+ * Check if a file path matches any .hmaignore path pattern. Exported so CLI
328
+ * can filter findings after NanoMind merge.
329
+ */
330
+ function isPathIgnored(filePath, ignoredPaths) {
331
+ if (!filePath || ignoredPaths.length === 0)
332
+ return false;
333
+ const normalized = filePath.replace(/\\/g, '/');
334
+ return ignoredPaths.some(pattern => {
335
+ const normalizedPattern = pattern.replace(/\\/g, '/').replace(/\/$/, '');
336
+ return normalized.startsWith(normalizedPattern + '/') || normalized === normalizedPattern;
337
+ });
338
+ }
339
+ /**
340
+ * Check if a checkId matches any .hmaignore check ID pattern.
341
+ * Supports exact match and trailing `*` wildcard (e.g. `SANDBOX-*`).
342
+ */
343
+ function isCheckIgnored(checkId, ignoredChecks) {
344
+ if (!checkId || ignoredChecks.length === 0)
345
+ return false;
346
+ return ignoredChecks.some(pattern => {
347
+ if (pattern.endsWith('*')) {
348
+ return checkId.startsWith(pattern.slice(0, -1));
349
+ }
350
+ return checkId === pattern;
351
+ });
352
+ }
286
353
  const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB max file size to prevent memory exhaustion
287
354
  const MAX_LINE_LENGTH = 10000; // 10KB max line length for regex safety
288
355
  /** Shell-escape a string for safe interpolation into advisory fix commands. */
@@ -488,6 +555,7 @@ class HardeningScanner {
488
555
  // Check ID suppression patterns from .hmaignore (supports wildcards)
489
556
  const suppressedCheckPatterns = hmaIgnore.checkIds;
490
557
  // Normalize ignore list to uppercase for case-insensitive matching
558
+ // Merge CLI --ignore flags with .hmaignore !-prefixed check IDs
491
559
  const ignoredChecks = new Set(ignore.map((id) => id.toUpperCase()));
492
560
  // In dry-run mode, we detect what would be fixed but don't modify anything
493
561
  const shouldFix = autoFix && !dryRun;
@@ -879,7 +947,7 @@ class HardeningScanner {
879
947
  */
880
948
  async detectProjectType(targetDir) {
881
949
  // Check for OpenClaw project indicators (check first as it's more specific)
882
- const openclawIndicators = ['.openclaw', '.moltbot', '.clawdbot', 'SKILL.md', 'openclaw.json'];
950
+ const openclawIndicators = ['.openclaw', '.moltbot', '.clawdbot', 'SKILL.md', 'HEARTBEAT.md', 'openclaw.json'];
883
951
  for (const indicator of openclawIndicators) {
884
952
  try {
885
953
  await fs.access(path.join(targetDir, indicator));
@@ -887,7 +955,7 @@ class HardeningScanner {
887
955
  }
888
956
  catch { }
889
957
  }
890
- // Check for *.skill.md files (OpenClaw skill project)
958
+ // Check for *.skill.md files at root level (OpenClaw skill project)
891
959
  try {
892
960
  const files = await fs.readdir(targetDir);
893
961
  if (files.some(f => f.endsWith('.skill.md'))) {
@@ -895,6 +963,12 @@ class HardeningScanner {
895
963
  }
896
964
  }
897
965
  catch { }
966
+ // Check for skills/ subdirectory with SKILL.md files (common OpenClaw layout)
967
+ try {
968
+ await fs.access(path.join(targetDir, 'skills'));
969
+ return 'openclaw';
970
+ }
971
+ catch { }
898
972
  try {
899
973
  const pkgPath = path.join(targetDir, 'package.json');
900
974
  const content = await fs.readFile(pkgPath, 'utf-8');
@@ -910,6 +984,12 @@ class HardeningScanner {
910
984
  pkg.name?.includes('mcp')) {
911
985
  return 'mcp';
912
986
  }
987
+ // Check for SDK/API client packages (requires 2+ signals).
988
+ // Must run before CLI check: some SDKs ship CLI shims (e.g., openai)
989
+ // but are primarily libraries.
990
+ if (this.detectSDKPackage(pkg, allDeps)) {
991
+ return 'sdk';
992
+ }
913
993
  // Check if it's a CLI tool (has bin field)
914
994
  if (pkg.bin) {
915
995
  return 'cli';
@@ -959,6 +1039,44 @@ class HardeningScanner {
959
1039
  // Default to library for generic projects
960
1040
  return 'library';
961
1041
  }
1042
+ /**
1043
+ * Detect if a package is an SDK/API client. Requires 2+ independent
1044
+ * signals to avoid false positives (a random library with axios isn't
1045
+ * necessarily an SDK).
1046
+ */
1047
+ detectSDKPackage(pkg, allDeps) {
1048
+ const name = (pkg.name ?? '').toLowerCase();
1049
+ const desc = (pkg.description ?? '').toLowerCase();
1050
+ const keywords = pkg.keywords ?? [];
1051
+ // Signal 1: Package name contains SDK/client indicators
1052
+ const nameSignals = ['/sdk', '-sdk', '-client', 'api-client', '-api']
1053
+ .some(s => name.includes(s)) || name.endsWith('sdk');
1054
+ // Signal 2: Description mentions SDK/client/wrapper/library-for-API patterns
1055
+ const descSignals = [
1056
+ 'sdk', 'client library', 'api client', 'api wrapper', 'official client',
1057
+ 'library for the', 'library for', 'client for the', 'client for',
1058
+ ].some(s => desc.includes(s)) && desc.includes('api');
1059
+ // Signal 3: Has library exports (main/exports). SDKs may also ship CLI
1060
+ // shims, so we don't exclude on bin presence.
1061
+ const hasLibraryExports = !!(pkg.main || pkg.exports || pkg.module);
1062
+ // Signal 4: Depends on HTTP clients
1063
+ const httpDeps = ['node-fetch', 'axios', 'got', 'undici', 'cross-fetch', 'ky', 'superagent']
1064
+ .some(d => d in allDeps);
1065
+ // Signal 5: Keywords include sdk/client
1066
+ const kwSignals = keywords.some(k => ['sdk', 'client', 'api-client', 'wrapper'].includes(k.toLowerCase()));
1067
+ // Signal 6: Description pattern "for the X API" -- strong signal that
1068
+ // this is an API client library
1069
+ const forApiPattern = /\bfor\s+the\s+\w+\s+api\b/i.test(desc) ||
1070
+ /\b(official|typescript|javascript|node)\s+\w*\s*(library|client|sdk)\b/i.test(desc);
1071
+ const signalCount = [
1072
+ nameSignals,
1073
+ descSignals,
1074
+ hasLibraryExports && httpDeps,
1075
+ kwSignals,
1076
+ forApiPattern && hasLibraryExports,
1077
+ ].filter(Boolean).length;
1078
+ return signalCount >= 2;
1079
+ }
962
1080
  /**
963
1081
  * Check if a finding applies to the given project type
964
1082
  */