agentlint 0.1.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.
- package/CHANGELOG.md +32 -0
- package/LICENSE +190 -0
- package/README.md +246 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +351 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/diff/index.d.ts +16 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +204 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/index.d.ts +2 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +18 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/types.d.ts +369 -0
- package/dist/ir/types.d.ts.map +1 -0
- package/dist/ir/types.js +12 -0
- package/dist/ir/types.js.map +1 -0
- package/dist/parsers/base.d.ts +104 -0
- package/dist/parsers/base.d.ts.map +1 -0
- package/dist/parsers/base.js +373 -0
- package/dist/parsers/base.js.map +1 -0
- package/dist/parsers/claude.d.ts +30 -0
- package/dist/parsers/claude.d.ts.map +1 -0
- package/dist/parsers/claude.js +453 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/cursor.d.ts +24 -0
- package/dist/parsers/cursor.d.ts.map +1 -0
- package/dist/parsers/cursor.js +305 -0
- package/dist/parsers/cursor.js.map +1 -0
- package/dist/parsers/factory.d.ts +30 -0
- package/dist/parsers/factory.d.ts.map +1 -0
- package/dist/parsers/factory.js +78 -0
- package/dist/parsers/factory.js.map +1 -0
- package/dist/parsers/index.d.ts +5 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +21 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/policy/index.d.ts +3 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +19 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/loader.d.ts +23 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +252 -0
- package/dist/policy/loader.js.map +1 -0
- package/dist/policy/types.d.ts +79 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +99 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/reports/index.d.ts +14 -0
- package/dist/reports/index.d.ts.map +1 -0
- package/dist/reports/index.js +54 -0
- package/dist/reports/index.js.map +1 -0
- package/dist/reports/json.d.ts +16 -0
- package/dist/reports/json.d.ts.map +1 -0
- package/dist/reports/json.js +126 -0
- package/dist/reports/json.js.map +1 -0
- package/dist/reports/sarif.d.ts +20 -0
- package/dist/reports/sarif.d.ts.map +1 -0
- package/dist/reports/sarif.js +169 -0
- package/dist/reports/sarif.js.map +1 -0
- package/dist/reports/text.d.ts +25 -0
- package/dist/reports/text.d.ts.map +1 -0
- package/dist/reports/text.js +283 -0
- package/dist/reports/text.js.map +1 -0
- package/dist/reports/types.d.ts +88 -0
- package/dist/reports/types.d.ts.map +1 -0
- package/dist/reports/types.js +6 -0
- package/dist/reports/types.js.map +1 -0
- package/dist/rules/base.d.ts +16 -0
- package/dist/rules/base.d.ts.map +1 -0
- package/dist/rules/base.js +48 -0
- package/dist/rules/base.js.map +1 -0
- package/dist/rules/engine.d.ts +61 -0
- package/dist/rules/engine.d.ts.map +1 -0
- package/dist/rules/engine.js +195 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/execution.d.ts +33 -0
- package/dist/rules/execution.d.ts.map +1 -0
- package/dist/rules/execution.js +154 -0
- package/dist/rules/execution.js.map +1 -0
- package/dist/rules/filesystem.d.ts +36 -0
- package/dist/rules/filesystem.d.ts.map +1 -0
- package/dist/rules/filesystem.js +227 -0
- package/dist/rules/filesystem.js.map +1 -0
- package/dist/rules/hook.d.ts +25 -0
- package/dist/rules/hook.d.ts.map +1 -0
- package/dist/rules/hook.js +112 -0
- package/dist/rules/hook.js.map +1 -0
- package/dist/rules/index.d.ts +12 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +28 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/instruction.d.ts +25 -0
- package/dist/rules/instruction.d.ts.map +1 -0
- package/dist/rules/instruction.js +162 -0
- package/dist/rules/instruction.js.map +1 -0
- package/dist/rules/network.d.ts +33 -0
- package/dist/rules/network.d.ts.map +1 -0
- package/dist/rules/network.js +145 -0
- package/dist/rules/network.js.map +1 -0
- package/dist/rules/observability.d.ts +25 -0
- package/dist/rules/observability.d.ts.map +1 -0
- package/dist/rules/observability.js +105 -0
- package/dist/rules/observability.js.map +1 -0
- package/dist/rules/scope.d.ts +37 -0
- package/dist/rules/scope.d.ts.map +1 -0
- package/dist/rules/scope.js +173 -0
- package/dist/rules/scope.js.map +1 -0
- package/dist/rules/secrets.d.ts +35 -0
- package/dist/rules/secrets.d.ts.map +1 -0
- package/dist/rules/secrets.js +273 -0
- package/dist/rules/secrets.js.map +1 -0
- package/dist/rules/types.d.ts +58 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +6 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/scanner.d.ts +61 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +441 -0
- package/dist/scanner.js.map +1 -0
- package/dist/utils/hash.d.ts +28 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +94 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base rule class with common functionality
|
|
3
|
+
*/
|
|
4
|
+
import { Finding, AgentDocument, Evidence, Anchors } from '../ir/types';
|
|
5
|
+
import { Rule, RuleDefinition, RuleContext } from './types';
|
|
6
|
+
export declare abstract class BaseRule implements Rule {
|
|
7
|
+
protected definition: RuleDefinition;
|
|
8
|
+
constructor(definition: RuleDefinition);
|
|
9
|
+
getDefinition(): RuleDefinition;
|
|
10
|
+
abstract evaluate(context: RuleContext): Finding[];
|
|
11
|
+
/**
|
|
12
|
+
* Create a finding with proper fingerprints
|
|
13
|
+
*/
|
|
14
|
+
protected createFinding(document: AgentDocument, location: Anchors, message: string, evidence: Evidence[], confidence?: number): Finding;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/rules/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAY,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAO5D,8BAAsB,QAAS,YAAW,IAAI;IAC5C,SAAS,CAAC,UAAU,EAAE,cAAc,CAAC;gBAEzB,UAAU,EAAE,cAAc;IAItC,aAAa,IAAI,cAAc;IAI/B,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAElD;;OAEG;IACH,SAAS,CAAC,aAAa,CACrB,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAAE,EACpB,UAAU,GAAE,MAAY,GACvB,OAAO;CA2CX"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base rule class with common functionality
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BaseRule = void 0;
|
|
7
|
+
const hash_1 = require("../utils/hash");
|
|
8
|
+
class BaseRule {
|
|
9
|
+
definition;
|
|
10
|
+
constructor(definition) {
|
|
11
|
+
this.definition = definition;
|
|
12
|
+
}
|
|
13
|
+
getDefinition() {
|
|
14
|
+
return this.definition;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a finding with proper fingerprints
|
|
18
|
+
*/
|
|
19
|
+
createFinding(document, location, message, evidence, confidence = 0.9) {
|
|
20
|
+
const evidenceValue = evidence.length > 0 ? evidence[0].value : '';
|
|
21
|
+
return {
|
|
22
|
+
finding_id: (0, hash_1.generateFindingId)(this.definition.id, document.path, location.start_line, evidenceValue),
|
|
23
|
+
rule_id: this.definition.id,
|
|
24
|
+
group: this.definition.group,
|
|
25
|
+
severity: this.definition.severity,
|
|
26
|
+
title: this.definition.title,
|
|
27
|
+
description: this.definition.description,
|
|
28
|
+
message,
|
|
29
|
+
recommendation: this.definition.recommendation,
|
|
30
|
+
confidence,
|
|
31
|
+
tags: this.definition.tags,
|
|
32
|
+
location: {
|
|
33
|
+
path: document.path,
|
|
34
|
+
start_line: location.start_line,
|
|
35
|
+
end_line: location.end_line,
|
|
36
|
+
},
|
|
37
|
+
evidence,
|
|
38
|
+
related_actions: [],
|
|
39
|
+
fingerprints: {
|
|
40
|
+
stable: (0, hash_1.generateFindingId)(this.definition.id, document.path, location.start_line, evidenceValue),
|
|
41
|
+
location: (0, hash_1.generateLocationFingerprint)(this.definition.id, document.path, location.start_line, location.end_line),
|
|
42
|
+
content: (0, hash_1.generateContentFingerprint)(this.definition.id, evidenceValue),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.BaseRule = BaseRule;
|
|
48
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/rules/base.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAIH,wCAIuB;AAEvB,MAAsB,QAAQ;IAClB,UAAU,CAAiB;IAErC,YAAY,UAA0B;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAID;;OAEG;IACO,aAAa,CACrB,QAAuB,EACvB,QAAiB,EACjB,OAAe,EACf,QAAoB,EACpB,aAAqB,GAAG;QAExB,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAEnE,OAAO;YACL,UAAU,EAAE,IAAA,wBAAiB,EAC3B,IAAI,CAAC,UAAU,CAAC,EAAE,EAClB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,UAAU,EACnB,aAAa,CACd;YACD,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE;YAC3B,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK;YAC5B,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ;YAClC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK;YAC5B,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;YACxC,OAAO;YACP,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,cAAc;YAC9C,UAAU;YACV,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI;YAC1B,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;aAC5B;YACD,QAAQ;YACR,eAAe,EAAE,EAAE;YACnB,YAAY,EAAE;gBACZ,MAAM,EAAE,IAAA,wBAAiB,EACvB,IAAI,CAAC,UAAU,CAAC,EAAE,EAClB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,UAAU,EACnB,aAAa,CACd;gBACD,QAAQ,EAAE,IAAA,kCAA2B,EACnC,IAAI,CAAC,UAAU,CAAC,EAAE,EAClB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,QAAQ,CAClB;gBACD,OAAO,EAAE,IAAA,iCAA0B,EAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,aAAa,CAAC;aACvE;SACF,CAAC;IACJ,CAAC;CACF;AAjED,4BAiEC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule Engine
|
|
3
|
+
* Orchestrates rule evaluation and finding generation
|
|
4
|
+
*/
|
|
5
|
+
import { AgentDocument, Finding, CapabilitySummary, Severity } from '../ir/types';
|
|
6
|
+
import { Rule, RuleDefinition, RuleEngineOptions, RuleGroup } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Rule Engine - evaluates all rules against documents
|
|
9
|
+
*/
|
|
10
|
+
export declare class RuleEngine {
|
|
11
|
+
private rules;
|
|
12
|
+
private options;
|
|
13
|
+
private ruleMap;
|
|
14
|
+
constructor(options?: Partial<RuleEngineOptions>);
|
|
15
|
+
/**
|
|
16
|
+
* Get all available rules
|
|
17
|
+
*/
|
|
18
|
+
getAllRules(): RuleDefinition[];
|
|
19
|
+
/**
|
|
20
|
+
* Get enabled rules (after applying disabled list)
|
|
21
|
+
*/
|
|
22
|
+
getEnabledRules(): RuleDefinition[];
|
|
23
|
+
/**
|
|
24
|
+
* Get a rule by ID
|
|
25
|
+
*/
|
|
26
|
+
getRule(ruleId: string): Rule | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Get rule definition by ID
|
|
29
|
+
*/
|
|
30
|
+
getRuleDefinition(ruleId: string): RuleDefinition | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Get rules by group
|
|
33
|
+
*/
|
|
34
|
+
getRulesByGroup(group: RuleGroup): RuleDefinition[];
|
|
35
|
+
/**
|
|
36
|
+
* Evaluate all rules against a single document
|
|
37
|
+
*/
|
|
38
|
+
evaluateDocument(document: AgentDocument, allDocuments: AgentDocument[], capabilitySummary: CapabilitySummary): Finding[];
|
|
39
|
+
/**
|
|
40
|
+
* Evaluate all rules against multiple documents
|
|
41
|
+
*/
|
|
42
|
+
evaluateAll(documents: AgentDocument[], capabilitySummary: CapabilitySummary): Finding[];
|
|
43
|
+
/**
|
|
44
|
+
* Sort findings by severity, path, and line number
|
|
45
|
+
*/
|
|
46
|
+
private sortFindings;
|
|
47
|
+
/**
|
|
48
|
+
* Count findings by severity
|
|
49
|
+
*/
|
|
50
|
+
countBySeverity(findings: Finding[]): Record<Severity, number>;
|
|
51
|
+
/**
|
|
52
|
+
* Filter findings by minimum severity
|
|
53
|
+
*/
|
|
54
|
+
filterBySeverity(findings: Finding[], minSeverity: Severity): Finding[];
|
|
55
|
+
/**
|
|
56
|
+
* Check if any finding meets or exceeds the threshold
|
|
57
|
+
*/
|
|
58
|
+
hasFindings(findings: Finding[], threshold: Severity | 'none'): boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare const defaultRuleEngine: RuleEngine;
|
|
61
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/rules/engine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,aAAa,EACb,OAAO,EACP,iBAAiB,EACjB,QAAQ,EACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,IAAI,EAAe,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAU1F;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM;IA0BpD;;OAEG;IACH,WAAW,IAAI,cAAc,EAAE;IAI/B;;OAEG;IACH,eAAe,IAAI,cAAc,EAAE;IAMnC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIzC;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAK7D;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,EAAE;IAMnD;;OAEG;IACH,gBAAgB,CACd,QAAQ,EAAE,aAAa,EACvB,YAAY,EAAE,aAAa,EAAE,EAC7B,iBAAiB,EAAE,iBAAiB,GACnC,OAAO,EAAE;IA0CZ;;OAEG;IACH,WAAW,CACT,SAAS,EAAE,aAAa,EAAE,EAC1B,iBAAiB,EAAE,iBAAiB,GACnC,OAAO,EAAE;IAgBZ;;OAEG;IACH,OAAO,CAAC,YAAY;IAyBpB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;IAc9D;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,EAAE;IAWvE;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO;CAIxE;AAGD,eAAO,MAAM,iBAAiB,YAAmB,CAAC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rule Engine
|
|
4
|
+
* Orchestrates rule evaluation and finding generation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.defaultRuleEngine = exports.RuleEngine = void 0;
|
|
8
|
+
const execution_1 = require("./execution");
|
|
9
|
+
const filesystem_1 = require("./filesystem");
|
|
10
|
+
const network_1 = require("./network");
|
|
11
|
+
const secrets_1 = require("./secrets");
|
|
12
|
+
const hook_1 = require("./hook");
|
|
13
|
+
const instruction_1 = require("./instruction");
|
|
14
|
+
const scope_1 = require("./scope");
|
|
15
|
+
const observability_1 = require("./observability");
|
|
16
|
+
/**
|
|
17
|
+
* Rule Engine - evaluates all rules against documents
|
|
18
|
+
*/
|
|
19
|
+
class RuleEngine {
|
|
20
|
+
rules;
|
|
21
|
+
options;
|
|
22
|
+
ruleMap;
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.options = {
|
|
25
|
+
minConfidence: options.minConfidence ?? 0.6,
|
|
26
|
+
disabledRules: options.disabledRules ?? [],
|
|
27
|
+
severityOverrides: options.severityOverrides ?? {},
|
|
28
|
+
};
|
|
29
|
+
// Collect all rules
|
|
30
|
+
this.rules = [
|
|
31
|
+
...execution_1.executionRules,
|
|
32
|
+
...filesystem_1.filesystemRules,
|
|
33
|
+
...network_1.networkRules,
|
|
34
|
+
...secrets_1.secretRules,
|
|
35
|
+
...hook_1.hookRules,
|
|
36
|
+
...instruction_1.instructionRules,
|
|
37
|
+
...scope_1.scopeRules,
|
|
38
|
+
...observability_1.observabilityRules,
|
|
39
|
+
];
|
|
40
|
+
// Build rule map for quick lookup
|
|
41
|
+
this.ruleMap = new Map();
|
|
42
|
+
for (const rule of this.rules) {
|
|
43
|
+
this.ruleMap.set(rule.getDefinition().id, rule);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get all available rules
|
|
48
|
+
*/
|
|
49
|
+
getAllRules() {
|
|
50
|
+
return this.rules.map(r => r.getDefinition());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get enabled rules (after applying disabled list)
|
|
54
|
+
*/
|
|
55
|
+
getEnabledRules() {
|
|
56
|
+
return this.rules
|
|
57
|
+
.filter(r => !this.options.disabledRules.includes(r.getDefinition().id))
|
|
58
|
+
.map(r => r.getDefinition());
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get a rule by ID
|
|
62
|
+
*/
|
|
63
|
+
getRule(ruleId) {
|
|
64
|
+
return this.ruleMap.get(ruleId);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get rule definition by ID
|
|
68
|
+
*/
|
|
69
|
+
getRuleDefinition(ruleId) {
|
|
70
|
+
const rule = this.ruleMap.get(ruleId);
|
|
71
|
+
return rule?.getDefinition();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get rules by group
|
|
75
|
+
*/
|
|
76
|
+
getRulesByGroup(group) {
|
|
77
|
+
return this.rules
|
|
78
|
+
.filter(r => r.getDefinition().group === group)
|
|
79
|
+
.map(r => r.getDefinition());
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Evaluate all rules against a single document
|
|
83
|
+
*/
|
|
84
|
+
evaluateDocument(document, allDocuments, capabilitySummary) {
|
|
85
|
+
const findings = [];
|
|
86
|
+
const context = {
|
|
87
|
+
document,
|
|
88
|
+
allDocuments,
|
|
89
|
+
capabilitySummary,
|
|
90
|
+
minConfidence: this.options.minConfidence,
|
|
91
|
+
};
|
|
92
|
+
for (const rule of this.rules) {
|
|
93
|
+
const definition = rule.getDefinition();
|
|
94
|
+
// Skip disabled rules
|
|
95
|
+
if (this.options.disabledRules.includes(definition.id)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const ruleFindings = rule.evaluate(context);
|
|
100
|
+
// Apply severity overrides and filter by confidence
|
|
101
|
+
for (const finding of ruleFindings) {
|
|
102
|
+
// Apply severity override if configured
|
|
103
|
+
if (this.options.severityOverrides[definition.id]) {
|
|
104
|
+
finding.severity = this.options.severityOverrides[definition.id];
|
|
105
|
+
}
|
|
106
|
+
// Filter by confidence threshold
|
|
107
|
+
if (finding.confidence >= this.options.minConfidence) {
|
|
108
|
+
findings.push(finding);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
// Log but don't fail on individual rule errors
|
|
114
|
+
console.error(`Error evaluating rule ${definition.id}:`, error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return findings;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Evaluate all rules against multiple documents
|
|
121
|
+
*/
|
|
122
|
+
evaluateAll(documents, capabilitySummary) {
|
|
123
|
+
const findings = [];
|
|
124
|
+
for (const document of documents) {
|
|
125
|
+
const docFindings = this.evaluateDocument(document, documents, capabilitySummary);
|
|
126
|
+
findings.push(...docFindings);
|
|
127
|
+
}
|
|
128
|
+
// Sort findings: severity (high first), then path, then line
|
|
129
|
+
return this.sortFindings(findings);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Sort findings by severity, path, and line number
|
|
133
|
+
*/
|
|
134
|
+
sortFindings(findings) {
|
|
135
|
+
const severityOrder = {
|
|
136
|
+
high: 0,
|
|
137
|
+
medium: 1,
|
|
138
|
+
low: 2,
|
|
139
|
+
};
|
|
140
|
+
return findings.sort((a, b) => {
|
|
141
|
+
// Sort by severity first
|
|
142
|
+
const severityDiff = severityOrder[a.severity] - severityOrder[b.severity];
|
|
143
|
+
if (severityDiff !== 0)
|
|
144
|
+
return severityDiff;
|
|
145
|
+
// Then by path
|
|
146
|
+
const pathDiff = a.location.path.localeCompare(b.location.path);
|
|
147
|
+
if (pathDiff !== 0)
|
|
148
|
+
return pathDiff;
|
|
149
|
+
// Then by line number
|
|
150
|
+
const lineDiff = a.location.start_line - b.location.start_line;
|
|
151
|
+
if (lineDiff !== 0)
|
|
152
|
+
return lineDiff;
|
|
153
|
+
// Finally by rule ID for stability
|
|
154
|
+
return a.rule_id.localeCompare(b.rule_id);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Count findings by severity
|
|
159
|
+
*/
|
|
160
|
+
countBySeverity(findings) {
|
|
161
|
+
const counts = {
|
|
162
|
+
high: 0,
|
|
163
|
+
medium: 0,
|
|
164
|
+
low: 0,
|
|
165
|
+
};
|
|
166
|
+
for (const finding of findings) {
|
|
167
|
+
counts[finding.severity]++;
|
|
168
|
+
}
|
|
169
|
+
return counts;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Filter findings by minimum severity
|
|
173
|
+
*/
|
|
174
|
+
filterBySeverity(findings, minSeverity) {
|
|
175
|
+
const severityLevel = {
|
|
176
|
+
high: 3,
|
|
177
|
+
medium: 2,
|
|
178
|
+
low: 1,
|
|
179
|
+
};
|
|
180
|
+
const minLevel = severityLevel[minSeverity];
|
|
181
|
+
return findings.filter(f => severityLevel[f.severity] >= minLevel);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check if any finding meets or exceeds the threshold
|
|
185
|
+
*/
|
|
186
|
+
hasFindings(findings, threshold) {
|
|
187
|
+
if (threshold === 'none')
|
|
188
|
+
return false;
|
|
189
|
+
return this.filterBySeverity(findings, threshold).length > 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
exports.RuleEngine = RuleEngine;
|
|
193
|
+
// Export a default instance
|
|
194
|
+
exports.defaultRuleEngine = new RuleEngine();
|
|
195
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/rules/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution Rules (EXEC)
|
|
3
|
+
* Rules for detecting shell execution risks
|
|
4
|
+
*/
|
|
5
|
+
import { Finding } from '../ir/types';
|
|
6
|
+
import { BaseRule } from './base';
|
|
7
|
+
import { RuleContext } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* EXEC-001: Dynamic Shell Execution
|
|
10
|
+
* Detects shell execution where the command is dynamically constructed or fetched
|
|
11
|
+
*/
|
|
12
|
+
export declare class DynamicShellExecutionRule extends BaseRule {
|
|
13
|
+
constructor();
|
|
14
|
+
evaluate(context: RuleContext): Finding[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* EXEC-002: Shell Execution in Non-Interactive Context
|
|
18
|
+
* Shell commands executed inside hooks or auto-triggered contexts
|
|
19
|
+
*/
|
|
20
|
+
export declare class ShellInNonInteractiveRule extends BaseRule {
|
|
21
|
+
constructor();
|
|
22
|
+
evaluate(context: RuleContext): Finding[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* EXEC-003: Broad Shell Capability Declaration
|
|
26
|
+
* Shell execution allowed without scope restriction
|
|
27
|
+
*/
|
|
28
|
+
export declare class BroadShellCapabilityRule extends BaseRule {
|
|
29
|
+
constructor();
|
|
30
|
+
evaluate(context: RuleContext): Finding[];
|
|
31
|
+
}
|
|
32
|
+
export declare const executionRules: (DynamicShellExecutionRule | ShellInNonInteractiveRule | BroadShellCapabilityRule)[];
|
|
33
|
+
//# sourceMappingURL=execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/rules/execution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,WAAW,EAAkB,MAAM,SAAS,CAAC;AAEtD;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,QAAQ;;IAerD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CA2C1C;AAED;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,QAAQ;;IAerD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAmC1C;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;;IAepD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAuC1C;AAGD,eAAO,MAAM,cAAc,sFAI1B,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Execution Rules (EXEC)
|
|
4
|
+
* Rules for detecting shell execution risks
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.executionRules = exports.BroadShellCapabilityRule = exports.ShellInNonInteractiveRule = exports.DynamicShellExecutionRule = void 0;
|
|
8
|
+
const base_1 = require("./base");
|
|
9
|
+
/**
|
|
10
|
+
* EXEC-001: Dynamic Shell Execution
|
|
11
|
+
* Detects shell execution where the command is dynamically constructed or fetched
|
|
12
|
+
*/
|
|
13
|
+
class DynamicShellExecutionRule extends base_1.BaseRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super({
|
|
16
|
+
id: 'EXEC-001',
|
|
17
|
+
group: 'execution',
|
|
18
|
+
severity: 'high',
|
|
19
|
+
title: 'Dynamic Shell Execution',
|
|
20
|
+
description: 'Detects shell execution where the command is dynamically constructed or fetched. This includes patterns like curl|bash, wget|sh, and eval with variables.',
|
|
21
|
+
recommendation: 'Replace with fixed commands or disable shell access. Use pinned, verified installers instead of fetching scripts from the network.',
|
|
22
|
+
tags: ['rce', 'supply-chain', 'dynamic-execution'],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
evaluate(context) {
|
|
26
|
+
const findings = [];
|
|
27
|
+
const { document, minConfidence } = context;
|
|
28
|
+
for (const action of document.actions) {
|
|
29
|
+
if (action.type !== 'shell_exec')
|
|
30
|
+
continue;
|
|
31
|
+
if (!action.shell?.dynamic)
|
|
32
|
+
continue;
|
|
33
|
+
const confidence = action.evidence[0]?.confidence || 0.9;
|
|
34
|
+
if (confidence < minConfidence)
|
|
35
|
+
continue;
|
|
36
|
+
const patterns = action.shell.patterns || [];
|
|
37
|
+
let message = 'Dynamic shell execution detected.';
|
|
38
|
+
if (patterns.includes('curl|bash') || patterns.includes('wget|bash')) {
|
|
39
|
+
message = 'Remote code execution risk: curl|bash or wget|bash pattern detected.';
|
|
40
|
+
}
|
|
41
|
+
else if (patterns.includes('eval')) {
|
|
42
|
+
message = 'Dynamic shell execution via eval detected.';
|
|
43
|
+
}
|
|
44
|
+
else if (patterns.includes('variable_interpolation')) {
|
|
45
|
+
message = 'Shell command with variable interpolation detected.';
|
|
46
|
+
}
|
|
47
|
+
const finding = this.createFinding(document, action.anchors, message, action.evidence, confidence);
|
|
48
|
+
// Add related action info
|
|
49
|
+
finding.related_actions.push({
|
|
50
|
+
action_type: action.type,
|
|
51
|
+
context: action.context,
|
|
52
|
+
summary: action.summary,
|
|
53
|
+
anchors: action.anchors,
|
|
54
|
+
});
|
|
55
|
+
findings.push(finding);
|
|
56
|
+
}
|
|
57
|
+
return findings;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.DynamicShellExecutionRule = DynamicShellExecutionRule;
|
|
61
|
+
/**
|
|
62
|
+
* EXEC-002: Shell Execution in Non-Interactive Context
|
|
63
|
+
* Shell commands executed inside hooks or auto-triggered contexts
|
|
64
|
+
*/
|
|
65
|
+
class ShellInNonInteractiveRule extends base_1.BaseRule {
|
|
66
|
+
constructor() {
|
|
67
|
+
super({
|
|
68
|
+
id: 'EXEC-002',
|
|
69
|
+
group: 'execution',
|
|
70
|
+
severity: 'high',
|
|
71
|
+
title: 'Shell Execution in Non-Interactive Context',
|
|
72
|
+
description: 'Shell commands executed inside hooks or auto-triggered contexts. Users do not explicitly approve these actions at runtime.',
|
|
73
|
+
recommendation: 'Move shell execution to interactive contexts where user approval is required, or remove automatic hook execution.',
|
|
74
|
+
tags: ['rce', 'hook', 'automation'],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
evaluate(context) {
|
|
78
|
+
const findings = [];
|
|
79
|
+
const { document, minConfidence } = context;
|
|
80
|
+
// Only applies to hook context
|
|
81
|
+
if (document.context_profile.primary !== 'hook') {
|
|
82
|
+
return findings;
|
|
83
|
+
}
|
|
84
|
+
for (const action of document.actions) {
|
|
85
|
+
if (action.type !== 'shell_exec')
|
|
86
|
+
continue;
|
|
87
|
+
const confidence = action.evidence[0]?.confidence || 0.9;
|
|
88
|
+
if (confidence < minConfidence)
|
|
89
|
+
continue;
|
|
90
|
+
const finding = this.createFinding(document, action.anchors, `Shell execution in hook context: ${action.summary}. Users do not explicitly approve hook actions.`, action.evidence, confidence);
|
|
91
|
+
finding.related_actions.push({
|
|
92
|
+
action_type: action.type,
|
|
93
|
+
context: action.context,
|
|
94
|
+
summary: action.summary,
|
|
95
|
+
anchors: action.anchors,
|
|
96
|
+
});
|
|
97
|
+
findings.push(finding);
|
|
98
|
+
}
|
|
99
|
+
return findings;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.ShellInNonInteractiveRule = ShellInNonInteractiveRule;
|
|
103
|
+
/**
|
|
104
|
+
* EXEC-003: Broad Shell Capability Declaration
|
|
105
|
+
* Shell execution allowed without scope restriction
|
|
106
|
+
*/
|
|
107
|
+
class BroadShellCapabilityRule extends base_1.BaseRule {
|
|
108
|
+
constructor() {
|
|
109
|
+
super({
|
|
110
|
+
id: 'EXEC-003',
|
|
111
|
+
group: 'execution',
|
|
112
|
+
severity: 'medium',
|
|
113
|
+
title: 'Broad Shell Capability Declaration',
|
|
114
|
+
description: 'Shell execution is allowed without command scope restriction. This enables arbitrary command execution.',
|
|
115
|
+
recommendation: 'Define an explicit command allowlist in the permission manifest, or disable shell execution.',
|
|
116
|
+
tags: ['shell', 'permissions', 'least-privilege'],
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
evaluate(context) {
|
|
120
|
+
const findings = [];
|
|
121
|
+
const { document, capabilitySummary } = context;
|
|
122
|
+
// Check if shell execution is enabled without restrictions
|
|
123
|
+
if (!capabilitySummary.shell_exec.enabled) {
|
|
124
|
+
return findings;
|
|
125
|
+
}
|
|
126
|
+
// Check each capability for unrestricted shell access
|
|
127
|
+
for (const cap of document.capabilities) {
|
|
128
|
+
if (cap.type !== 'shell_exec')
|
|
129
|
+
continue;
|
|
130
|
+
const hasAllowlist = cap.scope.shell_exec?.allowed_commands &&
|
|
131
|
+
cap.scope.shell_exec.allowed_commands.length > 0;
|
|
132
|
+
if (!hasAllowlist) {
|
|
133
|
+
const finding = this.createFinding(document, { start_line: 1, end_line: 1 }, 'Shell execution capability declared without command restrictions.', [
|
|
134
|
+
{
|
|
135
|
+
kind: 'heuristic',
|
|
136
|
+
value: 'shell_exec: enabled without allowlist',
|
|
137
|
+
confidence: 0.8,
|
|
138
|
+
},
|
|
139
|
+
], 0.8);
|
|
140
|
+
findings.push(finding);
|
|
141
|
+
break; // Only report once per document
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return findings;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.BroadShellCapabilityRule = BroadShellCapabilityRule;
|
|
148
|
+
// Export all execution rules
|
|
149
|
+
exports.executionRules = [
|
|
150
|
+
new DynamicShellExecutionRule(),
|
|
151
|
+
new ShellInNonInteractiveRule(),
|
|
152
|
+
new BroadShellCapabilityRule(),
|
|
153
|
+
];
|
|
154
|
+
//# sourceMappingURL=execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/rules/execution.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,iCAAkC;AAGlC;;;GAGG;AACH,MAAa,yBAA0B,SAAQ,eAAQ;IACrD;QACE,KAAK,CAAC;YACJ,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,WAAW;YAClB,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,yBAAyB;YAChC,WAAW,EACT,2JAA2J;YAC7J,cAAc,EACZ,oIAAoI;YACtI,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,mBAAmB,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,OAAoB;QAC3B,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;QAE5C,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO;gBAAE,SAAS;YAErC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,GAAG,CAAC;YACzD,IAAI,UAAU,GAAG,aAAa;gBAAE,SAAS;YAEzC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;YAC7C,IAAI,OAAO,GAAG,mCAAmC,CAAC;YAElD,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrE,OAAO,GAAG,sEAAsE,CAAC;YACnF,CAAC;iBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrC,OAAO,GAAG,4CAA4C,CAAC;YACzD,CAAC;iBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;gBACvD,OAAO,GAAG,qDAAqD,CAAC;YAClE,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAChC,QAAQ,EACR,MAAM,CAAC,OAAO,EACd,OAAO,EACP,MAAM,CAAC,QAAQ,EACf,UAAU,CACX,CAAC;YAEF,0BAA0B;YAC1B,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC;gBAC3B,WAAW,EAAE,MAAM,CAAC,IAAI;gBACxB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YAEH,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AA1DD,8DA0DC;AAED;;;GAGG;AACH,MAAa,yBAA0B,SAAQ,eAAQ;IACrD;QACE,KAAK,CAAC;YACJ,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,WAAW;YAClB,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,4CAA4C;YACnD,WAAW,EACT,4HAA4H;YAC9H,cAAc,EACZ,mHAAmH;YACrH,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,OAAoB;QAC3B,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;QAE5C,+BAA+B;QAC/B,IAAI,QAAQ,CAAC,eAAe,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAChD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAE3C,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,GAAG,CAAC;YACzD,IAAI,UAAU,GAAG,aAAa;gBAAE,SAAS;YAEzC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAChC,QAAQ,EACR,MAAM,CAAC,OAAO,EACd,oCAAoC,MAAM,CAAC,OAAO,iDAAiD,EACnG,MAAM,CAAC,QAAQ,EACf,UAAU,CACX,CAAC;YAEF,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC;gBAC3B,WAAW,EAAE,MAAM,CAAC,IAAI;gBACxB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YAEH,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAlDD,8DAkDC;AAED;;;GAGG;AACH,MAAa,wBAAyB,SAAQ,eAAQ;IACpD;QACE,KAAK,CAAC;YACJ,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,WAAW;YAClB,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,oCAAoC;YAC3C,WAAW,EACT,yGAAyG;YAC3G,cAAc,EACZ,8FAA8F;YAChG,IAAI,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,iBAAiB,CAAC;SAClD,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,OAAoB;QAC3B,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;QAEhD,2DAA2D;QAC3D,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YAC1C,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,sDAAsD;QACtD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;YACxC,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAExC,MAAM,YAAY,GAChB,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,gBAAgB;gBACtC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;YAEnD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAChC,QAAQ,EACR,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAC9B,mEAAmE,EACnE;oBACE;wBACE,IAAI,EAAE,WAAW;wBACjB,KAAK,EAAE,uCAAuC;wBAC9C,UAAU,EAAE,GAAG;qBAChB;iBACF,EACD,GAAG,CACJ,CAAC;gBAEF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACvB,MAAM,CAAC,gCAAgC;YACzC,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAtDD,4DAsDC;AAED,6BAA6B;AAChB,QAAA,cAAc,GAAG;IAC5B,IAAI,yBAAyB,EAAE;IAC/B,IAAI,yBAAyB,EAAE;IAC/B,IAAI,wBAAwB,EAAE;CAC/B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem Rules (FS)
|
|
3
|
+
* Rules for detecting filesystem access risks
|
|
4
|
+
*/
|
|
5
|
+
import { Finding } from '../ir/types';
|
|
6
|
+
import { BaseRule } from './base';
|
|
7
|
+
import { RuleContext } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* FS-001: Unscoped Write Access
|
|
10
|
+
* Agent writes to filesystem without a restricted path scope
|
|
11
|
+
*/
|
|
12
|
+
export declare class UnscopedWriteAccessRule extends BaseRule {
|
|
13
|
+
constructor();
|
|
14
|
+
evaluate(context: RuleContext): Finding[];
|
|
15
|
+
private isUnscopedPath;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* FS-002: Sensitive Path Write
|
|
19
|
+
* Writes to known sensitive locations
|
|
20
|
+
*/
|
|
21
|
+
export declare class SensitivePathWriteRule extends BaseRule {
|
|
22
|
+
constructor();
|
|
23
|
+
evaluate(context: RuleContext): Finding[];
|
|
24
|
+
private isSensitivePath;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* FS-003: Cross-Boundary Write
|
|
28
|
+
* Agent writes outside declared project scope
|
|
29
|
+
*/
|
|
30
|
+
export declare class CrossBoundaryWriteRule extends BaseRule {
|
|
31
|
+
constructor();
|
|
32
|
+
evaluate(context: RuleContext): Finding[];
|
|
33
|
+
private isCrossBoundaryPath;
|
|
34
|
+
}
|
|
35
|
+
export declare const filesystemRules: (UnscopedWriteAccessRule | SensitivePathWriteRule | CrossBoundaryWriteRule)[];
|
|
36
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/rules/filesystem.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,WAAW,EAAkB,MAAM,SAAS,CAAC;AAuBtD;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;;IAenD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IA0DzC,OAAO,CAAC,cAAc;CAiBvB;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;;IAelD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAoEzC,OAAO,CAAC,eAAe;CAMxB;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;;IAelD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAoCzC,OAAO,CAAC,mBAAmB;CAU5B;AAGD,eAAO,MAAM,eAAe,+EAI3B,CAAC"}
|