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 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
@@ -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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"}