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,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network Rules (NET)
|
|
3
|
+
* Rules for detecting network access risks
|
|
4
|
+
*/
|
|
5
|
+
import { Finding } from '../ir/types';
|
|
6
|
+
import { BaseRule } from './base';
|
|
7
|
+
import { RuleContext } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* NET-001: Undeclared Network Access
|
|
10
|
+
* Network calls detected without explicit declaration
|
|
11
|
+
*/
|
|
12
|
+
export declare class UndeclaredNetworkAccessRule extends BaseRule {
|
|
13
|
+
constructor();
|
|
14
|
+
evaluate(context: RuleContext): Finding[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* NET-002: Remote Script Fetch
|
|
18
|
+
* Network call that fetches executable content
|
|
19
|
+
*/
|
|
20
|
+
export declare class RemoteScriptFetchRule extends BaseRule {
|
|
21
|
+
constructor();
|
|
22
|
+
evaluate(context: RuleContext): Finding[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* NET-003: Broad Network Access
|
|
26
|
+
* Outbound network access without domain restriction
|
|
27
|
+
*/
|
|
28
|
+
export declare class BroadNetworkAccessRule extends BaseRule {
|
|
29
|
+
constructor();
|
|
30
|
+
evaluate(context: RuleContext): Finding[];
|
|
31
|
+
}
|
|
32
|
+
export declare const networkRules: (UndeclaredNetworkAccessRule | RemoteScriptFetchRule | BroadNetworkAccessRule)[];
|
|
33
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/rules/network.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,2BAA4B,SAAQ,QAAQ;;IAevD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CA+C1C;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;;IAejD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAgC1C;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;;IAelD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAuC1C;AAGD,eAAO,MAAM,YAAY,kFAIxB,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Network Rules (NET)
|
|
4
|
+
* Rules for detecting network access risks
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.networkRules = exports.BroadNetworkAccessRule = exports.RemoteScriptFetchRule = exports.UndeclaredNetworkAccessRule = void 0;
|
|
8
|
+
const base_1 = require("./base");
|
|
9
|
+
/**
|
|
10
|
+
* NET-001: Undeclared Network Access
|
|
11
|
+
* Network calls detected without explicit declaration
|
|
12
|
+
*/
|
|
13
|
+
class UndeclaredNetworkAccessRule extends base_1.BaseRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super({
|
|
16
|
+
id: 'NET-001',
|
|
17
|
+
group: 'network',
|
|
18
|
+
severity: 'high',
|
|
19
|
+
title: 'Undeclared Network Access',
|
|
20
|
+
description: 'Network calls detected without explicit capability declaration. This poses a silent exfiltration risk.',
|
|
21
|
+
recommendation: 'Explicitly declare network access in the permission manifest, or disable network access if not required.',
|
|
22
|
+
tags: ['network', 'exfiltration', 'undeclared'],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
evaluate(context) {
|
|
26
|
+
const findings = [];
|
|
27
|
+
const { document, capabilitySummary, minConfidence } = context;
|
|
28
|
+
// Check if network capability is declared
|
|
29
|
+
const hasNetworkCapability = capabilitySummary.network.outbound || capabilitySummary.network.inbound;
|
|
30
|
+
for (const action of document.actions) {
|
|
31
|
+
if (action.type !== 'network_call')
|
|
32
|
+
continue;
|
|
33
|
+
const confidence = action.evidence[0]?.confidence || 0.9;
|
|
34
|
+
if (confidence < minConfidence)
|
|
35
|
+
continue;
|
|
36
|
+
// If network actions exist but capability is not declared
|
|
37
|
+
const urls = action.network?.urls || [];
|
|
38
|
+
const domains = action.network?.domains || [];
|
|
39
|
+
// Check if this specific domain/URL is allowed
|
|
40
|
+
const isAllowed = hasNetworkCapability &&
|
|
41
|
+
domains.every(d => capabilitySummary.network.allowed_domains.includes(d));
|
|
42
|
+
if (!hasNetworkCapability || !isAllowed) {
|
|
43
|
+
const finding = this.createFinding(document, action.anchors, `Network access to ${urls.join(', ') || domains.join(', ')} detected without explicit declaration.`, action.evidence, confidence);
|
|
44
|
+
finding.related_actions.push({
|
|
45
|
+
action_type: action.type,
|
|
46
|
+
context: action.context,
|
|
47
|
+
summary: action.summary,
|
|
48
|
+
anchors: action.anchors,
|
|
49
|
+
});
|
|
50
|
+
findings.push(finding);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return findings;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.UndeclaredNetworkAccessRule = UndeclaredNetworkAccessRule;
|
|
57
|
+
/**
|
|
58
|
+
* NET-002: Remote Script Fetch
|
|
59
|
+
* Network call that fetches executable content
|
|
60
|
+
*/
|
|
61
|
+
class RemoteScriptFetchRule extends base_1.BaseRule {
|
|
62
|
+
constructor() {
|
|
63
|
+
super({
|
|
64
|
+
id: 'NET-002',
|
|
65
|
+
group: 'network',
|
|
66
|
+
severity: 'high',
|
|
67
|
+
title: 'Remote Script Fetch',
|
|
68
|
+
description: 'Network call that fetches executable content such as scripts or binaries. This is a major supply-chain risk.',
|
|
69
|
+
recommendation: 'Avoid fetching executable content from the network. Use pinned, verified artifacts from trusted sources.',
|
|
70
|
+
tags: ['network', 'executable', 'supply-chain'],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
evaluate(context) {
|
|
74
|
+
const findings = [];
|
|
75
|
+
const { document, minConfidence } = context;
|
|
76
|
+
for (const action of document.actions) {
|
|
77
|
+
if (action.type !== 'network_call')
|
|
78
|
+
continue;
|
|
79
|
+
if (!action.network?.fetches_executable)
|
|
80
|
+
continue;
|
|
81
|
+
const confidence = action.evidence[0]?.confidence || 0.95;
|
|
82
|
+
if (confidence < minConfidence)
|
|
83
|
+
continue;
|
|
84
|
+
const urls = action.network?.urls || [];
|
|
85
|
+
const finding = this.createFinding(document, action.anchors, `Remote executable content fetched from: ${urls.join(', ')}. This is a supply-chain attack vector.`, action.evidence, confidence);
|
|
86
|
+
finding.related_actions.push({
|
|
87
|
+
action_type: action.type,
|
|
88
|
+
context: action.context,
|
|
89
|
+
summary: action.summary,
|
|
90
|
+
anchors: action.anchors,
|
|
91
|
+
});
|
|
92
|
+
findings.push(finding);
|
|
93
|
+
}
|
|
94
|
+
return findings;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.RemoteScriptFetchRule = RemoteScriptFetchRule;
|
|
98
|
+
/**
|
|
99
|
+
* NET-003: Broad Network Access
|
|
100
|
+
* Outbound network access without domain restriction
|
|
101
|
+
*/
|
|
102
|
+
class BroadNetworkAccessRule extends base_1.BaseRule {
|
|
103
|
+
constructor() {
|
|
104
|
+
super({
|
|
105
|
+
id: 'NET-003',
|
|
106
|
+
group: 'network',
|
|
107
|
+
severity: 'medium',
|
|
108
|
+
title: 'Broad Network Access',
|
|
109
|
+
description: 'Outbound network access is enabled without domain restrictions. This allows data exfiltration to any destination.',
|
|
110
|
+
recommendation: 'Restrict network access to specific, trusted domains using an allowlist.',
|
|
111
|
+
tags: ['network', 'outbound', 'least-privilege'],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
evaluate(context) {
|
|
115
|
+
const findings = [];
|
|
116
|
+
const { document, capabilitySummary } = context;
|
|
117
|
+
// Check if outbound network is enabled without domain restrictions
|
|
118
|
+
if (!capabilitySummary.network.outbound) {
|
|
119
|
+
return findings;
|
|
120
|
+
}
|
|
121
|
+
const hasRestrictions = capabilitySummary.network.allowed_domains.length > 0;
|
|
122
|
+
if (!hasRestrictions) {
|
|
123
|
+
// Find the first network action for location reference
|
|
124
|
+
const networkAction = document.actions.find(a => a.type === 'network_call');
|
|
125
|
+
const anchors = networkAction?.anchors || { start_line: 1, end_line: 1 };
|
|
126
|
+
const finding = this.createFinding(document, anchors, 'Outbound network access enabled without domain restrictions.', [
|
|
127
|
+
{
|
|
128
|
+
kind: 'heuristic',
|
|
129
|
+
value: 'network.outbound: true without allowed_domains',
|
|
130
|
+
confidence: 0.8,
|
|
131
|
+
},
|
|
132
|
+
], 0.8);
|
|
133
|
+
findings.push(finding);
|
|
134
|
+
}
|
|
135
|
+
return findings;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.BroadNetworkAccessRule = BroadNetworkAccessRule;
|
|
139
|
+
// Export all network rules
|
|
140
|
+
exports.networkRules = [
|
|
141
|
+
new UndeclaredNetworkAccessRule(),
|
|
142
|
+
new RemoteScriptFetchRule(),
|
|
143
|
+
new BroadNetworkAccessRule(),
|
|
144
|
+
];
|
|
145
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/rules/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability & Audit Rules (OBS)
|
|
3
|
+
* Rules for ensuring visibility and auditability
|
|
4
|
+
*/
|
|
5
|
+
import { Finding } from '../ir/types';
|
|
6
|
+
import { BaseRule } from './base';
|
|
7
|
+
import { RuleContext } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* OBS-001: Missing Capability Declaration
|
|
10
|
+
* Actions present without declared capabilities
|
|
11
|
+
*/
|
|
12
|
+
export declare class MissingCapabilityDeclarationRule extends BaseRule {
|
|
13
|
+
constructor();
|
|
14
|
+
evaluate(context: RuleContext): Finding[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OBS-002: No Permission Manifest
|
|
18
|
+
* Agent config exists without explicit permission declaration
|
|
19
|
+
*/
|
|
20
|
+
export declare class NoPermissionManifestRule extends BaseRule {
|
|
21
|
+
constructor();
|
|
22
|
+
evaluate(context: RuleContext): Finding[];
|
|
23
|
+
}
|
|
24
|
+
export declare const observabilityRules: (MissingCapabilityDeclarationRule | NoPermissionManifestRule)[];
|
|
25
|
+
//# sourceMappingURL=observability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../../src/rules/observability.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,gCAAiC,SAAQ,QAAQ;;IAe5D,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CA2C1C;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;;IAepD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAkC1C;AAGD,eAAO,MAAM,kBAAkB,iEAG9B,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Observability & Audit Rules (OBS)
|
|
4
|
+
* Rules for ensuring visibility and auditability
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.observabilityRules = exports.NoPermissionManifestRule = exports.MissingCapabilityDeclarationRule = void 0;
|
|
8
|
+
const base_1 = require("./base");
|
|
9
|
+
/**
|
|
10
|
+
* OBS-001: Missing Capability Declaration
|
|
11
|
+
* Actions present without declared capabilities
|
|
12
|
+
*/
|
|
13
|
+
class MissingCapabilityDeclarationRule extends base_1.BaseRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super({
|
|
16
|
+
id: 'OBS-001',
|
|
17
|
+
group: 'observability',
|
|
18
|
+
severity: 'medium',
|
|
19
|
+
title: 'Missing Capability Declaration',
|
|
20
|
+
description: 'Actions are present without corresponding capability declarations. This creates opaque behavior that is difficult to audit.',
|
|
21
|
+
recommendation: 'Declare all capabilities explicitly in the permission manifest. This improves visibility and enables policy enforcement.',
|
|
22
|
+
tags: ['observability', 'capabilities', 'audit'],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
evaluate(context) {
|
|
26
|
+
const findings = [];
|
|
27
|
+
const { document, capabilitySummary } = context;
|
|
28
|
+
// Check for undeclared action types
|
|
29
|
+
const actionTypes = new Set(document.actions.map(a => a.type));
|
|
30
|
+
const declaredCapabilities = new Set(document.capabilities.map(c => c.type));
|
|
31
|
+
// Map action types to expected capability types
|
|
32
|
+
const actionToCapability = {
|
|
33
|
+
shell_exec: 'shell_exec',
|
|
34
|
+
network_call: 'network',
|
|
35
|
+
file_write: 'filesystem',
|
|
36
|
+
file_read: 'filesystem',
|
|
37
|
+
git_operation: 'git',
|
|
38
|
+
};
|
|
39
|
+
for (const actionType of actionTypes) {
|
|
40
|
+
const expectedCap = actionToCapability[actionType];
|
|
41
|
+
if (expectedCap && !declaredCapabilities.has(expectedCap)) {
|
|
42
|
+
// Find an action of this type for location
|
|
43
|
+
const action = document.actions.find(a => a.type === actionType);
|
|
44
|
+
if (action) {
|
|
45
|
+
const finding = this.createFinding(document, action.anchors, `Action "${actionType}" performed without declared capability.`, [
|
|
46
|
+
{
|
|
47
|
+
kind: 'heuristic',
|
|
48
|
+
value: `Action type ${actionType} without ${expectedCap} capability`,
|
|
49
|
+
confidence: 0.75,
|
|
50
|
+
},
|
|
51
|
+
], 0.75);
|
|
52
|
+
findings.push(finding);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return findings;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.MissingCapabilityDeclarationRule = MissingCapabilityDeclarationRule;
|
|
60
|
+
/**
|
|
61
|
+
* OBS-002: No Permission Manifest
|
|
62
|
+
* Agent config exists without explicit permission declaration
|
|
63
|
+
*/
|
|
64
|
+
class NoPermissionManifestRule extends base_1.BaseRule {
|
|
65
|
+
constructor() {
|
|
66
|
+
super({
|
|
67
|
+
id: 'OBS-002',
|
|
68
|
+
group: 'observability',
|
|
69
|
+
severity: 'low',
|
|
70
|
+
title: 'No Permission Manifest',
|
|
71
|
+
description: 'Agent configuration exists without an explicit permission declaration. This encourages good hygiene and auditability.',
|
|
72
|
+
recommendation: 'Add an explicit permission manifest to the agent configuration. This documents expected capabilities and enables policy enforcement.',
|
|
73
|
+
tags: ['observability', 'manifest', 'documentation'],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
evaluate(context) {
|
|
77
|
+
const findings = [];
|
|
78
|
+
const { document } = context;
|
|
79
|
+
// Check if document has any capabilities but no manifest
|
|
80
|
+
if (document.capabilities.length > 0) {
|
|
81
|
+
// Check if there's a permission declaration in instruction blocks
|
|
82
|
+
const hasPermissionBlock = document.instruction_blocks.some(b => b.text.toLowerCase().includes('permission') ||
|
|
83
|
+
b.text.toLowerCase().includes('capability') ||
|
|
84
|
+
b.text.toLowerCase().includes('allowed'));
|
|
85
|
+
if (!hasPermissionBlock) {
|
|
86
|
+
const finding = this.createFinding(document, { start_line: 1, end_line: 1 }, 'Agent configuration has capabilities but no explicit permission manifest.', [
|
|
87
|
+
{
|
|
88
|
+
kind: 'heuristic',
|
|
89
|
+
value: 'No permission declaration found in document',
|
|
90
|
+
confidence: 0.6,
|
|
91
|
+
},
|
|
92
|
+
], 0.6);
|
|
93
|
+
findings.push(finding);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return findings;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.NoPermissionManifestRule = NoPermissionManifestRule;
|
|
100
|
+
// Export all observability rules
|
|
101
|
+
exports.observabilityRules = [
|
|
102
|
+
new MissingCapabilityDeclarationRule(),
|
|
103
|
+
new NoPermissionManifestRule(),
|
|
104
|
+
];
|
|
105
|
+
//# sourceMappingURL=observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability.js","sourceRoot":"","sources":["../../src/rules/observability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope Expansion Rules (SCOPE)
|
|
3
|
+
* Rules for detecting capability and scope expansion
|
|
4
|
+
* Note: These rules are primarily used in diff mode
|
|
5
|
+
*/
|
|
6
|
+
import { Finding, CapabilitySummary } from '../ir/types';
|
|
7
|
+
import { BaseRule } from './base';
|
|
8
|
+
import { RuleContext } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* SCOPE-001: Capability Expansion Between Versions
|
|
11
|
+
* Diff detects new capabilities added
|
|
12
|
+
*/
|
|
13
|
+
export declare class CapabilityExpansionRule extends BaseRule {
|
|
14
|
+
constructor();
|
|
15
|
+
evaluate(context: RuleContext): Finding[];
|
|
16
|
+
/**
|
|
17
|
+
* Compare two capability summaries for expansion (used by diff engine)
|
|
18
|
+
*/
|
|
19
|
+
static detectExpansion(base: CapabilitySummary, target: CapabilitySummary): string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* SCOPE-002: Write Scope Widening
|
|
23
|
+
* File write paths have been broadened
|
|
24
|
+
*/
|
|
25
|
+
export declare class WriteScopeWideningRule extends BaseRule {
|
|
26
|
+
constructor();
|
|
27
|
+
evaluate(context: RuleContext): Finding[];
|
|
28
|
+
/**
|
|
29
|
+
* Compare two write scopes for widening (used by diff engine)
|
|
30
|
+
*/
|
|
31
|
+
static detectWidening(baseWrites: string[], targetWrites: string[]): {
|
|
32
|
+
widened: boolean;
|
|
33
|
+
changes: string[];
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare const scopeRules: (CapabilityExpansionRule | WriteScopeWideningRule)[];
|
|
37
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/rules/scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,WAAW,EAAkB,MAAM,SAAS,CAAC;AAGtD;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;;IAenD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAiDzC;;OAEG;IACH,MAAM,CAAC,eAAe,CACpB,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,iBAAiB,GACxB,MAAM,EAAE;CAoDZ;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;;IAelD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAiCzC;;OAEG;IACH,MAAM,CAAC,cAAc,CACnB,UAAU,EAAE,MAAM,EAAE,EACpB,YAAY,EAAE,MAAM,EAAE,GACrB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE;CA0B3C;AAGD,eAAO,MAAM,UAAU,sDAGtB,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Scope Expansion Rules (SCOPE)
|
|
4
|
+
* Rules for detecting capability and scope expansion
|
|
5
|
+
* Note: These rules are primarily used in diff mode
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.scopeRules = exports.WriteScopeWideningRule = exports.CapabilityExpansionRule = void 0;
|
|
9
|
+
const base_1 = require("./base");
|
|
10
|
+
/**
|
|
11
|
+
* SCOPE-001: Capability Expansion Between Versions
|
|
12
|
+
* Diff detects new capabilities added
|
|
13
|
+
*/
|
|
14
|
+
class CapabilityExpansionRule extends base_1.BaseRule {
|
|
15
|
+
constructor() {
|
|
16
|
+
super({
|
|
17
|
+
id: 'SCOPE-001',
|
|
18
|
+
group: 'scope',
|
|
19
|
+
severity: 'high',
|
|
20
|
+
title: 'Capability Expansion Between Versions',
|
|
21
|
+
description: 'New capabilities have been added, equivalent to permission escalation. This includes shell execution, network access, or sensitive file operations.',
|
|
22
|
+
recommendation: 'Review the capability expansion carefully. Ensure new capabilities are intentional and follow least-privilege principles.',
|
|
23
|
+
tags: ['scope', 'expansion', 'diff', 'permissions'],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
evaluate(context) {
|
|
27
|
+
// This rule is primarily for diff mode
|
|
28
|
+
// In scan mode, we report on detected high-risk capabilities
|
|
29
|
+
const findings = [];
|
|
30
|
+
const { document, capabilitySummary } = context;
|
|
31
|
+
// Report if dynamic shell execution is detected (capability expansion indicator)
|
|
32
|
+
if (capabilitySummary.shell_exec.dynamic_detected) {
|
|
33
|
+
const finding = this.createFinding(document, { start_line: 1, end_line: 1 }, 'Dynamic shell execution capability detected. This is a high-risk capability.', [
|
|
34
|
+
{
|
|
35
|
+
kind: 'heuristic',
|
|
36
|
+
value: 'shell_exec.dynamic_detected: true',
|
|
37
|
+
confidence: 0.9,
|
|
38
|
+
},
|
|
39
|
+
], 0.9);
|
|
40
|
+
findings.push(finding);
|
|
41
|
+
}
|
|
42
|
+
// Report if network + shell combination is detected
|
|
43
|
+
if (capabilitySummary.network.outbound &&
|
|
44
|
+
capabilitySummary.shell_exec.enabled &&
|
|
45
|
+
capabilitySummary.network.fetches_executable) {
|
|
46
|
+
const finding = this.createFinding(document, { start_line: 1, end_line: 1 }, 'Remote code execution capability pattern detected: network + shell + executable fetch.', [
|
|
47
|
+
{
|
|
48
|
+
kind: 'heuristic',
|
|
49
|
+
value: 'RCE pattern: network.outbound + shell_exec + fetches_executable',
|
|
50
|
+
confidence: 0.95,
|
|
51
|
+
},
|
|
52
|
+
], 0.95);
|
|
53
|
+
findings.push(finding);
|
|
54
|
+
}
|
|
55
|
+
return findings;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Compare two capability summaries for expansion (used by diff engine)
|
|
59
|
+
*/
|
|
60
|
+
static detectExpansion(base, target) {
|
|
61
|
+
const expansions = [];
|
|
62
|
+
// Shell execution expansion
|
|
63
|
+
if (!base.shell_exec.enabled && target.shell_exec.enabled) {
|
|
64
|
+
expansions.push('shell_exec: false → true');
|
|
65
|
+
}
|
|
66
|
+
if (!base.shell_exec.dynamic_detected && target.shell_exec.dynamic_detected) {
|
|
67
|
+
expansions.push('shell_exec.dynamic: false → true');
|
|
68
|
+
}
|
|
69
|
+
// Network expansion
|
|
70
|
+
if (!base.network.outbound && target.network.outbound) {
|
|
71
|
+
expansions.push('network.outbound: false → true');
|
|
72
|
+
}
|
|
73
|
+
if (!base.network.inbound && target.network.inbound) {
|
|
74
|
+
expansions.push('network.inbound: false → true');
|
|
75
|
+
}
|
|
76
|
+
if (!base.network.fetches_executable && target.network.fetches_executable) {
|
|
77
|
+
expansions.push('network.fetches_executable: false → true');
|
|
78
|
+
}
|
|
79
|
+
// Secrets expansion
|
|
80
|
+
const newSecretVars = target.secrets.env_vars_referenced.filter(v => !base.secrets.env_vars_referenced.includes(v));
|
|
81
|
+
if (newSecretVars.length > 0) {
|
|
82
|
+
expansions.push(`secrets.env_vars: added ${newSecretVars.join(', ')}`);
|
|
83
|
+
}
|
|
84
|
+
if (!base.secrets.propagation_detected && target.secrets.propagation_detected) {
|
|
85
|
+
expansions.push('secrets.propagation: false → true');
|
|
86
|
+
}
|
|
87
|
+
// Context expansion
|
|
88
|
+
if (!base.contexts.has_hooks && target.contexts.has_hooks) {
|
|
89
|
+
expansions.push('context.hooks: false → true');
|
|
90
|
+
}
|
|
91
|
+
if (!base.contexts.has_ci_context && target.contexts.has_ci_context) {
|
|
92
|
+
expansions.push('context.ci: false → true');
|
|
93
|
+
}
|
|
94
|
+
// Sensitive paths expansion
|
|
95
|
+
const newSensitivePaths = target.filesystem.touches_sensitive_paths.filter(p => !base.filesystem.touches_sensitive_paths.includes(p));
|
|
96
|
+
if (newSensitivePaths.length > 0) {
|
|
97
|
+
expansions.push(`filesystem.sensitive_paths: added ${newSensitivePaths.join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
return expansions;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.CapabilityExpansionRule = CapabilityExpansionRule;
|
|
103
|
+
/**
|
|
104
|
+
* SCOPE-002: Write Scope Widening
|
|
105
|
+
* File write paths have been broadened
|
|
106
|
+
*/
|
|
107
|
+
class WriteScopeWideningRule extends base_1.BaseRule {
|
|
108
|
+
constructor() {
|
|
109
|
+
super({
|
|
110
|
+
id: 'SCOPE-002',
|
|
111
|
+
group: 'scope',
|
|
112
|
+
severity: 'medium',
|
|
113
|
+
title: 'Write Scope Widening',
|
|
114
|
+
description: 'File write access scope has been widened, potentially allowing writes to more locations.',
|
|
115
|
+
recommendation: 'Verify that expanded write scope is intentional. Keep write access as narrow as possible.',
|
|
116
|
+
tags: ['scope', 'filesystem', 'write', 'diff'],
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
evaluate(context) {
|
|
120
|
+
// This rule is primarily for diff mode
|
|
121
|
+
// In scan mode, we check for broad write scopes
|
|
122
|
+
const findings = [];
|
|
123
|
+
const { document, capabilitySummary } = context;
|
|
124
|
+
// Check for overly broad write patterns
|
|
125
|
+
const broadPatterns = ['**/*', '**', '*', './'];
|
|
126
|
+
const writePaths = capabilitySummary.filesystem.write;
|
|
127
|
+
for (const path of writePaths) {
|
|
128
|
+
if (broadPatterns.some(p => path === p || path.startsWith(p + '/'))) {
|
|
129
|
+
const finding = this.createFinding(document, { start_line: 1, end_line: 1 }, `Broad write scope detected: "${path}". This allows writes to many locations.`, [
|
|
130
|
+
{
|
|
131
|
+
kind: 'heuristic',
|
|
132
|
+
value: `filesystem.write includes broad pattern: ${path}`,
|
|
133
|
+
confidence: 0.85,
|
|
134
|
+
},
|
|
135
|
+
], 0.85);
|
|
136
|
+
findings.push(finding);
|
|
137
|
+
break; // Report once per document
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return findings;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Compare two write scopes for widening (used by diff engine)
|
|
144
|
+
*/
|
|
145
|
+
static detectWidening(baseWrites, targetWrites) {
|
|
146
|
+
const changes = [];
|
|
147
|
+
let widened = false;
|
|
148
|
+
// Check for new broad patterns
|
|
149
|
+
const broadPatterns = ['**/*', '**', '*'];
|
|
150
|
+
// Check if target has broad patterns that base didn't have
|
|
151
|
+
for (const pattern of broadPatterns) {
|
|
152
|
+
const targetHas = targetWrites.some(w => w === pattern || w.includes(pattern));
|
|
153
|
+
const baseHad = baseWrites.some(w => w === pattern || w.includes(pattern));
|
|
154
|
+
if (targetHas && !baseHad) {
|
|
155
|
+
widened = true;
|
|
156
|
+
changes.push(`Write scope widened to include: ${pattern}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Check for new write paths
|
|
160
|
+
const newPaths = targetWrites.filter(p => !baseWrites.includes(p));
|
|
161
|
+
if (newPaths.length > 0) {
|
|
162
|
+
changes.push(`New write paths added: ${newPaths.join(', ')}`);
|
|
163
|
+
}
|
|
164
|
+
return { widened, changes };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.WriteScopeWideningRule = WriteScopeWideningRule;
|
|
168
|
+
// Export all scope rules
|
|
169
|
+
exports.scopeRules = [
|
|
170
|
+
new CapabilityExpansionRule(),
|
|
171
|
+
new WriteScopeWideningRule(),
|
|
172
|
+
];
|
|
173
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/rules/scope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential & Secret Rules (SEC)
|
|
3
|
+
* Rules for detecting credential and secret access risks
|
|
4
|
+
*/
|
|
5
|
+
import { Finding } from '../ir/types';
|
|
6
|
+
import { BaseRule } from './base';
|
|
7
|
+
import { RuleContext } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* SEC-001: Environment Secret Reference
|
|
10
|
+
* References to known secret environment variables
|
|
11
|
+
*/
|
|
12
|
+
export declare class EnvironmentSecretReferenceRule extends BaseRule {
|
|
13
|
+
constructor();
|
|
14
|
+
evaluate(context: RuleContext): Finding[];
|
|
15
|
+
private isKnownSecretVar;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* SEC-002: Implicit Secret Access
|
|
19
|
+
* Access to .env or config files likely containing secrets
|
|
20
|
+
*/
|
|
21
|
+
export declare class ImplicitSecretAccessRule extends BaseRule {
|
|
22
|
+
constructor();
|
|
23
|
+
evaluate(context: RuleContext): Finding[];
|
|
24
|
+
private isSecretFile;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* SEC-003: Secret Propagation
|
|
28
|
+
* Secrets used in shell commands, network calls, or file writes
|
|
29
|
+
*/
|
|
30
|
+
export declare class SecretPropagationRule extends BaseRule {
|
|
31
|
+
constructor();
|
|
32
|
+
evaluate(context: RuleContext): Finding[];
|
|
33
|
+
}
|
|
34
|
+
export declare const secretRules: (EnvironmentSecretReferenceRule | ImplicitSecretAccessRule | SecretPropagationRule)[];
|
|
35
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/rules/secrets.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;AAwEtD;;;GAGG;AACH,qBAAa,8BAA+B,SAAQ,QAAQ;;IAe1D,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAgEzC,OAAO,CAAC,gBAAgB;CAMzB;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;;IAepD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;IAuEzC,OAAO,CAAC,YAAY;CAQrB;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;;IAejD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE;CAwD1C;AAGD,eAAO,MAAM,WAAW,uFAIvB,CAAC"}
|