@agenshield/interceptor
Advanced tools
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAiBtD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,eAAe,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC3C,IAAI,CAuGN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CA6B5C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,WAAW,GAAG,IAAI,CAE9C"} | ||
| {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAiBtD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,eAAe,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC3C,IAAI,CAwGN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CA6B5C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,WAAW,GAAG,IAAI,CAE9C"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"child-process.d.ts","sourceRoot":"","sources":["../../src/interceptors/child-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAYzE,qBAAa,uBAAwB,SAAQ,eAAe;IAC1D,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,gBAAgB,CAA6C;IACrE,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,gBAAgB,CAA6C;IACrE,OAAO,CAAC,YAAY,CAAyC;gBAEjD,OAAO,EAAE,sBAAsB;IAkB3C,OAAO,IAAI,IAAI;IAsBf,SAAS,IAAI,IAAI;IAmBjB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAUjC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAkCvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA+CxB;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAsCrC,OAAO,CAAC,qBAAqB;IAsD7B,OAAO,CAAC,yBAAyB;IAwCjC,OAAO,CAAC,sBAAsB;IAiD9B,OAAO,CAAC,0BAA0B;IA0DlC,OAAO,CAAC,yBAAyB;IAoEjC,OAAO,CAAC,qBAAqB;CAyD9B"} | ||
| {"version":3,"file":"child-process.d.ts","sourceRoot":"","sources":["../../src/interceptors/child-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAYzE,qBAAa,uBAAwB,SAAQ,eAAe;IAC1D,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,gBAAgB,CAA6C;IACrE,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,gBAAgB,CAA6C;IACrE,OAAO,CAAC,YAAY,CAAyC;gBAEjD,OAAO,EAAE,sBAAsB;IAkB3C,OAAO,IAAI,IAAI;IAsBf,SAAS,IAAI,IAAI;IAmBjB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAUjC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAqCvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA+CxB;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAsCrC,OAAO,CAAC,qBAAqB;IAyD7B,OAAO,CAAC,yBAAyB;IAwCjC,OAAO,CAAC,sBAAsB;IAqD9B,OAAO,CAAC,0BAA0B;IA0DlC,OAAO,CAAC,yBAAyB;IAwEjC,OAAO,CAAC,qBAAqB;CA4D9B"} |
| /** | ||
| * HTTP/HTTPS Interceptor | ||
| * | ||
| * Intercepts Node.js http and https module calls. | ||
| * Intercepts Node.js http and https module calls with synchronous policy | ||
| * checking. Uses SyncClient to block before the request fires, preventing | ||
| * the race condition where async policy checks arrive after the request | ||
| * has already completed. | ||
| */ | ||
| import { BaseInterceptor, type BaseInterceptorOptions } from './base.js'; | ||
| export declare class HttpInterceptor extends BaseInterceptor { | ||
| private syncClient; | ||
| private originalHttpRequest; | ||
@@ -15,2 +19,11 @@ private originalHttpGet; | ||
| uninstall(): void; | ||
| /** | ||
| * Build execution context from config for RPC calls | ||
| */ | ||
| private getPolicyExecutionContext; | ||
| /** | ||
| * Synchronous policy check via SyncClient. | ||
| * Returns the full policy result or null if broker is unavailable and failOpen is true. | ||
| */ | ||
| private syncPolicyCheck; | ||
| private createInterceptedRequest; | ||
@@ -17,0 +30,0 @@ private createInterceptedGet; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/interceptors/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAQzE,qBAAa,eAAgB,SAAQ,eAAe;IAClD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,oBAAoB,CAAoC;IAChE,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,OAAO,EAAE,sBAAsB;IAI3C,OAAO,IAAI,IAAI;IAkBf,SAAS,IAAI,IAAI;IAuBjB,OAAO,CAAC,wBAAwB;IA0DhC,OAAO,CAAC,oBAAoB;CAoB7B"} | ||
| {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/interceptors/http.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAazE,qBAAa,eAAgB,SAAQ,eAAe;IAClD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,oBAAoB,CAAoC;IAChE,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,OAAO,EAAE,sBAAsB;IAW3C,OAAO,IAAI,IAAI;IAkBf,SAAS,IAAI,IAAI;IAuBjB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAUjC;;;OAGG;IACH,OAAO,CAAC,eAAe;IAkCvB,OAAO,CAAC,wBAAwB;IA6DhC,OAAO,CAAC,oBAAoB;CAoB7B"} |
+2
-2
| { | ||
| "name": "@agenshield/interceptor", | ||
| "version": "0.7.1", | ||
| "version": "0.7.2", | ||
| "type": "module", | ||
@@ -28,3 +28,3 @@ "description": "Node.js runtime interception via ESM loader and CJS preload", | ||
| "dependencies": { | ||
| "@agenshield/ipc": "0.7.1" | ||
| "@agenshield/ipc": "0.7.2" | ||
| }, | ||
@@ -31,0 +31,0 @@ "devDependencies": { |
+215
-137
@@ -286,136 +286,2 @@ "use strict"; | ||
| // libs/shield-interceptor/src/interceptors/http.ts | ||
| var httpModule = require("node:http"); | ||
| var httpsModule = require("node:https"); | ||
| var HttpInterceptor = class extends BaseInterceptor { | ||
| originalHttpRequest = null; | ||
| originalHttpGet = null; | ||
| originalHttpsRequest = null; | ||
| originalHttpsGet = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| this.originalHttpRequest = httpModule.request; | ||
| this.originalHttpGet = httpModule.get; | ||
| this.originalHttpsRequest = httpsModule.request; | ||
| this.originalHttpsGet = httpsModule.get; | ||
| httpModule.request = this.createInterceptedRequest("http", this.originalHttpRequest); | ||
| httpModule.get = this.createInterceptedGet("http", this.originalHttpGet); | ||
| httpsModule.request = this.createInterceptedRequest("https", this.originalHttpsRequest); | ||
| httpsModule.get = this.createInterceptedGet("https", this.originalHttpsGet); | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed) return; | ||
| if (this.originalHttpRequest) { | ||
| httpModule.request = this.originalHttpRequest; | ||
| } | ||
| if (this.originalHttpGet) { | ||
| httpModule.get = this.originalHttpGet; | ||
| } | ||
| if (this.originalHttpsRequest) { | ||
| httpsModule.request = this.originalHttpsRequest; | ||
| } | ||
| if (this.originalHttpsGet) { | ||
| httpsModule.get = this.originalHttpsGet; | ||
| } | ||
| this.originalHttpRequest = null; | ||
| this.originalHttpGet = null; | ||
| this.originalHttpsRequest = null; | ||
| this.originalHttpsGet = null; | ||
| this.installed = false; | ||
| } | ||
| createInterceptedRequest(protocol, original) { | ||
| const self = this; | ||
| return function interceptedRequest(urlOrOptions, optionsOrCallback, callback) { | ||
| let url; | ||
| let options; | ||
| let cb; | ||
| if (typeof urlOrOptions === "string" || urlOrOptions instanceof URL) { | ||
| url = urlOrOptions.toString(); | ||
| options = typeof optionsOrCallback === "object" ? optionsOrCallback : {}; | ||
| cb = typeof optionsOrCallback === "function" ? optionsOrCallback : callback; | ||
| } else { | ||
| options = urlOrOptions; | ||
| url = `${protocol}://${options.hostname || options.host || "localhost"}:${options.port || (protocol === "https" ? 443 : 80)}${options.path || "/"}`; | ||
| cb = optionsOrCallback; | ||
| } | ||
| if (self.isBrokerUrl(url)) { | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| } | ||
| const req = original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| self.eventReporter.intercept("http_request", url); | ||
| self.checkPolicy("http_request", url).catch((error) => { | ||
| req.destroy(error); | ||
| }); | ||
| return req; | ||
| }; | ||
| } | ||
| createInterceptedGet(protocol, original) { | ||
| const interceptedRequest = this.createInterceptedRequest( | ||
| protocol, | ||
| protocol === "http" ? this.originalHttpRequest : this.originalHttpsRequest | ||
| ); | ||
| return function interceptedGet(urlOrOptions, optionsOrCallback, callback) { | ||
| const req = interceptedRequest(urlOrOptions, optionsOrCallback, callback); | ||
| req.end(); | ||
| return req; | ||
| }; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/interceptors/websocket.ts | ||
| var WebSocketInterceptor = class extends BaseInterceptor { | ||
| originalWebSocket = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| if (typeof globalThis.WebSocket === "undefined") { | ||
| this.debug("WebSocket not available in this environment"); | ||
| return; | ||
| } | ||
| this.originalWebSocket = globalThis.WebSocket; | ||
| const self = this; | ||
| const OriginalWebSocket = this.originalWebSocket; | ||
| class InterceptedWebSocket extends OriginalWebSocket { | ||
| constructor(url, protocols) { | ||
| const urlString = url.toString(); | ||
| if (self.isBrokerUrl(urlString)) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| self.eventReporter.intercept("websocket", urlString); | ||
| super(url, protocols); | ||
| self.checkPolicy("websocket", urlString).catch((error) => { | ||
| this.close(1008, "Policy denied"); | ||
| const errorEvent = new Event("error"); | ||
| this.dispatchEvent(errorEvent); | ||
| }); | ||
| } | ||
| } | ||
| globalThis.WebSocket = InterceptedWebSocket; | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed || !this.originalWebSocket) return; | ||
| globalThis.WebSocket = this.originalWebSocket; | ||
| this.originalWebSocket = null; | ||
| this.installed = false; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/client/sync-client.ts | ||
@@ -624,2 +490,198 @@ var import_node_child_process = require("node:child_process"); | ||
| // libs/shield-interceptor/src/interceptors/http.ts | ||
| var httpModule = require("node:http"); | ||
| var httpsModule = require("node:https"); | ||
| var HttpInterceptor = class extends BaseInterceptor { | ||
| syncClient; | ||
| originalHttpRequest = null; | ||
| originalHttpGet = null; | ||
| originalHttpsRequest = null; | ||
| originalHttpsGet = null; | ||
| constructor(options) { | ||
| super(options); | ||
| const config = this.interceptorConfig; | ||
| this.syncClient = new SyncClient({ | ||
| socketPath: config?.socketPath || "/var/run/agenshield/agenshield.sock", | ||
| httpHost: config?.httpHost || "localhost", | ||
| httpPort: config?.httpPort || 5201, | ||
| timeout: config?.timeout || 3e4 | ||
| }); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| this.originalHttpRequest = httpModule.request; | ||
| this.originalHttpGet = httpModule.get; | ||
| this.originalHttpsRequest = httpsModule.request; | ||
| this.originalHttpsGet = httpsModule.get; | ||
| httpModule.request = this.createInterceptedRequest("http", this.originalHttpRequest); | ||
| httpModule.get = this.createInterceptedGet("http", this.originalHttpGet); | ||
| httpsModule.request = this.createInterceptedRequest("https", this.originalHttpsRequest); | ||
| httpsModule.get = this.createInterceptedGet("https", this.originalHttpsGet); | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed) return; | ||
| if (this.originalHttpRequest) { | ||
| httpModule.request = this.originalHttpRequest; | ||
| } | ||
| if (this.originalHttpGet) { | ||
| httpModule.get = this.originalHttpGet; | ||
| } | ||
| if (this.originalHttpsRequest) { | ||
| httpsModule.request = this.originalHttpsRequest; | ||
| } | ||
| if (this.originalHttpsGet) { | ||
| httpsModule.get = this.originalHttpsGet; | ||
| } | ||
| this.originalHttpRequest = null; | ||
| this.originalHttpGet = null; | ||
| this.originalHttpsRequest = null; | ||
| this.originalHttpsGet = null; | ||
| this.installed = false; | ||
| } | ||
| /** | ||
| * Build execution context from config for RPC calls | ||
| */ | ||
| getPolicyExecutionContext() { | ||
| const config = this.interceptorConfig; | ||
| return { | ||
| callerType: config?.contextType || "agent", | ||
| skillSlug: config?.contextSkillSlug, | ||
| agentId: config?.contextAgentId, | ||
| depth: 0 | ||
| }; | ||
| } | ||
| /** | ||
| * Synchronous policy check via SyncClient. | ||
| * Returns the full policy result or null if broker is unavailable and failOpen is true. | ||
| */ | ||
| syncPolicyCheck(url) { | ||
| const startTime = Date.now(); | ||
| try { | ||
| debugLog(`http.syncPolicyCheck START url=${url}`); | ||
| const context = this.getPolicyExecutionContext(); | ||
| const result = this.syncClient.request( | ||
| "policy_check", | ||
| { operation: "http_request", target: url, context } | ||
| ); | ||
| debugLog(`http.syncPolicyCheck DONE allowed=${result.allowed} url=${url}`); | ||
| if (!result.allowed) { | ||
| this.eventReporter.deny("http_request", url, result.policyId, result.reason); | ||
| throw new PolicyDeniedError(result.reason || "Operation denied by policy", { | ||
| operation: "http_request", | ||
| target: url, | ||
| policyId: result.policyId | ||
| }); | ||
| } | ||
| this.eventReporter.allow("http_request", url, result.policyId, Date.now() - startTime); | ||
| return result; | ||
| } catch (error) { | ||
| if (error instanceof PolicyDeniedError) { | ||
| throw error; | ||
| } | ||
| debugLog(`http.syncPolicyCheck ERROR: ${error.message} url=${url}`); | ||
| if (!this.failOpen) { | ||
| throw error; | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| createInterceptedRequest(protocol, original) { | ||
| const self = this; | ||
| return function interceptedRequest(urlOrOptions, optionsOrCallback, callback) { | ||
| let url; | ||
| let options; | ||
| let cb; | ||
| if (typeof urlOrOptions === "string" || urlOrOptions instanceof URL) { | ||
| url = urlOrOptions.toString(); | ||
| options = typeof optionsOrCallback === "object" ? optionsOrCallback : {}; | ||
| cb = typeof optionsOrCallback === "function" ? optionsOrCallback : callback; | ||
| } else { | ||
| options = urlOrOptions; | ||
| url = `${protocol}://${options.hostname || options.host || "localhost"}:${options.port || (protocol === "https" ? 443 : 80)}${options.path || "/"}`; | ||
| cb = optionsOrCallback; | ||
| } | ||
| if (self.isBrokerUrl(url)) { | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| } | ||
| self.eventReporter.intercept("http_request", url); | ||
| try { | ||
| self.syncPolicyCheck(url); | ||
| } catch (error) { | ||
| debugLog(`http.request DENIED url=${url}`); | ||
| const mod = protocol === "http" ? httpModule : httpsModule; | ||
| const denied = original.call(mod, "http://0.0.0.0:1", { method: "GET" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => denied.destroy(error)); | ||
| return denied; | ||
| } | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| }; | ||
| } | ||
| createInterceptedGet(protocol, original) { | ||
| const interceptedRequest = this.createInterceptedRequest( | ||
| protocol, | ||
| protocol === "http" ? this.originalHttpRequest : this.originalHttpsRequest | ||
| ); | ||
| return function interceptedGet(urlOrOptions, optionsOrCallback, callback) { | ||
| const req = interceptedRequest(urlOrOptions, optionsOrCallback, callback); | ||
| req.end(); | ||
| return req; | ||
| }; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/interceptors/websocket.ts | ||
| var WebSocketInterceptor = class extends BaseInterceptor { | ||
| originalWebSocket = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| if (typeof globalThis.WebSocket === "undefined") { | ||
| this.debug("WebSocket not available in this environment"); | ||
| return; | ||
| } | ||
| this.originalWebSocket = globalThis.WebSocket; | ||
| const self = this; | ||
| const OriginalWebSocket = this.originalWebSocket; | ||
| class InterceptedWebSocket extends OriginalWebSocket { | ||
| constructor(url, protocols) { | ||
| const urlString = url.toString(); | ||
| if (self.isBrokerUrl(urlString)) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| self.eventReporter.intercept("websocket", urlString); | ||
| super(url, protocols); | ||
| self.checkPolicy("websocket", urlString).catch((error) => { | ||
| this.close(1008, "Policy denied"); | ||
| const errorEvent = new Event("error"); | ||
| this.dispatchEvent(errorEvent); | ||
| }); | ||
| } | ||
| } | ||
| globalThis.WebSocket = InterceptedWebSocket; | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed || !this.originalWebSocket) return; | ||
| globalThis.WebSocket = this.originalWebSocket; | ||
| this.originalWebSocket = null; | ||
| this.installed = false; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/seatbelt/profile-manager.ts | ||
@@ -918,2 +980,3 @@ var fs3 = __toESM(require("node:fs"), 1); | ||
| this._checking = true; | ||
| const startTime = Date.now(); | ||
| try { | ||
@@ -928,2 +991,3 @@ debugLog(`cp.syncPolicyCheck START command=${fullCommand}`); | ||
| if (!result.allowed) { | ||
| this.eventReporter.deny("exec", fullCommand, result.policyId, result.reason); | ||
| throw new PolicyDeniedError(result.reason || "Operation denied by policy", { | ||
@@ -935,2 +999,3 @@ operation: "exec", | ||
| } | ||
| this.eventReporter.allow("exec", fullCommand, result.policyId, Date.now() - startTime); | ||
| return result; | ||
@@ -1062,6 +1127,10 @@ } catch (error) { | ||
| } catch (error) { | ||
| debugLog(`cp.exec DENIED command=${command}`); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| if (callback) { | ||
| process.nextTick(() => callback(error, "", "")); | ||
| } | ||
| return original('echo ""'); | ||
| return denied; | ||
| } | ||
@@ -1124,2 +1193,4 @@ const wrapped = self.wrapCommandStringWithSeatbelt(command, options, policyResult); | ||
| const denied = original("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => { | ||
@@ -1209,6 +1280,10 @@ denied.emit("error", error); | ||
| } catch (error) { | ||
| debugLog(`cp.execFile DENIED command=${fullCommand}`); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| if (callback) { | ||
| process.nextTick(() => callback(error, "", "")); | ||
| } | ||
| return original("false"); | ||
| return denied; | ||
| } | ||
@@ -1252,2 +1327,4 @@ const wrapped = self.wrapWithSeatbelt(file, args, options, policyResult); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => { | ||
@@ -1800,3 +1877,4 @@ denied.emit("error", error); | ||
| failOpen: config.failOpen, | ||
| brokerHttpPort: config.httpPort | ||
| brokerHttpPort: config.httpPort, | ||
| config | ||
| }); | ||
@@ -1803,0 +1881,0 @@ installed.http.install(); |
+215
-137
@@ -286,136 +286,2 @@ "use strict"; | ||
| // libs/shield-interceptor/src/interceptors/http.ts | ||
| var httpModule = require("node:http"); | ||
| var httpsModule = require("node:https"); | ||
| var HttpInterceptor = class extends BaseInterceptor { | ||
| originalHttpRequest = null; | ||
| originalHttpGet = null; | ||
| originalHttpsRequest = null; | ||
| originalHttpsGet = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| this.originalHttpRequest = httpModule.request; | ||
| this.originalHttpGet = httpModule.get; | ||
| this.originalHttpsRequest = httpsModule.request; | ||
| this.originalHttpsGet = httpsModule.get; | ||
| httpModule.request = this.createInterceptedRequest("http", this.originalHttpRequest); | ||
| httpModule.get = this.createInterceptedGet("http", this.originalHttpGet); | ||
| httpsModule.request = this.createInterceptedRequest("https", this.originalHttpsRequest); | ||
| httpsModule.get = this.createInterceptedGet("https", this.originalHttpsGet); | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed) return; | ||
| if (this.originalHttpRequest) { | ||
| httpModule.request = this.originalHttpRequest; | ||
| } | ||
| if (this.originalHttpGet) { | ||
| httpModule.get = this.originalHttpGet; | ||
| } | ||
| if (this.originalHttpsRequest) { | ||
| httpsModule.request = this.originalHttpsRequest; | ||
| } | ||
| if (this.originalHttpsGet) { | ||
| httpsModule.get = this.originalHttpsGet; | ||
| } | ||
| this.originalHttpRequest = null; | ||
| this.originalHttpGet = null; | ||
| this.originalHttpsRequest = null; | ||
| this.originalHttpsGet = null; | ||
| this.installed = false; | ||
| } | ||
| createInterceptedRequest(protocol, original) { | ||
| const self = this; | ||
| return function interceptedRequest(urlOrOptions, optionsOrCallback, callback) { | ||
| let url; | ||
| let options; | ||
| let cb; | ||
| if (typeof urlOrOptions === "string" || urlOrOptions instanceof URL) { | ||
| url = urlOrOptions.toString(); | ||
| options = typeof optionsOrCallback === "object" ? optionsOrCallback : {}; | ||
| cb = typeof optionsOrCallback === "function" ? optionsOrCallback : callback; | ||
| } else { | ||
| options = urlOrOptions; | ||
| url = `${protocol}://${options.hostname || options.host || "localhost"}:${options.port || (protocol === "https" ? 443 : 80)}${options.path || "/"}`; | ||
| cb = optionsOrCallback; | ||
| } | ||
| if (self.isBrokerUrl(url)) { | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| } | ||
| const req = original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| self.eventReporter.intercept("http_request", url); | ||
| self.checkPolicy("http_request", url).catch((error) => { | ||
| req.destroy(error); | ||
| }); | ||
| return req; | ||
| }; | ||
| } | ||
| createInterceptedGet(protocol, original) { | ||
| const interceptedRequest = this.createInterceptedRequest( | ||
| protocol, | ||
| protocol === "http" ? this.originalHttpRequest : this.originalHttpsRequest | ||
| ); | ||
| return function interceptedGet(urlOrOptions, optionsOrCallback, callback) { | ||
| const req = interceptedRequest(urlOrOptions, optionsOrCallback, callback); | ||
| req.end(); | ||
| return req; | ||
| }; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/interceptors/websocket.ts | ||
| var WebSocketInterceptor = class extends BaseInterceptor { | ||
| originalWebSocket = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| if (typeof globalThis.WebSocket === "undefined") { | ||
| this.debug("WebSocket not available in this environment"); | ||
| return; | ||
| } | ||
| this.originalWebSocket = globalThis.WebSocket; | ||
| const self = this; | ||
| const OriginalWebSocket = this.originalWebSocket; | ||
| class InterceptedWebSocket extends OriginalWebSocket { | ||
| constructor(url, protocols) { | ||
| const urlString = url.toString(); | ||
| if (self.isBrokerUrl(urlString)) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| self.eventReporter.intercept("websocket", urlString); | ||
| super(url, protocols); | ||
| self.checkPolicy("websocket", urlString).catch((error) => { | ||
| this.close(1008, "Policy denied"); | ||
| const errorEvent = new Event("error"); | ||
| this.dispatchEvent(errorEvent); | ||
| }); | ||
| } | ||
| } | ||
| globalThis.WebSocket = InterceptedWebSocket; | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed || !this.originalWebSocket) return; | ||
| globalThis.WebSocket = this.originalWebSocket; | ||
| this.originalWebSocket = null; | ||
| this.installed = false; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/client/sync-client.ts | ||
@@ -624,2 +490,198 @@ var import_node_child_process = require("node:child_process"); | ||
| // libs/shield-interceptor/src/interceptors/http.ts | ||
| var httpModule = require("node:http"); | ||
| var httpsModule = require("node:https"); | ||
| var HttpInterceptor = class extends BaseInterceptor { | ||
| syncClient; | ||
| originalHttpRequest = null; | ||
| originalHttpGet = null; | ||
| originalHttpsRequest = null; | ||
| originalHttpsGet = null; | ||
| constructor(options) { | ||
| super(options); | ||
| const config = this.interceptorConfig; | ||
| this.syncClient = new SyncClient({ | ||
| socketPath: config?.socketPath || "/var/run/agenshield/agenshield.sock", | ||
| httpHost: config?.httpHost || "localhost", | ||
| httpPort: config?.httpPort || 5201, | ||
| timeout: config?.timeout || 3e4 | ||
| }); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| this.originalHttpRequest = httpModule.request; | ||
| this.originalHttpGet = httpModule.get; | ||
| this.originalHttpsRequest = httpsModule.request; | ||
| this.originalHttpsGet = httpsModule.get; | ||
| httpModule.request = this.createInterceptedRequest("http", this.originalHttpRequest); | ||
| httpModule.get = this.createInterceptedGet("http", this.originalHttpGet); | ||
| httpsModule.request = this.createInterceptedRequest("https", this.originalHttpsRequest); | ||
| httpsModule.get = this.createInterceptedGet("https", this.originalHttpsGet); | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed) return; | ||
| if (this.originalHttpRequest) { | ||
| httpModule.request = this.originalHttpRequest; | ||
| } | ||
| if (this.originalHttpGet) { | ||
| httpModule.get = this.originalHttpGet; | ||
| } | ||
| if (this.originalHttpsRequest) { | ||
| httpsModule.request = this.originalHttpsRequest; | ||
| } | ||
| if (this.originalHttpsGet) { | ||
| httpsModule.get = this.originalHttpsGet; | ||
| } | ||
| this.originalHttpRequest = null; | ||
| this.originalHttpGet = null; | ||
| this.originalHttpsRequest = null; | ||
| this.originalHttpsGet = null; | ||
| this.installed = false; | ||
| } | ||
| /** | ||
| * Build execution context from config for RPC calls | ||
| */ | ||
| getPolicyExecutionContext() { | ||
| const config = this.interceptorConfig; | ||
| return { | ||
| callerType: config?.contextType || "agent", | ||
| skillSlug: config?.contextSkillSlug, | ||
| agentId: config?.contextAgentId, | ||
| depth: 0 | ||
| }; | ||
| } | ||
| /** | ||
| * Synchronous policy check via SyncClient. | ||
| * Returns the full policy result or null if broker is unavailable and failOpen is true. | ||
| */ | ||
| syncPolicyCheck(url) { | ||
| const startTime = Date.now(); | ||
| try { | ||
| debugLog(`http.syncPolicyCheck START url=${url}`); | ||
| const context = this.getPolicyExecutionContext(); | ||
| const result = this.syncClient.request( | ||
| "policy_check", | ||
| { operation: "http_request", target: url, context } | ||
| ); | ||
| debugLog(`http.syncPolicyCheck DONE allowed=${result.allowed} url=${url}`); | ||
| if (!result.allowed) { | ||
| this.eventReporter.deny("http_request", url, result.policyId, result.reason); | ||
| throw new PolicyDeniedError(result.reason || "Operation denied by policy", { | ||
| operation: "http_request", | ||
| target: url, | ||
| policyId: result.policyId | ||
| }); | ||
| } | ||
| this.eventReporter.allow("http_request", url, result.policyId, Date.now() - startTime); | ||
| return result; | ||
| } catch (error) { | ||
| if (error instanceof PolicyDeniedError) { | ||
| throw error; | ||
| } | ||
| debugLog(`http.syncPolicyCheck ERROR: ${error.message} url=${url}`); | ||
| if (!this.failOpen) { | ||
| throw error; | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| createInterceptedRequest(protocol, original) { | ||
| const self = this; | ||
| return function interceptedRequest(urlOrOptions, optionsOrCallback, callback) { | ||
| let url; | ||
| let options; | ||
| let cb; | ||
| if (typeof urlOrOptions === "string" || urlOrOptions instanceof URL) { | ||
| url = urlOrOptions.toString(); | ||
| options = typeof optionsOrCallback === "object" ? optionsOrCallback : {}; | ||
| cb = typeof optionsOrCallback === "function" ? optionsOrCallback : callback; | ||
| } else { | ||
| options = urlOrOptions; | ||
| url = `${protocol}://${options.hostname || options.host || "localhost"}:${options.port || (protocol === "https" ? 443 : 80)}${options.path || "/"}`; | ||
| cb = optionsOrCallback; | ||
| } | ||
| if (self.isBrokerUrl(url)) { | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| } | ||
| self.eventReporter.intercept("http_request", url); | ||
| try { | ||
| self.syncPolicyCheck(url); | ||
| } catch (error) { | ||
| debugLog(`http.request DENIED url=${url}`); | ||
| const mod = protocol === "http" ? httpModule : httpsModule; | ||
| const denied = original.call(mod, "http://0.0.0.0:1", { method: "GET" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => denied.destroy(error)); | ||
| return denied; | ||
| } | ||
| return original.call( | ||
| protocol === "http" ? httpModule : httpsModule, | ||
| urlOrOptions, | ||
| optionsOrCallback, | ||
| callback | ||
| ); | ||
| }; | ||
| } | ||
| createInterceptedGet(protocol, original) { | ||
| const interceptedRequest = this.createInterceptedRequest( | ||
| protocol, | ||
| protocol === "http" ? this.originalHttpRequest : this.originalHttpsRequest | ||
| ); | ||
| return function interceptedGet(urlOrOptions, optionsOrCallback, callback) { | ||
| const req = interceptedRequest(urlOrOptions, optionsOrCallback, callback); | ||
| req.end(); | ||
| return req; | ||
| }; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/interceptors/websocket.ts | ||
| var WebSocketInterceptor = class extends BaseInterceptor { | ||
| originalWebSocket = null; | ||
| constructor(options) { | ||
| super(options); | ||
| } | ||
| install() { | ||
| if (this.installed) return; | ||
| if (typeof globalThis.WebSocket === "undefined") { | ||
| this.debug("WebSocket not available in this environment"); | ||
| return; | ||
| } | ||
| this.originalWebSocket = globalThis.WebSocket; | ||
| const self = this; | ||
| const OriginalWebSocket = this.originalWebSocket; | ||
| class InterceptedWebSocket extends OriginalWebSocket { | ||
| constructor(url, protocols) { | ||
| const urlString = url.toString(); | ||
| if (self.isBrokerUrl(urlString)) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| self.eventReporter.intercept("websocket", urlString); | ||
| super(url, protocols); | ||
| self.checkPolicy("websocket", urlString).catch((error) => { | ||
| this.close(1008, "Policy denied"); | ||
| const errorEvent = new Event("error"); | ||
| this.dispatchEvent(errorEvent); | ||
| }); | ||
| } | ||
| } | ||
| globalThis.WebSocket = InterceptedWebSocket; | ||
| this.installed = true; | ||
| } | ||
| uninstall() { | ||
| if (!this.installed || !this.originalWebSocket) return; | ||
| globalThis.WebSocket = this.originalWebSocket; | ||
| this.originalWebSocket = null; | ||
| this.installed = false; | ||
| } | ||
| }; | ||
| // libs/shield-interceptor/src/seatbelt/profile-manager.ts | ||
@@ -918,2 +980,3 @@ var fs3 = __toESM(require("node:fs"), 1); | ||
| this._checking = true; | ||
| const startTime = Date.now(); | ||
| try { | ||
@@ -928,2 +991,3 @@ debugLog(`cp.syncPolicyCheck START command=${fullCommand}`); | ||
| if (!result.allowed) { | ||
| this.eventReporter.deny("exec", fullCommand, result.policyId, result.reason); | ||
| throw new PolicyDeniedError(result.reason || "Operation denied by policy", { | ||
@@ -935,2 +999,3 @@ operation: "exec", | ||
| } | ||
| this.eventReporter.allow("exec", fullCommand, result.policyId, Date.now() - startTime); | ||
| return result; | ||
@@ -1062,6 +1127,10 @@ } catch (error) { | ||
| } catch (error) { | ||
| debugLog(`cp.exec DENIED command=${command}`); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| if (callback) { | ||
| process.nextTick(() => callback(error, "", "")); | ||
| } | ||
| return original('echo ""'); | ||
| return denied; | ||
| } | ||
@@ -1124,2 +1193,4 @@ const wrapped = self.wrapCommandStringWithSeatbelt(command, options, policyResult); | ||
| const denied = original("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => { | ||
@@ -1209,6 +1280,10 @@ denied.emit("error", error); | ||
| } catch (error) { | ||
| debugLog(`cp.execFile DENIED command=${fullCommand}`); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| if (callback) { | ||
| process.nextTick(() => callback(error, "", "")); | ||
| } | ||
| return original("false"); | ||
| return denied; | ||
| } | ||
@@ -1252,2 +1327,4 @@ const wrapped = self.wrapWithSeatbelt(file, args, options, policyResult); | ||
| const denied = self.originalSpawn("false", [], { stdio: "pipe" }); | ||
| denied.once("error", () => { | ||
| }); | ||
| process.nextTick(() => { | ||
@@ -1800,3 +1877,4 @@ denied.emit("error", error); | ||
| failOpen: config.failOpen, | ||
| brokerHttpPort: config.httpPort | ||
| brokerHttpPort: config.httpPort, | ||
| config | ||
| }); | ||
@@ -1803,0 +1881,0 @@ installed.http.install(); |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
238747
3.95%6376
4.03%+ Added
- Removed
Updated