@attested-intelligence/aga-mcp-server 2.2.0 → 2.2.1

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.
Files changed (80) hide show
  1. package/README.md +77 -65
  2. package/dist/adapters/openclaw.d.ts +0 -1
  3. package/dist/adapters/openclaw.d.ts.map +1 -1
  4. package/dist/adapters/openclaw.js +0 -1
  5. package/dist/adapters/openclaw.js.map +1 -1
  6. package/dist/proxy/evaluator.d.ts +0 -1
  7. package/dist/proxy/evaluator.d.ts.map +1 -1
  8. package/dist/proxy/evaluator.js +0 -1
  9. package/dist/proxy/evaluator.js.map +1 -1
  10. package/dist/proxy/index.d.ts +0 -1
  11. package/dist/proxy/index.d.ts.map +1 -1
  12. package/dist/proxy/index.js +0 -1
  13. package/dist/proxy/index.js.map +1 -1
  14. package/dist/proxy/profiles.d.ts +0 -1
  15. package/dist/proxy/profiles.d.ts.map +1 -1
  16. package/dist/proxy/profiles.js +0 -1
  17. package/dist/proxy/profiles.js.map +1 -1
  18. package/dist/proxy/server.d.ts +0 -1
  19. package/dist/proxy/server.d.ts.map +1 -1
  20. package/dist/proxy/server.js +0 -1
  21. package/dist/proxy/server.js.map +1 -1
  22. package/dist/proxy/stdio-bridge.d.ts +0 -1
  23. package/dist/proxy/stdio-bridge.d.ts.map +1 -1
  24. package/dist/proxy/stdio-bridge.js +0 -1
  25. package/dist/proxy/stdio-bridge.js.map +1 -1
  26. package/dist/proxy/types.d.ts +0 -1
  27. package/dist/proxy/types.d.ts.map +1 -1
  28. package/dist/proxy/types.js +0 -1
  29. package/dist/proxy/types.js.map +1 -1
  30. package/dist/proxy/verify.d.ts +0 -1
  31. package/dist/proxy/verify.d.ts.map +1 -1
  32. package/dist/proxy/verify.js +0 -1
  33. package/dist/proxy/verify.js.map +1 -1
  34. package/package.json +92 -97
  35. package/SECURITY.md +0 -59
  36. package/independent-verifier/README.md +0 -31
  37. package/independent-verifier/package.json +0 -18
  38. package/independent-verifier/verify.ts +0 -211
  39. package/src/adapters/openclaw.ts +0 -125
  40. package/src/core/artifact.ts +0 -45
  41. package/src/core/attestation.ts +0 -33
  42. package/src/core/behavioral.ts +0 -132
  43. package/src/core/bundle.ts +0 -45
  44. package/src/core/chain.ts +0 -72
  45. package/src/core/checkpoint.ts +0 -22
  46. package/src/core/delegation.ts +0 -146
  47. package/src/core/disclosure.ts +0 -32
  48. package/src/core/identity.ts +0 -62
  49. package/src/core/index.ts +0 -14
  50. package/src/core/portal.ts +0 -117
  51. package/src/core/quarantine.ts +0 -16
  52. package/src/core/receipt.ts +0 -33
  53. package/src/core/subject.ts +0 -11
  54. package/src/core/types.ts +0 -285
  55. package/src/crypto/hash.ts +0 -33
  56. package/src/crypto/index.ts +0 -5
  57. package/src/crypto/merkle.ts +0 -43
  58. package/src/crypto/salt.ts +0 -18
  59. package/src/crypto/sign.ts +0 -42
  60. package/src/crypto/types.ts +0 -19
  61. package/src/index.ts +0 -12
  62. package/src/middleware/governance.ts +0 -95
  63. package/src/middleware/index.ts +0 -1
  64. package/src/proxy/evaluator.ts +0 -176
  65. package/src/proxy/index.ts +0 -259
  66. package/src/proxy/profiles.ts +0 -48
  67. package/src/proxy/server.ts +0 -499
  68. package/src/proxy/stdio-bridge.ts +0 -171
  69. package/src/proxy/types.ts +0 -40
  70. package/src/proxy/verify.ts +0 -202
  71. package/src/server.ts +0 -435
  72. package/src/storage/index.ts +0 -3
  73. package/src/storage/interface.ts +0 -21
  74. package/src/storage/memory.ts +0 -27
  75. package/src/storage/sqlite.ts +0 -45
  76. package/src/tools/README.md +0 -13
  77. package/src/utils/canonical.ts +0 -14
  78. package/src/utils/constants.ts +0 -3
  79. package/src/utils/timestamp.ts +0 -12
  80. package/src/utils/uuid.ts +0 -2
@@ -1,42 +0,0 @@
1
- import * as ed from '@noble/ed25519';
2
- import { sha256 } from '@noble/hashes/sha256';
3
- import { sha512 } from '@noble/hashes/sha512';
4
- import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
5
- import type { KeyPair, Signature, SignatureBase64 } from './types.js';
6
-
7
- // Set sha512 sync ONCE at module load
8
- ed.etc.sha512Sync = (...m: Uint8Array[]) => {
9
- const total = m.reduce((n, a) => n + a.length, 0);
10
- const buf = new Uint8Array(total);
11
- let off = 0;
12
- for (const a of m) { buf.set(a, off); off += a.length; }
13
- return sha512(buf);
14
- };
15
-
16
- const enc = new TextEncoder();
17
-
18
- export function generateKeyPair(): KeyPair {
19
- const secretKey = ed.utils.randomPrivateKey();
20
- return { publicKey: ed.getPublicKey(secretKey), secretKey };
21
- }
22
-
23
- export function sign(msg: Uint8Array, sk: Uint8Array): Signature { return ed.sign(msg, sk); }
24
- export function signStr(msg: string, sk: Uint8Array): Signature { return sign(enc.encode(msg), sk); }
25
-
26
- export function verify(sig: Signature, msg: Uint8Array, pk: Uint8Array): boolean {
27
- try { return ed.verify(sig, msg, pk); } catch { return false; }
28
- }
29
- export function verifyStr(sig: Signature, msg: string, pk: Uint8Array): boolean {
30
- return verify(sig, enc.encode(msg), pk);
31
- }
32
-
33
- export const sigToB64 = (s: Signature): SignatureBase64 => Buffer.from(s).toString('base64');
34
- export const b64ToSig = (b: SignatureBase64): Signature => new Uint8Array(Buffer.from(b, 'base64'));
35
- export const pkToHex = (pk: Uint8Array): string => bytesToHex(pk);
36
- export const hexToPk = (h: string): Uint8Array => hexToBytes(h);
37
-
38
- /** Key fingerprint: SHA-256 prefix of public key hex, 16-char hex identifier. */
39
- export function keyFingerprint(publicKeyHex: string): string {
40
- const hash = bytesToHex(sha256(new TextEncoder().encode(publicKeyHex)));
41
- return hash.slice(0, 16);
42
- }
@@ -1,19 +0,0 @@
1
- export type PublicKey = Uint8Array;
2
- export type SecretKey = Uint8Array;
3
- export interface KeyPair { publicKey: PublicKey; secretKey: SecretKey; }
4
- export type Signature = Uint8Array;
5
- export type HashHex = string;
6
- export type SignatureBase64 = string;
7
- export type SaltHex = string;
8
-
9
- export interface SaltedCommitment {
10
- commitment: HashHex;
11
- salt: SaltHex;
12
- }
13
-
14
- export interface MerkleInclusionProof {
15
- leafHash: HashHex;
16
- leafIndex: number;
17
- siblings: Array<{ hash: HashHex; position: 'left' | 'right' }>;
18
- root: HashHex;
19
- }
package/src/index.ts DELETED
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { createAGAServer } from './server.js';
4
-
5
- async function main() {
6
- const server = await createAGAServer();
7
- const transport = new StdioServerTransport();
8
- await server.connect(transport);
9
- console.error('AGA MCP Server running on stdio');
10
- }
11
-
12
- main().catch(e => { console.error('Fatal:', e); process.exit(1); });
@@ -1,95 +0,0 @@
1
- /**
2
- * Governance Middleware - wraps every MCP tool handler.
3
- *
4
- * NCCoE filing Section 4: "The portal operates as a Policy Enforcement Point (PEP)...
5
- * Every tool invocation, API call, actuator command, and data access passes through
6
- * the portal, which evaluates it against the sealed artifact's enforcement parameters."
7
- *
8
- * Behavior:
9
- * - TERMINATED state → reject all governed tools
10
- * - PHANTOM_QUARANTINE → capture tool call as forensic input, reject
11
- * - ACTIVE_MONITORING → allow, log to chain
12
- * - Ungoverned tools (get_server_info, get_portal_state, list_claims) → always allow
13
- */
14
- import type { Portal } from '../core/portal.js';
15
- import type { QuarantineState } from '../core/types.js';
16
- import { captureInput } from '../core/quarantine.js';
17
- import type { BehavioralMonitor } from '../core/behavioral.js';
18
- import { sha256Str } from '../crypto/hash.js';
19
- import { canonicalize } from '../utils/canonical.js';
20
-
21
- export type ToolResult = { content: Array<{ type: 'text'; text: string }> };
22
- export type ToolHandler<T = any> = (args: T) => Promise<ToolResult>;
23
-
24
- const UNGOVERNED_TOOLS = new Set([
25
- 'get_server_info',
26
- 'get_portal_state',
27
- 'get_receipts',
28
- 'get_chain_events',
29
- 'list_claims',
30
- 'init_chain', // must work before attestation
31
- 'attest_subject', // creates the governance relationship
32
- 'verify_chain', // read-only verification
33
- ]);
34
-
35
- export function createGovernanceWrapper(
36
- portal: Portal,
37
- quarantine: { current: QuarantineState | null },
38
- toolName: string,
39
- behavioralMonitor?: BehavioralMonitor
40
- ) {
41
- const isGoverned = !UNGOVERNED_TOOLS.has(toolName);
42
-
43
- return function wrapHandler<T>(handler: ToolHandler<T>): ToolHandler<T> {
44
- if (!isGoverned) return handler;
45
-
46
- return async (args: T): Promise<ToolResult> => {
47
- const j = (x: unknown): ToolResult => ({
48
- content: [{ type: 'text', text: JSON.stringify(x, null, 2) }]
49
- });
50
-
51
- // TERMINATED → reject everything
52
- if (portal.state === 'TERMINATED') {
53
- return j({
54
- success: false,
55
- error: 'GOVERNANCE_BLOCKED: Portal is terminated. Agent governance has been revoked. Re-attestation required.',
56
- portal_state: portal.state,
57
- tool: toolName,
58
- });
59
- }
60
-
61
- // PHANTOM_QUARANTINE → capture as forensic input, reject
62
- if (portal.state === 'PHANTOM_QUARANTINE' && quarantine.current?.active) {
63
- captureInput(quarantine.current, `tool_call:${toolName}`, {
64
- tool: toolName,
65
- args,
66
- timestamp: new Date().toISOString(),
67
- });
68
- return j({
69
- success: false,
70
- error: 'GOVERNANCE_QUARANTINED: Agent is in phantom quarantine. All outputs are severed. Inputs are being captured for forensic analysis.',
71
- portal_state: portal.state,
72
- tool: toolName,
73
- forensic_capture: true,
74
- });
75
- }
76
-
77
- // INITIALIZATION or ARTIFACT_VERIFICATION → not yet governed
78
- if (portal.state === 'INITIALIZATION' || portal.state === 'ARTIFACT_VERIFICATION') {
79
- return j({
80
- success: false,
81
- error: 'GOVERNANCE_NOT_READY: No active policy artifact. Call attest_subject first.',
82
- portal_state: portal.state,
83
- tool: toolName,
84
- });
85
- }
86
-
87
- // ACTIVE_MONITORING or DRIFT_DETECTED → record + allow through
88
- if (behavioralMonitor) {
89
- const argsHash = sha256Str(canonicalize(args));
90
- behavioralMonitor.recordInvocation(toolName, argsHash);
91
- }
92
- return handler(args);
93
- };
94
- };
95
- }
@@ -1 +0,0 @@
1
- export * from './governance.js';
@@ -1,176 +0,0 @@
1
- /**
2
- * AGA Governance Proxy - Tool Policy Evaluator
3
- * Ported from aga-mcp-gateway/src/governance/policy.ts with rate limiting.
4
- *
5
- * Patent: USPTO App. No. 19/433,835
6
- * Copyright (c) 2026 Attested Intelligence Holdings LLC
7
- * SPDX-License-Identifier: MIT
8
- */
9
-
10
- import type { ToolPolicy, ToolCallDecision } from './types.js';
11
-
12
- // ── Rate Limiter ────────────────────────────────────────────
13
-
14
- interface RateWindow {
15
- timestamps: number[];
16
- }
17
-
18
- const rateLimits = new Map<string, RateWindow>();
19
-
20
- function checkRateLimit(toolName: string, maxPerMinute: number): boolean {
21
- const now = Date.now();
22
- const cutoff = now - 60_000;
23
-
24
- let window = rateLimits.get(toolName);
25
- if (!window) {
26
- window = { timestamps: [] };
27
- rateLimits.set(toolName, window);
28
- }
29
-
30
- // Prune expired entries
31
- window.timestamps = window.timestamps.filter(t => t > cutoff);
32
-
33
- if (window.timestamps.length >= maxPerMinute) return false;
34
-
35
- window.timestamps.push(now);
36
- return true;
37
- }
38
-
39
- export function resetRateLimits(): void {
40
- rateLimits.clear();
41
- }
42
-
43
- // ── Path Utilities (from aga-mcp-gateway) ───────────────────
44
-
45
- export function cleanPath(p: string): string {
46
- p = p.replace(/\\/g, '/');
47
- p = p.replace(/\/+/g, '/');
48
-
49
- const segments = p.split('/');
50
- const resolved: string[] = [];
51
- const absolute = segments[0] === '';
52
-
53
- for (const seg of segments) {
54
- if (seg === '' || seg === '.') continue;
55
- if (seg === '..') {
56
- if (resolved.length > 0 && resolved[resolved.length - 1] !== '..') {
57
- resolved.pop();
58
- } else if (!absolute) {
59
- resolved.push('..');
60
- }
61
- } else {
62
- resolved.push(seg);
63
- }
64
- }
65
-
66
- let result = (absolute ? '/' : '') + resolved.join('/');
67
- if (result === '') result = '.';
68
- return result;
69
- }
70
-
71
- export function matchesPrefix(prefix: string, candidate: string): boolean {
72
- const cleanPrefix = cleanPath(prefix);
73
- const cleanCandidate = cleanPath(candidate);
74
-
75
- if (cleanCandidate === cleanPrefix) return true;
76
- const prefixWithSlash = cleanPrefix.endsWith('/') ? cleanPrefix : cleanPrefix + '/';
77
- return cleanCandidate.startsWith(prefixWithSlash);
78
- }
79
-
80
- function checkPathConstraints(
81
- constraint: { path_prefix?: string; path_keys?: string[] },
82
- args?: Record<string, unknown>,
83
- ): string | null {
84
- if (!constraint.path_prefix) return null;
85
- const keys = constraint.path_keys?.length ? constraint.path_keys : ['path'];
86
- if (!args) return null;
87
-
88
- for (const key of keys) {
89
- const val = args[key];
90
- if (typeof val === 'string') {
91
- if (!matchesPrefix(constraint.path_prefix, val)) {
92
- return `path "${val}" outside allowed prefix "${constraint.path_prefix}"`;
93
- }
94
- }
95
- }
96
- return null;
97
- }
98
-
99
- function checkDeniedPatterns(
100
- constraint: { denied_patterns?: string[] },
101
- args?: Record<string, unknown>,
102
- ): string | null {
103
- if (!constraint.denied_patterns?.length) return null;
104
- if (!args) return null;
105
-
106
- for (const [, val] of Object.entries(args)) {
107
- if (typeof val !== 'string') continue;
108
- for (const pattern of constraint.denied_patterns) {
109
- if (val.includes(pattern)) {
110
- return `argument value matches denied pattern "${pattern}"`;
111
- }
112
- }
113
- }
114
- return null;
115
- }
116
-
117
- // ── Main Evaluator ──────────────────────────────────────────
118
-
119
- export function evaluate(
120
- policy: ToolPolicy,
121
- toolName: string,
122
- args?: Record<string, unknown>,
123
- ): ToolCallDecision {
124
- const base = { tool_name: toolName, policy_mode: policy.mode };
125
-
126
- // Audit-only mode: always permit
127
- if (policy.mode === 'audit_only') {
128
- return { ...base, allowed: true, reason: 'audit_only: all calls permitted' };
129
- }
130
-
131
- if (policy.mode !== 'allowlist' && policy.mode !== 'denylist') {
132
- return { ...base, allowed: false, reason: `unknown policy mode: ${policy.mode}` };
133
- }
134
-
135
- const constraint = policy.constraints[toolName];
136
-
137
- if (policy.mode === 'allowlist') {
138
- if (!constraint) {
139
- return { ...base, allowed: false, reason: 'tool not in allowlist' };
140
- }
141
- if (!constraint.allowed) {
142
- return { ...base, allowed: false, reason: 'tool explicitly disallowed' };
143
- }
144
-
145
- // Rate limit check
146
- if (constraint.max_calls_per_minute) {
147
- if (!checkRateLimit(toolName, constraint.max_calls_per_minute)) {
148
- return { ...base, allowed: false, reason: `rate limit exceeded: ${constraint.max_calls_per_minute}/min` };
149
- }
150
- }
151
-
152
- const pathResult = checkPathConstraints(constraint, args);
153
- if (pathResult !== null) {
154
- return { ...base, allowed: false, reason: pathResult };
155
- }
156
- const patternResult = checkDeniedPatterns(constraint, args);
157
- if (patternResult !== null) {
158
- return { ...base, allowed: false, reason: patternResult };
159
- }
160
- return { ...base, allowed: true, reason: 'tool permitted by allowlist' };
161
- }
162
-
163
- // Denylist mode
164
- if (constraint && !constraint.allowed) {
165
- return { ...base, allowed: false, reason: 'tool denied by denylist' };
166
- }
167
-
168
- // Rate limit check for denylist mode (tool not explicitly denied)
169
- if (constraint?.max_calls_per_minute) {
170
- if (!checkRateLimit(toolName, constraint.max_calls_per_minute)) {
171
- return { ...base, allowed: false, reason: `rate limit exceeded: ${constraint.max_calls_per_minute}/min` };
172
- }
173
- }
174
-
175
- return { ...base, allowed: true, reason: 'tool not denied' };
176
- }
@@ -1,259 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * AGA Governance Proxy - CLI Entry Point
4
- *
5
- * Usage:
6
- * aga-proxy start --upstream "node server.js" # stdio upstream
7
- * aga-proxy start --upstream-url http://host:port # HTTP upstream
8
- * aga-proxy start --profile standard # policy profile
9
- * aga-proxy stop
10
- * aga-proxy status
11
- * aga-proxy export --output bundle.json
12
- * aga-proxy verify bundle.json
13
- *
14
- * Patent: USPTO App. No. 19/433,835
15
- * Copyright (c) 2026 Attested Intelligence Holdings LLC
16
- * SPDX-License-Identifier: MIT
17
- */
18
-
19
- import { Command } from 'commander';
20
- import * as fs from 'node:fs';
21
- import * as path from 'node:path';
22
- import * as os from 'node:os';
23
- import { GovernanceProxy } from './server.js';
24
- import { PROFILES } from './profiles.js';
25
- import type { ToolPolicy } from './types.js';
26
-
27
- const program = new Command();
28
- let proxy: GovernanceProxy | null = null;
29
-
30
- function getDataDir(): string {
31
- return path.join(os.homedir(), '.aga-proxy');
32
- }
33
-
34
- function getPidFile(): string {
35
- return path.join(getDataDir(), 'proxy.pid');
36
- }
37
-
38
- program
39
- .name('aga-proxy')
40
- .description('AGA Governance Proxy - cryptographic runtime governance for MCP tool calls')
41
- .version('0.1.0');
42
-
43
- // ── start ────────────────────────────────────────────────────
44
-
45
- program
46
- .command('start')
47
- .description('Start the governance proxy')
48
- .option('-p, --port <port>', 'Proxy port', '18800')
49
- .option('--upstream <command>', 'Downstream MCP server command (stdio)')
50
- .option('--upstream-url <url>', 'Downstream MCP server URL (HTTP)')
51
- .option('--profile <name>', 'Policy profile: permissive, standard, restrictive', 'permissive')
52
- .option('--policy <path>', 'Custom policy JSON file')
53
- .action(async (opts) => {
54
- const port = parseInt(opts.port, 10);
55
- let policy: ToolPolicy;
56
-
57
- if (opts.policy) {
58
- policy = JSON.parse(fs.readFileSync(opts.policy, 'utf-8'));
59
- } else {
60
- policy = PROFILES[opts.profile] ?? PROFILES.permissive;
61
- }
62
-
63
- const upstream = opts.upstream ? parseUpstreamCommand(opts.upstream) : undefined;
64
-
65
- proxy = new GovernanceProxy({
66
- port,
67
- policy,
68
- upstream,
69
- upstreamUrl: opts.upstreamUrl,
70
- });
71
-
72
- proxy.on('started', ({ port: p }: { port: number }) => {
73
- console.log(`AGA Governance Proxy started on port ${p}`);
74
- console.log(`Policy mode: ${policy.mode}`);
75
- if (opts.upstream) console.log(`Upstream (stdio): ${opts.upstream}`);
76
- if (opts.upstreamUrl) console.log(`Upstream (HTTP): ${opts.upstreamUrl}`);
77
- });
78
-
79
- proxy.on('error', (err: Error) => {
80
- console.error(`Proxy error: ${err.message}`);
81
- });
82
-
83
- // Ensure data dir exists
84
- const dataDir = getDataDir();
85
- if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
86
-
87
- await proxy.start();
88
-
89
- // Write PID file
90
- fs.writeFileSync(getPidFile(), String(process.pid));
91
-
92
- // Graceful shutdown
93
- const shutdown = async () => {
94
- console.log('\nShutting down...');
95
- if (proxy) {
96
- await proxy.stop();
97
- try { fs.unlinkSync(getPidFile()); } catch { /* ok */ }
98
- }
99
- process.exit(0);
100
- };
101
-
102
- process.on('SIGINT', shutdown);
103
- process.on('SIGTERM', shutdown);
104
- });
105
-
106
- // ── run (foreground, alias for start) ────────────────────────
107
-
108
- program
109
- .command('run')
110
- .description('Run proxy in foreground (same as start, Ctrl+C to stop)')
111
- .option('-p, --port <port>', 'Proxy port', '18800')
112
- .option('--upstream <command>', 'Downstream MCP server command (stdio)')
113
- .option('--upstream-url <url>', 'Downstream MCP server URL (HTTP)')
114
- .option('--profile <name>', 'Policy profile', 'permissive')
115
- .option('--policy <path>', 'Custom policy JSON file')
116
- .action(async (opts) => {
117
- // Delegate to start - identical behavior in Node.js
118
- await program.commands.find(c => c.name() === 'start')!.parseAsync(
119
- ['node', 'aga-proxy', 'start', ...process.argv.slice(3)],
120
- );
121
- });
122
-
123
- // ── stop ─────────────────────────────────────────────────────
124
-
125
- program
126
- .command('stop')
127
- .description('Stop the running proxy')
128
- .action(async () => {
129
- const pidFile = getPidFile();
130
- if (!fs.existsSync(pidFile)) {
131
- console.log('No running proxy found');
132
- return;
133
- }
134
- const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
135
- try {
136
- process.kill(pid, 'SIGTERM');
137
- console.log(`Sent SIGTERM to proxy (PID ${pid})`);
138
- fs.unlinkSync(pidFile);
139
- } catch {
140
- console.log('Proxy process not found, cleaning up PID file');
141
- fs.unlinkSync(pidFile);
142
- }
143
- });
144
-
145
- // ── status ───────────────────────────────────────────────────
146
-
147
- program
148
- .command('status')
149
- .description('Show proxy status')
150
- .action(async () => {
151
- if (proxy) {
152
- console.log(JSON.stringify(proxy.getStatus(), null, 2));
153
- } else {
154
- const pidFile = getPidFile();
155
- if (fs.existsSync(pidFile)) {
156
- const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
157
- try {
158
- process.kill(pid, 0); // Check if alive
159
- console.log(JSON.stringify({ running: true, pid }, null, 2));
160
- } catch {
161
- console.log(JSON.stringify({ running: false, stale_pid: pid }, null, 2));
162
- }
163
- } else {
164
- console.log(JSON.stringify({ running: false }, null, 2));
165
- }
166
- }
167
- });
168
-
169
- // ── export ───────────────────────────────────────────────────
170
-
171
- program
172
- .command('export')
173
- .description('Export evidence bundle')
174
- .option('-o, --output <path>', 'Output file', 'evidence-bundle.json')
175
- .action(async (opts) => {
176
- if (!proxy) {
177
- console.error('Proxy not running in this process. Start the proxy first.');
178
- process.exit(1);
179
- }
180
- const bundle = await proxy.exportBundle();
181
- fs.writeFileSync(opts.output, JSON.stringify(bundle, null, 2));
182
- console.log(`Evidence bundle exported to ${opts.output}`);
183
- });
184
-
185
- // ── verify ───────────────────────────────────────────────────
186
-
187
- program
188
- .command('verify <bundle>')
189
- .description('Verify an evidence bundle (Ed25519-SHA256-JCS format)')
190
- .action(async (bundlePath) => {
191
- const { verifyGatewayBundle } = await import('./verify.js');
192
- const bundleJson = fs.readFileSync(bundlePath, 'utf-8');
193
- const result = await verifyGatewayBundle(bundleJson);
194
-
195
- console.log(`Algorithm: ${result.algorithm_valid ? 'PASS' : 'FAIL'}`);
196
- console.log(`Signatures: ${result.receipt_signatures_valid ? 'PASS' : 'FAIL'} (${result.receipts_checked} receipts)`);
197
- console.log(`Chain integrity: ${result.chain_integrity_valid ? 'PASS' : 'FAIL'}`);
198
- console.log(`Merkle proofs: ${result.merkle_proofs_valid ? 'PASS' : 'FAIL'}`);
199
- console.log(`Consistency: ${result.bundle_consistent ? 'PASS' : 'FAIL'}`);
200
- console.log(`\nOVERALL: ${result.overall_valid ? 'VERIFIED' : 'FAILED'}`);
201
- if (result.error) console.log(`Error: ${result.error}`);
202
-
203
- process.exit(result.overall_valid ? 0 : 1);
204
- });
205
-
206
- // ── policy ───────────────────────────────────────────────────
207
-
208
- const policyCmd = program.command('policy').description('Policy management');
209
-
210
- policyCmd
211
- .command('show')
212
- .description('Show current policy')
213
- .action(() => {
214
- if (!proxy) {
215
- console.error('Proxy not running in this process.');
216
- process.exit(1);
217
- }
218
- console.log(JSON.stringify(proxy.getStatus(), null, 2));
219
- });
220
-
221
- policyCmd
222
- .command('switch <profile>')
223
- .description('Switch policy profile')
224
- .action(async (profile) => {
225
- if (!proxy) {
226
- console.error('Proxy not running in this process.');
227
- process.exit(1);
228
- }
229
- const newPolicy = PROFILES[profile];
230
- if (!newPolicy) {
231
- console.error(`Unknown profile: ${profile}. Available: ${Object.keys(PROFILES).join(', ')}`);
232
- process.exit(1);
233
- }
234
- await proxy.switchPolicy(newPolicy);
235
- console.log(`Switched to ${profile} profile`);
236
- });
237
-
238
- // ── helpers ──────────────────────────────────────────────────
239
-
240
- function parseUpstreamCommand(cmd: string): { command: string; args: string[] } {
241
- const parts = cmd.split(/\s+/);
242
- return { command: parts[0], args: parts.slice(1) };
243
- }
244
-
245
- // ── main ─────────────────────────────────────────────────────
246
-
247
- export { GovernanceProxy } from './server.js';
248
- export { evaluate, resetRateLimits } from './evaluator.js';
249
- export { PROFILES, PERMISSIVE, STANDARD, RESTRICTIVE } from './profiles.js';
250
- export type { ToolPolicy, ToolConstraint, ToolCallDecision, ProxyConfig } from './types.js';
251
-
252
- // Only parse CLI if run directly
253
- const isDirectRun = process.argv[1]?.includes('proxy') || process.argv[1]?.includes('aga-proxy');
254
- if (isDirectRun) {
255
- program.parseAsync().catch((err) => {
256
- console.error(err);
257
- process.exit(1);
258
- });
259
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * AGA Governance Proxy - Built-in Policy Profiles
3
- *
4
- * Patent: USPTO App. No. 19/433,835
5
- * Copyright (c) 2026 Attested Intelligence Holdings LLC
6
- * SPDX-License-Identifier: MIT
7
- */
8
-
9
- import type { ToolPolicy } from './types.js';
10
-
11
- /** All tools permitted, no rate limits, logging only. */
12
- export const PERMISSIVE: ToolPolicy = {
13
- mode: 'audit_only',
14
- constraints: {},
15
- };
16
-
17
- /** All common tools allowed with rate limits. Dangerous patterns denied. */
18
- export const STANDARD: ToolPolicy = {
19
- mode: 'allowlist',
20
- constraints: {
21
- filesystem_read: { name: 'filesystem_read', allowed: true, max_calls_per_minute: 30 },
22
- filesystem_write: { name: 'filesystem_write', allowed: true, max_calls_per_minute: 30, denied_patterns: ['/etc/', '/sys/', '/proc/'] },
23
- shell_execute: { name: 'shell_execute', allowed: true, max_calls_per_minute: 10, denied_patterns: ['rm -rf', 'mkfs', 'dd if=', ':(){:|:&};:'] },
24
- web_search: { name: 'web_search', allowed: true, max_calls_per_minute: 20 },
25
- web_fetch: { name: 'web_fetch', allowed: true, max_calls_per_minute: 20 },
26
- send_message: { name: 'send_message', allowed: true, max_calls_per_minute: 5 },
27
- calendar_create: { name: 'calendar_create', allowed: true, max_calls_per_minute: 5 },
28
- memory_search: { name: 'memory_search', allowed: true, max_calls_per_minute: 30 },
29
- memory_store: { name: 'memory_store', allowed: true, max_calls_per_minute: 10 },
30
- code_execute: { name: 'code_execute', allowed: true, max_calls_per_minute: 10 },
31
- },
32
- };
33
-
34
- /** Explicit allowlist only. All unrecognized tools denied. Low rate limits. */
35
- export const RESTRICTIVE: ToolPolicy = {
36
- mode: 'allowlist',
37
- constraints: {
38
- filesystem_read: { name: 'filesystem_read', allowed: true, max_calls_per_minute: 10, path_prefix: '/home' },
39
- web_search: { name: 'web_search', allowed: true, max_calls_per_minute: 5 },
40
- memory_search: { name: 'memory_search', allowed: true, max_calls_per_minute: 10 },
41
- },
42
- };
43
-
44
- export const PROFILES: Record<string, ToolPolicy> = {
45
- permissive: PERMISSIVE,
46
- standard: STANDARD,
47
- restrictive: RESTRICTIVE,
48
- };