@kaia-team/n8n-nodes-kaia
Version:
n8n node to interact with Kaia API for signal capture and security gating
178 lines (177 loc) • 7.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecurityGate = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class SecurityGate {
constructor() {
this.description = {
displayName: 'KAIA Security Gate',
name: 'securityGate',
icon: 'file:kaia.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["entityId"]}}',
description: 'Check entity context and block workflow if conditions are not met',
defaults: {
name: 'KAIA Security Gate',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'kaiaApi',
required: true,
},
],
properties: [
{
displayName: 'Entity ID',
name: 'entityId',
type: 'string',
default: '',
required: true,
description: 'Entity identifier to check in the knowledge graph',
placeholder: 'user-123',
},
{
displayName: 'Condition',
name: 'condition',
type: 'collection',
placeholder: 'Add Condition',
default: {},
description: 'Optional condition to evaluate. If not provided, gate will check if entity exists.',
options: [
{
displayName: 'Relation',
name: 'relation',
type: 'string',
default: '',
required: true,
description: 'Relation name to check (e.g., "status", "role", "permission")',
placeholder: 'status',
},
{
displayName: 'Operator',
name: 'operator',
type: 'options',
options: [
{
name: 'Equals',
value: '==',
description: 'Check if relation equals value (proceed if true, block if false)',
},
{
name: 'Not Equals',
value: '!=',
description: 'Check if relation does not equal value (block if true, proceed if false)',
},
{
name: 'Exists',
value: 'exists',
description: 'Check if relation exists (proceed if exists, block if not)',
},
{
name: 'Not Exists',
value: 'not_exists',
description: 'Check if relation does not exist (block if exists, proceed if not)',
},
],
default: 'exists',
required: true,
description: 'Comparison operator',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
required: false,
description: 'Value to compare against (required for == and != operators)',
displayOptions: {
show: {
operator: ['==', '!='],
},
},
},
],
},
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
// Get credentials
const credentials = await this.getCredentials('kaiaApi');
const baseUrl = credentials?.baseUrl || '';
const token = credentials?.token || '';
if (!baseUrl || !token) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Kaia API credentials are required');
}
// Get parameters
const entityId = this.getNodeParameter('entityId', i);
const condition = this.getNodeParameter('condition', i);
if (!entityId) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Entity ID is required');
}
// Build request body
const body = {
entity_id: entityId,
};
// Add condition if provided
if (condition.relation && condition.operator) {
const conditionObj = {
relation: condition.relation,
operator: condition.operator,
};
// Add value for == and != operators
if ((condition.operator === '==' || condition.operator === '!=') && condition.value) {
conditionObj.value = condition.value;
}
body.condition = conditionObj;
}
// Make API request
const requestUrl = `${baseUrl}/api/kaia/context/gate`;
const options = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
method: 'POST',
body,
url: requestUrl,
json: true,
};
const response = await this.helpers.httpRequest(options);
// Check decision
if (response.decision === 'block') {
const reason = response.reason || 'Entity context check failed';
const confidence = response.confidence || 0;
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Security Gate blocked: ${reason} (confidence: ${confidence})`, {
description: 'The workflow execution was blocked by the Security Gate node based on entity context evaluation.',
itemIndex: i,
});
}
// Decision is "proceed" - continue with output
returnData.push(response);
}
catch (error) {
// If it's a NodeOperationError (block decision), re-throw it
if (error instanceof n8n_workflow_1.NodeOperationError) {
throw error;
}
// For other errors, handle based on continueOnFail setting
if (this.continueOnFail()) {
const errorMessage = error instanceof Error ? error.message : String(error);
returnData.push({ error: errorMessage });
continue;
}
throw error;
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}
exports.SecurityGate = SecurityGate;