Add missing resources to CLI, MCP, and n8n surfaces

Audit all three API surfaces against the console GraphQL schema and add
missing resources: asset, audit, datum, dpia, evidence upload, measure,
obligation, processing activity, rights request, snapshot, task, tia,
trust center (with references/files), and vendor management CLI
commands; MCP tools for deletes, rights requests, trust center, vendor
contacts/services, and compliance external URLs; n8n nodes for
obligation, finding, task, evidence, processing activity, dpia, tia,
rights request, snapshot, audit log, access review, organization
context, trust center, and additional control/measure/vendor operations.

Include MCP e2e test infrastructure (testutil MCP client with API key
auth and JSON-RPC session management) and tests covering all new MCP
tools.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-04-21 16:08:37 +02:00
parent f505e23cb0
commit 7be92defcc
220 changed files with 26395 additions and 7 deletions

View File

@@ -18,6 +18,16 @@ import * as updateOp from './update.operation';
import * as deleteOp from './delete.operation';
import * as getOp from './get.operation';
import * as getAllOp from './getAll.operation';
import * as linkMeasureOp from './linkMeasure.operation';
import * as unlinkMeasureOp from './unlinkMeasure.operation';
import * as linkDocumentOp from './linkDocument.operation';
import * as unlinkDocumentOp from './unlinkDocument.operation';
import * as linkAuditOp from './linkAudit.operation';
import * as unlinkAuditOp from './unlinkAudit.operation';
import * as linkObligationOp from './linkObligation.operation';
import * as unlinkObligationOp from './unlinkObligation.operation';
import * as linkSnapshotOp from './linkSnapshot.operation';
import * as unlinkSnapshotOp from './unlinkSnapshot.operation';
export const description: INodeProperties[] = [
{
@@ -55,6 +65,66 @@ export const description: INodeProperties[] = [
description: 'Get many controls',
action: 'Get many controls',
},
{
name: 'Link Audit',
value: 'linkAudit',
description: 'Link an audit to a control',
action: 'Link an audit to a control',
},
{
name: 'Link Document',
value: 'linkDocument',
description: 'Link a document to a control',
action: 'Link a document to a control',
},
{
name: 'Link Measure',
value: 'linkMeasure',
description: 'Link a measure to a control',
action: 'Link a measure to a control',
},
{
name: 'Link Obligation',
value: 'linkObligation',
description: 'Link an obligation to a control',
action: 'Link an obligation to a control',
},
{
name: 'Link Snapshot',
value: 'linkSnapshot',
description: 'Link a snapshot to a control',
action: 'Link a snapshot to a control',
},
{
name: 'Unlink Audit',
value: 'unlinkAudit',
description: 'Unlink an audit from a control',
action: 'Unlink an audit from a control',
},
{
name: 'Unlink Document',
value: 'unlinkDocument',
description: 'Unlink a document from a control',
action: 'Unlink a document from a control',
},
{
name: 'Unlink Measure',
value: 'unlinkMeasure',
description: 'Unlink a measure from a control',
action: 'Unlink a measure from a control',
},
{
name: 'Unlink Obligation',
value: 'unlinkObligation',
description: 'Unlink an obligation from a control',
action: 'Unlink an obligation from a control',
},
{
name: 'Unlink Snapshot',
value: 'unlinkSnapshot',
description: 'Unlink a snapshot from a control',
action: 'Unlink a snapshot from a control',
},
{
name: 'Update',
value: 'update',
@@ -69,6 +139,32 @@ export const description: INodeProperties[] = [
...deleteOp.description,
...getOp.description,
...getAllOp.description,
...linkMeasureOp.description,
...unlinkMeasureOp.description,
...linkDocumentOp.description,
...unlinkDocumentOp.description,
...linkAuditOp.description,
...unlinkAuditOp.description,
...linkObligationOp.description,
...unlinkObligationOp.description,
...linkSnapshotOp.description,
...unlinkSnapshotOp.description,
];
export { createOp as create, updateOp as update, deleteOp as delete, getOp as get, getAllOp as getAll };
export {
createOp as create,
updateOp as update,
deleteOp as delete,
getOp as get,
getAllOp as getAll,
linkMeasureOp as linkMeasure,
unlinkMeasureOp as unlinkMeasure,
linkDocumentOp as linkDocument,
unlinkDocumentOp as unlinkDocument,
linkAuditOp as linkAudit,
unlinkAuditOp as unlinkAudit,
linkObligationOp as linkObligation,
unlinkObligationOp as unlinkObligation,
linkSnapshotOp as linkSnapshot,
unlinkSnapshotOp as unlinkSnapshot,
};

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkAudit'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Audit ID',
name: 'auditId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkAudit'],
},
},
default: '',
description: 'The ID of the audit to link',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const auditId = this.getNodeParameter('auditId', itemIndex) as string;
const query = `
mutation CreateControlAuditMapping($input: CreateControlAuditMappingInput!) {
createControlAuditMapping(input: $input) {
controlEdge {
node {
id
name
}
}
auditEdge {
node {
id
name
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, auditId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkDocument'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Document ID',
name: 'documentId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkDocument'],
},
},
default: '',
description: 'The ID of the document to link',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const documentId = this.getNodeParameter('documentId', itemIndex) as string;
const query = `
mutation CreateControlDocumentMapping($input: CreateControlDocumentMappingInput!) {
createControlDocumentMapping(input: $input) {
controlEdge {
node {
id
name
}
}
documentEdge {
node {
id
title
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, documentId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkMeasure'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Measure ID',
name: 'measureId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkMeasure'],
},
},
default: '',
description: 'The ID of the measure to link',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const measureId = this.getNodeParameter('measureId', itemIndex) as string;
const query = `
mutation CreateControlMeasureMapping($input: CreateControlMeasureMappingInput!) {
createControlMeasureMapping(input: $input) {
controlEdge {
node {
id
name
}
}
measureEdge {
node {
id
name
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, measureId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkObligation'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Obligation ID',
name: 'obligationId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkObligation'],
},
},
default: '',
description: 'The ID of the obligation to link',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const obligationId = this.getNodeParameter('obligationId', itemIndex) as string;
const query = `
mutation CreateControlObligationMapping($input: CreateControlObligationMappingInput!) {
createControlObligationMapping(input: $input) {
controlEdge {
node {
id
name
}
}
obligationEdge {
node {
id
name
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, obligationId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkSnapshot'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Snapshot ID',
name: 'snapshotId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['linkSnapshot'],
},
},
default: '',
description: 'The ID of the snapshot to link',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const snapshotId = this.getNodeParameter('snapshotId', itemIndex) as string;
const query = `
mutation CreateControlSnapshotMapping($input: CreateControlSnapshotMappingInput!) {
createControlSnapshotMapping(input: $input) {
controlEdge {
node {
id
name
}
}
snapshotEdge {
node {
id
name
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, snapshotId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkAudit'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Audit ID',
name: 'auditId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkAudit'],
},
},
default: '',
description: 'The ID of the audit to unlink',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const auditId = this.getNodeParameter('auditId', itemIndex) as string;
const query = `
mutation DeleteControlAuditMapping($input: DeleteControlAuditMappingInput!) {
deleteControlAuditMapping(input: $input) {
deletedControlId
deletedAuditId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, auditId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkDocument'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Document ID',
name: 'documentId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkDocument'],
},
},
default: '',
description: 'The ID of the document to unlink',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const documentId = this.getNodeParameter('documentId', itemIndex) as string;
const query = `
mutation DeleteControlDocumentMapping($input: DeleteControlDocumentMappingInput!) {
deleteControlDocumentMapping(input: $input) {
deletedControlId
deletedDocumentId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, documentId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkMeasure'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Measure ID',
name: 'measureId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkMeasure'],
},
},
default: '',
description: 'The ID of the measure to unlink',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const measureId = this.getNodeParameter('measureId', itemIndex) as string;
const query = `
mutation DeleteControlMeasureMapping($input: DeleteControlMeasureMappingInput!) {
deleteControlMeasureMapping(input: $input) {
deletedControlId
deletedMeasureId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, measureId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkObligation'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Obligation ID',
name: 'obligationId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkObligation'],
},
},
default: '',
description: 'The ID of the obligation to unlink',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const obligationId = this.getNodeParameter('obligationId', itemIndex) as string;
const query = `
mutation DeleteControlObligationMapping($input: DeleteControlObligationMappingInput!) {
deleteControlObligationMapping(input: $input) {
deletedControlId
deletedObligationId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, obligationId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Control ID',
name: 'controlId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkSnapshot'],
},
},
default: '',
description: 'The ID of the control',
required: true,
},
{
displayName: 'Snapshot ID',
name: 'snapshotId',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['unlinkSnapshot'],
},
},
default: '',
description: 'The ID of the snapshot to unlink',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const controlId = this.getNodeParameter('controlId', itemIndex) as string;
const snapshotId = this.getNodeParameter('snapshotId', itemIndex) as string;
const query = `
mutation DeleteControlSnapshotMapping($input: DeleteControlSnapshotMappingInput!) {
deleteControlSnapshotMapping(input: $input) {
deletedControlId
deletedSnapshotId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { controlId, snapshotId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}