@integsec/agentic-pentest-proxy 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/README.md +731 -0
- package/dist/bin/integsec-agentic-pentest-proxy.d.ts +3 -0
- package/dist/bin/integsec-agentic-pentest-proxy.d.ts.map +1 -0
- package/dist/bin/integsec-agentic-pentest-proxy.js +51 -0
- package/dist/bin/integsec-agentic-pentest-proxy.js.map +1 -0
- package/dist/src/audit/azure-monitor.d.ts +22 -0
- package/dist/src/audit/azure-monitor.d.ts.map +1 -0
- package/dist/src/audit/azure-monitor.js +62 -0
- package/dist/src/audit/azure-monitor.js.map +1 -0
- package/dist/src/audit/cloudwatch.d.ts +20 -0
- package/dist/src/audit/cloudwatch.d.ts.map +1 -0
- package/dist/src/audit/cloudwatch.js +89 -0
- package/dist/src/audit/cloudwatch.js.map +1 -0
- package/dist/src/audit/gcp-logging.d.ts +23 -0
- package/dist/src/audit/gcp-logging.d.ts.map +1 -0
- package/dist/src/audit/gcp-logging.js +70 -0
- package/dist/src/audit/gcp-logging.js.map +1 -0
- package/dist/src/audit/index.d.ts +49 -0
- package/dist/src/audit/index.d.ts.map +1 -0
- package/dist/src/audit/index.js +79 -0
- package/dist/src/audit/index.js.map +1 -0
- package/dist/src/audit/local.d.ts +25 -0
- package/dist/src/audit/local.d.ts.map +1 -0
- package/dist/src/audit/local.js +51 -0
- package/dist/src/audit/local.js.map +1 -0
- package/dist/src/config.d.ts +25 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +26 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/dns-resolver.d.ts +21 -0
- package/dist/src/dns-resolver.d.ts.map +1 -0
- package/dist/src/dns-resolver.js +68 -0
- package/dist/src/dns-resolver.js.map +1 -0
- package/dist/src/domain-matcher.d.ts +35 -0
- package/dist/src/domain-matcher.d.ts.map +1 -0
- package/dist/src/domain-matcher.js +97 -0
- package/dist/src/domain-matcher.js.map +1 -0
- package/dist/src/extractor.d.ts +30 -0
- package/dist/src/extractor.d.ts.map +1 -0
- package/dist/src/extractor.js +176 -0
- package/dist/src/extractor.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ip-matcher.d.ts +38 -0
- package/dist/src/ip-matcher.d.ts.map +1 -0
- package/dist/src/ip-matcher.js +128 -0
- package/dist/src/ip-matcher.js.map +1 -0
- package/dist/src/manifest-schema.d.ts +77 -0
- package/dist/src/manifest-schema.d.ts.map +1 -0
- package/dist/src/manifest-schema.js +34 -0
- package/dist/src/manifest-schema.js.map +1 -0
- package/dist/src/manifest.d.ts +3 -0
- package/dist/src/manifest.d.ts.map +1 -0
- package/dist/src/manifest.js +115 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/proxy.d.ts +16 -0
- package/dist/src/proxy.d.ts.map +1 -0
- package/dist/src/proxy.js +72 -0
- package/dist/src/proxy.js.map +1 -0
- package/dist/src/sanitizer.d.ts +19 -0
- package/dist/src/sanitizer.d.ts.map +1 -0
- package/dist/src/sanitizer.js +68 -0
- package/dist/src/sanitizer.js.map +1 -0
- package/dist/src/technique-checker.d.ts +50 -0
- package/dist/src/technique-checker.d.ts.map +1 -0
- package/dist/src/technique-checker.js +110 -0
- package/dist/src/technique-checker.js.map +1 -0
- package/dist/src/transports/http.d.ts +3 -0
- package/dist/src/transports/http.d.ts.map +1 -0
- package/dist/src/transports/http.js +67 -0
- package/dist/src/transports/http.js.map +1 -0
- package/dist/src/transports/stdio.d.ts +3 -0
- package/dist/src/transports/stdio.d.ts.map +1 -0
- package/dist/src/transports/stdio.js +50 -0
- package/dist/src/transports/stdio.js.map +1 -0
- package/dist/src/types.d.ts +43 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/validator.d.ts +54 -0
- package/dist/src/validator.d.ts.map +1 -0
- package/dist/src/validator.js +200 -0
- package/dist/src/validator.js.map +1 -0
- package/examples/claude-desktop-config.json +15 -0
- package/examples/scope-manifest.json +18 -0
- package/examples/technique-map.json +10 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integsec-agentic-pentest-proxy.d.ts","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-proxy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadConfig } from "../src/config.js";
|
|
3
|
+
import { loadManifest } from "../src/manifest.js";
|
|
4
|
+
import { ScopeEnforcementProxy } from "../src/proxy.js";
|
|
5
|
+
import { runStdioProxy } from "../src/transports/stdio.js";
|
|
6
|
+
import { runHttpProxy } from "../src/transports/http.js";
|
|
7
|
+
import { CloudWatchAuditLogger } from "../src/audit/cloudwatch.js";
|
|
8
|
+
import { AzureMonitorAuditLogger } from "../src/audit/azure-monitor.js";
|
|
9
|
+
import { GcpAuditLogger } from "../src/audit/gcp-logging.js";
|
|
10
|
+
async function main() {
|
|
11
|
+
console.error("[integsec-agentic-pentest-proxy] Starting...");
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const manifest = await loadManifest();
|
|
14
|
+
console.error(`[integsec-agentic-pentest-proxy] Loaded scope for engagement ${manifest.engagement_id} (${manifest.client})`);
|
|
15
|
+
console.error(`[integsec-agentic-pentest-proxy] Window: ${manifest.engagement_window.start} to ${manifest.engagement_window.end}`);
|
|
16
|
+
console.error(`[integsec-agentic-pentest-proxy] Transport: ${config.transport}`);
|
|
17
|
+
const proxy = new ScopeEnforcementProxy(manifest, config);
|
|
18
|
+
const auditLogger = proxy.getAuditLogger();
|
|
19
|
+
// Add cloud backends if configured
|
|
20
|
+
if (config.awsLogGroup) {
|
|
21
|
+
auditLogger.addBackend(new CloudWatchAuditLogger(config.awsLogGroup, config.awsRegion));
|
|
22
|
+
console.error(`[integsec-agentic-pentest-proxy] CloudWatch logging enabled: ${config.awsLogGroup}`);
|
|
23
|
+
}
|
|
24
|
+
if (config.azureLogWorkspaceId && config.azureDcrImmutableId) {
|
|
25
|
+
auditLogger.addBackend(new AzureMonitorAuditLogger(config.azureLogWorkspaceId, config.azureDcrImmutableId, config.azureDcrStreamName));
|
|
26
|
+
console.error("[integsec-agentic-pentest-proxy] Azure Monitor logging enabled");
|
|
27
|
+
}
|
|
28
|
+
if (config.gcpProject) {
|
|
29
|
+
auditLogger.addBackend(new GcpAuditLogger(config.gcpProject));
|
|
30
|
+
console.error("[integsec-agentic-pentest-proxy] GCP Cloud Logging enabled");
|
|
31
|
+
}
|
|
32
|
+
if (config.transport === "stdio") {
|
|
33
|
+
if (!config.upstreamMcpCommand) {
|
|
34
|
+
console.error("[integsec-agentic-pentest-proxy] ERROR: UPSTREAM_MCP_COMMAND is required for stdio transport");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
await runStdioProxy(proxy, config.upstreamMcpCommand, config.upstreamMcpArgs);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
if (!config.upstreamMcpUrl) {
|
|
41
|
+
console.error("[integsec-agentic-pentest-proxy] ERROR: UPSTREAM_MCP_URL is required for HTTP transport");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
await runHttpProxy(proxy, config.upstreamMcpUrl, config.proxyPort);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
main().catch((err) => {
|
|
48
|
+
console.error(`[integsec-agentic-pentest-proxy] Fatal error: ${err.message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=integsec-agentic-pentest-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integsec-agentic-pentest-proxy.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
import type { AuditBackend } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* AzureMonitorAuditLogger buffers AuditEntry objects and sends them to Azure
|
|
5
|
+
* Monitor via the Logs Ingestion API on flush().
|
|
6
|
+
*
|
|
7
|
+
* Requires the optional dependencies @azure/monitor-ingestion and
|
|
8
|
+
* @azure/identity. If either SDK is not installed the logger is silently
|
|
9
|
+
* disabled.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AzureMonitorAuditLogger implements AuditBackend {
|
|
12
|
+
private workspaceId;
|
|
13
|
+
private dcrImmutableId;
|
|
14
|
+
private streamName;
|
|
15
|
+
private buffer;
|
|
16
|
+
/** Set to false when the SDKs cannot be loaded so we never crash. */
|
|
17
|
+
private enabled;
|
|
18
|
+
constructor(workspaceId: string, dcrImmutableId: string, streamName: string);
|
|
19
|
+
log(entry: AuditEntry): Promise<void>;
|
|
20
|
+
flush(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=azure-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-monitor.d.ts","sourceRoot":"","sources":["../../../src/audit/azure-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;GAOG;AACH,qBAAa,uBAAwB,YAAW,YAAY;IAC1D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAoB;IAClC,qEAAqE;IACrE,OAAO,CAAC,OAAO,CAAQ;gBAEX,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAMrE,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA4C7B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AzureMonitorAuditLogger buffers AuditEntry objects and sends them to Azure
|
|
3
|
+
* Monitor via the Logs Ingestion API on flush().
|
|
4
|
+
*
|
|
5
|
+
* Requires the optional dependencies @azure/monitor-ingestion and
|
|
6
|
+
* @azure/identity. If either SDK is not installed the logger is silently
|
|
7
|
+
* disabled.
|
|
8
|
+
*/
|
|
9
|
+
export class AzureMonitorAuditLogger {
|
|
10
|
+
workspaceId;
|
|
11
|
+
dcrImmutableId;
|
|
12
|
+
streamName;
|
|
13
|
+
buffer = [];
|
|
14
|
+
/** Set to false when the SDKs cannot be loaded so we never crash. */
|
|
15
|
+
enabled = true;
|
|
16
|
+
constructor(workspaceId, dcrImmutableId, streamName) {
|
|
17
|
+
this.workspaceId = workspaceId;
|
|
18
|
+
this.dcrImmutableId = dcrImmutableId;
|
|
19
|
+
this.streamName = streamName;
|
|
20
|
+
}
|
|
21
|
+
async log(entry) {
|
|
22
|
+
if (!this.enabled)
|
|
23
|
+
return;
|
|
24
|
+
this.buffer.push(entry);
|
|
25
|
+
}
|
|
26
|
+
async flush() {
|
|
27
|
+
if (!this.enabled || this.buffer.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
// Snapshot and clear the in-flight entries; restore on error.
|
|
30
|
+
const toSend = this.buffer.splice(0);
|
|
31
|
+
let ingestionModule;
|
|
32
|
+
let identityModule;
|
|
33
|
+
try {
|
|
34
|
+
[ingestionModule, identityModule] = await Promise.all([
|
|
35
|
+
import("@azure/monitor-ingestion"),
|
|
36
|
+
import("@azure/identity"),
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
console.warn("[AzureMonitorAuditLogger] @azure/monitor-ingestion or @azure/identity is not " +
|
|
41
|
+
"installed. Azure Monitor audit logging is disabled.");
|
|
42
|
+
this.enabled = false;
|
|
43
|
+
// Entries are already removed from the buffer — drop them gracefully.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { LogsIngestionClient } = ingestionModule;
|
|
47
|
+
const { DefaultAzureCredential } = identityModule;
|
|
48
|
+
const endpoint = `https://${this.workspaceId}.ingest.monitor.azure.com`;
|
|
49
|
+
const credential = new DefaultAzureCredential();
|
|
50
|
+
const client = new LogsIngestionClient(endpoint, credential);
|
|
51
|
+
try {
|
|
52
|
+
// The SDK types require Record<string, unknown>[] — cast via unknown.
|
|
53
|
+
await client.upload(this.dcrImmutableId, this.streamName, toSend);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error("[AzureMonitorAuditLogger] flush() failed:", err);
|
|
57
|
+
// Put entries back at the front of the buffer for the next retry.
|
|
58
|
+
this.buffer.unshift(...toSend);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=azure-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-monitor.js","sourceRoot":"","sources":["../../../src/audit/azure-monitor.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,uBAAuB;IAC1B,WAAW,CAAS;IACpB,cAAc,CAAS;IACvB,UAAU,CAAS;IACnB,MAAM,GAAiB,EAAE,CAAC;IAClC,qEAAqE;IAC7D,OAAO,GAAG,IAAI,CAAC;IAEvB,YAAY,WAAmB,EAAE,cAAsB,EAAE,UAAkB;QACzE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEtD,8DAA8D;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,eAA0D,CAAC;QAC/D,IAAI,cAAgD,CAAC;QAErD,IAAI,CAAC;YACH,CAAC,eAAe,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACpD,MAAM,CAAC,0BAA0B,CAAC;gBAClC,MAAM,CAAC,iBAAiB,CAAC;aAC1B,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CACV,+EAA+E;gBAC7E,qDAAqD,CACxD,CAAC;YACF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,sEAAsE;YACtE,OAAO;QACT,CAAC;QAED,MAAM,EAAE,mBAAmB,EAAE,GAAG,eAAe,CAAC;QAChD,MAAM,EAAE,sBAAsB,EAAE,GAAG,cAAc,CAAC;QAElD,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,WAAW,2BAA2B,CAAC;QACxE,MAAM,UAAU,GAAG,IAAI,sBAAsB,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAE7D,IAAI,CAAC;YACH,sEAAsE;YACtE,MAAM,MAAM,CAAC,MAAM,CACjB,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,UAAU,EACf,MAA8C,CAC/C,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;YAChE,kEAAkE;YAClE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
import type { AuditBackend } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* CloudWatchAuditLogger buffers AuditEntry objects and sends them to AWS
|
|
5
|
+
* CloudWatch Logs on flush().
|
|
6
|
+
*
|
|
7
|
+
* Requires the optional dependency @aws-sdk/client-cloudwatch-logs.
|
|
8
|
+
* If the SDK is not installed the logger is silently disabled.
|
|
9
|
+
*/
|
|
10
|
+
export declare class CloudWatchAuditLogger implements AuditBackend {
|
|
11
|
+
private logGroup;
|
|
12
|
+
private region;
|
|
13
|
+
private buffer;
|
|
14
|
+
/** Set to false when the SDK cannot be loaded so we never crash. */
|
|
15
|
+
private enabled;
|
|
16
|
+
constructor(logGroup: string, region?: string);
|
|
17
|
+
log(entry: AuditEntry): Promise<void>;
|
|
18
|
+
flush(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cloudwatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudwatch.d.ts","sourceRoot":"","sources":["../../../src/audit/cloudwatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;GAMG;AACH,qBAAa,qBAAsB,YAAW,YAAY;IACxD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAoB;IAClC,oEAAoE;IACpE,OAAO,CAAC,OAAO,CAAQ;gBAEX,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAKvC,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAyE7B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CloudWatchAuditLogger buffers AuditEntry objects and sends them to AWS
|
|
3
|
+
* CloudWatch Logs on flush().
|
|
4
|
+
*
|
|
5
|
+
* Requires the optional dependency @aws-sdk/client-cloudwatch-logs.
|
|
6
|
+
* If the SDK is not installed the logger is silently disabled.
|
|
7
|
+
*/
|
|
8
|
+
export class CloudWatchAuditLogger {
|
|
9
|
+
logGroup;
|
|
10
|
+
region;
|
|
11
|
+
buffer = [];
|
|
12
|
+
/** Set to false when the SDK cannot be loaded so we never crash. */
|
|
13
|
+
enabled = true;
|
|
14
|
+
constructor(logGroup, region) {
|
|
15
|
+
this.logGroup = logGroup;
|
|
16
|
+
this.region = region;
|
|
17
|
+
}
|
|
18
|
+
async log(entry) {
|
|
19
|
+
if (!this.enabled)
|
|
20
|
+
return;
|
|
21
|
+
this.buffer.push(entry);
|
|
22
|
+
}
|
|
23
|
+
async flush() {
|
|
24
|
+
if (!this.enabled || this.buffer.length === 0)
|
|
25
|
+
return;
|
|
26
|
+
// Snapshot and clear the in-flight entries; restore on error.
|
|
27
|
+
const toSend = this.buffer.splice(0);
|
|
28
|
+
let sdk;
|
|
29
|
+
try {
|
|
30
|
+
sdk = await import("@aws-sdk/client-cloudwatch-logs");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
console.warn("[CloudWatchAuditLogger] @aws-sdk/client-cloudwatch-logs is not installed. " +
|
|
34
|
+
"CloudWatch audit logging is disabled.");
|
|
35
|
+
this.enabled = false;
|
|
36
|
+
// Entries are already removed from the buffer — drop them gracefully.
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { CloudWatchLogsClient, CreateLogGroupCommand, CreateLogStreamCommand, PutLogEventsCommand, } = sdk;
|
|
40
|
+
const client = new CloudWatchLogsClient(this.region ? { region: this.region } : {});
|
|
41
|
+
// Derive a log stream per engagement / date so streams stay manageable.
|
|
42
|
+
// Use the first entry's engagement_id and today's UTC date.
|
|
43
|
+
const engagementId = toSend[0]?.engagement_id ?? "unknown";
|
|
44
|
+
const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
|
45
|
+
const logStream = `${engagementId}/${date}`;
|
|
46
|
+
try {
|
|
47
|
+
// Ensure the log group exists (idempotent).
|
|
48
|
+
try {
|
|
49
|
+
await client.send(new CreateLogGroupCommand({ logGroupName: this.logGroup }));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (!isResourceAlreadyExists(err))
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
// Ensure the log stream exists (idempotent).
|
|
56
|
+
try {
|
|
57
|
+
await client.send(new CreateLogStreamCommand({
|
|
58
|
+
logGroupName: this.logGroup,
|
|
59
|
+
logStreamName: logStream,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (!isResourceAlreadyExists(err))
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
// Publish the buffered entries.
|
|
67
|
+
await client.send(new PutLogEventsCommand({
|
|
68
|
+
logGroupName: this.logGroup,
|
|
69
|
+
logStreamName: logStream,
|
|
70
|
+
logEvents: toSend.map((entry) => ({
|
|
71
|
+
timestamp: new Date(entry.timestamp).getTime(),
|
|
72
|
+
message: JSON.stringify(entry),
|
|
73
|
+
})),
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error("[CloudWatchAuditLogger] flush() failed:", err);
|
|
78
|
+
// Put entries back at the front of the buffer for the next retry.
|
|
79
|
+
this.buffer.unshift(...toSend);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isResourceAlreadyExists(err) {
|
|
84
|
+
return (typeof err === "object" &&
|
|
85
|
+
err !== null &&
|
|
86
|
+
"name" in err &&
|
|
87
|
+
err.name === "ResourceAlreadyExistsException");
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=cloudwatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudwatch.js","sourceRoot":"","sources":["../../../src/audit/cloudwatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
import type { AuditBackend } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* GcpAuditLogger buffers AuditEntry objects and writes them to Google Cloud
|
|
5
|
+
* Logging on flush().
|
|
6
|
+
*
|
|
7
|
+
* Requires the optional dependency @google-cloud/logging. If the SDK is not
|
|
8
|
+
* installed the logger is silently disabled.
|
|
9
|
+
*
|
|
10
|
+
* Severity mapping:
|
|
11
|
+
* BLOCKED* decisions → WARNING
|
|
12
|
+
* ALLOWED* decisions → INFO
|
|
13
|
+
*/
|
|
14
|
+
export declare class GcpAuditLogger implements AuditBackend {
|
|
15
|
+
private projectId;
|
|
16
|
+
private buffer;
|
|
17
|
+
/** Set to false when the SDK cannot be loaded so we never crash. */
|
|
18
|
+
private enabled;
|
|
19
|
+
constructor(projectId?: string);
|
|
20
|
+
log(entry: AuditEntry): Promise<void>;
|
|
21
|
+
flush(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=gcp-logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-logging.d.ts","sourceRoot":"","sources":["../../../src/audit/gcp-logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,YAAW,YAAY;IACjD,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,MAAM,CAAoB;IAClC,oEAAoE;IACpE,OAAO,CAAC,OAAO,CAAQ;gBAEX,SAAS,CAAC,EAAE,MAAM;IAIxB,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAqD7B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const LOG_NAME = "mcp-proxy-audit";
|
|
2
|
+
/**
|
|
3
|
+
* GcpAuditLogger buffers AuditEntry objects and writes them to Google Cloud
|
|
4
|
+
* Logging on flush().
|
|
5
|
+
*
|
|
6
|
+
* Requires the optional dependency @google-cloud/logging. If the SDK is not
|
|
7
|
+
* installed the logger is silently disabled.
|
|
8
|
+
*
|
|
9
|
+
* Severity mapping:
|
|
10
|
+
* BLOCKED* decisions → WARNING
|
|
11
|
+
* ALLOWED* decisions → INFO
|
|
12
|
+
*/
|
|
13
|
+
export class GcpAuditLogger {
|
|
14
|
+
projectId;
|
|
15
|
+
buffer = [];
|
|
16
|
+
/** Set to false when the SDK cannot be loaded so we never crash. */
|
|
17
|
+
enabled = true;
|
|
18
|
+
constructor(projectId) {
|
|
19
|
+
this.projectId = projectId;
|
|
20
|
+
}
|
|
21
|
+
async log(entry) {
|
|
22
|
+
if (!this.enabled)
|
|
23
|
+
return;
|
|
24
|
+
this.buffer.push(entry);
|
|
25
|
+
}
|
|
26
|
+
async flush() {
|
|
27
|
+
if (!this.enabled || this.buffer.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
// Snapshot and clear the in-flight entries; restore on error.
|
|
30
|
+
const toSend = this.buffer.splice(0);
|
|
31
|
+
let sdk;
|
|
32
|
+
try {
|
|
33
|
+
sdk = await import("@google-cloud/logging");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
console.warn("[GcpAuditLogger] @google-cloud/logging is not installed. " +
|
|
37
|
+
"GCP audit logging is disabled.");
|
|
38
|
+
this.enabled = false;
|
|
39
|
+
// Entries are already removed from the buffer — drop them gracefully.
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { Logging } = sdk;
|
|
43
|
+
const loggingClient = this.projectId
|
|
44
|
+
? new Logging({ projectId: this.projectId })
|
|
45
|
+
: new Logging();
|
|
46
|
+
const log = loggingClient.log(LOG_NAME);
|
|
47
|
+
try {
|
|
48
|
+
const gcpEntries = toSend.map((entry) => {
|
|
49
|
+
const severity = entry.decision.startsWith("BLOCKED") ? "WARNING" : "INFO";
|
|
50
|
+
return log.entry({
|
|
51
|
+
severity,
|
|
52
|
+
resource: {
|
|
53
|
+
type: "global",
|
|
54
|
+
labels: {
|
|
55
|
+
engagement_id: entry.engagement_id,
|
|
56
|
+
client: entry.client,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}, entry);
|
|
60
|
+
});
|
|
61
|
+
await log.write(gcpEntries);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error("[GcpAuditLogger] flush() failed:", err);
|
|
65
|
+
// Put entries back at the front of the buffer for the next retry.
|
|
66
|
+
this.buffer.unshift(...toSend);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=gcp-logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp-logging.js","sourceRoot":"","sources":["../../../src/audit/gcp-logging.ts"],"names":[],"mappings":"AAGA,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAc;IACjB,SAAS,CAAqB;IAC9B,MAAM,GAAiB,EAAE,CAAC;IAClC,oEAAoE;IAC5D,OAAO,GAAG,IAAI,CAAC;IAEvB,YAAY,SAAkB;QAC5B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEtD,8DAA8D;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,GAA2C,CAAC;QAChD,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CACV,2DAA2D;gBACzD,gCAAgC,CACnC,CAAC;YACF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,sEAAsE;YACtE,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;QAExB,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS;YAClC,CAAC,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5C,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;QAElB,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;gBAE3E,OAAO,GAAG,CAAC,KAAK,CACd;oBACE,QAAQ;oBACR,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ;wBACd,MAAM,EAAE;4BACN,aAAa,EAAE,KAAK,CAAC,aAAa;4BAClC,MAAM,EAAE,KAAK,CAAC,MAAM;yBACrB;qBACF;iBACF,EACD,KAAK,CACN,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,MAAM,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YACvD,kEAAkE;YAClE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
export type { AuditEntry };
|
|
3
|
+
/**
|
|
4
|
+
* Common interface that every audit backend must implement.
|
|
5
|
+
*/
|
|
6
|
+
export interface AuditBackend {
|
|
7
|
+
log(entry: AuditEntry): Promise<void>;
|
|
8
|
+
flush(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* AuditLogger is the central facade for audit logging.
|
|
12
|
+
*
|
|
13
|
+
* - Always includes a LocalAuditLogger backend (writes JSONL files).
|
|
14
|
+
* - Additional cloud backends can be registered via addBackend().
|
|
15
|
+
* - Errors from any backend are caught and logged to console.error; they
|
|
16
|
+
* never propagate to callers.
|
|
17
|
+
* - A periodic flush timer can be started/stopped via start()/stop().
|
|
18
|
+
*/
|
|
19
|
+
export declare class AuditLogger {
|
|
20
|
+
private backends;
|
|
21
|
+
private flushIntervalMs;
|
|
22
|
+
private timer;
|
|
23
|
+
constructor(localPath: string, flushIntervalMs?: number);
|
|
24
|
+
/**
|
|
25
|
+
* Register an additional backend (e.g. a cloud logging sink).
|
|
26
|
+
*/
|
|
27
|
+
addBackend(backend: AuditBackend): void;
|
|
28
|
+
/**
|
|
29
|
+
* Start the periodic flush timer.
|
|
30
|
+
*/
|
|
31
|
+
start(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Dispatch an entry to all backends.
|
|
34
|
+
* Errors from individual backends are caught and reported via console.error
|
|
35
|
+
* but never thrown.
|
|
36
|
+
*/
|
|
37
|
+
log(entry: AuditEntry): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Flush all backends.
|
|
40
|
+
* Each backend is flushed independently; a failure in one does NOT prevent
|
|
41
|
+
* the others from being flushed.
|
|
42
|
+
*/
|
|
43
|
+
flush(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Stop the flush timer and perform one final flush.
|
|
46
|
+
*/
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,KAAK,CAA+C;gBAEhD,SAAS,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM;IAMvD;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAIvC;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;;;OAIG;IACG,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3C;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAO5B"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { LocalAuditLogger } from "./local.js";
|
|
2
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 5000;
|
|
3
|
+
/**
|
|
4
|
+
* AuditLogger is the central facade for audit logging.
|
|
5
|
+
*
|
|
6
|
+
* - Always includes a LocalAuditLogger backend (writes JSONL files).
|
|
7
|
+
* - Additional cloud backends can be registered via addBackend().
|
|
8
|
+
* - Errors from any backend are caught and logged to console.error; they
|
|
9
|
+
* never propagate to callers.
|
|
10
|
+
* - A periodic flush timer can be started/stopped via start()/stop().
|
|
11
|
+
*/
|
|
12
|
+
export class AuditLogger {
|
|
13
|
+
backends = [];
|
|
14
|
+
flushIntervalMs;
|
|
15
|
+
timer = null;
|
|
16
|
+
constructor(localPath, flushIntervalMs) {
|
|
17
|
+
this.flushIntervalMs = flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
18
|
+
// Local backend is always present
|
|
19
|
+
this.backends.push(new LocalAuditLogger(localPath));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register an additional backend (e.g. a cloud logging sink).
|
|
23
|
+
*/
|
|
24
|
+
addBackend(backend) {
|
|
25
|
+
this.backends.push(backend);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start the periodic flush timer.
|
|
29
|
+
*/
|
|
30
|
+
start() {
|
|
31
|
+
if (this.timer !== null) {
|
|
32
|
+
return; // already running
|
|
33
|
+
}
|
|
34
|
+
this.timer = setInterval(() => {
|
|
35
|
+
void this.flush();
|
|
36
|
+
}, this.flushIntervalMs);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Dispatch an entry to all backends.
|
|
40
|
+
* Errors from individual backends are caught and reported via console.error
|
|
41
|
+
* but never thrown.
|
|
42
|
+
*/
|
|
43
|
+
async log(entry) {
|
|
44
|
+
await Promise.all(this.backends.map(async (backend) => {
|
|
45
|
+
try {
|
|
46
|
+
await backend.log(entry);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error("[AuditLogger] Backend log() failed:", err);
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Flush all backends.
|
|
55
|
+
* Each backend is flushed independently; a failure in one does NOT prevent
|
|
56
|
+
* the others from being flushed.
|
|
57
|
+
*/
|
|
58
|
+
async flush() {
|
|
59
|
+
await Promise.all(this.backends.map(async (backend) => {
|
|
60
|
+
try {
|
|
61
|
+
await backend.flush();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error("[AuditLogger] Backend flush() failed:", err);
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Stop the flush timer and perform one final flush.
|
|
70
|
+
*/
|
|
71
|
+
async stop() {
|
|
72
|
+
if (this.timer !== null) {
|
|
73
|
+
clearInterval(this.timer);
|
|
74
|
+
this.timer = null;
|
|
75
|
+
}
|
|
76
|
+
await this.flush();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audit/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAY9C,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,OAAO,WAAW;IACd,QAAQ,GAAmB,EAAE,CAAC;IAC9B,eAAe,CAAS;IACxB,KAAK,GAA0C,IAAI,CAAC;IAE5D,YAAY,SAAiB,EAAE,eAAwB;QACrD,IAAI,CAAC,eAAe,GAAG,eAAe,IAAI,yBAAyB,CAAC;QACpE,kCAAkC;QAClC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,OAAqB;QAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,CAAC,kBAAkB;QAC5B,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* LocalAuditLogger buffers AuditEntry objects in memory, keyed by engagement_id,
|
|
4
|
+
* and writes them to JSONL files on disk when flush() is called.
|
|
5
|
+
*
|
|
6
|
+
* Each file lives at: {basePath}/{engagement_id}.jsonl
|
|
7
|
+
* Entries are appended (not overwritten) so multiple sessions accumulate.
|
|
8
|
+
*/
|
|
9
|
+
export declare class LocalAuditLogger {
|
|
10
|
+
private basePath;
|
|
11
|
+
/** Buffer: engagement_id -> list of serialized JSON lines */
|
|
12
|
+
private buffer;
|
|
13
|
+
constructor(basePath: string);
|
|
14
|
+
/**
|
|
15
|
+
* Buffer an entry in memory. Does NOT write to disk.
|
|
16
|
+
*/
|
|
17
|
+
log(entry: AuditEntry): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Write all buffered entries to disk and clear the buffer.
|
|
20
|
+
* Creates the base directory if it does not exist.
|
|
21
|
+
* Appends to any existing file for the same engagement_id.
|
|
22
|
+
*/
|
|
23
|
+
flush(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/audit/local.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,6DAA6D;IAC7D,OAAO,CAAC,MAAM,CAAwC;gBAE1C,QAAQ,EAAE,MAAM;IAI5B;;OAEG;IACG,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAsB7B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* LocalAuditLogger buffers AuditEntry objects in memory, keyed by engagement_id,
|
|
5
|
+
* and writes them to JSONL files on disk when flush() is called.
|
|
6
|
+
*
|
|
7
|
+
* Each file lives at: {basePath}/{engagement_id}.jsonl
|
|
8
|
+
* Entries are appended (not overwritten) so multiple sessions accumulate.
|
|
9
|
+
*/
|
|
10
|
+
export class LocalAuditLogger {
|
|
11
|
+
basePath;
|
|
12
|
+
/** Buffer: engagement_id -> list of serialized JSON lines */
|
|
13
|
+
buffer = new Map();
|
|
14
|
+
constructor(basePath) {
|
|
15
|
+
this.basePath = basePath;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Buffer an entry in memory. Does NOT write to disk.
|
|
19
|
+
*/
|
|
20
|
+
async log(entry) {
|
|
21
|
+
const id = entry.engagement_id;
|
|
22
|
+
if (!this.buffer.has(id)) {
|
|
23
|
+
this.buffer.set(id, []);
|
|
24
|
+
}
|
|
25
|
+
this.buffer.get(id).push(entry);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Write all buffered entries to disk and clear the buffer.
|
|
29
|
+
* Creates the base directory if it does not exist.
|
|
30
|
+
* Appends to any existing file for the same engagement_id.
|
|
31
|
+
*/
|
|
32
|
+
async flush() {
|
|
33
|
+
if (this.buffer.size === 0) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Ensure the base directory exists
|
|
37
|
+
fs.mkdirSync(this.basePath, { recursive: true });
|
|
38
|
+
for (const [engagementId, entries] of this.buffer.entries()) {
|
|
39
|
+
if (entries.length === 0) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const filePath = path.join(this.basePath, `${engagementId}.jsonl`);
|
|
43
|
+
// Build the content to append: one JSON object per line, terminated with \n
|
|
44
|
+
const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
45
|
+
fs.appendFileSync(filePath, lines, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
// Clear buffer after successful flush
|
|
48
|
+
this.buffer.clear();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/audit/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IACnB,QAAQ,CAAS;IACzB,6DAA6D;IACrD,MAAM,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEtD,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QAED,mCAAmC;QACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjD,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,YAAY,QAAQ,CAAC,CAAC;YACnE,4EAA4E;YAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACtE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QAED,sCAAsC;QACtC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ProxyConfig {
|
|
2
|
+
manifestPath?: string;
|
|
3
|
+
manifestJson?: string;
|
|
4
|
+
manifestSecretArn?: string;
|
|
5
|
+
manifestKeyvaultUri?: string;
|
|
6
|
+
manifestGcpSecret?: string;
|
|
7
|
+
transport: "stdio" | "sse";
|
|
8
|
+
upstreamMcpUrl?: string;
|
|
9
|
+
upstreamMcpCommand?: string;
|
|
10
|
+
upstreamMcpArgs?: string[];
|
|
11
|
+
proxyPort: number;
|
|
12
|
+
auditLogPath: string;
|
|
13
|
+
awsLogGroup?: string;
|
|
14
|
+
awsRegion?: string;
|
|
15
|
+
azureLogWorkspaceId?: string;
|
|
16
|
+
azureDcrImmutableId?: string;
|
|
17
|
+
azureDcrStreamName: string;
|
|
18
|
+
gcpProject?: string;
|
|
19
|
+
techniqueMapPath?: string;
|
|
20
|
+
dnsCacheTtl: number;
|
|
21
|
+
logLevel: string;
|
|
22
|
+
proxyVersion: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function loadConfig(): ProxyConfig;
|
|
25
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,OAAO,GAAG,KAAK,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,UAAU,IAAI,WAAW,CAwBxC"}
|