@groundnuty/macf-channel-server 0.2.0-rc.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/dist/collision.d.ts +25 -0
- package/dist/collision.d.ts.map +1 -0
- package/dist/collision.js +94 -0
- package/dist/collision.js.map +1 -0
- package/dist/health.d.ts +3 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +33 -0
- package/dist/health.js.map +1 -0
- package/dist/https.d.ts +25 -0
- package/dist/https.d.ts.map +1 -0
- package/dist/https.js +361 -0
- package/dist/https.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +6 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +43 -0
- package/dist/mcp.js.map +1 -0
- package/dist/notify-formatter.d.ts +19 -0
- package/dist/notify-formatter.d.ts.map +1 -0
- package/dist/notify-formatter.js +43 -0
- package/dist/notify-formatter.js.map +1 -0
- package/dist/otel.d.ts +59 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +122 -0
- package/dist/otel.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +256 -0
- package/dist/server.js.map +1 -0
- package/dist/shutdown.d.ts +15 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +53 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/startup-issues.d.ts +24 -0
- package/dist/startup-issues.d.ts.map +1 -0
- package/dist/startup-issues.js +75 -0
- package/dist/startup-issues.js.map +1 -0
- package/dist/tmux-wake.d.ts +106 -0
- package/dist/tmux-wake.d.ts.map +1 -0
- package/dist/tmux-wake.js +196 -0
- package/dist/tmux-wake.js.map +1 -0
- package/dist/tracing.d.ts +38 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +68 -0
- package/dist/tracing.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AgentInfo, Registry } from '@groundnuty/macf-core';
|
|
2
|
+
import type { Logger } from '@groundnuty/macf-core';
|
|
3
|
+
import { MacfError } from '@groundnuty/macf-core';
|
|
4
|
+
export declare class CollisionError extends MacfError {
|
|
5
|
+
constructor(name: string, host: string, port: number);
|
|
6
|
+
}
|
|
7
|
+
export type CollisionResult = {
|
|
8
|
+
readonly action: 'register';
|
|
9
|
+
} | {
|
|
10
|
+
readonly action: 'takeover';
|
|
11
|
+
readonly previous: AgentInfo;
|
|
12
|
+
} | {
|
|
13
|
+
readonly action: 'abort';
|
|
14
|
+
readonly existing: AgentInfo;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Check if an agent is already registered and alive.
|
|
18
|
+
* Returns the action to take: register (fresh), takeover (dead), or abort (alive).
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkCollision(name: string, registry: Registry, certPaths: {
|
|
21
|
+
readonly caCertPath: string;
|
|
22
|
+
readonly agentCertPath: string;
|
|
23
|
+
readonly agentKeyPath: string;
|
|
24
|
+
}, logger: Logger): Promise<CollisionResult>;
|
|
25
|
+
//# sourceMappingURL=collision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAQrD;AAgED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/D;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE;IACT,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,EACD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CAwC1B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { request } from 'node:https';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { MacfError } from '@groundnuty/macf-core';
|
|
4
|
+
export class CollisionError extends MacfError {
|
|
5
|
+
constructor(name, host, port) {
|
|
6
|
+
super('AGENT_COLLISION', `Agent '${name}' is already running at ${host}:${port}. ` +
|
|
7
|
+
'Stop the existing agent before starting another.');
|
|
8
|
+
this.name = 'CollisionError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const HEALTH_PING_TIMEOUT_MS = 5000;
|
|
12
|
+
/**
|
|
13
|
+
* Ping an agent's /health endpoint via mTLS.
|
|
14
|
+
* Returns true if the agent responds, false if unreachable.
|
|
15
|
+
*/
|
|
16
|
+
function pingHealth(host, port, caCertPath, agentCertPath, agentKeyPath, timeoutMs = HEALTH_PING_TIMEOUT_MS) {
|
|
17
|
+
// readFileSync on missing/unreadable cert files throws ENOENT/EACCES
|
|
18
|
+
// as raw Node errors with no descriptive context. During a cert-
|
|
19
|
+
// rotation race at startup, the agent cert/key files may be
|
|
20
|
+
// momentarily absent — without this guard the error propagates as
|
|
21
|
+
// an unhandled rejection up through main() and crashes startup.
|
|
22
|
+
// Treat any read error the same way we treat network errors: the
|
|
23
|
+
// peer is effectively unreachable for the purpose of the collision
|
|
24
|
+
// check. Ultrareview finding H3.
|
|
25
|
+
let ca;
|
|
26
|
+
let cert;
|
|
27
|
+
let key;
|
|
28
|
+
try {
|
|
29
|
+
ca = readFileSync(caCertPath);
|
|
30
|
+
cert = readFileSync(agentCertPath);
|
|
31
|
+
key = readFileSync(agentKeyPath);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return Promise.resolve(false);
|
|
35
|
+
}
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
const req = request({
|
|
38
|
+
hostname: host,
|
|
39
|
+
port,
|
|
40
|
+
method: 'GET',
|
|
41
|
+
path: '/health',
|
|
42
|
+
ca,
|
|
43
|
+
cert,
|
|
44
|
+
key,
|
|
45
|
+
rejectUnauthorized: true,
|
|
46
|
+
timeout: timeoutMs,
|
|
47
|
+
}, (res) => {
|
|
48
|
+
// Any 2xx response means the agent is alive
|
|
49
|
+
resolve(res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300);
|
|
50
|
+
res.resume(); // drain response
|
|
51
|
+
});
|
|
52
|
+
req.on('error', () => resolve(false));
|
|
53
|
+
req.on('timeout', () => {
|
|
54
|
+
req.destroy();
|
|
55
|
+
resolve(false);
|
|
56
|
+
});
|
|
57
|
+
req.end();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if an agent is already registered and alive.
|
|
62
|
+
* Returns the action to take: register (fresh), takeover (dead), or abort (alive).
|
|
63
|
+
*/
|
|
64
|
+
export async function checkCollision(name, registry, certPaths, logger) {
|
|
65
|
+
const existing = await registry.get(name);
|
|
66
|
+
if (existing === null) {
|
|
67
|
+
logger.info('collision_check', { result: 'fresh', agent: name });
|
|
68
|
+
return { action: 'register' };
|
|
69
|
+
}
|
|
70
|
+
logger.info('collision_check', {
|
|
71
|
+
result: 'variable_exists',
|
|
72
|
+
agent: name,
|
|
73
|
+
host: existing.host,
|
|
74
|
+
port: existing.port,
|
|
75
|
+
instance_id: existing.instance_id,
|
|
76
|
+
});
|
|
77
|
+
const alive = await pingHealth(existing.host, existing.port, certPaths.caCertPath, certPaths.agentCertPath, certPaths.agentKeyPath);
|
|
78
|
+
if (alive) {
|
|
79
|
+
logger.warn('collision_check', {
|
|
80
|
+
result: 'abort',
|
|
81
|
+
agent: name,
|
|
82
|
+
host: existing.host,
|
|
83
|
+
port: existing.port,
|
|
84
|
+
});
|
|
85
|
+
return { action: 'abort', existing };
|
|
86
|
+
}
|
|
87
|
+
logger.info('collision_check', {
|
|
88
|
+
result: 'takeover',
|
|
89
|
+
agent: name,
|
|
90
|
+
previous_instance: existing.instance_id,
|
|
91
|
+
});
|
|
92
|
+
return { action: 'takeover', previous: existing };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=collision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"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"}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAQzE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CA4BnF"}
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
function readVersion() {
|
|
4
|
+
const pkgPath = resolve(import.meta.dirname, '..', 'package.json');
|
|
5
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
6
|
+
return pkg.version;
|
|
7
|
+
}
|
|
8
|
+
export function createHealthState(agentName, agentType) {
|
|
9
|
+
const version = readVersion();
|
|
10
|
+
const startTime = Date.now();
|
|
11
|
+
let currentIssue = null;
|
|
12
|
+
let lastNotification = null;
|
|
13
|
+
return {
|
|
14
|
+
getHealth() {
|
|
15
|
+
return {
|
|
16
|
+
agent: agentName,
|
|
17
|
+
status: 'online',
|
|
18
|
+
type: agentType,
|
|
19
|
+
uptime_seconds: Math.floor((Date.now() - startTime) / 1000),
|
|
20
|
+
current_issue: currentIssue,
|
|
21
|
+
version,
|
|
22
|
+
last_notification: lastNotification,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
setCurrentIssue(issueNumber) {
|
|
26
|
+
currentIssue = issueNumber;
|
|
27
|
+
},
|
|
28
|
+
recordNotification() {
|
|
29
|
+
lastNotification = new Date().toISOString();
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,SAAS,WAAW;IAClB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACnE,MAAM,GAAG,GAAwB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5E,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,SAAiB;IACpE,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,gBAAgB,GAAkB,IAAI,CAAC;IAE3C,OAAO;QACL,SAAS;YACP,OAAO;gBACL,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,QAAQ;gBAChB,IAAI,EAAE,SAAS;gBACf,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;gBAC3D,aAAa,EAAE,YAAY;gBAC3B,OAAO;gBACP,iBAAiB,EAAE,gBAAgB;aACpC,CAAC;QACJ,CAAC;QAED,eAAe,CAAC,WAA0B;YACxC,YAAY,GAAG,WAAW,CAAC;QAC7B,CAAC;QAED,kBAAkB;YAChB,gBAAgB,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC9C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/https.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NotifyPayload, SignRequest, HealthResponse, HttpsServer, Logger } from '@groundnuty/macf-core';
|
|
2
|
+
export declare const PORT_RANGE_START = 8800;
|
|
3
|
+
export declare const PORT_RANGE_SIZE = 1000;
|
|
4
|
+
export declare const CLIENT_AUTH_EKU_OID = "1.3.6.1.5.5.7.3.2";
|
|
5
|
+
/**
|
|
6
|
+
* Check whether the presented peer cert carries the clientAuth EKU.
|
|
7
|
+
* Node's `tls.TLSSocket.getPeerCertificate()` exposes EKU as
|
|
8
|
+
* `ext_key_usage` — an array of OID strings. If the field is absent
|
|
9
|
+
* or empty, the cert carries no EKU; if present, we require the
|
|
10
|
+
* clientAuth OID specifically. Exported for tests.
|
|
11
|
+
*/
|
|
12
|
+
export declare function peerCertHasClientAuthEKU(peerCert: {
|
|
13
|
+
readonly ext_key_usage?: readonly string[];
|
|
14
|
+
}): boolean;
|
|
15
|
+
export declare function randomPort(): number;
|
|
16
|
+
export declare function createHttpsServer(config: {
|
|
17
|
+
readonly caCertPath: string;
|
|
18
|
+
readonly agentCertPath: string;
|
|
19
|
+
readonly agentKeyPath: string;
|
|
20
|
+
readonly onNotify: (payload: NotifyPayload) => Promise<void>;
|
|
21
|
+
readonly onHealth: () => HealthResponse;
|
|
22
|
+
readonly onSign?: (request: SignRequest) => Promise<Record<string, unknown>>;
|
|
23
|
+
readonly logger: Logger;
|
|
24
|
+
}): HttpsServer;
|
|
25
|
+
//# sourceMappingURL=https.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"https.d.ts","sourceRoot":"","sources":["../src/https.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAK7G,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,eAAe,OAAO,CAAC;AAQpC,eAAO,MAAM,mBAAmB,sBAAsB,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE;IACjD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C,GAAG,OAAO,CAGV;AAUD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAyDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,cAAc,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GAAG,WAAW,CAiUd"}
|
package/dist/https.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { createServer } from 'node:https';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { randomInt } from 'node:crypto';
|
|
4
|
+
import { context, propagation, SpanKind, SpanStatusCode } from '@opentelemetry/api';
|
|
5
|
+
import { NotifyPayloadSchema, SignRequestSchema } from '@groundnuty/macf-core';
|
|
6
|
+
import { PortExhaustedError, PortUnavailableError, HttpsServerError, HttpError } from '@groundnuty/macf-core';
|
|
7
|
+
import { getTracer, SpanNames, Attr, GenAiAttr, operationNameForNotifyType } from './tracing.js';
|
|
8
|
+
const MAX_BODY_BYTES = 64 * 1024; // 64KB
|
|
9
|
+
export const PORT_RANGE_START = 8800;
|
|
10
|
+
export const PORT_RANGE_SIZE = 1000;
|
|
11
|
+
const MAX_PORT_ATTEMPTS = 10;
|
|
12
|
+
// clientAuth EKU OID — RFC 5280 §4.2.1.12. Peer certs emit this via
|
|
13
|
+
// generateAgentCert + signCSR (#125); the routing-action client cert
|
|
14
|
+
// emits it too (#119). Enforced at the server as the final step of
|
|
15
|
+
// DR-004 v2 EKU rollout (#121). Non-EKU certs are rejected at
|
|
16
|
+
// /notify + /health + /sign uniformly.
|
|
17
|
+
export const CLIENT_AUTH_EKU_OID = '1.3.6.1.5.5.7.3.2';
|
|
18
|
+
/**
|
|
19
|
+
* Check whether the presented peer cert carries the clientAuth EKU.
|
|
20
|
+
* Node's `tls.TLSSocket.getPeerCertificate()` exposes EKU as
|
|
21
|
+
* `ext_key_usage` — an array of OID strings. If the field is absent
|
|
22
|
+
* or empty, the cert carries no EKU; if present, we require the
|
|
23
|
+
* clientAuth OID specifically. Exported for tests.
|
|
24
|
+
*/
|
|
25
|
+
export function peerCertHasClientAuthEKU(peerCert) {
|
|
26
|
+
return Array.isArray(peerCert.ext_key_usage)
|
|
27
|
+
&& peerCert.ext_key_usage.includes(CLIENT_AUTH_EKU_OID);
|
|
28
|
+
}
|
|
29
|
+
// Exported for tests (#109 H1). Uses crypto.randomInt (CSPRNG)
|
|
30
|
+
// rather than a weak PRNG — port numbers aren't secrets, but the
|
|
31
|
+
// canonical defensive pattern for random in security-adjacent code
|
|
32
|
+
// paths is the CSPRNG.
|
|
33
|
+
export function randomPort() {
|
|
34
|
+
return PORT_RANGE_START + randomInt(PORT_RANGE_SIZE);
|
|
35
|
+
}
|
|
36
|
+
function sendJson(res, status, body) {
|
|
37
|
+
const json = JSON.stringify(body);
|
|
38
|
+
res.writeHead(status, {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'Content-Length': Buffer.byteLength(json),
|
|
41
|
+
});
|
|
42
|
+
res.end(json);
|
|
43
|
+
}
|
|
44
|
+
function readBody(req) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const chunks = [];
|
|
47
|
+
let size = 0;
|
|
48
|
+
let settled = false;
|
|
49
|
+
req.on('data', (chunk) => {
|
|
50
|
+
size += chunk.length;
|
|
51
|
+
if (size > MAX_BODY_BYTES && !settled) {
|
|
52
|
+
settled = true;
|
|
53
|
+
// Destroy the underlying socket (not just req) so the half-open
|
|
54
|
+
// write-side (res) is also torn down. `req.destroy()` alone
|
|
55
|
+
// leaves res attached to a destroyed request, which can retain
|
|
56
|
+
// GC references under high-throughput abuse — see ultrareview
|
|
57
|
+
// finding H2.
|
|
58
|
+
req.socket.destroy();
|
|
59
|
+
reject(new HttpsServerError('Body too large'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!settled) {
|
|
63
|
+
chunks.push(chunk);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
req.on('end', () => {
|
|
67
|
+
if (!settled) {
|
|
68
|
+
settled = true;
|
|
69
|
+
resolve(Buffer.concat(chunks).toString('utf-8'));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
req.on('error', (err) => {
|
|
73
|
+
if (!settled) {
|
|
74
|
+
settled = true;
|
|
75
|
+
reject(err);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export function createHttpsServer(config) {
|
|
81
|
+
const { onNotify, onHealth, onSign, logger } = config;
|
|
82
|
+
const tlsOptions = {
|
|
83
|
+
key: readFileSync(config.agentKeyPath),
|
|
84
|
+
cert: readFileSync(config.agentCertPath),
|
|
85
|
+
ca: readFileSync(config.caCertPath),
|
|
86
|
+
requestCert: true,
|
|
87
|
+
rejectUnauthorized: true,
|
|
88
|
+
};
|
|
89
|
+
let server;
|
|
90
|
+
async function handleRequest(req, res) {
|
|
91
|
+
// Defense-in-depth: reject at HTTP level even if TLS handshake passed.
|
|
92
|
+
// Protects against misconfigured rejectUnauthorized during debugging.
|
|
93
|
+
const tlsSocket = req.socket;
|
|
94
|
+
if (!tlsSocket.authorized) {
|
|
95
|
+
sendJson(res, 401, { error: 'Unauthorized' });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Step 3 of the DR-004 v2 EKU rollout (#121): require the peer
|
|
99
|
+
// cert to carry the clientAuth EKU. Peer certs emit it via
|
|
100
|
+
// generateAgentCert + signCSR (#125); routing-action client cert
|
|
101
|
+
// emits it via generateClientCert (#119). A CA-signed cert
|
|
102
|
+
// WITHOUT the EKU — e.g. an old peer cert pre-#125 that hasn't
|
|
103
|
+
// been rotated — is rejected uniformly at /health, /notify,
|
|
104
|
+
// /sign. Operators who miss a rotation see 403 with a clear
|
|
105
|
+
// message pointing at `macf certs rotate`.
|
|
106
|
+
const peerCert = tlsSocket.getPeerCertificate();
|
|
107
|
+
if (!peerCertHasClientAuthEKU(peerCert)) {
|
|
108
|
+
const cn = peerCert.subject?.CN ?? 'unknown';
|
|
109
|
+
logger.warn('client_cert_missing_eku', {
|
|
110
|
+
from_cn: cn,
|
|
111
|
+
url: req.url ?? '',
|
|
112
|
+
});
|
|
113
|
+
sendJson(res, 403, {
|
|
114
|
+
error: 'Forbidden: client certificate missing clientAuth Extended Key Usage. Run `macf certs rotate` to pick up an EKU-enabled cert.',
|
|
115
|
+
});
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const { method, url } = req;
|
|
119
|
+
if (method === 'GET' && url === '/health') {
|
|
120
|
+
const health = onHealth();
|
|
121
|
+
const clientCn = req.socket
|
|
122
|
+
.getPeerCertificate()?.subject?.CN;
|
|
123
|
+
logger.info('health_pinged', { from_cn: clientCn ?? 'unknown' });
|
|
124
|
+
sendJson(res, 200, health);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (method === 'POST' && url === '/notify') {
|
|
128
|
+
const contentType = req.headers['content-type'] ?? '';
|
|
129
|
+
if (!contentType.includes('application/json')) {
|
|
130
|
+
sendJson(res, 415, { error: 'Content-Type must be application/json' });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
let body;
|
|
134
|
+
try {
|
|
135
|
+
body = await readBody(req);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
sendJson(res, 413, { error: 'Body too large (max 64KB)' });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(body);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
sendJson(res, 400, { error: 'Invalid JSON' });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const result = NotifyPayloadSchema.safeParse(parsed);
|
|
150
|
+
if (!result.success) {
|
|
151
|
+
sendJson(res, 400, { error: `Validation failed: ${result.error.message}` });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// macf#194: wrap onNotify in a SERVER span so child operations
|
|
155
|
+
// (MCP push, tmux wake) attach to it via active-context
|
|
156
|
+
// propagation. Parent context extracted from W3C `traceparent`
|
|
157
|
+
// header if the routing Action sent one; otherwise a new root.
|
|
158
|
+
// Span + any mcp/tmux children roll up to the same trace-id
|
|
159
|
+
// in Langfuse/SigNoz, giving one unified trace per coord event.
|
|
160
|
+
const parentCtx = propagation.extract(context.active(), req.headers);
|
|
161
|
+
const clientCn = req.socket
|
|
162
|
+
.getPeerCertificate()?.subject?.CN ?? 'unknown';
|
|
163
|
+
const tracer = getTracer();
|
|
164
|
+
await tracer.startActiveSpan(SpanNames.NotifyReceived, {
|
|
165
|
+
kind: SpanKind.SERVER,
|
|
166
|
+
attributes: {
|
|
167
|
+
[GenAiAttr.System]: 'macf',
|
|
168
|
+
[GenAiAttr.OperationName]: operationNameForNotifyType(result.data.type),
|
|
169
|
+
[Attr.NotifyType]: result.data.type,
|
|
170
|
+
[Attr.RemoteCn]: clientCn,
|
|
171
|
+
...(result.data.issue_number !== undefined
|
|
172
|
+
? { [Attr.IssueNumber]: result.data.issue_number }
|
|
173
|
+
: {}),
|
|
174
|
+
},
|
|
175
|
+
}, parentCtx, async (span) => {
|
|
176
|
+
try {
|
|
177
|
+
await onNotify(result.data);
|
|
178
|
+
sendJson(res, 200, { status: 'received' });
|
|
179
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
logger.error('notify_push_failed', {
|
|
183
|
+
error: err instanceof Error ? err.message : String(err),
|
|
184
|
+
});
|
|
185
|
+
span.recordException(err);
|
|
186
|
+
span.setStatus({
|
|
187
|
+
code: SpanStatusCode.ERROR,
|
|
188
|
+
message: err instanceof Error ? err.message : String(err),
|
|
189
|
+
});
|
|
190
|
+
sendJson(res, 500, { error: 'Failed to push notification' });
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
span.end();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (method === 'POST' && url === '/sign') {
|
|
199
|
+
if (!onSign) {
|
|
200
|
+
sendJson(res, 503, { error: 'Signing not available on this agent' });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const contentType = req.headers['content-type'] ?? '';
|
|
204
|
+
if (!contentType.includes('application/json')) {
|
|
205
|
+
sendJson(res, 415, { error: 'Content-Type must be application/json' });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
let body;
|
|
209
|
+
try {
|
|
210
|
+
body = await readBody(req);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
sendJson(res, 413, { error: 'Body too large (max 64KB)' });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
let parsed;
|
|
217
|
+
try {
|
|
218
|
+
parsed = JSON.parse(body);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
sendJson(res, 400, { error: 'Invalid JSON' });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const result = SignRequestSchema.safeParse(parsed);
|
|
225
|
+
if (!result.success) {
|
|
226
|
+
sendJson(res, 400, { error: `Validation failed: ${result.error.message}` });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
// macf#194: /sign SERVER span. Audit-trail value — every cert
|
|
230
|
+
// issuance gets a trace entry correlatable to the requester
|
|
231
|
+
// (cn + agent_name) + the trace-parent (who kicked off the
|
|
232
|
+
// rotation?).
|
|
233
|
+
const signParentCtx = propagation.extract(context.active(), req.headers);
|
|
234
|
+
const signClientCn = req.socket
|
|
235
|
+
.getPeerCertificate()?.subject?.CN ?? 'unknown';
|
|
236
|
+
const signTracer = getTracer();
|
|
237
|
+
await signTracer.startActiveSpan(SpanNames.SignCsr, {
|
|
238
|
+
kind: SpanKind.SERVER,
|
|
239
|
+
attributes: {
|
|
240
|
+
[GenAiAttr.System]: 'macf',
|
|
241
|
+
[Attr.RemoteCn]: signClientCn,
|
|
242
|
+
[GenAiAttr.AgentName]: result.data.agent_name,
|
|
243
|
+
},
|
|
244
|
+
}, signParentCtx, async (span) => {
|
|
245
|
+
try {
|
|
246
|
+
const response = await onSign(result.data);
|
|
247
|
+
sendJson(res, 200, response);
|
|
248
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
// Typed HttpError carries a specific intended status;
|
|
252
|
+
// anything else is an unexpected server-side failure → 500.
|
|
253
|
+
const status = err instanceof HttpError ? err.httpStatus : 500;
|
|
254
|
+
sendJson(res, status, {
|
|
255
|
+
error: err instanceof Error ? err.message : 'Signing failed',
|
|
256
|
+
});
|
|
257
|
+
span.recordException(err);
|
|
258
|
+
span.setStatus({
|
|
259
|
+
code: SpanStatusCode.ERROR,
|
|
260
|
+
message: err instanceof Error ? err.message : String(err),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
span.end();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
sendJson(res, 404, { error: 'Not found' });
|
|
270
|
+
}
|
|
271
|
+
function listenOnPort(srv, port, host) {
|
|
272
|
+
return new Promise((resolve, reject) => {
|
|
273
|
+
const onError = (err) => {
|
|
274
|
+
srv.removeListener('error', onError);
|
|
275
|
+
reject(err);
|
|
276
|
+
};
|
|
277
|
+
srv.on('error', onError);
|
|
278
|
+
srv.listen(port, host, () => {
|
|
279
|
+
srv.removeListener('error', onError);
|
|
280
|
+
const addr = srv.address();
|
|
281
|
+
const actualPort = typeof addr === 'object' && addr !== null ? addr.port : port;
|
|
282
|
+
resolve(actualPort);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function requestHandler(req, res) {
|
|
287
|
+
handleRequest(req, res).catch((err) => {
|
|
288
|
+
logger.error('request_error', {
|
|
289
|
+
error: err instanceof Error ? err.message : String(err),
|
|
290
|
+
});
|
|
291
|
+
if (!res.headersSent) {
|
|
292
|
+
sendJson(res, 500, { error: 'Internal server error' });
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
async start(port, host) {
|
|
298
|
+
server = createServer(tlsOptions, requestHandler);
|
|
299
|
+
// TLS-layer handshake failures (no cert, expired cert, wrong CA,
|
|
300
|
+
// missing clientAuth EKU per #121) never reach requestHandler.
|
|
301
|
+
// Without this listener, operators see a dead connection with
|
|
302
|
+
// no log entry explaining why. Log enough to triage — ultrareview
|
|
303
|
+
// finding H1.
|
|
304
|
+
server.on('tlsClientError', (err, tlsSocket) => {
|
|
305
|
+
const peerCn = tlsSocket.getPeerCertificate?.()
|
|
306
|
+
?.subject?.CN ?? 'unknown';
|
|
307
|
+
logger.warn('tls_client_error', {
|
|
308
|
+
error: err.message,
|
|
309
|
+
code: err.code ?? 'unknown',
|
|
310
|
+
from_cn: peerCn,
|
|
311
|
+
remote_addr: tlsSocket.remoteAddress ?? 'unknown',
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
// Explicit port: fail immediately if busy
|
|
315
|
+
if (port !== 0) {
|
|
316
|
+
try {
|
|
317
|
+
const actualPort = await listenOnPort(server, port, host);
|
|
318
|
+
return { actualPort };
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
const nodeErr = err;
|
|
322
|
+
if (nodeErr.code === 'EADDRINUSE') {
|
|
323
|
+
throw new PortUnavailableError(port);
|
|
324
|
+
}
|
|
325
|
+
throw new HttpsServerError(`Failed to start server: ${nodeErr.message}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Random port: retry up to MAX_PORT_ATTEMPTS times
|
|
329
|
+
for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {
|
|
330
|
+
const candidatePort = randomPort();
|
|
331
|
+
try {
|
|
332
|
+
const actualPort = await listenOnPort(server, candidatePort, host);
|
|
333
|
+
return { actualPort };
|
|
334
|
+
}
|
|
335
|
+
catch (err) {
|
|
336
|
+
const nodeErr = err;
|
|
337
|
+
if (nodeErr.code !== 'EADDRINUSE') {
|
|
338
|
+
throw new HttpsServerError(`Failed to start server: ${nodeErr.message}`);
|
|
339
|
+
}
|
|
340
|
+
// Close and recreate server for retry
|
|
341
|
+
await new Promise((r) => server.close(() => r()));
|
|
342
|
+
server = createServer(tlsOptions, requestHandler);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
throw new PortExhaustedError();
|
|
346
|
+
},
|
|
347
|
+
async stop() {
|
|
348
|
+
if (!server)
|
|
349
|
+
return;
|
|
350
|
+
return new Promise((resolve, reject) => {
|
|
351
|
+
server.close((err) => {
|
|
352
|
+
if (err)
|
|
353
|
+
reject(new HttpsServerError(`Failed to stop server: ${err.message}`));
|
|
354
|
+
else
|
|
355
|
+
resolve();
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=https.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"https.js","sourceRoot":"","sources":["../src/https.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Agent Coordination Framework (MACF)
|
|
3
|
+
*
|
|
4
|
+
* Coordinates multiple Claude Code agents via GitHub,
|
|
5
|
+
* using MCP channels (HTTP/mTLS) for communication.
|
|
6
|
+
*/
|
|
7
|
+
export { MacfError, ConfigError, McpChannelError, HttpsServerError, PortUnavailableError, PortExhaustedError, ValidationError } from '@groundnuty/macf-core';
|
|
8
|
+
export { createMcpChannel } from './mcp.js';
|
|
9
|
+
export { createHttpsServer } from './https.js';
|
|
10
|
+
export { createHealthState } from './health.js';
|
|
11
|
+
export { createLogger } from '@groundnuty/macf-core';
|
|
12
|
+
export { loadConfig } from '@groundnuty/macf-core';
|
|
13
|
+
export { NotifyPayloadSchema, NotifyTypeSchema, HealthResponseSchema, CiCompletionPayloadSchema, CheckSuiteConclusionSchema, } from '@groundnuty/macf-core';
|
|
14
|
+
export type { NotifyPayload, NotifyType, HealthResponse, AgentConfig, Logger, McpChannel, HttpsServer, HealthState, CiCompletionPayload, CheckSuiteConclusion, } from '@groundnuty/macf-core';
|
|
15
|
+
export { createRegistryFromConfig, createRegistry, createGitHubClient, GitHubApiError, AgentInfoSchema, RegistryConfigSchema } from '@groundnuty/macf-core';
|
|
16
|
+
export type { AgentInfo, Registry, RegistryConfig, GitHubVariablesClient } from '@groundnuty/macf-core';
|
|
17
|
+
export { checkCollision, CollisionError } from './collision.js';
|
|
18
|
+
export type { CollisionResult } from './collision.js';
|
|
19
|
+
export { registerShutdownHandler } from './shutdown.js';
|
|
20
|
+
export { generateToken } from '@groundnuty/macf-core';
|
|
21
|
+
export { checkPendingIssues } from './startup-issues.js';
|
|
22
|
+
export { createCA, backupCAKey, recoverCAKey, encryptCAKey, decryptCAKey, loadCA, CaError } from '@groundnuty/macf-core';
|
|
23
|
+
export type { CaKeyPair } from '@groundnuty/macf-core';
|
|
24
|
+
export { generateAgentCert, generateCSR, signCSR, AgentCertError } from '@groundnuty/macf-core';
|
|
25
|
+
export type { AgentCertResult } from '@groundnuty/macf-core';
|
|
26
|
+
export { createChallenge, verifyAndConsumeChallenge, ChallengeError } from '@groundnuty/macf-core';
|
|
27
|
+
export { SignRequestSchema, SignChallengeResponseSchema, SignCertResponseSchema } from '@groundnuty/macf-core';
|
|
28
|
+
export type { SignRequest } from '@groundnuty/macf-core';
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7J,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,mBAAmB,EAAE,gBAAgB,EAAE,oBAAoB,EAC3D,yBAAyB,EAAE,0BAA0B,GACtD,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAC9D,UAAU,EAAE,WAAW,EAAE,WAAW,EACpC,mBAAmB,EAAE,oBAAoB,GAC1C,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,wBAAwB,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC5J,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACxG,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACzH,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAChG,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/G,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"}
|