@elmoxbt/agentskillguard 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/src/types.ts ADDED
@@ -0,0 +1,37 @@
1
+ export type Severity = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
2
+
3
+ export interface Finding {
4
+ ruleId: string;
5
+ capability: string;
6
+ severity: Severity;
7
+ description: string;
8
+ file: string;
9
+ line: number;
10
+ snippet: string;
11
+ }
12
+
13
+ export interface ToolMetadata {
14
+ name?: string;
15
+ version?: string;
16
+ description?: string;
17
+ declaredTools?: string[];
18
+ source: string;
19
+ }
20
+
21
+ export interface Violation {
22
+ capability: string;
23
+ severity: Severity;
24
+ message: string;
25
+ }
26
+
27
+ export interface ScanResult {
28
+ target: string;
29
+ scannedAt: string;
30
+ filesScanned: number;
31
+ metadata: ToolMetadata | null;
32
+ findings: Finding[];
33
+ capabilities: string[];
34
+ violations: Violation[];
35
+ verdict: 'ALLOW' | 'WARN' | 'BLOCK';
36
+ verdictReason: string;
37
+ }
@@ -0,0 +1,37 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ const EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx']);
5
+ const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'coverage']);
6
+
7
+ /**
8
+ * Recursively collects source files under `root` (or returns `[root]` if
9
+ * it's already a single file). Skips node_modules/build output/dotfolders
10
+ * so a scan of a whole agent repo doesn't churn through vendored code.
11
+ */
12
+ export function walk(root: string): string[] {
13
+ const stat = fs.statSync(root);
14
+ if (stat.isFile()) {
15
+ return [root];
16
+ }
17
+
18
+ const results: string[] = [];
19
+
20
+ function recurse(dir: string) {
21
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
22
+ if (entry.isDirectory()) {
23
+ if (IGNORE_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;
24
+ recurse(path.join(dir, entry.name));
25
+ } else if (entry.isFile()) {
26
+ const ext = path.extname(entry.name);
27
+ if (entry.name.endsWith('.d.ts')) continue;
28
+ if (EXTENSIONS.has(ext)) {
29
+ results.push(path.join(dir, entry.name));
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ recurse(root);
36
+ return results;
37
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Minimal assertion-based smoke test — no test framework dependency.
3
+ * Run with: npm test
4
+ */
5
+ import * as assert from 'assert';
6
+ import * as path from 'path';
7
+ import { scanTarget } from '../src/scanner';
8
+ import { loadPolicy } from '../src/policy/loader';
9
+
10
+ function run() {
11
+ const policy = loadPolicy(path.join(__dirname, '../policies/example-swap-agent.yaml'));
12
+
13
+ const malicious = scanTarget(path.join(__dirname, '../examples/malicious-tool'), policy);
14
+ assert.strictEqual(malicious.verdict, 'BLOCK', `expected malicious-tool to BLOCK, got ${malicious.verdict}`);
15
+ assert.ok(malicious.findings.some((f) => f.capability === 'wallet.private_key_access'), 'expected private key finding');
16
+ assert.ok(malicious.findings.some((f) => f.capability === 'system.shell_exec'), 'expected shell-exec finding');
17
+ assert.ok(malicious.findings.some((f) => f.capability === 'code.dynamic_load'), 'expected dynamic-code-load finding');
18
+ console.log('\u2713 malicious-tool correctly BLOCKED (%d findings, %d violations)', malicious.findings.length, malicious.violations.length);
19
+
20
+ const safe = scanTarget(path.join(__dirname, '../examples/safe-tool'), policy);
21
+ assert.strictEqual(safe.verdict, 'ALLOW', `expected safe-tool to ALLOW, got ${safe.verdict}`);
22
+ console.log('\u2713 safe-tool correctly ALLOWED (%d findings, %d violations)', safe.findings.length, safe.violations.length);
23
+
24
+ // No policy supplied at all: hard-floor capabilities must still block.
25
+ const noPolicy = scanTarget(path.join(__dirname, '../examples/malicious-tool'), null);
26
+ assert.strictEqual(noPolicy.verdict, 'BLOCK', 'expected hard-floor capabilities to BLOCK even with no policy');
27
+ console.log('\u2713 hard-floor capabilities BLOCK even without a policy manifest');
28
+
29
+ console.log('\nAll tests passed.');
30
+ }
31
+
32
+ run();
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020"],
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "declaration": false,
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "strict": true,
13
+ "skipLibCheck": true,
14
+ "resolveJsonModule": true
15
+ },
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["node_modules", "dist", "examples", "test"]
18
+ }