aegis-mcp-server 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/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +144 -0
- package/dist/index.js.map +1 -0
- package/dist/services/enforcement-engine.d.ts +64 -0
- package/dist/services/enforcement-engine.d.ts.map +1 -0
- package/dist/services/enforcement-engine.js +271 -0
- package/dist/services/enforcement-engine.js.map +1 -0
- package/dist/services/policy-loader.d.ts +56 -0
- package/dist/services/policy-loader.d.ts.map +1 -0
- package/dist/services/policy-loader.js +202 -0
- package/dist/services/policy-loader.js.map +1 -0
- package/dist/tools/file-tools.d.ts +21 -0
- package/dist/tools/file-tools.d.ts.map +1 -0
- package/dist/tools/file-tools.js +369 -0
- package/dist/tools/file-tools.js.map +1 -0
- package/dist/types.d.ts +286 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
- package/src/index.ts +171 -0
- package/src/services/enforcement-engine.ts +322 -0
- package/src/services/policy-loader.ts +255 -0
- package/src/tools/file-tools.ts +453 -0
- package/src/types.ts +305 -0
- package/tsconfig.json +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Cleburn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# aegis-mcp-server
|
|
2
|
+
|
|
3
|
+
**MCP enforcement layer for the [Aegis](https://github.com/cleburn/aegis-spec) agent governance specification.**
|
|
4
|
+
|
|
5
|
+
The spec writes the law. The CLI generates the law. This enforces the law.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
`aegis-mcp-server` is an MCP server that validates every agent action against your `.agentpolicy/` files **before** it happens. Path permissions, content scanning, role boundaries, quality gates — all enforced at runtime with zero token overhead to the agent.
|
|
10
|
+
|
|
11
|
+
The agent never loads your governance files. The MCP server reads them into its own process memory and validates silently. The agent calls governed tools (`aegis_write_file`, `aegis_read_file`, etc.) and gets back either a success or a blocked response with the specific reason.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g aegis-mcp-server
|
|
17
|
+
|
|
18
|
+
# Or use npx
|
|
19
|
+
npx aegis-mcp-server --project . --role default
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Claude Code Configuration
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"aegis": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["aegis-mcp-server", "--project", ".", "--role", "default"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For role-specific enforcement:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"aegis": {
|
|
41
|
+
"command": "npx",
|
|
42
|
+
"args": ["aegis-mcp-server", "--project", ".", "--role", "backend"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
| Tool | What it does | Token cost |
|
|
51
|
+
|------|-------------|------------|
|
|
52
|
+
| `aegis_check_permissions` | Pre-check if an operation is allowed | Tiny — just the verdict |
|
|
53
|
+
| `aegis_write_file` | Write with path + content validation | Same as a normal write |
|
|
54
|
+
| `aegis_read_file` | Read with path validation | Same as a normal read |
|
|
55
|
+
| `aegis_delete_file` | Delete with path validation | Tiny — just the verdict |
|
|
56
|
+
| `aegis_execute` | Execute a command in project root | Command output only |
|
|
57
|
+
| `aegis_complete_task` | Run quality gates before marking done | Gate results only |
|
|
58
|
+
| `aegis_policy_summary` | Minimal role + permissions summary | ~200 tokens |
|
|
59
|
+
|
|
60
|
+
## Zero Token Overhead
|
|
61
|
+
|
|
62
|
+
Traditional approach: load governance files into the agent's context window. Token cost scales with policy complexity.
|
|
63
|
+
|
|
64
|
+
Aegis MCP approach: the server loads policy into its own process memory. The agent calls tools and gets structured results. A project with 200 lines of governance has the same token cost as one with 20 lines. The complexity is absorbed by the server, not the agent.
|
|
65
|
+
|
|
66
|
+
## Enforcement
|
|
67
|
+
|
|
68
|
+
- **Governance boundaries** — `writable`, `read_only`, `forbidden` path lists from governance.json
|
|
69
|
+
- **Role scoping** — agents confined to their role's writable and readable paths
|
|
70
|
+
- **Sensitive pattern detection** — content scanned against governance-defined patterns
|
|
71
|
+
- **Cross-domain boundaries** — imports validated against shared interface rules (when configured)
|
|
72
|
+
- **Quality gate validation** — `pre_commit` flags mapped to `build_commands` and executed
|
|
73
|
+
- **Override logging** — violations logged to append-only `overrides.jsonl`
|
|
74
|
+
- **Immutable policies** — designated rules that cannot be overridden, even with human confirmation
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Agent ──→ aegis-mcp-server ──→ File System
|
|
80
|
+
│
|
|
81
|
+
├── Loads .agentpolicy/ into process memory (once)
|
|
82
|
+
├── Watches for policy changes (auto-reload)
|
|
83
|
+
├── Validates every tool call against policy
|
|
84
|
+
└── Returns success or blocked with reason
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Three artifacts, one governance framework:
|
|
88
|
+
|
|
89
|
+
- [**aegis-spec**](https://github.com/cleburn/aegis-spec) — Writes the law
|
|
90
|
+
- [**aegis-cli**](https://github.com/cleburn/aegis-cli) — Generates the law
|
|
91
|
+
- **aegis-mcp-server** — Enforces the law
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aegis MCP Server — Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Starts the MCP enforcement server. Loads .agentpolicy/ into process memory,
|
|
6
|
+
* registers governed tools, and connects via stdio transport.
|
|
7
|
+
*
|
|
8
|
+
* The agent connects to this server and calls governed tools (aegis_write_file,
|
|
9
|
+
* aegis_read_file, etc.) instead of raw file system operations. All validation
|
|
10
|
+
* happens in this process at zero token cost to the agent.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* aegis-mcp --project /path/to/project --role backend
|
|
14
|
+
*
|
|
15
|
+
* Claude Code MCP config:
|
|
16
|
+
* {
|
|
17
|
+
* "mcpServers": {
|
|
18
|
+
* "aegis": {
|
|
19
|
+
* "command": "npx",
|
|
20
|
+
* "args": ["aegis-mcp-server", "--project", ".", "--role", "default"]
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aegis MCP Server — Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Starts the MCP enforcement server. Loads .agentpolicy/ into process memory,
|
|
6
|
+
* registers governed tools, and connects via stdio transport.
|
|
7
|
+
*
|
|
8
|
+
* The agent connects to this server and calls governed tools (aegis_write_file,
|
|
9
|
+
* aegis_read_file, etc.) instead of raw file system operations. All validation
|
|
10
|
+
* happens in this process at zero token cost to the agent.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* aegis-mcp --project /path/to/project --role backend
|
|
14
|
+
*
|
|
15
|
+
* Claude Code MCP config:
|
|
16
|
+
* {
|
|
17
|
+
* "mcpServers": {
|
|
18
|
+
* "aegis": {
|
|
19
|
+
* "command": "npx",
|
|
20
|
+
* "args": ["aegis-mcp-server", "--project", ".", "--role", "default"]
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
26
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
27
|
+
import { resolve } from 'node:path';
|
|
28
|
+
import { PolicyLoader } from './services/policy-loader.js';
|
|
29
|
+
import { EnforcementEngine } from './services/enforcement-engine.js';
|
|
30
|
+
import { registerTools } from './tools/file-tools.js';
|
|
31
|
+
// ─── Parse CLI Args ─────────────────────────────────────────────────────────
|
|
32
|
+
function parseArgs() {
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
let projectRoot = process.cwd();
|
|
35
|
+
let role = 'default';
|
|
36
|
+
let policyDir;
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
switch (args[i]) {
|
|
39
|
+
case '--project':
|
|
40
|
+
case '-p':
|
|
41
|
+
projectRoot = resolve(args[++i] ?? '.');
|
|
42
|
+
break;
|
|
43
|
+
case '--role':
|
|
44
|
+
case '-r':
|
|
45
|
+
role = args[++i] ?? 'default';
|
|
46
|
+
break;
|
|
47
|
+
case '--policy-dir':
|
|
48
|
+
policyDir = args[++i];
|
|
49
|
+
break;
|
|
50
|
+
case '--help':
|
|
51
|
+
case '-h':
|
|
52
|
+
printHelp();
|
|
53
|
+
process.exit(0);
|
|
54
|
+
break;
|
|
55
|
+
case '--version':
|
|
56
|
+
case '-v':
|
|
57
|
+
log('aegis-mcp-server v0.1.0');
|
|
58
|
+
process.exit(0);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { projectRoot, role, policyDir };
|
|
63
|
+
}
|
|
64
|
+
function printHelp() {
|
|
65
|
+
log(`
|
|
66
|
+
aegis-mcp-server — MCP enforcement layer for Aegis agent governance
|
|
67
|
+
|
|
68
|
+
USAGE:
|
|
69
|
+
aegis-mcp-server [OPTIONS]
|
|
70
|
+
|
|
71
|
+
OPTIONS:
|
|
72
|
+
-p, --project <path> Project root directory (default: cwd)
|
|
73
|
+
-r, --role <role-id> Agent role to enforce (default: "default")
|
|
74
|
+
--policy-dir <dir> Policy directory name (default: ".agentpolicy")
|
|
75
|
+
-h, --help Show this help
|
|
76
|
+
-v, --version Show version
|
|
77
|
+
|
|
78
|
+
CLAUDE CODE CONFIG:
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"aegis": {
|
|
82
|
+
"command": "npx",
|
|
83
|
+
"args": ["aegis-mcp-server", "--project", ".", "--role", "default"]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
TOOLS PROVIDED:
|
|
89
|
+
aegis_check_permissions Pre-check if an operation is allowed
|
|
90
|
+
aegis_write_file Governed file write with content scanning
|
|
91
|
+
aegis_read_file Governed file read
|
|
92
|
+
aegis_delete_file Governed file delete
|
|
93
|
+
aegis_execute Governed command execution
|
|
94
|
+
aegis_complete_task Task completion with quality gate validation
|
|
95
|
+
aegis_policy_summary Minimal summary of current role and permissions
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
99
|
+
async function main() {
|
|
100
|
+
const config = parseArgs();
|
|
101
|
+
log('Starting aegis-mcp-server');
|
|
102
|
+
log(` Project: ${config.projectRoot}`);
|
|
103
|
+
log(` Role: ${config.role}`);
|
|
104
|
+
log(` Policy dir: ${config.policyDir ?? '.agentpolicy'}`);
|
|
105
|
+
// 1. Load policy into process memory
|
|
106
|
+
const loader = new PolicyLoader(config);
|
|
107
|
+
let state = await loader.load();
|
|
108
|
+
let activeRole = loader.getActiveRole();
|
|
109
|
+
let engine = new EnforcementEngine(state, activeRole);
|
|
110
|
+
// 2. Watch for policy changes and auto-reload
|
|
111
|
+
loader.startWatching(() => {
|
|
112
|
+
state = loader.getState();
|
|
113
|
+
activeRole = loader.getActiveRole();
|
|
114
|
+
engine.updateState(state, activeRole);
|
|
115
|
+
log('Policy reloaded');
|
|
116
|
+
});
|
|
117
|
+
// 3. Create MCP server
|
|
118
|
+
const server = new McpServer({
|
|
119
|
+
name: 'aegis-mcp-server',
|
|
120
|
+
version: '0.1.0',
|
|
121
|
+
});
|
|
122
|
+
// 4. Register governed tools
|
|
123
|
+
registerTools(server, () => engine, () => state, () => activeRole);
|
|
124
|
+
// 5. Connect via stdio transport
|
|
125
|
+
const transport = new StdioServerTransport();
|
|
126
|
+
await server.connect(transport);
|
|
127
|
+
log('Connected via stdio — enforcement active');
|
|
128
|
+
// Graceful shutdown
|
|
129
|
+
const shutdown = async () => {
|
|
130
|
+
log('Shutting down...');
|
|
131
|
+
await loader.stopWatching();
|
|
132
|
+
process.exit(0);
|
|
133
|
+
};
|
|
134
|
+
process.on('SIGINT', shutdown);
|
|
135
|
+
process.on('SIGTERM', shutdown);
|
|
136
|
+
}
|
|
137
|
+
function log(message) {
|
|
138
|
+
process.stderr.write(`[aegis-mcp] ${message}\n`);
|
|
139
|
+
}
|
|
140
|
+
main().catch((err) => {
|
|
141
|
+
process.stderr.write(`[aegis-mcp] Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnforcementEngine — Validates agent actions against loaded policy.
|
|
3
|
+
*
|
|
4
|
+
* All validation happens in Node.js process memory. The agent never sees
|
|
5
|
+
* the policy files. It only sees the verdict: allowed, or blocked with reason.
|
|
6
|
+
*
|
|
7
|
+
* Two-layer enforcement:
|
|
8
|
+
* Layer 1 (skeleton): permissions.boundaries, scope paths, override_protocol
|
|
9
|
+
* Layer 2 (extensions): sensitive_patterns, cross_domain_rules, sensitivity_tiers
|
|
10
|
+
*/
|
|
11
|
+
import type { PolicyState, ResolvedRole, EnforcementVerdict, OverrideLogEntry } from '../types.js';
|
|
12
|
+
export declare class EnforcementEngine {
|
|
13
|
+
private state;
|
|
14
|
+
private activeRole;
|
|
15
|
+
constructor(state: PolicyState, activeRole: ResolvedRole);
|
|
16
|
+
/**
|
|
17
|
+
* Update references when policy reloads.
|
|
18
|
+
*/
|
|
19
|
+
updateState(state: PolicyState, role: ResolvedRole): void;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a write to the given path is allowed.
|
|
22
|
+
* Checks in order: governance forbidden → role excluded → role writable scope.
|
|
23
|
+
*/
|
|
24
|
+
validateWrite(targetPath: string): EnforcementVerdict;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a read of the given path is allowed.
|
|
27
|
+
*/
|
|
28
|
+
validateRead(targetPath: string): EnforcementVerdict;
|
|
29
|
+
/**
|
|
30
|
+
* Scan proposed file content for sensitive patterns.
|
|
31
|
+
* Uses governance.permissions.sensitive_patterns when present.
|
|
32
|
+
*/
|
|
33
|
+
scanContent(content: string, targetPath: string): EnforcementVerdict;
|
|
34
|
+
/**
|
|
35
|
+
* Validate that a cross-domain import respects boundaries.
|
|
36
|
+
* Uses governance.cross_domain_rules when present (extension field).
|
|
37
|
+
*/
|
|
38
|
+
validateCrossDomain(sourcePath: string, importPath: string): EnforcementVerdict;
|
|
39
|
+
/**
|
|
40
|
+
* Determine how to handle a policy violation based on the override protocol.
|
|
41
|
+
*/
|
|
42
|
+
getOverrideBehavior(policyRef: string): {
|
|
43
|
+
behavior: 'block_and_log' | 'warn_confirm_and_log' | 'log_only';
|
|
44
|
+
isImmutable: boolean;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Log an override to the append-only overrides.jsonl file.
|
|
48
|
+
*/
|
|
49
|
+
logOverride(entry: OverrideLogEntry): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Build the list of commands to run for quality gate validation.
|
|
52
|
+
* Maps pre_commit booleans to build_commands from constitution or governance.
|
|
53
|
+
*/
|
|
54
|
+
getQualityGateCommands(): Array<{
|
|
55
|
+
name: string;
|
|
56
|
+
command: string;
|
|
57
|
+
}>;
|
|
58
|
+
private matchesAny;
|
|
59
|
+
private toRelativePath;
|
|
60
|
+
private getDomain;
|
|
61
|
+
private compilePattern;
|
|
62
|
+
private log;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=enforcement-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement-engine.d.ts","sourceRoot":"","sources":["../../src/services/enforcement-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,UAAU;gBADV,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,YAAY;IAGlC;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IAOzD;;;OAGG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB;IAoErD;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB;IAyCpD;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,kBAAkB;IAuBpE;;;OAGG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,kBAAkB;IA8B/E;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG;QACtC,QAAQ,EAAE,eAAe,GAAG,sBAAsB,GAAG,UAAU,CAAC;QAChE,WAAW,EAAE,OAAO,CAAC;KACtB;IAaD;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;;OAGG;IACH,sBAAsB,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IA8BlE,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,GAAG;CAGZ"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnforcementEngine — Validates agent actions against loaded policy.
|
|
3
|
+
*
|
|
4
|
+
* All validation happens in Node.js process memory. The agent never sees
|
|
5
|
+
* the policy files. It only sees the verdict: allowed, or blocked with reason.
|
|
6
|
+
*
|
|
7
|
+
* Two-layer enforcement:
|
|
8
|
+
* Layer 1 (skeleton): permissions.boundaries, scope paths, override_protocol
|
|
9
|
+
* Layer 2 (extensions): sensitive_patterns, cross_domain_rules, sensitivity_tiers
|
|
10
|
+
*/
|
|
11
|
+
import { appendFile, mkdir } from 'node:fs/promises';
|
|
12
|
+
import { dirname, join, relative, isAbsolute } from 'node:path';
|
|
13
|
+
import { minimatch } from 'minimatch';
|
|
14
|
+
export class EnforcementEngine {
|
|
15
|
+
state;
|
|
16
|
+
activeRole;
|
|
17
|
+
constructor(state, activeRole) {
|
|
18
|
+
this.state = state;
|
|
19
|
+
this.activeRole = activeRole;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Update references when policy reloads.
|
|
23
|
+
*/
|
|
24
|
+
updateState(state, role) {
|
|
25
|
+
this.state = state;
|
|
26
|
+
this.activeRole = role;
|
|
27
|
+
}
|
|
28
|
+
// ─── Write Validation ─────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Check if a write to the given path is allowed.
|
|
31
|
+
* Checks in order: governance forbidden → role excluded → role writable scope.
|
|
32
|
+
*/
|
|
33
|
+
validateWrite(targetPath) {
|
|
34
|
+
const relPath = this.toRelativePath(targetPath);
|
|
35
|
+
// 1. Governance-level forbidden paths (highest priority)
|
|
36
|
+
const forbidden = this.state.governance.permissions.boundaries.forbidden;
|
|
37
|
+
if (forbidden && this.matchesAny(relPath, forbidden)) {
|
|
38
|
+
return {
|
|
39
|
+
allowed: false,
|
|
40
|
+
reason: `Path "${relPath}" is in the forbidden list. This path must never be read or modified.`,
|
|
41
|
+
policy_ref: 'governance.json > permissions > boundaries > forbidden',
|
|
42
|
+
immutable: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// 2. Governance-level read_only paths
|
|
46
|
+
const readOnly = this.state.governance.permissions.boundaries.read_only;
|
|
47
|
+
if (readOnly && this.matchesAny(relPath, readOnly)) {
|
|
48
|
+
return {
|
|
49
|
+
allowed: false,
|
|
50
|
+
reason: `Path "${relPath}" is read-only per governance policy.`,
|
|
51
|
+
policy_ref: 'governance.json > permissions > boundaries > read_only',
|
|
52
|
+
immutable: false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// 3. Role excluded paths
|
|
56
|
+
if (this.activeRole.excluded_paths.length > 0 &&
|
|
57
|
+
this.matchesAny(relPath, this.activeRole.excluded_paths)) {
|
|
58
|
+
return {
|
|
59
|
+
allowed: false,
|
|
60
|
+
reason: `Path "${relPath}" is excluded for role "${this.activeRole.id}".`,
|
|
61
|
+
policy_ref: `roles/${this.activeRole.id}.json > scope > excluded_paths`,
|
|
62
|
+
immutable: false,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// 4. Role writable scope — must be in writable_paths or secondary_paths
|
|
66
|
+
if (this.activeRole.writable_paths.length > 0) {
|
|
67
|
+
const inWritable = this.matchesAny(relPath, this.activeRole.writable_paths);
|
|
68
|
+
const inSecondary = this.activeRole.secondary_paths.length > 0 &&
|
|
69
|
+
this.matchesAny(relPath, this.activeRole.secondary_paths);
|
|
70
|
+
if (!inWritable && !inSecondary) {
|
|
71
|
+
return {
|
|
72
|
+
allowed: false,
|
|
73
|
+
reason: `Path "${relPath}" is outside the writable scope of role "${this.activeRole.id}".`,
|
|
74
|
+
policy_ref: `roles/${this.activeRole.id}.json > scope`,
|
|
75
|
+
immutable: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// 5. Governance-level writable whitelist (if defined, path must match)
|
|
80
|
+
const writable = this.state.governance.permissions.boundaries.writable;
|
|
81
|
+
if (writable && writable.length > 0 && !this.matchesAny(relPath, writable)) {
|
|
82
|
+
return {
|
|
83
|
+
allowed: false,
|
|
84
|
+
reason: `Path "${relPath}" is not in the governance writable list.`,
|
|
85
|
+
policy_ref: 'governance.json > permissions > boundaries > writable',
|
|
86
|
+
immutable: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return { allowed: true };
|
|
90
|
+
}
|
|
91
|
+
// ─── Read Validation ──────────────────────────────────────────────────────
|
|
92
|
+
/**
|
|
93
|
+
* Check if a read of the given path is allowed.
|
|
94
|
+
*/
|
|
95
|
+
validateRead(targetPath) {
|
|
96
|
+
const relPath = this.toRelativePath(targetPath);
|
|
97
|
+
// Governance-level forbidden
|
|
98
|
+
const forbidden = this.state.governance.permissions.boundaries.forbidden;
|
|
99
|
+
if (forbidden && this.matchesAny(relPath, forbidden)) {
|
|
100
|
+
return {
|
|
101
|
+
allowed: false,
|
|
102
|
+
reason: `Path "${relPath}" is forbidden. This path must never be read or modified.`,
|
|
103
|
+
policy_ref: 'governance.json > permissions > boundaries > forbidden',
|
|
104
|
+
immutable: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// Role excluded paths block reads too
|
|
108
|
+
if (this.activeRole.excluded_paths.length > 0 &&
|
|
109
|
+
this.matchesAny(relPath, this.activeRole.excluded_paths)) {
|
|
110
|
+
return {
|
|
111
|
+
allowed: false,
|
|
112
|
+
reason: `Path "${relPath}" is excluded for role "${this.activeRole.id}".`,
|
|
113
|
+
policy_ref: `roles/${this.activeRole.id}.json > scope > excluded_paths`,
|
|
114
|
+
immutable: false,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Role readable scope — if defined, must match
|
|
118
|
+
if (this.activeRole.readable_paths.length > 0 &&
|
|
119
|
+
!this.matchesAny(relPath, this.activeRole.readable_paths)) {
|
|
120
|
+
return {
|
|
121
|
+
allowed: false,
|
|
122
|
+
reason: `Path "${relPath}" is outside the readable scope of role "${this.activeRole.id}".`,
|
|
123
|
+
policy_ref: `roles/${this.activeRole.id}.json > paths > read`,
|
|
124
|
+
immutable: false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return { allowed: true };
|
|
128
|
+
}
|
|
129
|
+
// ─── Content Scanning ─────────────────────────────────────────────────────
|
|
130
|
+
/**
|
|
131
|
+
* Scan proposed file content for sensitive patterns.
|
|
132
|
+
* Uses governance.permissions.sensitive_patterns when present.
|
|
133
|
+
*/
|
|
134
|
+
scanContent(content, targetPath) {
|
|
135
|
+
const patterns = this.state.governance.permissions.sensitive_patterns;
|
|
136
|
+
if (!patterns || patterns.length === 0)
|
|
137
|
+
return { allowed: true };
|
|
138
|
+
for (const sp of patterns) {
|
|
139
|
+
const regex = this.compilePattern(sp.pattern);
|
|
140
|
+
if (!regex)
|
|
141
|
+
continue;
|
|
142
|
+
if (regex.test(content)) {
|
|
143
|
+
return {
|
|
144
|
+
allowed: false,
|
|
145
|
+
reason: `Content for "${targetPath}" contains a sensitive pattern: ${sp.reason}`,
|
|
146
|
+
policy_ref: 'governance.json > permissions > sensitive_patterns',
|
|
147
|
+
immutable: false,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return { allowed: true };
|
|
152
|
+
}
|
|
153
|
+
// ─── Cross-Domain Validation ──────────────────────────────────────────────
|
|
154
|
+
/**
|
|
155
|
+
* Validate that a cross-domain import respects boundaries.
|
|
156
|
+
* Uses governance.cross_domain_rules when present (extension field).
|
|
157
|
+
*/
|
|
158
|
+
validateCrossDomain(sourcePath, importPath) {
|
|
159
|
+
const rules = this.state.governance.cross_domain_rules;
|
|
160
|
+
if (!rules || !rules.shared_interfaces_path)
|
|
161
|
+
return { allowed: true };
|
|
162
|
+
const domains = this.state.constitution.project.domains;
|
|
163
|
+
if (!domains || domains.length === 0)
|
|
164
|
+
return { allowed: true };
|
|
165
|
+
const sourceDomain = this.getDomain(sourcePath, domains);
|
|
166
|
+
const importDomain = this.getDomain(importPath, domains);
|
|
167
|
+
// Same domain or can't determine — allow
|
|
168
|
+
if (!sourceDomain || !importDomain || sourceDomain === importDomain) {
|
|
169
|
+
return { allowed: true };
|
|
170
|
+
}
|
|
171
|
+
// Cross-domain — must go through shared interfaces
|
|
172
|
+
if (!importPath.includes(rules.shared_interfaces_path)) {
|
|
173
|
+
return {
|
|
174
|
+
allowed: false,
|
|
175
|
+
reason: `Cross-domain import from "${sourceDomain}" to "${importDomain}" must go through "${rules.shared_interfaces_path}". Direct import of "${importPath}" is not allowed.`,
|
|
176
|
+
policy_ref: 'governance.json > cross_domain_rules',
|
|
177
|
+
immutable: false,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return { allowed: true };
|
|
181
|
+
}
|
|
182
|
+
// ─── Override Protocol ────────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Determine how to handle a policy violation based on the override protocol.
|
|
185
|
+
*/
|
|
186
|
+
getOverrideBehavior(policyRef) {
|
|
187
|
+
const protocol = this.state.governance.override_protocol;
|
|
188
|
+
const behavior = protocol?.behavior ?? 'warn_confirm_and_log';
|
|
189
|
+
const immutable = protocol?.immutable_policies ?? [];
|
|
190
|
+
const isImmutable = immutable.some((p) => policyRef.includes(p));
|
|
191
|
+
return {
|
|
192
|
+
behavior: isImmutable ? 'block_and_log' : behavior,
|
|
193
|
+
isImmutable,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Log an override to the append-only overrides.jsonl file.
|
|
198
|
+
*/
|
|
199
|
+
async logOverride(entry) {
|
|
200
|
+
const logPath = join(this.state.policyDir, 'state', 'overrides.jsonl');
|
|
201
|
+
await mkdir(dirname(logPath), { recursive: true });
|
|
202
|
+
const line = JSON.stringify(entry) + '\n';
|
|
203
|
+
await appendFile(logPath, line, 'utf-8');
|
|
204
|
+
}
|
|
205
|
+
// ─── Quality Gates ────────────────────────────────────────────────────────
|
|
206
|
+
/**
|
|
207
|
+
* Build the list of commands to run for quality gate validation.
|
|
208
|
+
* Maps pre_commit booleans to build_commands from constitution or governance.
|
|
209
|
+
*/
|
|
210
|
+
getQualityGateCommands() {
|
|
211
|
+
const gates = this.state.governance.quality_gate.pre_commit;
|
|
212
|
+
const commands = this.state.constitution.build_commands ??
|
|
213
|
+
this.state.governance.build_commands ??
|
|
214
|
+
{};
|
|
215
|
+
const result = [];
|
|
216
|
+
if (gates.must_pass_tests && commands.test) {
|
|
217
|
+
result.push({ name: 'tests', command: commands.test });
|
|
218
|
+
}
|
|
219
|
+
if (gates.must_pass_lint && commands.lint) {
|
|
220
|
+
result.push({ name: 'lint', command: commands.lint });
|
|
221
|
+
}
|
|
222
|
+
if (gates.must_pass_typecheck && commands.typecheck) {
|
|
223
|
+
result.push({ name: 'typecheck', command: commands.typecheck });
|
|
224
|
+
}
|
|
225
|
+
// Custom checks from quality gate
|
|
226
|
+
if (gates.custom_checks) {
|
|
227
|
+
for (const check of gates.custom_checks) {
|
|
228
|
+
result.push({ name: check.name, command: check.command });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
// ─── Private Helpers ──────────────────────────────────────────────────────
|
|
234
|
+
matchesAny(path, patterns) {
|
|
235
|
+
return patterns.some((pattern) => {
|
|
236
|
+
// Normalize: "compliance/" should match "compliance/src/index.ts"
|
|
237
|
+
const normalized = pattern.endsWith('/')
|
|
238
|
+
? pattern + '**'
|
|
239
|
+
: pattern;
|
|
240
|
+
return minimatch(path, normalized, { dot: true });
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
toRelativePath(targetPath) {
|
|
244
|
+
if (isAbsolute(targetPath)) {
|
|
245
|
+
return relative(this.state.projectRoot, targetPath);
|
|
246
|
+
}
|
|
247
|
+
return targetPath;
|
|
248
|
+
}
|
|
249
|
+
getDomain(filePath, domains) {
|
|
250
|
+
for (const domain of domains) {
|
|
251
|
+
const domainPath = domain.path.replace(/\/$/, '');
|
|
252
|
+
if (filePath.startsWith(domainPath + '/') || filePath.startsWith(domainPath)) {
|
|
253
|
+
return domain.name;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
compilePattern(pattern) {
|
|
259
|
+
try {
|
|
260
|
+
return new RegExp(pattern, 'gi');
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
this.log(`Invalid regex in sensitive_patterns: ${pattern}`);
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
log(message) {
|
|
268
|
+
process.stderr.write(`[aegis-enforce] ${message}\n`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=enforcement-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement-engine.js","sourceRoot":"","sources":["../../src/services/enforcement-engine.ts"],"names":[],"mappings":"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"}
|