hackmyagent 0.17.0 → 0.17.2
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/dist/.integrity-manifest.json +1 -1
- package/dist/checker/skill-identifier.d.ts.map +1 -1
- package/dist/checker/skill-identifier.js +4 -3
- package/dist/checker/skill-identifier.js.map +1 -1
- package/dist/cli.js +201 -58
- package/dist/cli.js.map +1 -1
- package/dist/hardening/index.d.ts +1 -1
- package/dist/hardening/index.d.ts.map +1 -1
- package/dist/hardening/index.js +2 -1
- package/dist/hardening/index.js.map +1 -1
- package/dist/hardening/scanner.d.ts +16 -0
- package/dist/hardening/scanner.d.ts.map +1 -1
- package/dist/hardening/scanner.js +28 -28
- package/dist/hardening/scanner.js.map +1 -1
- package/dist/hardening/taxonomy.d.ts +5 -0
- package/dist/hardening/taxonomy.d.ts.map +1 -1
- package/dist/hardening/taxonomy.js +66 -0
- package/dist/hardening/taxonomy.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/nanomind-core/analyzers/credential-analyzer.js +6 -0
- package/dist/nanomind-core/analyzers/credential-analyzer.js.map +1 -1
- package/dist/nanomind-core/compiler/semantic-compiler.js +7 -2
- package/dist/nanomind-core/compiler/semantic-compiler.js.map +1 -1
- package/dist/nanomind-core/index.d.ts +2 -0
- package/dist/nanomind-core/index.d.ts.map +1 -1
- package/dist/nanomind-core/index.js +12 -2
- package/dist/nanomind-core/index.js.map +1 -1
- package/dist/nanomind-core/inference/analm-infer.py +104 -0
- package/dist/nanomind-core/inference/security-analyst.d.ts +95 -0
- package/dist/nanomind-core/inference/security-analyst.d.ts.map +1 -0
- package/dist/nanomind-core/inference/security-analyst.js +372 -0
- package/dist/nanomind-core/inference/security-analyst.js.map +1 -0
- package/dist/nanomind-core/orchestrate.d.ts +7 -0
- package/dist/nanomind-core/orchestrate.d.ts.map +1 -1
- package/dist/nanomind-core/orchestrate.js +68 -2
- package/dist/nanomind-core/orchestrate.js.map +1 -1
- package/dist/nanomind-core/scanner-bridge.d.ts.map +1 -1
- package/dist/nanomind-core/scanner-bridge.js +33 -5
- package/dist/nanomind-core/scanner-bridge.js.map +1 -1
- package/dist/registry/client.d.ts +5 -0
- package/dist/registry/client.d.ts.map +1 -1
- package/dist/registry/client.js +10 -1
- package/dist/registry/client.js.map +1 -1
- package/dist/registry/publish.d.ts.map +1 -1
- package/dist/registry/publish.js +3 -4
- package/dist/registry/publish.js.map +1 -1
- package/dist/scanner/external-scanner.js +2 -2
- package/dist/scanner/external-scanner.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hardening module
|
|
3
3
|
*/
|
|
4
|
-
export { HardeningScanner } from './scanner';
|
|
4
|
+
export { HardeningScanner, calculateSecurityScore } from './scanner';
|
|
5
5
|
export type { ScanOptions, ScanDepth } from './scanner';
|
|
6
6
|
export type { SecurityCheck, CheckResult, FixResult, SecurityFinding, ScanResult, Severity, } from './security-check';
|
|
7
7
|
export { getAttackClass, enrichWithTaxonomy } from './taxonomy';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hardening/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hardening/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAExD,YAAY,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,8BAA8B,CAAC"}
|
package/dist/hardening/index.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Hardening module
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.validateCapabilities = exports.inferActualCapabilities = exports.parseDeclaredCapabilities = exports.isLikelyFalsePositive = exports.classifySkillSection = exports.NEMOCLAW_CATEGORIES = exports.NemoClawScanner = exports.enrichWithTaxonomy = exports.getAttackClass = exports.HardeningScanner = void 0;
|
|
6
|
+
exports.validateCapabilities = exports.inferActualCapabilities = exports.parseDeclaredCapabilities = exports.isLikelyFalsePositive = exports.classifySkillSection = exports.NEMOCLAW_CATEGORIES = exports.NemoClawScanner = exports.enrichWithTaxonomy = exports.getAttackClass = exports.calculateSecurityScore = exports.HardeningScanner = void 0;
|
|
7
7
|
var scanner_1 = require("./scanner");
|
|
8
8
|
Object.defineProperty(exports, "HardeningScanner", { enumerable: true, get: function () { return scanner_1.HardeningScanner; } });
|
|
9
|
+
Object.defineProperty(exports, "calculateSecurityScore", { enumerable: true, get: function () { return scanner_1.calculateSecurityScore; } });
|
|
9
10
|
var taxonomy_1 = require("./taxonomy");
|
|
10
11
|
Object.defineProperty(exports, "getAttackClass", { enumerable: true, get: function () { return taxonomy_1.getAttackClass; } });
|
|
11
12
|
Object.defineProperty(exports, "enrichWithTaxonomy", { enumerable: true, get: function () { return taxonomy_1.enrichWithTaxonomy; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hardening/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hardening/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,qCAAqE;AAA5D,2GAAA,gBAAgB,OAAA;AAAE,iHAAA,sBAAsB,OAAA;AAYjD,uCAAgE;AAAvD,0GAAA,cAAc,OAAA;AAAE,8GAAA,kBAAkB,OAAA;AAC3C,uDAA0E;AAAjE,mHAAA,eAAe,OAAA;AAAE,uHAAA,mBAAmB,OAAA;AAC7C,iDAA8E;AAArE,qHAAA,oBAAoB,OAAA;AAAE,sHAAA,qBAAqB,OAAA;AAEpD,2EAIsC;AAHpC,uIAAA,yBAAyB,OAAA;AACzB,qIAAA,uBAAuB,OAAA;AACvB,kIAAA,oBAAoB,OAAA"}
|
|
@@ -28,6 +28,22 @@ export interface ScanOptions {
|
|
|
28
28
|
/** CLI command prefix for fix messages (default: 'hackmyagent') */
|
|
29
29
|
cliName?: string;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Standalone scoring function using exponential decay with governance weight.
|
|
33
|
+
* This is the canonical scoring formula — all score paths must use it.
|
|
34
|
+
*
|
|
35
|
+
* Accepts findings with at minimum: { passed?, fixed?, severity, category, checkId }.
|
|
36
|
+
*/
|
|
37
|
+
export declare function calculateSecurityScore(findings: Array<{
|
|
38
|
+
passed?: boolean;
|
|
39
|
+
fixed?: boolean;
|
|
40
|
+
severity: string;
|
|
41
|
+
category?: string;
|
|
42
|
+
checkId?: string;
|
|
43
|
+
}>): {
|
|
44
|
+
score: number;
|
|
45
|
+
maxScore: number;
|
|
46
|
+
};
|
|
31
47
|
export declare class HardeningScanner {
|
|
32
48
|
private cliName;
|
|
33
49
|
private static readonly BACKUP_FILES;
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.HardeningScanner = void 0;
|
|
41
|
+
exports.calculateSecurityScore = calculateSecurityScore;
|
|
41
42
|
const fs = __importStar(require("fs/promises"));
|
|
42
43
|
const crypto = __importStar(require("crypto"));
|
|
43
44
|
const path = __importStar(require("path"));
|
|
@@ -241,6 +242,32 @@ const SEVERITY_WEIGHTS = {
|
|
|
241
242
|
medium: 8,
|
|
242
243
|
low: 3,
|
|
243
244
|
};
|
|
245
|
+
/**
|
|
246
|
+
* Standalone scoring function using exponential decay with governance weight.
|
|
247
|
+
* This is the canonical scoring formula — all score paths must use it.
|
|
248
|
+
*
|
|
249
|
+
* Accepts findings with at minimum: { passed?, fixed?, severity, category, checkId }.
|
|
250
|
+
*/
|
|
251
|
+
function calculateSecurityScore(findings) {
|
|
252
|
+
const GOVERNANCE_CATEGORIES = new Set(['governance', 'Governance', 'injection-hardening', 'trust-hierarchy']);
|
|
253
|
+
const GOVERNANCE_PREFIXES = ['AST-GOV', 'AST-GOVERN', 'AST-PROMPT', 'AST-HEARTBEAT'];
|
|
254
|
+
const GOVERNANCE_WEIGHT = 0.4;
|
|
255
|
+
const DECAY_CONSTANT = 150;
|
|
256
|
+
let weightedSum = 0;
|
|
257
|
+
for (const finding of findings) {
|
|
258
|
+
if (!finding.passed && !finding.fixed) {
|
|
259
|
+
const isGovernance = GOVERNANCE_CATEGORIES.has(finding.category || '') ||
|
|
260
|
+
GOVERNANCE_PREFIXES.some(p => (finding.checkId || '').startsWith(p));
|
|
261
|
+
const multiplier = isGovernance ? GOVERNANCE_WEIGHT : 1;
|
|
262
|
+
const sevWeight = SEVERITY_WEIGHTS[finding.severity] ?? 0;
|
|
263
|
+
weightedSum += sevWeight * multiplier;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const score = weightedSum === 0
|
|
267
|
+
? 100
|
|
268
|
+
: Math.round(100 * Math.exp(-weightedSum / DECAY_CONSTANT));
|
|
269
|
+
return { score, maxScore: 100 };
|
|
270
|
+
}
|
|
244
271
|
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB max file size to prevent memory exhaustion
|
|
245
272
|
const MAX_LINE_LENGTH = 10000; // 10KB max line length for regex safety
|
|
246
273
|
/** Shell-escape a string for safe interpolation into advisory fix commands. */
|
|
@@ -4099,34 +4126,7 @@ dist/
|
|
|
4099
4126
|
return findings;
|
|
4100
4127
|
}
|
|
4101
4128
|
calculateScore(findings) {
|
|
4102
|
-
|
|
4103
|
-
// are important but shouldn't tank scores the way code vulnerabilities do.
|
|
4104
|
-
// A project with only governance gaps is not malware — it needs hardening.
|
|
4105
|
-
const GOVERNANCE_CATEGORIES = new Set(['governance', 'Governance', 'injection-hardening', 'trust-hierarchy']);
|
|
4106
|
-
const GOVERNANCE_PREFIXES = ['AST-GOV', 'AST-GOVERN', 'AST-PROMPT', 'AST-HEARTBEAT'];
|
|
4107
|
-
const GOVERNANCE_WEIGHT = 0.4; // 40% of normal weight
|
|
4108
|
-
// Sum severity weights for all failed, unfixed findings
|
|
4109
|
-
let weightedSum = 0;
|
|
4110
|
-
for (const finding of findings) {
|
|
4111
|
-
if (!finding.passed && !finding.fixed) {
|
|
4112
|
-
const isGovernance = GOVERNANCE_CATEGORIES.has(finding.category) ||
|
|
4113
|
-
GOVERNANCE_PREFIXES.some(p => finding.checkId.startsWith(p));
|
|
4114
|
-
const multiplier = isGovernance ? GOVERNANCE_WEIGHT : 1;
|
|
4115
|
-
weightedSum += SEVERITY_WEIGHTS[finding.severity] * multiplier;
|
|
4116
|
-
}
|
|
4117
|
-
}
|
|
4118
|
-
// Exponential decay: each additional finding has diminishing impact.
|
|
4119
|
-
// Prevents score=0 for repos with many findings (e.g. full-clone GitHub repos)
|
|
4120
|
-
// while preserving near-identical scores for sparse scans (1-2 findings).
|
|
4121
|
-
// Decay constant 150 calibrated so: 1 medium(8)=95, 1 critical(25)=85,
|
|
4122
|
-
// 3crit+9high(210)=25, extreme(700)=1
|
|
4123
|
-
// With governance at 0.4x: 1 gov-critical(10)=94, 6 gov-high(36)=79
|
|
4124
|
-
const DECAY_CONSTANT = 150;
|
|
4125
|
-
const score = weightedSum === 0
|
|
4126
|
-
? 100
|
|
4127
|
-
: Math.round(100 * Math.exp(-weightedSum / DECAY_CONSTANT));
|
|
4128
|
-
const maxScore = 100;
|
|
4129
|
-
return { score, maxScore };
|
|
4129
|
+
return calculateSecurityScore(findings);
|
|
4130
4130
|
}
|
|
4131
4131
|
/**
|
|
4132
4132
|
* Create a backup of files that may be modified during auto-fix
|