@xshieldai/n8n-nodes 1.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 ADDED
@@ -0,0 +1,70 @@
1
+ # @ankr/n8n-nodes-kavachos
2
+
3
+ **KavachOS n8n community nodes** — pre-execution DAN gate and kernel enforcement for AI agents.
4
+
5
+ Part of the **xShieldAI Posture Suite** · [kavachos.xshieldai.com](https://kavachos.xshieldai.com)
6
+
7
+ ---
8
+
9
+ ## Nodes
10
+
11
+ ### KavachGate
12
+
13
+ Intercepts AI agent actions **before execution**. Calls the Aegis KAVACH HTTP gate to:
14
+
15
+ 1. Classify danger level (DAN 1–4)
16
+ 2. Notify approvers via Telegram / WhatsApp (opt-in, requires `webhook_url` in `~/.aegis/config.json`)
17
+ 3. Wait for ALLOW or STOP
18
+ 4. Block the workflow on STOP or timeout (silence = STOP)
19
+
20
+ **Framework-neutral**: all policy lives in Aegis (`localhost:4850`). The n8n node is a thin HTTP client.
21
+
22
+ ### KavachRun
23
+
24
+ Wraps a subprocess in kavachos **kernel enforcement** (seccomp-bpf + cgroup BPF egress firewall).
25
+
26
+ - Linux only — gracefully degrades on macOS/Windows with a configurable fallback (warn / skip / throw)
27
+ - Use **after** KavachGate for defense in depth: policy gate + kernel enforcement
28
+ - `trust_mask` controls which syscall groups the process may call
29
+ - `domain` selects the egress allowlist (maritime, logistics, OT, finance, general)
30
+
31
+ ---
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ # In your n8n data directory
37
+ npm install @ankr/n8n-nodes-kavachos
38
+ ```
39
+
40
+ Then restart n8n and add the **Aegis API** credential pointing to your Aegis dashboard (`http://localhost:4850` by default).
41
+
42
+ ---
43
+
44
+ ## Quick Start
45
+
46
+ 1. **Start Aegis**: `npx @rocketlang/aegis` (or `kavachos run n8n --domain=general`)
47
+ 2. **Add credential**: Aegis API → base URL `http://localhost:4850`
48
+ 3. **Import template**: `examples/n8n-governed-agent.json`
49
+ 4. **Run**: Trigger → KavachGate → AI Agent → Audit
50
+
51
+ ---
52
+
53
+ ## Gate API
54
+
55
+ The `KavachGate` node calls:
56
+
57
+ ```
58
+ POST http://localhost:4850/api/v1/kavach/gate
59
+ { "command": "...", "tool_name": "n8n-agent", "session_id": "...", "dry_run": false }
60
+
61
+ → { "allow": true|false, "level": 0-4, "reason": "...", "decision": "ALLOW|STOP|TIMEOUT", "approval_id": "...", "_meta": {...} }
62
+ ```
63
+
64
+ `allow: false` → KavachGate throws (halt workflow) or passes `allow=false` downstream — configurable per node.
65
+
66
+ ---
67
+
68
+ ## License
69
+
70
+ AGPL-3.0 — governance layer is open. Enterprise Edition (multi-tenant, Merkle ledger, EU AI Act evidence): [xshieldai.com](https://xshieldai.com)
@@ -0,0 +1,7 @@
1
+ import type { ICredentialType, INodeProperties } from "n8n-workflow";
2
+ export declare class AegisApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AegisApi = void 0;
4
+ class AegisApi {
5
+ constructor() {
6
+ this.name = "aegisApi";
7
+ this.displayName = "Aegis API";
8
+ this.documentationUrl = "https://kavachos.xshieldai.com";
9
+ this.properties = [
10
+ {
11
+ displayName: "Aegis Base URL",
12
+ name: "baseUrl",
13
+ type: "string",
14
+ default: "http://localhost:4850",
15
+ placeholder: "http://localhost:4850",
16
+ description: "URL of the Aegis dashboard server (runs POST /api/v1/kavach/gate)",
17
+ },
18
+ {
19
+ displayName: "API Token (optional)",
20
+ name: "token",
21
+ type: "string",
22
+ typeOptions: { password: true },
23
+ default: "",
24
+ description: "Bearer token if Aegis dashboard auth is enabled",
25
+ },
26
+ ];
27
+ }
28
+ }
29
+ exports.AegisApi = AegisApi;
@@ -0,0 +1,5 @@
1
+ export { KavachGate } from "./nodes/KavachGate/KavachGate.node";
2
+ export { KavachRun } from "./nodes/KavachRun/KavachRun.node";
3
+ export { KavachBudget } from "./nodes/KavachBudget/KavachBudget.node";
4
+ export { KavachAudit } from "./nodes/KavachAudit/KavachAudit.node";
5
+ export { AegisApi } from "./credentials/AegisApi.credentials";
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AegisApi = exports.KavachAudit = exports.KavachBudget = exports.KavachRun = exports.KavachGate = void 0;
4
+ // SPDX-License-Identifier: AGPL-3.0-only
5
+ var KavachGate_node_1 = require("./nodes/KavachGate/KavachGate.node");
6
+ Object.defineProperty(exports, "KavachGate", { enumerable: true, get: function () { return KavachGate_node_1.KavachGate; } });
7
+ var KavachRun_node_1 = require("./nodes/KavachRun/KavachRun.node");
8
+ Object.defineProperty(exports, "KavachRun", { enumerable: true, get: function () { return KavachRun_node_1.KavachRun; } });
9
+ var KavachBudget_node_1 = require("./nodes/KavachBudget/KavachBudget.node");
10
+ Object.defineProperty(exports, "KavachBudget", { enumerable: true, get: function () { return KavachBudget_node_1.KavachBudget; } });
11
+ var KavachAudit_node_1 = require("./nodes/KavachAudit/KavachAudit.node");
12
+ Object.defineProperty(exports, "KavachAudit", { enumerable: true, get: function () { return KavachAudit_node_1.KavachAudit; } });
13
+ var AegisApi_credentials_1 = require("./credentials/AegisApi.credentials");
14
+ Object.defineProperty(exports, "AegisApi", { enumerable: true, get: function () { return AegisApi_credentials_1.AegisApi; } });
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class KavachAudit implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KavachAudit = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class KavachAudit {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: "Kavach Audit",
9
+ name: "kavachAudit",
10
+ icon: "file:kavach-audit.svg",
11
+ group: ["transform"],
12
+ version: 1,
13
+ subtitle: "Query DAN gate audit log",
14
+ description: "Queries the AEGIS audit log (kavach_approvals table). Returns gate decisions filtered by " +
15
+ "session ID, status, DAN level, or date range. Use for compliance reporting or post-incident review.",
16
+ defaults: { name: "Kavach Audit" },
17
+ inputs: ["main"],
18
+ outputs: ["main"],
19
+ credentials: [
20
+ {
21
+ name: "aegisApi",
22
+ required: true,
23
+ },
24
+ ],
25
+ properties: [
26
+ {
27
+ displayName: "Filter by Session ID",
28
+ name: "sessionId",
29
+ type: "string",
30
+ default: "",
31
+ placeholder: "exec_abc123",
32
+ description: "Return only records for this session. Leave empty for all sessions.",
33
+ },
34
+ {
35
+ displayName: "Filter by Status",
36
+ name: "status",
37
+ type: "options",
38
+ options: [
39
+ { name: "All", value: "all" },
40
+ { name: "Pending", value: "pending" },
41
+ { name: "Allowed", value: "allow" },
42
+ { name: "Stopped", value: "stop" },
43
+ { name: "Timed Out", value: "timeout" },
44
+ ],
45
+ default: "all",
46
+ description: "Return only records matching this approval status.",
47
+ },
48
+ {
49
+ displayName: "Filter by DAN Level",
50
+ name: "danLevel",
51
+ type: "options",
52
+ options: [
53
+ { name: "All levels", value: 0 },
54
+ { name: "DAN-1 (safe)", value: 1 },
55
+ { name: "DAN-2 (elevated)", value: 2 },
56
+ { name: "DAN-3 (dangerous)", value: 3 },
57
+ { name: "DAN-4 (catastrophic)", value: 4 },
58
+ ],
59
+ default: 0,
60
+ description: "Return only records at this DAN level. 0 = all levels.",
61
+ },
62
+ {
63
+ displayName: "Limit",
64
+ name: "limit",
65
+ type: "number",
66
+ default: 50,
67
+ description: "Maximum number of records to return.",
68
+ },
69
+ ],
70
+ };
71
+ }
72
+ async execute() {
73
+ const items = this.getInputData();
74
+ const results = [];
75
+ const credentials = await this.getCredentials("aegisApi");
76
+ const baseUrl = credentials.baseUrl.replace(/\/$/, "");
77
+ const token = credentials.token;
78
+ for (let i = 0; i < items.length; i++) {
79
+ const sessionId = this.getNodeParameter("sessionId", i).trim();
80
+ const status = this.getNodeParameter("status", i);
81
+ const danLevel = this.getNodeParameter("danLevel", i);
82
+ const limit = this.getNodeParameter("limit", i);
83
+ const params = new URLSearchParams();
84
+ if (sessionId)
85
+ params.set("session_id", sessionId);
86
+ if (status !== "all")
87
+ params.set("status", status);
88
+ if (danLevel > 0)
89
+ params.set("level", danLevel.toString());
90
+ params.set("limit", limit.toString());
91
+ const headers = {};
92
+ if (token)
93
+ headers["Authorization"] = `Bearer ${token}`;
94
+ let auditResult;
95
+ try {
96
+ const url = `${baseUrl}/api/v1/kavach/audit?${params.toString()}`;
97
+ const res = await fetch(url, { headers });
98
+ if (!res.ok) {
99
+ const text = await res.text().catch(() => res.status.toString());
100
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Aegis audit returned HTTP ${res.status}: ${text}`, { itemIndex: i });
101
+ }
102
+ auditResult = (await res.json());
103
+ }
104
+ catch (err) {
105
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot reach Aegis audit at ${baseUrl}: ${err.message}`, { itemIndex: i });
106
+ }
107
+ results.push({
108
+ json: {
109
+ ...items[i].json,
110
+ kavach_audit: {
111
+ records: auditResult.records,
112
+ total: auditResult.total,
113
+ _meta: auditResult._meta,
114
+ },
115
+ },
116
+ pairedItem: i,
117
+ });
118
+ }
119
+ return [results];
120
+ }
121
+ }
122
+ exports.KavachAudit = KavachAudit;
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class KavachBudget implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KavachBudget = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class KavachBudget {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: "Kavach Budget",
9
+ name: "kavachBudget",
10
+ icon: "file:kavach-budget.svg",
11
+ group: ["transform"],
12
+ version: 1,
13
+ subtitle: "Budget + valve state",
14
+ description: "Reads the current AEGIS budget state (daily spend, limit, remaining, breach flag) and " +
15
+ "gate-valve status. Use to guard expensive workflows or to surface cost data in dashboards.",
16
+ defaults: { name: "Kavach Budget" },
17
+ inputs: ["main"],
18
+ outputs: ["main", "main"],
19
+ outputNames: ["within budget", "breached"],
20
+ credentials: [
21
+ {
22
+ name: "aegisApi",
23
+ required: true,
24
+ },
25
+ ],
26
+ properties: [
27
+ {
28
+ displayName: "Halt on Breach",
29
+ name: "haltOnBreach",
30
+ type: "boolean",
31
+ default: false,
32
+ description: "When true and budget is breached, throw an error instead of routing to the 'breached' output.",
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ async execute() {
38
+ const items = this.getInputData();
39
+ const withinBudget = [];
40
+ const breachedItems = [];
41
+ const credentials = await this.getCredentials("aegisApi");
42
+ const baseUrl = credentials.baseUrl.replace(/\/$/, "");
43
+ const token = credentials.token;
44
+ for (let i = 0; i < items.length; i++) {
45
+ const haltOnBreach = this.getNodeParameter("haltOnBreach", i);
46
+ const headers = {};
47
+ if (token)
48
+ headers["Authorization"] = `Bearer ${token}`;
49
+ let state;
50
+ try {
51
+ const res = await fetch(`${baseUrl}/api/v1/kavach/state`, { headers });
52
+ if (!res.ok) {
53
+ const text = await res.text().catch(() => res.status.toString());
54
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Aegis state returned HTTP ${res.status}: ${text}`, { itemIndex: i });
55
+ }
56
+ state = (await res.json());
57
+ }
58
+ catch (err) {
59
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot reach Aegis state at ${baseUrl}: ${err.message}`, { itemIndex: i });
60
+ }
61
+ const output = {
62
+ json: {
63
+ ...items[i].json,
64
+ kavach_budget: {
65
+ daily_spent_usd: state.budget.daily_spent_usd,
66
+ daily_limit_usd: state.budget.daily_limit_usd,
67
+ daily_remaining_usd: state.budget.daily_remaining_usd,
68
+ breached: state.budget.breached,
69
+ kavach_enabled: state.kavach_enabled,
70
+ _meta: state._meta,
71
+ },
72
+ },
73
+ pairedItem: i,
74
+ };
75
+ if (state.budget.breached) {
76
+ if (haltOnBreach) {
77
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `KAVACH budget breached: $${state.budget.daily_spent_usd.toFixed(4)} of $${state.budget.daily_limit_usd} daily limit used`, { itemIndex: i });
78
+ }
79
+ breachedItems.push(output);
80
+ }
81
+ else {
82
+ withinBudget.push(output);
83
+ }
84
+ }
85
+ return [withinBudget, breachedItems];
86
+ }
87
+ }
88
+ exports.KavachBudget = KavachBudget;
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class KavachGate implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KavachGate = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class KavachGate {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: "Kavach Gate",
9
+ name: "kavachGate",
10
+ icon: "file:kavach-gate.svg",
11
+ group: ["transform"],
12
+ version: 1,
13
+ subtitle: "Pre-execution DAN gate",
14
+ description: "Intercepts AI agent actions before execution. Calls the Aegis KAVACH gate to classify danger level (DAN 1-4), notify approvers, and wait for ALLOW/STOP. Blocks the workflow on STOP or timeout.",
15
+ defaults: { name: "Kavach Gate" },
16
+ inputs: ["main"],
17
+ outputs: ["main"],
18
+ credentials: [
19
+ {
20
+ name: "aegisApi",
21
+ required: true,
22
+ },
23
+ ],
24
+ properties: [
25
+ {
26
+ displayName: "Command",
27
+ name: "command",
28
+ type: "string",
29
+ default: "={{ $json.command }}",
30
+ required: true,
31
+ description: "The command or action the agent wants to execute. Accepts an expression referencing upstream node output.",
32
+ placeholder: "prisma migrate reset",
33
+ },
34
+ {
35
+ displayName: "Tool Name",
36
+ name: "toolName",
37
+ type: "string",
38
+ default: "n8n-agent",
39
+ description: "Name of the tool/node calling this gate. Appears in audit records.",
40
+ },
41
+ {
42
+ displayName: "Session ID",
43
+ name: "sessionId",
44
+ type: "string",
45
+ default: "={{ $execution.id }}",
46
+ description: "Workflow execution ID used for audit trail grouping.",
47
+ },
48
+ {
49
+ displayName: "Dry Run",
50
+ name: "dryRun",
51
+ type: "boolean",
52
+ default: false,
53
+ description: "Classify danger level only — no notification sent, no polling. Use for testing the gate without blocking.",
54
+ },
55
+ {
56
+ displayName: "On STOP / Timeout",
57
+ name: "onBlock",
58
+ type: "options",
59
+ options: [
60
+ { name: "Throw Error (halt workflow)", value: "throw" },
61
+ { name: "Continue with allow=false", value: "continue" },
62
+ ],
63
+ default: "throw",
64
+ description: "What to do when the gate blocks the action. Default: throw error to halt the workflow.",
65
+ },
66
+ ],
67
+ };
68
+ }
69
+ async execute() {
70
+ const items = this.getInputData();
71
+ const results = [];
72
+ const credentials = await this.getCredentials("aegisApi");
73
+ const baseUrl = credentials.baseUrl.replace(/\/$/, "");
74
+ const token = credentials.token;
75
+ for (let i = 0; i < items.length; i++) {
76
+ const command = this.getNodeParameter("command", i);
77
+ const toolName = this.getNodeParameter("toolName", i);
78
+ const sessionId = this.getNodeParameter("sessionId", i);
79
+ const dryRun = this.getNodeParameter("dryRun", i);
80
+ const onBlock = this.getNodeParameter("onBlock", i);
81
+ if (!command?.trim()) {
82
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "command must not be empty", { itemIndex: i });
83
+ }
84
+ const headers = { "Content-Type": "application/json" };
85
+ if (token)
86
+ headers["Authorization"] = `Bearer ${token}`;
87
+ let gateResult;
88
+ try {
89
+ const res = await fetch(`${baseUrl}/api/v1/kavach/gate`, {
90
+ method: "POST",
91
+ headers,
92
+ body: JSON.stringify({ command, tool_name: toolName, session_id: sessionId, dry_run: dryRun }),
93
+ });
94
+ if (!res.ok && res.status !== 200) {
95
+ const text = await res.text().catch(() => res.status.toString());
96
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Aegis gate returned HTTP ${res.status}: ${text}`, { itemIndex: i });
97
+ }
98
+ gateResult = (await res.json());
99
+ }
100
+ catch (err) {
101
+ // Network error — aegis unreachable
102
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot reach Aegis gate at ${baseUrl}: ${err.message}`, { itemIndex: i });
103
+ }
104
+ if (!gateResult.allow) {
105
+ if (onBlock === "throw") {
106
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `KAVACH blocked action (DAN ${gateResult.level ?? "?"}): ${gateResult.reason}`, { itemIndex: i });
107
+ }
108
+ // continue mode — pass allow=false downstream
109
+ }
110
+ results.push({
111
+ json: {
112
+ ...items[i].json,
113
+ kavach: {
114
+ allow: gateResult.allow,
115
+ level: gateResult.level,
116
+ reason: gateResult.reason,
117
+ decision: gateResult.decision,
118
+ approval_id: gateResult.approval_id,
119
+ _meta: gateResult._meta,
120
+ },
121
+ },
122
+ pairedItem: i,
123
+ });
124
+ }
125
+ return [results];
126
+ }
127
+ }
128
+ exports.KavachGate = KavachGate;
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class KavachRun implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KavachRun = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const child_process_1 = require("child_process");
6
+ function isLinux() {
7
+ return process.platform === "linux";
8
+ }
9
+ function kavachosAvailable() {
10
+ try {
11
+ (0, child_process_1.execSync)("which kavachos", { stdio: "pipe" });
12
+ return true;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ class KavachRun {
19
+ constructor() {
20
+ this.description = {
21
+ displayName: "Kavach Run",
22
+ name: "kavachRun",
23
+ icon: "file:kavach-run.svg",
24
+ group: ["transform"],
25
+ version: 1,
26
+ subtitle: "Kernel-enforced subprocess (Linux)",
27
+ description: "Wraps a subprocess in kavachos kernel enforcement (seccomp-bpf + cgroup BPF egress). " +
28
+ "Linux only — gracefully degrades on macOS/Windows with a warning. " +
29
+ "Use after KavachGate for defense in depth: policy gate + kernel enforcement.",
30
+ defaults: { name: "Kavach Run" },
31
+ inputs: ["main"],
32
+ outputs: ["main"],
33
+ properties: [
34
+ {
35
+ displayName: "Binary",
36
+ name: "binary",
37
+ type: "string",
38
+ default: "",
39
+ required: true,
40
+ placeholder: "bun",
41
+ description: "The binary to execute under kernel enforcement.",
42
+ },
43
+ {
44
+ displayName: "Arguments",
45
+ name: "args",
46
+ type: "string",
47
+ default: "",
48
+ placeholder: "src/my-agent.ts --port 4900",
49
+ description: "Space-separated arguments to pass to the binary.",
50
+ },
51
+ {
52
+ displayName: "Trust Mask (hex)",
53
+ name: "trustMask",
54
+ type: "string",
55
+ default: "0xFF",
56
+ description: "Seccomp-bpf trust mask. Controls which syscall groups the process is allowed to call. " +
57
+ "0xFF = infrastructure bits. See KavachOS trust_mask docs.",
58
+ },
59
+ {
60
+ displayName: "Domain",
61
+ name: "domain",
62
+ type: "options",
63
+ options: [
64
+ { name: "general", value: "general" },
65
+ { name: "maritime", value: "maritime" },
66
+ { name: "logistics", value: "logistics" },
67
+ { name: "ot", value: "ot" },
68
+ { name: "finance", value: "finance" },
69
+ ],
70
+ default: "general",
71
+ description: "Domain profile — controls egress allowlist and Falco rule set.",
72
+ },
73
+ {
74
+ displayName: "Enable Falco",
75
+ name: "falco",
76
+ type: "boolean",
77
+ default: false,
78
+ description: "Enable Falco CRITICAL rule monitoring (requires Falco installed on host).",
79
+ },
80
+ {
81
+ displayName: "On Non-Linux",
82
+ name: "onNonLinux",
83
+ type: "options",
84
+ options: [
85
+ { name: "Warn and run unwrapped", value: "warn" },
86
+ { name: "Skip execution entirely", value: "skip" },
87
+ { name: "Throw error", value: "throw" },
88
+ ],
89
+ default: "warn",
90
+ description: "Behavior when running on macOS or Windows where kernel enforcement is unavailable.",
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ async execute() {
96
+ const items = this.getInputData();
97
+ const results = [];
98
+ for (let i = 0; i < items.length; i++) {
99
+ const binary = this.getNodeParameter("binary", i);
100
+ const args = this.getNodeParameter("args", i).trim();
101
+ const trustMask = this.getNodeParameter("trustMask", i);
102
+ const domain = this.getNodeParameter("domain", i);
103
+ const falco = this.getNodeParameter("falco", i);
104
+ const onNonLinux = this.getNodeParameter("onNonLinux", i);
105
+ if (!binary?.trim()) {
106
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "binary must not be empty", { itemIndex: i });
107
+ }
108
+ const linux = isLinux();
109
+ const hasKavachos = linux && kavachosAvailable();
110
+ if (!linux || !hasKavachos) {
111
+ const platform = process.platform;
112
+ const reason = !linux
113
+ ? `KavachRun kernel enforcement not available on ${platform} — requires Linux with seccomp-bpf`
114
+ : "kavachos CLI not found — install with: npm install -g @rocketlang/kavachos";
115
+ if (onNonLinux === "throw") {
116
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), reason, { itemIndex: i });
117
+ }
118
+ if (onNonLinux === "skip") {
119
+ results.push({
120
+ json: { ...items[i].json, kavach_run: { skipped: true, reason } },
121
+ pairedItem: i,
122
+ });
123
+ continue;
124
+ }
125
+ // warn: run unwrapped with a flag in output
126
+ process.stderr.write(`[KavachRun] WARNING: ${reason} — running ${binary} unwrapped\n`);
127
+ const argList = args ? args.split(/\s+/) : [];
128
+ const proc = (0, child_process_1.spawnSync)(binary, argList, { encoding: "utf8" });
129
+ results.push({
130
+ json: {
131
+ ...items[i].json,
132
+ kavach_run: {
133
+ enforced: false,
134
+ reason,
135
+ stdout: proc.stdout,
136
+ stderr: proc.stderr,
137
+ exit_code: proc.status,
138
+ },
139
+ },
140
+ pairedItem: i,
141
+ });
142
+ continue;
143
+ }
144
+ // Linux + kavachos available — build command
145
+ const kavachArgs = [
146
+ "run",
147
+ `--trust-mask=${trustMask}`,
148
+ `--domain=${domain}`,
149
+ ...(falco ? ["--falco"] : []),
150
+ binary,
151
+ ...(args ? args.split(/\s+/) : []),
152
+ ];
153
+ const proc = (0, child_process_1.spawnSync)("kavachos", kavachArgs, { encoding: "utf8" });
154
+ if (proc.error) {
155
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `kavachos run failed: ${proc.error.message}`, { itemIndex: i });
156
+ }
157
+ results.push({
158
+ json: {
159
+ ...items[i].json,
160
+ kavach_run: {
161
+ enforced: true,
162
+ trust_mask: trustMask,
163
+ domain,
164
+ falco_enabled: falco,
165
+ stdout: proc.stdout,
166
+ stderr: proc.stderr,
167
+ exit_code: proc.status,
168
+ },
169
+ },
170
+ pairedItem: i,
171
+ });
172
+ }
173
+ return [results];
174
+ }
175
+ }
176
+ exports.KavachRun = KavachRun;
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@xshieldai/n8n-nodes",
3
+ "version": "1.1.0",
4
+ "description": "xShieldAI n8n community nodes — DAN gate, kernel enforcement, budget check, and audit log for AI agents.",
5
+ "license": "AGPL-3.0",
6
+ "author": "Capt. Anil Sharma <capt.anil.sharma@powerpbox.org>",
7
+ "homepage": "https://kavachos.xshieldai.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/rocketlang/aegis.git",
11
+ "directory": "packages/n8n-nodes-kavachos"
12
+ },
13
+ "keywords": [
14
+ "n8n-community-node-package",
15
+ "kavachos",
16
+ "xshieldai",
17
+ "ai-governance",
18
+ "seccomp",
19
+ "agent-safety"
20
+ ],
21
+ "main": "dist/index.js",
22
+ "types": "dist/index.d.ts",
23
+ "files": [
24
+ "dist/",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "n8n": {
29
+ "n8nNodesApiVersion": 1,
30
+ "credentials": [
31
+ "dist/credentials/AegisApi.credentials.js"
32
+ ],
33
+ "nodes": [
34
+ "dist/nodes/KavachGate/KavachGate.node.js",
35
+ "dist/nodes/KavachRun/KavachRun.node.js",
36
+ "dist/nodes/KavachBudget/KavachBudget.node.js",
37
+ "dist/nodes/KavachAudit/KavachAudit.node.js"
38
+ ]
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "dev": "tsc --watch",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "devDependencies": {
46
+ "typescript": "^5.0.0",
47
+ "n8n-workflow": "^1.0.0",
48
+ "@types/node": "^20.0.0"
49
+ },
50
+ "peerDependencies": {
51
+ "n8n-workflow": ">=1.0.0"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ }
59
+ }