Remove deprecated SOA code

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-02-17 13:55:56 +01:00
parent e9263fb42f
commit 40e4db9278
50 changed files with 285 additions and 2669 deletions

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<35c2c66dca0c895c7abca2b0f4917a68>> * @generated SignedSource<<10bdb7f9b009009a66d93605d3d671c4>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,15 +10,12 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type ControlStatus = "EXCLUDED" | "INCLUDED";
export type CreateControlInput = { export type CreateControlInput = {
bestPractice: boolean; bestPractice: boolean;
description?: string | null | undefined; description?: string | null | undefined;
exclusionJustification?: string | null | undefined;
frameworkId: string; frameworkId: string;
name: string; name: string;
sectionTitle: string; sectionTitle: string;
status: ControlStatus;
}; };
export type FrameworkControlDialogCreateMutation$variables = { export type FrameworkControlDialogCreateMutation$variables = {
connections: ReadonlyArray<string>; connections: ReadonlyArray<string>;
@@ -169,20 +166,6 @@ return {
"name": "sectionTitle", "name": "sectionTitle",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -218,12 +201,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "81df1f9c65937d3e387edffc6e9a28ac", "cacheID": "51536092f1e2e37d1499182357306138",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "FrameworkControlDialogCreateMutation", "name": "FrameworkControlDialogCreateMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation FrameworkControlDialogCreateMutation(\n $input: CreateControlInput!\n) {\n createControl(input: $input) {\n controlEdge {\n node {\n ...FrameworkControlDialogFragment\n id\n }\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n bestPractice\n}\n" "text": "mutation FrameworkControlDialogCreateMutation(\n $input: CreateControlInput!\n) {\n createControl(input: $input) {\n controlEdge {\n node {\n ...FrameworkControlDialogFragment\n id\n }\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n bestPractice\n}\n"
} }
}; };
})(); })();

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<3a62e5f931a990d83caca02ab629b0c0>> * @generated SignedSource<<43181b3f35ce7df5f54b19bf82eeaad0>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -9,16 +9,13 @@
// @ts-nocheck // @ts-nocheck
import { ReaderFragment } from 'relay-runtime'; import { ReaderFragment } from 'relay-runtime';
export type ControlStatus = "EXCLUDED" | "INCLUDED";
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type FrameworkControlDialogFragment$data = { export type FrameworkControlDialogFragment$data = {
readonly bestPractice: boolean; readonly bestPractice: boolean;
readonly description: string | null | undefined; readonly description: string | null | undefined;
readonly exclusionJustification: string | null | undefined;
readonly id: string; readonly id: string;
readonly name: string; readonly name: string;
readonly sectionTitle: string; readonly sectionTitle: string;
readonly status: ControlStatus;
readonly " $fragmentType": "FrameworkControlDialogFragment"; readonly " $fragmentType": "FrameworkControlDialogFragment";
}; };
export type FrameworkControlDialogFragment$key = { export type FrameworkControlDialogFragment$key = {
@@ -60,20 +57,6 @@ const node: ReaderFragment = {
"name": "sectionTitle", "name": "sectionTitle",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -86,6 +69,6 @@ const node: ReaderFragment = {
"abstractKey": null "abstractKey": null
}; };
(node as any).hash = "481f75ce8c525c1fa12517ef173ad868"; (node as any).hash = "3ca9ebd60cc24f1080a594bf4ca0b928";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<7ee3c72e16fa86d6c006c004e4f93c95>> * @generated SignedSource<<791e18651a3911865d78b730f268f489>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,15 +10,12 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type ControlStatus = "EXCLUDED" | "INCLUDED";
export type UpdateControlInput = { export type UpdateControlInput = {
bestPractice?: boolean | null | undefined; bestPractice?: boolean | null | undefined;
description?: string | null | undefined; description?: string | null | undefined;
exclusionJustification?: string | null | undefined;
id: string; id: string;
name?: string | null | undefined; name?: string | null | undefined;
sectionTitle?: string | null | undefined; sectionTitle?: string | null | undefined;
status?: ControlStatus | null | undefined;
}; };
export type FrameworkControlDialogUpdateMutation$variables = { export type FrameworkControlDialogUpdateMutation$variables = {
input: UpdateControlInput; input: UpdateControlInput;
@@ -138,20 +135,6 @@ return {
"name": "sectionTitle", "name": "sectionTitle",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -168,12 +151,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "374c69b33dd6e94dec75829fe0777f58", "cacheID": "a44a5055f8167fa3754f4f389cee598f",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "FrameworkControlDialogUpdateMutation", "name": "FrameworkControlDialogUpdateMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation FrameworkControlDialogUpdateMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n ...FrameworkControlDialogFragment\n id\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n bestPractice\n}\n" "text": "mutation FrameworkControlDialogUpdateMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n ...FrameworkControlDialogFragment\n id\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n bestPractice\n}\n"
} }
}; };
})(); })();

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<3db987ede3a3aa1dfa570e76a00ef224>> * @generated SignedSource<<b78ad7244ad348d2622288743eff7a9b>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -9,24 +9,20 @@
// @ts-nocheck // @ts-nocheck
import { ReaderFragment } from 'relay-runtime'; import { ReaderFragment } from 'relay-runtime';
export type ControlStatus = "EXCLUDED" | "INCLUDED";
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type FrameworkDetailPageFragment$data = { export type FrameworkDetailPageFragment$data = {
readonly canCreateControl: boolean; readonly canCreateControl: boolean;
readonly canDelete: boolean; readonly canDelete: boolean;
readonly canExport: boolean; readonly canExport: boolean;
readonly canGenerateSOA: boolean;
readonly canUpdate: boolean; readonly canUpdate: boolean;
readonly controls: { readonly controls: {
readonly __id: string; readonly __id: string;
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
readonly bestPractice: boolean; readonly bestPractice: boolean;
readonly exclusionJustification: string | null | undefined;
readonly id: string; readonly id: string;
readonly name: string; readonly name: string;
readonly sectionTitle: string; readonly sectionTitle: string;
readonly status: ControlStatus;
}; };
}>; }>;
}; };
@@ -141,19 +137,6 @@ return {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create\")" "storageKey": "permission(action:\"core:control:create\")"
}, },
{
"alias": "canGenerateSOA",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:generate-state-of-applicability"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:generate-state-of-applicability\")"
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -213,20 +196,6 @@ return {
"storageKey": null "storageKey": null
}, },
(v1/*: any*/), (v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -261,6 +230,6 @@ return {
}; };
})(); })();
(node as any).hash = "a3eb8b9d80c69d7faa83eae88e3b986b"; (node as any).hash = "f6eba8f00d1e491f79bc201851b8c69d";
export default node; export default node;

View File

@@ -1,95 +0,0 @@
/**
* @generated SignedSource<<b7c54e98eb3ba12bf4619530b45fdbab>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation$variables = {
frameworkId: string;
};
export type FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation$data = {
readonly generateFrameworkStateOfApplicability: {
readonly data: string;
};
};
export type FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation = {
response: FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation$data;
variables: FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "frameworkId"
}
],
v1 = [
{
"alias": null,
"args": [
{
"fields": [
{
"kind": "Variable",
"name": "frameworkId",
"variableName": "frameworkId"
}
],
"kind": "ObjectValue",
"name": "input"
}
],
"concreteType": "GenerateFrameworkStateOfApplicabilityPayload",
"kind": "LinkedField",
"name": "generateFrameworkStateOfApplicability",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "data",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "80185d474f3a9c5d20f97a387b219511",
"id": null,
"metadata": {},
"name": "FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation",
"operationKind": "mutation",
"text": "mutation FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation(\n $frameworkId: ID!\n) {\n generateFrameworkStateOfApplicability(input: {frameworkId: $frameworkId}) {\n data\n }\n}\n"
}
};
})();
(node as any).hash = "eac70164d676cb8e19d7fe7f06b2b817";
export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<0c1816374b8fe7e0c0c79e9013aeb2b4>> * @generated SignedSource<<72da3c2c267ec4fd2da7aee87f38c51b>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,7 +10,6 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type ControlStatus = "EXCLUDED" | "INCLUDED";
export type FrameworkGraphControlNodeQuery$variables = { export type FrameworkGraphControlNodeQuery$variables = {
controlId: string; controlId: string;
}; };
@@ -47,7 +46,6 @@ export type FrameworkGraphControlNodeQuery$data = {
}; };
}>; }>;
}; };
readonly exclusionJustification?: string | null | undefined;
readonly id?: string; readonly id?: string;
readonly measures?: { readonly measures?: {
readonly __id: string; readonly __id: string;
@@ -78,7 +76,6 @@ export type FrameworkGraphControlNodeQuery$data = {
}; };
}>; }>;
}; };
readonly status?: ControlStatus;
readonly " $fragmentSpreads": FragmentRefs<"FrameworkControlDialogFragment">; readonly " $fragmentSpreads": FragmentRefs<"FrameworkControlDialogFragment">;
}; };
}; };
@@ -131,20 +128,6 @@ v5 = {
"storageKey": null "storageKey": null
}, },
v6 = { v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
v8 = {
"alias": "canUpdate", "alias": "canUpdate",
"args": [ "args": [
{ {
@@ -157,7 +140,7 @@ v8 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:update\")" "storageKey": "permission(action:\"core:control:update\")"
}, },
v9 = { v7 = {
"alias": "canDelete", "alias": "canDelete",
"args": [ "args": [
{ {
@@ -170,7 +153,7 @@ v9 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete\")" "storageKey": "permission(action:\"core:control:delete\")"
}, },
v10 = { v8 = {
"alias": "canCreateMeasureMapping", "alias": "canCreateMeasureMapping",
"args": [ "args": [
{ {
@@ -183,7 +166,7 @@ v10 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create-measure-mapping\")" "storageKey": "permission(action:\"core:control:create-measure-mapping\")"
}, },
v11 = { v9 = {
"alias": "canDeleteMeasureMapping", "alias": "canDeleteMeasureMapping",
"args": [ "args": [
{ {
@@ -196,7 +179,7 @@ v11 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete-measure-mapping\")" "storageKey": "permission(action:\"core:control:delete-measure-mapping\")"
}, },
v12 = { v10 = {
"alias": "canCreateDocumentMapping", "alias": "canCreateDocumentMapping",
"args": [ "args": [
{ {
@@ -209,7 +192,7 @@ v12 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create-document-mapping\")" "storageKey": "permission(action:\"core:control:create-document-mapping\")"
}, },
v13 = { v11 = {
"alias": "canDeleteDocumentMapping", "alias": "canDeleteDocumentMapping",
"args": [ "args": [
{ {
@@ -222,7 +205,7 @@ v13 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete-document-mapping\")" "storageKey": "permission(action:\"core:control:delete-document-mapping\")"
}, },
v14 = { v12 = {
"alias": "canCreateAuditMapping", "alias": "canCreateAuditMapping",
"args": [ "args": [
{ {
@@ -235,7 +218,7 @@ v14 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create-audit-mapping\")" "storageKey": "permission(action:\"core:control:create-audit-mapping\")"
}, },
v15 = { v13 = {
"alias": "canDeleteAuditMapping", "alias": "canDeleteAuditMapping",
"args": [ "args": [
{ {
@@ -248,7 +231,7 @@ v15 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete-audit-mapping\")" "storageKey": "permission(action:\"core:control:delete-audit-mapping\")"
}, },
v16 = { v14 = {
"alias": "canCreateSnapshotMapping", "alias": "canCreateSnapshotMapping",
"args": [ "args": [
{ {
@@ -261,7 +244,7 @@ v16 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create-snapshot-mapping\")" "storageKey": "permission(action:\"core:control:create-snapshot-mapping\")"
}, },
v17 = { v15 = {
"alias": "canDeleteSnapshotMapping", "alias": "canDeleteSnapshotMapping",
"args": [ "args": [
{ {
@@ -274,7 +257,7 @@ v17 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete-snapshot-mapping\")" "storageKey": "permission(action:\"core:control:delete-snapshot-mapping\")"
}, },
v18 = { v16 = {
"alias": "canCreateObligationMapping", "alias": "canCreateObligationMapping",
"args": [ "args": [
{ {
@@ -287,7 +270,7 @@ v18 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create-obligation-mapping\")" "storageKey": "permission(action:\"core:control:create-obligation-mapping\")"
}, },
v19 = { v17 = {
"alias": "canDeleteObligationMapping", "alias": "canDeleteObligationMapping",
"args": [ "args": [
{ {
@@ -300,21 +283,21 @@ v19 = {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:delete-obligation-mapping\")" "storageKey": "permission(action:\"core:control:delete-obligation-mapping\")"
}, },
v20 = { v18 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "__typename", "name": "__typename",
"storageKey": null "storageKey": null
}, },
v21 = { v19 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "cursor", "name": "cursor",
"storageKey": null "storageKey": null
}, },
v22 = { v20 = {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "PageInfo", "concreteType": "PageInfo",
@@ -339,7 +322,7 @@ v22 = {
], ],
"storageKey": null "storageKey": null
}, },
v23 = { v21 = {
"kind": "ClientExtension", "kind": "ClientExtension",
"selections": [ "selections": [
{ {
@@ -351,26 +334,33 @@ v23 = {
} }
] ]
}, },
v24 = [ v22 = [
{ {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
"value": 100 "value": 100
} }
], ],
v25 = { v23 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "state", "name": "state",
"storageKey": null "storageKey": null
}, },
v26 = { v24 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "createdAt", "name": "createdAt",
"storageKey": null "storageKey": null
},
v25 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
}; };
return { return {
"fragment": { "fragment": {
@@ -406,8 +396,6 @@ return {
(v15/*: any*/), (v15/*: any*/),
(v16/*: any*/), (v16/*: any*/),
(v17/*: any*/), (v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
{ {
"args": null, "args": null,
"kind": "FragmentSpread", "kind": "FragmentSpread",
@@ -443,16 +431,16 @@ return {
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "LinkedMeasuresCardFragment" "name": "LinkedMeasuresCardFragment"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -486,16 +474,16 @@ return {
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "LinkedDocumentsCardFragment" "name": "LinkedDocumentsCardFragment"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -529,16 +517,16 @@ return {
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "LinkedAuditsCardFragment" "name": "LinkedAuditsCardFragment"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -572,16 +560,16 @@ return {
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "LinkedObligationsCardFragment" "name": "LinkedObligationsCardFragment"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -615,16 +603,16 @@ return {
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "LinkedSnapshotsCardFragment" "name": "LinkedSnapshotsCardFragment"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": null "storageKey": null
} }
@@ -653,7 +641,7 @@ return {
"name": "node", "name": "node",
"plural": false, "plural": false,
"selections": [ "selections": [
(v20/*: any*/), (v18/*: any*/),
(v2/*: any*/), (v2/*: any*/),
{ {
"kind": "InlineFragment", "kind": "InlineFragment",
@@ -673,8 +661,6 @@ return {
(v15/*: any*/), (v15/*: any*/),
(v16/*: any*/), (v16/*: any*/),
(v17/*: any*/), (v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -684,7 +670,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"concreteType": "MeasureConnection", "concreteType": "MeasureConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "measures", "name": "measures",
@@ -708,23 +694,23 @@ return {
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v3/*: any*/), (v3/*: any*/),
(v25/*: any*/), (v23/*: any*/),
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": "measures(first:100)" "storageKey": "measures(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "FrameworkGraphControl_measures", "key": "FrameworkGraphControl_measures",
@@ -733,7 +719,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"concreteType": "DocumentConnection", "concreteType": "DocumentConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "documents", "name": "documents",
@@ -763,7 +749,7 @@ return {
"name": "title", "name": "title",
"storageKey": null "storageKey": null
}, },
(v26/*: any*/), (v24/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -802,7 +788,7 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v6/*: any*/) (v25/*: any*/)
], ],
"storageKey": null "storageKey": null
} }
@@ -812,22 +798,22 @@ return {
], ],
"storageKey": "versions(first:1)" "storageKey": "versions(first:1)"
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": "documents(first:100)" "storageKey": "documents(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "FrameworkGraphControl_documents", "key": "FrameworkGraphControl_documents",
@@ -836,7 +822,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"concreteType": "AuditConnection", "concreteType": "AuditConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "audits", "name": "audits",
@@ -860,8 +846,8 @@ return {
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v3/*: any*/), (v3/*: any*/),
(v26/*: any*/), (v24/*: any*/),
(v25/*: any*/), (v23/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -889,22 +875,22 @@ return {
], ],
"storageKey": null "storageKey": null
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": "audits(first:100)" "storageKey": "audits(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "FrameworkGraphControl_audits", "key": "FrameworkGraphControl_audits",
@@ -913,7 +899,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"concreteType": "ObligationConnection", "concreteType": "ObligationConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "obligations", "name": "obligations",
@@ -957,7 +943,7 @@ return {
"name": "source", "name": "source",
"storageKey": null "storageKey": null
}, },
(v6/*: any*/), (v25/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -977,22 +963,22 @@ return {
], ],
"storageKey": null "storageKey": null
}, },
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": "obligations(first:100)" "storageKey": "obligations(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "FrameworkGraphControl_obligations", "key": "FrameworkGraphControl_obligations",
@@ -1001,7 +987,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"concreteType": "SnapshotConnection", "concreteType": "SnapshotConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "snapshots", "name": "snapshots",
@@ -1033,23 +1019,23 @@ return {
"name": "type", "name": "type",
"storageKey": null "storageKey": null
}, },
(v26/*: any*/), (v24/*: any*/),
(v20/*: any*/) (v18/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v21/*: any*/) (v19/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v22/*: any*/), (v20/*: any*/),
(v23/*: any*/) (v21/*: any*/)
], ],
"storageKey": "snapshots(first:100)" "storageKey": "snapshots(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v24/*: any*/), "args": (v22/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "FrameworkGraphControl_snapshots", "key": "FrameworkGraphControl_snapshots",
@@ -1066,7 +1052,7 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "759f31a603a2a7d2b2ad1bfcbe1f24bd", "cacheID": "d177e11d82fa12c1622578238707b173",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -1119,11 +1105,11 @@ return {
}, },
"name": "FrameworkGraphControlNodeQuery", "name": "FrameworkGraphControlNodeQuery",
"operationKind": "query", "operationKind": "query",
"text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n status\n exclusionJustification\n canUpdate: permission(action: \"core:control:update\")\n canDelete: permission(action: \"core:control:delete\")\n canCreateMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n canCreateDocumentMapping: permission(action: \"core:control:create-document-mapping\")\n canDeleteDocumentMapping: permission(action: \"core:control:delete-document-mapping\")\n canCreateAuditMapping: permission(action: \"core:control:create-audit-mapping\")\n canDeleteAuditMapping: permission(action: \"core:control:delete-audit-mapping\")\n canCreateSnapshotMapping: permission(action: \"core:control:create-snapshot-mapping\")\n canDeleteSnapshotMapping: permission(action: \"core:control:delete-snapshot-mapping\")\n canCreateObligationMapping: permission(action: \"core:control:create-obligation-mapping\")\n canDeleteObligationMapping: permission(action: \"core:control:delete-obligation-mapping\")\n ...FrameworkControlDialogFragment\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n audits(first: 100) {\n edges {\n node {\n id\n ...LinkedAuditsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n obligations(first: 100) {\n edges {\n node {\n id\n ...LinkedObligationsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n snapshots(first: 100) {\n edges {\n node {\n id\n ...LinkedSnapshotsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n bestPractice\n}\n\nfragment LinkedAuditsCardFragment on Audit {\n id\n name\n createdAt\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment LinkedObligationsCardFragment on Obligation {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n}\n\nfragment LinkedSnapshotsCardFragment on Snapshot {\n id\n name\n description\n type\n createdAt\n}\n" "text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n canUpdate: permission(action: \"core:control:update\")\n canDelete: permission(action: \"core:control:delete\")\n canCreateMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n canCreateDocumentMapping: permission(action: \"core:control:create-document-mapping\")\n canDeleteDocumentMapping: permission(action: \"core:control:delete-document-mapping\")\n canCreateAuditMapping: permission(action: \"core:control:create-audit-mapping\")\n canDeleteAuditMapping: permission(action: \"core:control:delete-audit-mapping\")\n canCreateSnapshotMapping: permission(action: \"core:control:create-snapshot-mapping\")\n canDeleteSnapshotMapping: permission(action: \"core:control:delete-snapshot-mapping\")\n canCreateObligationMapping: permission(action: \"core:control:create-obligation-mapping\")\n canDeleteObligationMapping: permission(action: \"core:control:delete-obligation-mapping\")\n ...FrameworkControlDialogFragment\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n audits(first: 100) {\n edges {\n node {\n id\n ...LinkedAuditsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n obligations(first: 100) {\n edges {\n node {\n id\n ...LinkedObligationsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n snapshots(first: 100) {\n edges {\n node {\n id\n ...LinkedSnapshotsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n bestPractice\n}\n\nfragment LinkedAuditsCardFragment on Audit {\n id\n name\n createdAt\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment LinkedObligationsCardFragment on Obligation {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n}\n\nfragment LinkedSnapshotsCardFragment on Snapshot {\n id\n name\n description\n type\n createdAt\n}\n"
} }
}; };
})(); })();
(node as any).hash = "d320f2f2ee2e7f9b9f398dd1ff46ac2b"; (node as any).hash = "c5a03208206812d371f5133c8963a710";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<a493a708fe8353db1159647a455582ad>> * @generated SignedSource<<4716483592ffb7c9bb7d96ea56503734>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -189,19 +189,6 @@ return {
"name": "permission", "name": "permission",
"storageKey": "permission(action:\"core:control:create\")" "storageKey": "permission(action:\"core:control:create\")"
}, },
{
"alias": "canGenerateSOA",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:generate-state-of-applicability"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:generate-state-of-applicability\")"
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -262,20 +249,6 @@ return {
"storageKey": null "storageKey": null
}, },
(v3/*: any*/), (v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "exclusionJustification",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -314,12 +287,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "58485d98106169267addab7729095131", "cacheID": "9cb1289702b4dd6c83330a0ef84297d6",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "FrameworkGraphNodeQuery", "name": "FrameworkGraphNodeQuery",
"operationKind": "query", "operationKind": "query",
"text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canExport: permission(action: \"core:franework:export\")\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n canCreateControl: permission(action: \"core:control:create\")\n canGenerateSOA: permission(action: \"core:framework:generate-state-of-applicability\")\n organization {\n name\n id\n }\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n status\n exclusionJustification\n bestPractice\n }\n }\n }\n}\n" "text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canExport: permission(action: \"core:franework:export\")\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n canCreateControl: permission(action: \"core:control:create\")\n organization {\n name\n id\n }\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n bestPractice\n }\n }\n }\n}\n"
} }
}; };
})(); })();

View File

@@ -101,8 +101,6 @@ export const frameworkControlNodeQuery = graphql`
name name
sectionTitle sectionTitle
description description
status
exclusionJustification
canUpdate: permission(action: "core:control:update") canUpdate: permission(action: "core:control:update")
canDelete: permission(action: "core:control:delete") canDelete: permission(action: "core:control:delete")
canCreateMeasureMapping: permission( canCreateMeasureMapping: permission(

View File

@@ -336,22 +336,7 @@ export default function FrameworkControlPage({ queryRef }: Props) {
</div> </div>
</div> </div>
{control.status === "EXCLUDED" && ( <div>
<div className="bg-danger border border-border-danger rounded-lg p-4">
<div className="flex items-center gap-2 mb-2">
<div className="font-medium text-txt-danger">
{__("This control is excluded")}
</div>
</div>
<div className="text-sm">
<strong>{__("Justification:")}</strong>
{" "}
{control.exclusionJustification
|| __("No justification provided")}
</div>
</div>
)}
<div className={control.status === "EXCLUDED" ? "opacity-60" : ""}>
<div className="text-base mb-1">{control.name}</div> <div className="text-base mb-1">{control.name}</div>
{control.description && ( {control.description && (
<div className="text-sm text-txt-secondary mb-4 whitespace-pre-wrap"> <div className="text-sm text-txt-secondary mb-4 whitespace-pre-wrap">

View File

@@ -21,7 +21,6 @@ import { ConnectionHandler, graphql } from "relay-runtime";
import type { FrameworkDetailPageExportFrameworkMutation } from "#/__generated__/core/FrameworkDetailPageExportFrameworkMutation.graphql"; import type { FrameworkDetailPageExportFrameworkMutation } from "#/__generated__/core/FrameworkDetailPageExportFrameworkMutation.graphql";
import type { FrameworkDetailPageFragment$key } from "#/__generated__/core/FrameworkDetailPageFragment.graphql"; import type { FrameworkDetailPageFragment$key } from "#/__generated__/core/FrameworkDetailPageFragment.graphql";
import type { FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation } from "#/__generated__/core/FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation.graphql";
import type { FrameworkGraphNodeQuery } from "#/__generated__/core/FrameworkGraphNodeQuery.graphql"; import type { FrameworkGraphNodeQuery } from "#/__generated__/core/FrameworkGraphNodeQuery.graphql";
import { import {
connectionListKey, connectionListKey,
@@ -45,7 +44,6 @@ const frameworkDetailFragment = graphql`
canUpdate: permission(action: "core:framework:update") canUpdate: permission(action: "core:framework:update")
canDelete: permission(action: "core:framework:delete") canDelete: permission(action: "core:framework:delete")
canCreateControl: permission(action: "core:control:create") canCreateControl: permission(action: "core:control:create")
canGenerateSOA: permission(action: "core:framework:generate-state-of-applicability")
organization { organization {
name name
} }
@@ -59,8 +57,6 @@ const frameworkDetailFragment = graphql`
id id
sectionTitle sectionTitle
name name
status
exclusionJustification
bestPractice bestPractice
} }
} }
@@ -68,18 +64,6 @@ const frameworkDetailFragment = graphql`
} }
`; `;
const generateFrameworkStateOfApplicabilityMutation = graphql`
mutation FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation(
$frameworkId: ID!
) {
generateFrameworkStateOfApplicability(
input: { frameworkId: $frameworkId }
) {
data
}
}
`;
const exportFrameworkMutation = graphql` const exportFrameworkMutation = graphql`
mutation FrameworkDetailPageExportFrameworkMutation($frameworkId: ID!) { mutation FrameworkDetailPageExportFrameworkMutation($frameworkId: ID!) {
exportFramework(input: { frameworkId: $frameworkId }) { exportFramework(input: { frameworkId: $frameworkId }) {
@@ -116,17 +100,6 @@ export default function FrameworkDetailPage(props: Props) {
framework, framework,
ConnectionHandler.getConnectionID(organizationId, connectionListKey), ConnectionHandler.getConnectionID(organizationId, connectionListKey),
); );
const [generateFrameworkStateOfApplicability]
= useMutationWithToasts<FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation>(
generateFrameworkStateOfApplicabilityMutation,
{
errorMessage:
"Failed to generate framework state of applicability",
successMessage:
"Framework state of applicability generated successfully",
},
);
const [exportFramework] const [exportFramework]
= useMutationWithToasts<FrameworkDetailPageExportFrameworkMutation>( = useMutationWithToasts<FrameworkDetailPageExportFrameworkMutation>(
exportFrameworkMutation, exportFrameworkMutation,
@@ -154,7 +127,7 @@ export default function FrameworkDetailPage(props: Props) {
); );
} }
const hasAnyAction = framework.canExport || framework.canDelete || framework.canGenerateSOA; const hasAnyAction = framework.canExport || framework.canDelete;
return ( return (
<div className="space-y-6"> <div className="space-y-6">
@@ -178,35 +151,6 @@ export default function FrameworkDetailPage(props: Props) {
)} )}
{hasAnyAction && ( {hasAnyAction && (
<ActionDropdown variant="secondary"> <ActionDropdown variant="secondary">
{framework.canGenerateSOA
&& (
<DropdownItem
variant="primary"
onClick={() => {
void generateFrameworkStateOfApplicability({
variables: { frameworkId: framework.id },
onCompleted: (data) => {
if (
data
.generateFrameworkStateOfApplicability
?.data
) {
const link
= window.document.createElement("a");
link.href
= data.generateFrameworkStateOfApplicability.data;
link.download = `${framework.organization.name}-${framework.name}-SOA.xlsx`;
window.document.body.appendChild(link);
link.click();
window.document.body.removeChild(link);
}
},
});
}}
>
{__("Download SOA")}
</DropdownItem>
)}
{framework.canExport {framework.canExport
&& ( && (
<DropdownItem <DropdownItem
@@ -245,7 +189,6 @@ export default function FrameworkDetailPage(props: Props) {
key={control.id} key={control.id}
id={control.sectionTitle} id={control.sectionTitle}
description={control.name} description={control.name}
excluded={control.status === "EXCLUDED"}
to={`/organizations/${organizationId}/frameworks/${framework.id}/controls/${control.id}`} to={`/organizations/${organizationId}/frameworks/${framework.id}/controls/${control.id}`}
active={selectedControl?.id === control.id} active={selectedControl?.id === control.id}
/> />

View File

@@ -33,8 +33,6 @@ const controlFragment = graphql`
name name
description description
sectionTitle sectionTitle
status
exclusionJustification
bestPractice bestPractice
} }
`; `;
@@ -64,31 +62,12 @@ const updateMutation = graphql`
} }
`; `;
const schema = z const schema = z.object({
.object({ name: z.string(),
name: z.string(), description: z.string().optional().nullable(),
description: z.string().optional().nullable(), sectionTitle: z.string(),
sectionTitle: z.string(), bestPractice: z.boolean(),
status: z.enum(["INCLUDED", "EXCLUDED"]), });
exclusionJustification: z.string().optional(),
bestPractice: z.boolean(),
})
.refine(
(data) => {
if (data.status === "EXCLUDED") {
return (
data.exclusionJustification
&& data.exclusionJustification.trim().length > 0
);
}
return true;
},
{
message:
"Exclusion justification is required when status is excluded",
path: ["exclusionJustification"],
},
);
export function FrameworkControlDialog(props: Props) { export function FrameworkControlDialog(props: Props) {
const { __ } = useTranslate(); const { __ } = useTranslate();
@@ -111,9 +90,6 @@ export function FrameworkControlDialog(props: Props) {
name: frameworkControl?.name ?? "", name: frameworkControl?.name ?? "",
description: frameworkControl?.description ?? "", description: frameworkControl?.description ?? "",
sectionTitle: frameworkControl?.sectionTitle ?? "", sectionTitle: frameworkControl?.sectionTitle ?? "",
status: frameworkControl?.status ?? "INCLUDED",
exclusionJustification:
frameworkControl?.exclusionJustification ?? "",
bestPractice: frameworkControl?.bestPractice ?? true, bestPractice: frameworkControl?.bestPractice ?? true,
}), }),
[frameworkControl], [frameworkControl],
@@ -141,11 +117,6 @@ export function FrameworkControlDialog(props: Props) {
description: data.description || null, description: data.description || null,
sectionTitle: data.sectionTitle, sectionTitle: data.sectionTitle,
bestPractice: data.bestPractice, bestPractice: data.bestPractice,
status: data.status,
exclusionJustification:
data.status === "EXCLUDED"
? data.exclusionJustification
: null,
}, },
}, },
}); });
@@ -159,11 +130,6 @@ export function FrameworkControlDialog(props: Props) {
description: data.description || null, description: data.description || null,
sectionTitle: data.sectionTitle, sectionTitle: data.sectionTitle,
bestPractice: data.bestPractice ?? true, bestPractice: data.bestPractice ?? true,
status: data.status,
exclusionJustification:
data.status === "EXCLUDED"
? data.exclusionJustification
: null,
}, },
connections: [props.connectionId!], connections: [props.connectionId!],
}, },

View File

@@ -39,7 +39,6 @@ func TestControl_Create(t *testing.T) {
id id
name name
sectionTitle sectionTitle
status
} }
} }
} }
@@ -53,7 +52,6 @@ func TestControl_Create(t *testing.T) {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
SectionTitle string `json:"sectionTitle"` SectionTitle string `json:"sectionTitle"`
Status string `json:"status"`
} `json:"node"` } `json:"node"`
} `json:"controlEdge"` } `json:"controlEdge"`
} `json:"createControl"` } `json:"createControl"`
@@ -65,7 +63,6 @@ func TestControl_Create(t *testing.T) {
"sectionTitle": "A.5", "sectionTitle": "A.5",
"name": "Information Security Policies", "name": "Information Security Policies",
"description": "Policies for information security", "description": "Policies for information security",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &result) }, &result)
@@ -75,52 +72,6 @@ func TestControl_Create(t *testing.T) {
assert.NotEmpty(t, control.ID) assert.NotEmpty(t, control.ID)
assert.Equal(t, "Information Security Policies", control.Name) assert.Equal(t, "Information Security Policies", control.Name)
assert.Equal(t, "A.5", control.SectionTitle) assert.Equal(t, "A.5", control.SectionTitle)
assert.Equal(t, "INCLUDED", control.Status)
})
t.Run("with excluded status and justification", func(t *testing.T) {
query := `
mutation CreateControl($input: CreateControlInput!) {
createControl(input: $input) {
controlEdge {
node {
id
status
exclusionJustification
}
}
}
}
`
var result struct {
CreateControl struct {
ControlEdge struct {
Node struct {
ID string `json:"id"`
Status string `json:"status"`
ExclusionJustification *string `json:"exclusionJustification"`
} `json:"node"`
} `json:"controlEdge"`
} `json:"createControl"`
}
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"frameworkId": frameworkID,
"sectionTitle": "A.10",
"name": "Cryptography",
"description": "Cryptography controls",
"status": "EXCLUDED",
"exclusionJustification": "Not applicable - no cryptographic data processing",
"bestPractice": false,
},
}, &result)
require.NoError(t, err)
control := result.CreateControl.ControlEdge.Node
assert.Equal(t, "EXCLUDED", control.Status)
assert.Equal(t, "Not applicable - no cryptographic data processing", *control.ExclusionJustification)
}) })
} }
@@ -167,46 +118,6 @@ func TestControl_Update(t *testing.T) {
assert.Equal(t, "Updated Control Name", result.UpdateControl.Control.Name) assert.Equal(t, "Updated Control Name", result.UpdateControl.Control.Name)
}) })
t.Run("changes status from INCLUDED to EXCLUDED", func(t *testing.T) {
statusTestControlID := factory.CreateControl(owner, frameworkID, factory.Attrs{
"name": "Status Change Control",
"status": "INCLUDED",
})
query := `
mutation UpdateControl($input: UpdateControlInput!) {
updateControl(input: $input) {
control {
id
status
exclusionJustification
}
}
}
`
var result struct {
UpdateControl struct {
Control struct {
ID string `json:"id"`
Status string `json:"status"`
ExclusionJustification *string `json:"exclusionJustification"`
} `json:"control"`
} `json:"updateControl"`
}
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"id": statusTestControlID,
"status": "EXCLUDED",
"exclusionJustification": "No physical assets in scope",
},
}, &result)
require.NoError(t, err)
assert.Equal(t, "EXCLUDED", result.UpdateControl.Control.Status)
assert.Equal(t, "No physical assets in scope", *result.UpdateControl.Control.ExclusionJustification)
})
} }
func TestControl_Delete(t *testing.T) { func TestControl_Delete(t *testing.T) {
@@ -357,7 +268,6 @@ func TestControl_RequiredFields(t *testing.T) {
"name": "Test Control", "name": "Test Control",
"description": "Test", "description": "Test",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, },
@@ -370,7 +280,6 @@ func TestControl_RequiredFields(t *testing.T) {
"frameworkId": frameworkID, "frameworkId": frameworkID,
"description": "Test", "description": "Test",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, },
@@ -383,20 +292,6 @@ func TestControl_RequiredFields(t *testing.T) {
"frameworkId": frameworkID, "frameworkId": frameworkID,
"name": "Test Control", "name": "Test Control",
"description": "Test", "description": "Test",
"status": "INCLUDED",
"bestPractice": true,
},
},
wantError: true,
},
{
name: "Missing status should fail",
variables: map[string]any{
"input": map[string]any{
"frameworkId": frameworkID,
"name": "Test Control",
"description": "Test",
"sectionTitle": "Section 1",
"bestPractice": true, "bestPractice": true,
}, },
}, },
@@ -409,7 +304,6 @@ func TestControl_RequiredFields(t *testing.T) {
"frameworkId": frameworkID, "frameworkId": frameworkID,
"name": "Test Control", "name": "Test Control",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, },
@@ -423,21 +317,6 @@ func TestControl_RequiredFields(t *testing.T) {
"name": "Test Control", "name": "Test Control",
"description": "Test", "description": "Test",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
},
},
wantError: true,
},
{
name: "Invalid status enum should fail",
variables: map[string]any{
"input": map[string]any{
"frameworkId": frameworkID,
"name": "Test Control",
"description": "Test",
"sectionTitle": "Section 1",
"status": "INVALID_STATUS",
"bestPractice": true,
}, },
}, },
wantError: true, wantError: true,
@@ -524,7 +403,6 @@ func TestControl_OmittableDescription(t *testing.T) {
"name": "Omittable Test Control", "name": "Omittable Test Control",
"description": "Initial description", "description": "Initial description",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &createResult) }, &createResult)
@@ -689,7 +567,6 @@ func TestControl_SubResolvers(t *testing.T) {
"name": "SubResolver Test Control", "name": "SubResolver Test Control",
"description": "Test description", "description": "Test description",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &controlResult) }, &controlResult)
@@ -832,152 +709,3 @@ func TestControl_SubResolvers(t *testing.T) {
assert.GreaterOrEqual(t, len(result.Node.Measures.Edges), 1) assert.GreaterOrEqual(t, len(result.Node.Measures.Edges), 1)
}) })
} }
func TestControl_ExclusionJustification(t *testing.T) {
t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner)
// Create framework
createFrameworkQuery := `
mutation CreateFramework($input: CreateFrameworkInput!) {
createFramework(input: $input) {
frameworkEdge {
node {
id
}
}
}
}
`
var frameworkResult struct {
CreateFramework struct {
FrameworkEdge struct {
Node struct {
ID string `json:"id"`
} `json:"node"`
} `json:"frameworkEdge"`
} `json:"createFramework"`
}
err := owner.Execute(createFrameworkQuery, map[string]any{
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"name": fmt.Sprintf("Exclusion Test %d", time.Now().UnixNano()),
},
}, &frameworkResult)
require.NoError(t, err)
frameworkID := frameworkResult.CreateFramework.FrameworkEdge.Node.ID
t.Run("EXCLUDED status should have exclusionJustification", func(t *testing.T) {
createControlQuery := `
mutation CreateControl($input: CreateControlInput!) {
createControl(input: $input) {
controlEdge {
node {
id
status
exclusionJustification
}
}
}
}
`
var result struct {
CreateControl struct {
ControlEdge struct {
Node struct {
ID string `json:"id"`
Status string `json:"status"`
ExclusionJustification string `json:"exclusionJustification"`
} `json:"node"`
} `json:"controlEdge"`
} `json:"createControl"`
}
err := owner.Execute(createControlQuery, map[string]any{
"input": map[string]any{
"frameworkId": frameworkID,
"name": "Excluded Control",
"description": "Test",
"sectionTitle": "Section 1",
"status": "EXCLUDED",
"exclusionJustification": "Not applicable to our business",
"bestPractice": false,
},
}, &result)
require.NoError(t, err)
assert.Equal(t, "EXCLUDED", result.CreateControl.ControlEdge.Node.Status)
assert.Equal(t, "Not applicable to our business", result.CreateControl.ControlEdge.Node.ExclusionJustification)
})
t.Run("Change status from INCLUDED to EXCLUDED", func(t *testing.T) {
// Create included control first
createControlQuery := `
mutation CreateControl($input: CreateControlInput!) {
createControl(input: $input) {
controlEdge {
node {
id
}
}
}
}
`
var createResult struct {
CreateControl struct {
ControlEdge struct {
Node struct {
ID string `json:"id"`
} `json:"node"`
} `json:"controlEdge"`
} `json:"createControl"`
}
err := owner.Execute(createControlQuery, map[string]any{
"input": map[string]any{
"frameworkId": frameworkID,
"name": "To Be Excluded Control",
"description": "Test",
"sectionTitle": "Section 2",
"status": "INCLUDED",
"bestPractice": true,
},
}, &createResult)
require.NoError(t, err)
// Update to excluded
updateControlQuery := `
mutation UpdateControl($input: UpdateControlInput!) {
updateControl(input: $input) {
control {
id
status
exclusionJustification
}
}
}
`
var updateResult struct {
UpdateControl struct {
Control struct {
ID string `json:"id"`
Status string `json:"status"`
ExclusionJustification string `json:"exclusionJustification"`
} `json:"control"`
} `json:"updateControl"`
}
err = owner.Execute(updateControlQuery, map[string]any{
"input": map[string]any{
"id": createResult.CreateControl.ControlEdge.Node.ID,
"status": "EXCLUDED",
"exclusionJustification": "Decided to exclude",
},
}, &updateResult)
require.NoError(t, err)
})
}

View File

@@ -81,7 +81,6 @@ func TestControlMeasureMapping_CreateDelete(t *testing.T) {
"name": "Control for Mapping", "name": "Control for Mapping",
"description": "Test control for mapping", "description": "Test control for mapping",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &createControlResult) }, &createControlResult)
@@ -361,7 +360,6 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
"name": "Control for Document Mapping", "name": "Control for Document Mapping",
"description": "Test control", "description": "Test control",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &createControlResult) }, &createControlResult)
@@ -503,7 +501,6 @@ func TestControlAuditMapping_CreateDelete(t *testing.T) {
"name": "Control for Audit Mapping", "name": "Control for Audit Mapping",
"description": "Test control", "description": "Test control",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &createControlResult) }, &createControlResult)
@@ -641,7 +638,6 @@ func TestControlSnapshotMapping_CreateDelete(t *testing.T) {
"name": "Control for Snapshot Mapping", "name": "Control for Snapshot Mapping",
"description": "Test control", "description": "Test control",
"sectionTitle": "Section 1", "sectionTitle": "Section 1",
"status": "INCLUDED",
"bestPractice": true, "bestPractice": true,
}, },
}, &createControlResult) }, &createControlResult)

View File

@@ -384,7 +384,7 @@ func TestRBAC(t *testing.T) {
client: owner, client: owner,
query: createControlMutation, query: createControlMutation,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Owner"), "status": "INCLUDED", "bestPractice": true}} return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Owner"), "bestPractice": true}}
}, },
shouldAllow: true, shouldAllow: true,
}, },
@@ -394,7 +394,7 @@ func TestRBAC(t *testing.T) {
client: admin, client: admin,
query: createControlMutation, query: createControlMutation,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Admin"), "status": "INCLUDED", "bestPractice": true}} return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Admin"), "bestPractice": true}}
}, },
shouldAllow: true, shouldAllow: true,
}, },
@@ -404,7 +404,7 @@ func TestRBAC(t *testing.T) {
client: viewer, client: viewer,
query: createControlMutation, query: createControlMutation,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Viewer"), "status": "INCLUDED", "bestPractice": true}} return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Viewer"), "bestPractice": true}}
}, },
shouldAllow: false, shouldAllow: false,
}, },

View File

@@ -205,7 +205,6 @@ func CreateControl(c *testutil.Client, frameworkID string, attrs ...Attrs) strin
"name": a.getString("name", SafeName("Control")), "name": a.getString("name", SafeName("Control")),
"description": a.getString("description", "Test control description"), "description": a.getString("description", "Test control description"),
"sectionTitle": a.getString("sectionTitle", fmt.Sprintf("Section %s", gofakeit.LetterN(3))), "sectionTitle": a.getString("sectionTitle", fmt.Sprintf("Section %s", gofakeit.LetterN(3))),
"status": a.getString("status", "INCLUDED"),
"bestPractice": a.getBool("bestPractice", true), "bestPractice": a.getBool("bestPractice", true),
} }

6
go.mod
View File

@@ -26,7 +26,6 @@ require (
github.com/scim2/filter-parser/v2 v2.2.0 github.com/scim2/filter-parser/v2 v2.2.0
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/vektah/gqlparser/v2 v2.5.31 github.com/vektah/gqlparser/v2 v2.5.31
github.com/xuri/excelize/v2 v2.10.0
github.com/yuin/goldmark v1.7.16 github.com/yuin/goldmark v1.7.16
go.gearno.de/crypto/uuid v0.1.1-0.20251208105319-3f587312a712 go.gearno.de/crypto/uuid v0.1.1-0.20251208105319-3f587312a712
go.gearno.de/kit v0.1.1 go.gearno.de/kit v0.1.1
@@ -109,8 +108,6 @@ require (
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect github.com/prometheus/procfs v0.19.2 // indirect
github.com/richardlehane/mscfb v1.0.6 // indirect
github.com/richardlehane/msoleps v1.0.6 // indirect
github.com/russellhaering/goxmldsig v1.5.0 // indirect github.com/russellhaering/goxmldsig v1.5.0 // indirect
github.com/sosodev/duration v1.3.1 // indirect github.com/sosodev/duration v1.3.1 // indirect
github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/cobra v1.10.1 // indirect
@@ -120,10 +117,7 @@ require (
github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/match v1.2.0 // indirect
github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect github.com/tidwall/sjson v1.2.5 // indirect
github.com/tiendc/go-deepcopy v1.7.2 // indirect
github.com/urfave/cli/v3 v3.6.1 // indirect github.com/urfave/cli/v3 v3.6.1 // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.gearno.de/x/panicf v0.1.1 // indirect go.gearno.de/x/panicf v0.1.1 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect

12
go.sum
View File

@@ -205,10 +205,6 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8=
github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russellhaering/goxmldsig v1.5.0 h1:AU2UkkYIUOTyZRbe08XMThaOCelArgvNfYapcmSjBNw= github.com/russellhaering/goxmldsig v1.5.0 h1:AU2UkkYIUOTyZRbe08XMThaOCelArgvNfYapcmSjBNw=
@@ -245,18 +241,10 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo= github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo=
github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k= github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k=
github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstfW4=
github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=

View File

@@ -44,30 +44,6 @@ export const description: INodeProperties[] = [
description: 'The name of the control', description: 'The name of the control',
required: true, required: true,
}, },
{
displayName: 'Status',
name: 'status',
type: 'options',
displayOptions: {
show: {
resource: ['control'],
operation: ['create'],
},
},
options: [
{
name: 'Included',
value: 'INCLUDED',
},
{
name: 'Excluded',
value: 'EXCLUDED',
},
],
default: 'INCLUDED',
description: 'The status of the control',
required: true,
},
{ {
displayName: 'Description', displayName: 'Description',
name: 'description', name: 'description',
@@ -81,19 +57,6 @@ export const description: INodeProperties[] = [
default: '', default: '',
description: 'The description of the control', description: 'The description of the control',
}, },
{
displayName: 'Exclusion Justification',
name: 'exclusionJustification',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['create'],
},
},
default: '',
description: 'The justification for excluding the control',
},
]; ];
export async function execute( export async function execute(
@@ -103,9 +66,7 @@ export async function execute(
const frameworkId = this.getNodeParameter('frameworkId', itemIndex) as string; const frameworkId = this.getNodeParameter('frameworkId', itemIndex) as string;
const sectionTitle = this.getNodeParameter('sectionTitle', itemIndex) as string; const sectionTitle = this.getNodeParameter('sectionTitle', itemIndex) as string;
const name = this.getNodeParameter('name', itemIndex) as string; const name = this.getNodeParameter('name', itemIndex) as string;
const status = this.getNodeParameter('status', itemIndex) as string;
const description = this.getNodeParameter('description', itemIndex, '') as string; const description = this.getNodeParameter('description', itemIndex, '') as string;
const exclusionJustification = this.getNodeParameter('exclusionJustification', itemIndex, '') as string;
const query = ` const query = `
mutation CreateControl($input: CreateControlInput!) { mutation CreateControl($input: CreateControlInput!) {
@@ -116,8 +77,6 @@ export async function execute(
sectionTitle sectionTitle
name name
description description
status
exclusionJustification
createdAt createdAt
updatedAt updatedAt
} }
@@ -131,9 +90,8 @@ export async function execute(
frameworkId, frameworkId,
sectionTitle, sectionTitle,
name, name,
status, bestPractice: true,
...(description && { description }), ...(description && { description }),
...(exclusionJustification && { exclusionJustification }),
}, },
}; };
@@ -144,4 +102,3 @@ export async function execute(
pairedItem: { item: itemIndex }, pairedItem: { item: itemIndex },
}; };
} }

View File

@@ -32,8 +32,6 @@ export async function execute(
sectionTitle sectionTitle
name name
description description
status
exclusionJustification
createdAt createdAt
updatedAt updatedAt
} }

View File

@@ -67,8 +67,6 @@ export async function execute(
sectionTitle sectionTitle
name name
description description
status
exclusionJustification
createdAt createdAt
updatedAt updatedAt
} }

View File

@@ -55,42 +55,6 @@ export const description: INodeProperties[] = [
default: '', default: '',
description: 'The description of the control', description: 'The description of the control',
}, },
{
displayName: 'Status',
name: 'status',
type: 'options',
displayOptions: {
show: {
resource: ['control'],
operation: ['update'],
},
},
options: [
{
name: 'Included',
value: 'INCLUDED',
},
{
name: 'Excluded',
value: 'EXCLUDED',
},
],
default: 'INCLUDED',
description: 'The status of the control',
},
{
displayName: 'Exclusion Justification',
name: 'exclusionJustification',
type: 'string',
displayOptions: {
show: {
resource: ['control'],
operation: ['update'],
},
},
default: '',
description: 'The justification for excluding the control',
},
]; ];
export async function execute( export async function execute(
@@ -101,8 +65,6 @@ export async function execute(
const sectionTitle = this.getNodeParameter('sectionTitle', itemIndex, '') as string; const sectionTitle = this.getNodeParameter('sectionTitle', itemIndex, '') as string;
const name = this.getNodeParameter('name', itemIndex, '') as string; const name = this.getNodeParameter('name', itemIndex, '') as string;
const description = this.getNodeParameter('description', itemIndex, '') as string; const description = this.getNodeParameter('description', itemIndex, '') as string;
const status = this.getNodeParameter('status', itemIndex, '') as string;
const exclusionJustification = this.getNodeParameter('exclusionJustification', itemIndex, '') as string;
const query = ` const query = `
mutation UpdateControl($input: UpdateControlInput!) { mutation UpdateControl($input: UpdateControlInput!) {
@@ -112,8 +74,6 @@ export async function execute(
sectionTitle sectionTitle
name name
description description
status
exclusionJustification
createdAt createdAt
updatedAt updatedAt
} }
@@ -125,8 +85,6 @@ export async function execute(
if (sectionTitle) input.sectionTitle = sectionTitle; if (sectionTitle) input.sectionTitle = sectionTitle;
if (name) input.name = name; if (name) input.name = name;
if (description) input.description = description; if (description) input.description = description;
if (status) input.status = status;
if (exclusionJustification) input.exclusionJustification = exclusionJustification;
const responseData = await proboApiRequest.call(this, query, { input }); const responseData = await proboApiRequest.call(this, query, { input });
@@ -135,4 +93,3 @@ export async function execute(
pairedItem: { item: itemIndex }, pairedItem: { item: itemIndex },
}; };
} }

View File

@@ -6,7 +6,6 @@ type Props = {
active?: boolean; active?: boolean;
id: string; id: string;
description?: string; description?: string;
excluded?: boolean;
to: string; to: string;
} & HTMLAttributes<HTMLAnchorElement>; } & HTMLAttributes<HTMLAnchorElement>;
@@ -27,39 +26,19 @@ const classNames = tv({
id: "bg-highlight", id: "bg-highlight",
}, },
}, },
excluded: {
true: {
wrapper: "opacity-60",
},
false: {
wrapper: "",
},
},
}, },
compoundVariants: [
{
active: true,
excluded: true,
class: {
wrapper: "bg-tertiary-pressed opacity-60",
id: "bg-active",
},
},
],
defaultVariants: { defaultVariants: {
active: false, active: false,
excluded: false,
}, },
}); });
export function ControlItem({ active, id, description, excluded, to, ...props }: Props) { export function ControlItem({ active, id, description, to, ...props }: Props) {
const { const {
wrapper, wrapper,
id: idCls, id: idCls,
description: descriptionCls, description: descriptionCls,
} = classNames({ } = classNames({
active, active,
excluded,
}); });
const ref = useRef<HTMLAnchorElement>(null); const ref = useRef<HTMLAnchorElement>(null);

View File

@@ -30,17 +30,15 @@ import (
type ( type (
Control struct { Control struct {
ID gid.GID `db:"id"` ID gid.GID `db:"id"`
OrganizationID gid.GID `db:"organization_id"` OrganizationID gid.GID `db:"organization_id"`
SectionTitle string `db:"section_title"` SectionTitle string `db:"section_title"`
FrameworkID gid.GID `db:"framework_id"` FrameworkID gid.GID `db:"framework_id"`
Name string `db:"name"` Name string `db:"name"`
Description *string `db:"description"` Description *string `db:"description"`
Status ControlStatus `db:"status"` BestPractice bool `db:"best_practice"`
ExclusionJustification *string `db:"exclusion_justification"` CreatedAt time.Time `db:"created_at"`
BestPractice bool `db:"best_practice"` UpdatedAt time.Time `db:"updated_at"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
} }
Controls []*Control Controls []*Control
@@ -132,8 +130,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -152,8 +148,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -245,8 +239,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -265,8 +257,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -364,8 +354,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -390,8 +378,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -471,8 +457,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -567,8 +551,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -587,8 +569,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -635,8 +615,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -685,8 +663,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -739,8 +715,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -783,8 +757,6 @@ INSERT INTO
section_title, section_title,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -797,8 +769,6 @@ VALUES (
@section_title, @section_title,
@name, @name,
@description, @description,
@status,
@exclusion_justification,
@best_practice, @best_practice,
@created_at, @created_at,
@updated_at @updated_at
@@ -806,18 +776,16 @@ VALUES (
` `
args := pgx.StrictNamedArgs{ args := pgx.StrictNamedArgs{
"tenant_id": scope.GetTenantID(), "tenant_id": scope.GetTenantID(),
"control_id": c.ID, "control_id": c.ID,
"organization_id": c.OrganizationID, "organization_id": c.OrganizationID,
"framework_id": c.FrameworkID, "framework_id": c.FrameworkID,
"section_title": c.SectionTitle, "section_title": c.SectionTitle,
"name": c.Name, "name": c.Name,
"description": c.Description, "description": c.Description,
"status": c.Status, "best_practice": c.BestPractice,
"exclusion_justification": c.ExclusionJustification, "created_at": c.CreatedAt,
"best_practice": c.BestPractice, "updated_at": c.UpdatedAt,
"created_at": c.CreatedAt,
"updated_at": c.UpdatedAt,
} }
_, err := conn.Exec(ctx, q, args) _, err := conn.Exec(ctx, q, args)
@@ -866,8 +834,6 @@ UPDATE controls SET
name = @name, name = @name,
description = @description, description = @description,
section_title = @section_title, section_title = @section_title,
status = @status,
exclusion_justification = @exclusion_justification,
best_practice = @best_practice, best_practice = @best_practice,
updated_at = @updated_at updated_at = @updated_at
WHERE %s WHERE %s
@@ -876,14 +842,12 @@ WHERE %s
q = fmt.Sprintf(q, scope.SQLFragment()) q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{ args := pgx.StrictNamedArgs{
"control_id": c.ID, "control_id": c.ID,
"name": c.Name, "name": c.Name,
"description": c.Description, "description": c.Description,
"section_title": c.SectionTitle, "section_title": c.SectionTitle,
"status": c.Status, "best_practice": c.BestPractice,
"exclusion_justification": c.ExclusionJustification, "updated_at": c.UpdatedAt,
"best_practice": c.BestPractice,
"updated_at": c.UpdatedAt,
} }
maps.Copy(args, scope.SQLArguments()) maps.Copy(args, scope.SQLArguments())
@@ -963,8 +927,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -983,8 +945,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at
@@ -1077,8 +1037,6 @@ WITH ctrl AS (
c.tenant_id, c.tenant_id,
c.name, c.name,
c.description, c.description,
c.status,
c.exclusion_justification,
c.best_practice, c.best_practice,
c.created_at, c.created_at,
c.updated_at, c.updated_at,
@@ -1097,8 +1055,6 @@ SELECT
organization_id, organization_id,
name, name,
description, description,
status,
exclusion_justification,
best_practice, best_practice,
created_at, created_at,
updated_at updated_at

View File

@@ -1,59 +0,0 @@
// Copyright (c) 2025 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.
package coredata
import (
"database/sql/driver"
"fmt"
)
type ControlStatus string
const (
ControlStatusIncluded ControlStatus = "INCLUDED"
ControlStatusExcluded ControlStatus = "EXCLUDED"
)
func ControlStatuses() []ControlStatus {
return []ControlStatus{
ControlStatusIncluded,
ControlStatusExcluded,
}
}
func (cs ControlStatus) String() string {
return string(cs)
}
func (cs *ControlStatus) Scan(value interface{}) error {
switch v := value.(type) {
case string:
switch v {
case "INCLUDED":
*cs = ControlStatusIncluded
case "EXCLUDED":
*cs = ControlStatusExcluded
default:
return fmt.Errorf("invalid ControlStatus value: %q", v)
}
default:
return fmt.Errorf("unsupported type for ControlStatus: %T", value)
}
return nil
}
func (cs ControlStatus) Value() (driver.Value, error) {
return cs.String(), nil
}

View File

@@ -88,7 +88,7 @@ func (states DocumentVersionSignatureStates) Value() (driver.Value, error) {
if i > 0 { if i > 0 {
result.WriteString(",") result.WriteString(",")
} }
result.WriteString(fmt.Sprintf("%q", state.String())) fmt.Fprintf(&result, "%q", state.String())
} }
result.WriteString("}") result.WriteString("}")
return result.String(), nil return result.String(), nil

View File

@@ -21,7 +21,7 @@ import (
) )
type ( type (
InvitationStatus string InvitationStatus string
InvitationStatuses []InvitationStatus InvitationStatuses []InvitationStatus
) )
@@ -74,7 +74,7 @@ func (statuses InvitationStatuses) Value() (driver.Value, error) {
if i > 0 { if i > 0 {
result.WriteString(",") result.WriteString(",")
} }
result.WriteString(fmt.Sprintf("%q", status.String())) fmt.Fprintf(&result, "%q", status.String())
} }
result.WriteString("}") result.WriteString("}")
return result.String(), nil return result.String(), nil

View File

@@ -0,0 +1,6 @@
ALTER TABLE controls ALTER COLUMN status DROP NOT NULL;
-- TODO: drop columns and type once all code references are fully removed
-- ALTER TABLE controls DROP COLUMN status;
-- ALTER TABLE controls DROP COLUMN exclusion_justification;
-- DROP TYPE control_status;

View File

@@ -105,8 +105,7 @@ const (
ActionFrameworkCreate = "core:framework:create" ActionFrameworkCreate = "core:framework:create"
ActionFrameworkUpdate = "core:framework:update" ActionFrameworkUpdate = "core:framework:update"
ActionFrameworkDelete = "core:framework:delete" ActionFrameworkDelete = "core:framework:delete"
ActionFrameworkStateOfApplicabilityGenerate = "core:framework:generate-state-of-applicability" ActionFrameworkExport = "core:framework:export"
ActionFrameworkExport = "core:framework:export"
ActionFrameworkImport = "core:framework:import" ActionFrameworkImport = "core:framework:import"
// Control actions // Control actions

View File

@@ -32,24 +32,20 @@ type (
} }
CreateControlRequest struct { CreateControlRequest struct {
ID gid.GID ID gid.GID
FrameworkID gid.GID FrameworkID gid.GID
Name string Name string
Description *string Description *string
SectionTitle string SectionTitle string
Status *coredata.ControlStatus BestPractice bool
ExclusionJustification *string
BestPractice bool
} }
UpdateControlRequest struct { UpdateControlRequest struct {
ID gid.GID ID gid.GID
Name *string Name *string
Description **string Description **string
SectionTitle *string SectionTitle *string
Status *coredata.ControlStatus BestPractice *bool
ExclusionJustification *string
BestPractice *bool
} }
) )
@@ -60,8 +56,6 @@ func (ccr *CreateControlRequest) Validate() error {
v.Check(ccr.Name, "name", validator.Required(), validator.SafeTextNoNewLine(TitleMaxLength)) v.Check(ccr.Name, "name", validator.Required(), validator.SafeTextNoNewLine(TitleMaxLength))
v.Check(ccr.Description, "description", validator.Required(), validator.SafeText(ContentMaxLength)) v.Check(ccr.Description, "description", validator.Required(), validator.SafeText(ContentMaxLength))
v.Check(ccr.SectionTitle, "section_title", validator.Required(), validator.SafeTextNoNewLine(TitleMaxLength)) v.Check(ccr.SectionTitle, "section_title", validator.Required(), validator.SafeTextNoNewLine(TitleMaxLength))
v.Check(ccr.Status, "status", validator.Required(), validator.OneOfSlice(coredata.ControlStatuses()))
v.Check(ccr.ExclusionJustification, "exclusion_justification", validator.SafeText(TitleMaxLength))
return v.Error() return v.Error()
} }
@@ -73,8 +67,6 @@ func (ucr *UpdateControlRequest) Validate() error {
v.Check(ucr.Name, "name", validator.SafeTextNoNewLine(TitleMaxLength)) v.Check(ucr.Name, "name", validator.SafeTextNoNewLine(TitleMaxLength))
v.Check(ucr.Description, "description", validator.SafeText(ContentMaxLength)) v.Check(ucr.Description, "description", validator.SafeText(ContentMaxLength))
v.Check(ucr.SectionTitle, "section_title", validator.SafeTextNoNewLine(TitleMaxLength)) v.Check(ucr.SectionTitle, "section_title", validator.SafeTextNoNewLine(TitleMaxLength))
v.Check(ucr.Status, "status", validator.OneOfSlice(coredata.ControlStatuses()))
v.Check(ucr.ExclusionJustification, "exclusion_justification", validator.SafeText(TitleMaxLength))
return v.Error() return v.Error()
} }
@@ -839,16 +831,14 @@ func (s ControlService) Create(
framework := &coredata.Framework{} framework := &coredata.Framework{}
control := &coredata.Control{ control := &coredata.Control{
ID: gid.New(s.svc.scope.GetTenantID(), coredata.ControlEntityType), ID: gid.New(s.svc.scope.GetTenantID(), coredata.ControlEntityType),
FrameworkID: req.FrameworkID, FrameworkID: req.FrameworkID,
Name: req.Name, Name: req.Name,
Description: req.Description, Description: req.Description,
SectionTitle: req.SectionTitle, SectionTitle: req.SectionTitle,
Status: *req.Status, BestPractice: req.BestPractice,
ExclusionJustification: req.ExclusionJustification, CreatedAt: now,
BestPractice: req.BestPractice, UpdatedAt: now,
CreatedAt: now,
UpdatedAt: now,
} }
err := s.svc.pg.WithTx( err := s.svc.pg.WithTx(
@@ -921,14 +911,6 @@ func (s ControlService) Update(
control.SectionTitle = *req.SectionTitle control.SectionTitle = *req.SectionTitle
} }
if req.Status != nil {
control.Status = *req.Status
}
if req.ExclusionJustification != nil {
control.ExclusionJustification = req.ExclusionJustification
}
if req.BestPractice != nil { if req.BestPractice != nil {
control.BestPractice = *req.BestPractice control.BestPractice = *req.BestPractice
} }

View File

@@ -36,12 +36,10 @@ import (
"go.probo.inc/probo/pkg/mail" "go.probo.inc/probo/pkg/mail"
"go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/slug" "go.probo.inc/probo/pkg/slug"
"go.probo.inc/probo/pkg/soagen"
"go.probo.inc/probo/pkg/validator" "go.probo.inc/probo/pkg/validator"
) )
const ( const (
maxStateOfApplicabilityLimit = 10_000
frameworkExportEmailExpiresIn = 24 * time.Hour frameworkExportEmailExpiresIn = 24 * time.Hour
) )
@@ -584,7 +582,6 @@ func (s FrameworkService) Import(
SectionTitle: control.ID, SectionTitle: control.ID,
Name: control.Name, Name: control.Name,
Description: &description, Description: &description,
Status: coredata.ControlStatusIncluded,
BestPractice: bestPractice, BestPractice: bestPractice,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
@@ -605,182 +602,6 @@ func (s FrameworkService) Import(
return framework, nil return framework, nil
} }
func (s FrameworkService) StateOfApplicability(ctx context.Context, frameworkID gid.GID) ([]byte, error) {
rows := []soagen.SOARowData{}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
framework := &coredata.Framework{}
if err := framework.LoadByID(ctx, conn, s.svc.scope, frameworkID); err != nil {
return fmt.Errorf("cannot load framework: %w", err)
}
controls := coredata.Controls{}
err := controls.LoadByFrameworkID(
ctx,
conn,
s.svc.scope,
frameworkID,
page.NewCursor(
maxStateOfApplicabilityLimit,
nil,
page.Head,
page.OrderBy[coredata.ControlOrderField]{
Field: coredata.ControlOrderFieldSectionTitle,
Direction: page.OrderDirectionAsc,
},
),
coredata.NewControlFilter(nil),
)
if err != nil {
return fmt.Errorf("cannot load controls: %w", err)
}
for _, control := range controls {
exclusionJustification := ""
if control.Status == coredata.ControlStatusExcluded {
if control.ExclusionJustification == nil {
return fmt.Errorf("exclusion justification is required for excluded controls")
}
exclusionJustification = *control.ExclusionJustification
}
applicability := soagen.NewApplicability("Yes", true)
if control.Status == coredata.ControlStatusExcluded {
applicability = soagen.NewApplicability("No", false)
}
bestPractice := ref.Ref(true)
if control.Status == coredata.ControlStatusExcluded {
bestPractice = ref.Ref(false)
}
row := soagen.SOARowData{
SectionTitle: control.SectionTitle,
ControlName: control.Name,
Applicability: applicability,
ExclusionJustification: exclusionJustification,
Regulatory: ref.Ref(false),
Contractual: ref.Ref(false),
BestPractice: bestPractice,
RiskAssessment: ref.Ref(false),
SecurityMeasures: []string{},
}
if control.Status == coredata.ControlStatusExcluded {
rows = append(rows, row)
continue
}
measures := coredata.Measures{}
err = measures.LoadByControlID(
ctx,
conn,
s.svc.scope,
control.ID,
page.NewCursor(
maxStateOfApplicabilityLimit,
nil,
page.Head,
page.OrderBy[coredata.MeasureOrderField]{
Field: coredata.MeasureOrderFieldCreatedAt,
Direction: page.OrderDirectionAsc,
},
),
coredata.NewMeasureFilter(nil, nil),
)
if err != nil {
return fmt.Errorf("cannot load measures: %w", err)
}
for _, measure := range measures {
risks := coredata.Risks{}
var nilSnapshotID *gid.GID = nil
risksCount, err := risks.CountByMeasureID(
ctx,
conn,
s.svc.scope,
measure.ID,
coredata.NewRiskFilter(nil, &nilSnapshotID),
)
if err != nil {
return fmt.Errorf("cannot count risks: %w", err)
}
if risksCount > 0 {
row.RiskAssessment = ref.Ref(true)
}
row.SecurityMeasures = append(row.SecurityMeasures, measure.Name)
}
documents := coredata.Documents{}
err = documents.LoadByControlID(
ctx,
conn,
s.svc.scope,
control.ID,
page.NewCursor(
0,
nil,
page.Head,
page.OrderBy[coredata.DocumentOrderField]{
Field: coredata.DocumentOrderFieldCreatedAt,
Direction: page.OrderDirectionAsc,
},
),
coredata.NewDocumentFilter(nil),
)
if err != nil {
return fmt.Errorf("cannot load documents: %w", err)
}
for _, document := range documents {
risks := coredata.Risks{}
var nilSnapshotID *gid.GID = nil
risksCount, err := risks.CountByDocumentID(
ctx,
conn,
s.svc.scope,
document.ID,
coredata.NewRiskFilter(nil, &nilSnapshotID),
)
if err != nil {
return fmt.Errorf("cannot count risks: %w", err)
}
if risksCount > 0 {
row.RiskAssessment = ref.Ref(true)
}
row.SecurityMeasures = append(row.SecurityMeasures, document.Title)
}
rows = append(rows, row)
}
return nil
},
)
if err != nil {
return nil, err
}
output, err := soagen.GenerateExcel(
soagen.SOAData{
Rows: rows,
},
)
if err != nil {
return nil, fmt.Errorf("cannot generate Excel file: %w", err)
}
return output, nil
}
func (s FrameworkService) SendExportEmail( func (s FrameworkService) SendExportEmail(
ctx context.Context, ctx context.Context,
fileID gid.GID, fileID gid.GID,

View File

@@ -1030,14 +1030,6 @@ enum DataClassification
) )
} }
enum ControlStatus
@goModel(model: "go.probo.inc/probo/pkg/coredata.ControlStatus") {
INCLUDED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ControlStatusIncluded")
EXCLUDED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ControlStatusExcluded")
}
enum AuditOrderField enum AuditOrderField
@goModel(model: "go.probo.inc/probo/pkg/coredata.AuditOrderField") { @goModel(model: "go.probo.inc/probo/pkg/coredata.AuditOrderField") {
CREATED_AT CREATED_AT
@@ -2051,8 +2043,6 @@ type Control implements Node {
sectionTitle: String! sectionTitle: String!
name: String! name: String!
description: String description: String
status: ControlStatus!
exclusionJustification: String
bestPractice: Boolean! bestPractice: Boolean!
regulatory: Boolean! @goField(forceResolver: true) regulatory: Boolean! @goField(forceResolver: true)
contractual: Boolean! @goField(forceResolver: true) contractual: Boolean! @goField(forceResolver: true)
@@ -3287,9 +3277,6 @@ type Mutation {
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload! importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload!
deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload! deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload!
generateFrameworkStateOfApplicability(
input: GenerateFrameworkStateOfApplicabilityInput!
): GenerateFrameworkStateOfApplicabilityPayload!
exportFramework(input: ExportFrameworkInput!): ExportFrameworkPayload! exportFramework(input: ExportFrameworkInput!): ExportFrameworkPayload!
# Control mutations # Control mutations
createControl(input: CreateControlInput!): CreateControlPayload! createControl(input: CreateControlInput!): CreateControlPayload!
@@ -3576,14 +3563,6 @@ type Mutation {
} }
# Input Types # Input Types
input GenerateFrameworkStateOfApplicabilityInput {
frameworkId: ID!
}
type GenerateFrameworkStateOfApplicabilityPayload {
data: String!
}
input UpdateOrganizationContextInput { input UpdateOrganizationContextInput {
organizationId: ID! organizationId: ID!
summary: String @goField(omittable: true) summary: String @goField(omittable: true)
@@ -4146,8 +4125,6 @@ input CreateControlInput {
sectionTitle: String! sectionTitle: String!
name: String! name: String!
description: String description: String
status: ControlStatus!
exclusionJustification: String
bestPractice: Boolean! bestPractice: Boolean!
} }
@@ -4156,8 +4133,6 @@ input UpdateControlInput {
sectionTitle: String sectionTitle: String
name: String name: String
description: String @goField(omittable: true) description: String @goField(omittable: true)
status: ControlStatus
exclusionJustification: String
bestPractice: Boolean bestPractice: Boolean
} }

View File

@@ -258,26 +258,24 @@ type ComplexityRoot struct {
} }
Control struct { Control struct {
Audits func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) int Audits func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) int
BestPractice func(childComplexity int) int BestPractice func(childComplexity int) int
Contractual func(childComplexity int) int Contractual func(childComplexity int) int
CreatedAt func(childComplexity int) int CreatedAt func(childComplexity int) int
Description func(childComplexity int) int Description func(childComplexity int) int
Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) int Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) int
ExclusionJustification func(childComplexity int) int Framework func(childComplexity int) int
Framework func(childComplexity int) int ID func(childComplexity int) int
ID func(childComplexity int) int Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int
Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int Name func(childComplexity int) int
Name func(childComplexity int) int Obligations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) int
Obligations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) int Organization func(childComplexity int) int
Organization func(childComplexity int) int Permission func(childComplexity int, action string) int
Permission func(childComplexity int, action string) int Regulatory func(childComplexity int) int
Regulatory func(childComplexity int) int RiskAssessment func(childComplexity int) int
RiskAssessment func(childComplexity int) int SectionTitle func(childComplexity int) int
SectionTitle func(childComplexity int) int Snapshots func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) int
Snapshots func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) int UpdatedAt func(childComplexity int) int
Status func(childComplexity int) int
UpdatedAt func(childComplexity int) int
} }
ControlConnection struct { ControlConnection struct {
@@ -873,10 +871,6 @@ type ComplexityRoot struct {
Changelog func(childComplexity int) int Changelog func(childComplexity int) int
} }
GenerateFrameworkStateOfApplicabilityPayload struct {
Data func(childComplexity int) int
}
GetTrustCenterFilePayload struct { GetTrustCenterFilePayload struct {
TrustCenterFile func(childComplexity int) int TrustCenterFile func(childComplexity int) int
} }
@@ -1034,7 +1028,6 @@ type ComplexityRoot struct {
ExportStateOfApplicabilityPDF func(childComplexity int, input types.ExportStateOfApplicabilityPDFInput) int ExportStateOfApplicabilityPDF func(childComplexity int, input types.ExportStateOfApplicabilityPDFInput) int
ExportTransferImpactAssessmentsPDF func(childComplexity int, input types.ExportTransferImpactAssessmentsPDFInput) int ExportTransferImpactAssessmentsPDF func(childComplexity int, input types.ExportTransferImpactAssessmentsPDFInput) int
GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int
GenerateFrameworkStateOfApplicability func(childComplexity int, input types.GenerateFrameworkStateOfApplicabilityInput) int
GetTrustCenterFile func(childComplexity int, input types.GetTrustCenterFileInput) int GetTrustCenterFile func(childComplexity int, input types.GetTrustCenterFileInput) int
ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int
ImportMeasure func(childComplexity int, input types.ImportMeasureInput) int ImportMeasure func(childComplexity int, input types.ImportMeasureInput) int
@@ -2164,7 +2157,6 @@ type MutationResolver interface {
UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error)
ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error)
DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error)
GenerateFrameworkStateOfApplicability(ctx context.Context, input types.GenerateFrameworkStateOfApplicabilityInput) (*types.GenerateFrameworkStateOfApplicabilityPayload, error)
ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error)
CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error)
UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error)
@@ -3104,12 +3096,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
} }
return e.complexity.Control.Documents(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.DocumentOrderBy), args["filter"].(*types.DocumentFilter)), true return e.complexity.Control.Documents(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.DocumentOrderBy), args["filter"].(*types.DocumentFilter)), true
case "Control.exclusionJustification":
if e.complexity.Control.ExclusionJustification == nil {
break
}
return e.complexity.Control.ExclusionJustification(childComplexity), true
case "Control.framework": case "Control.framework":
if e.complexity.Control.Framework == nil { if e.complexity.Control.Framework == nil {
break break
@@ -3196,12 +3182,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
} }
return e.complexity.Control.Snapshots(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.SnapshotOrderBy)), true return e.complexity.Control.Snapshots(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.SnapshotOrderBy)), true
case "Control.status":
if e.complexity.Control.Status == nil {
break
}
return e.complexity.Control.Status(childComplexity), true
case "Control.updatedAt": case "Control.updatedAt":
if e.complexity.Control.UpdatedAt == nil { if e.complexity.Control.UpdatedAt == nil {
break break
@@ -4887,13 +4867,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.GenerateDocumentChangelogPayload.Changelog(childComplexity), true return e.complexity.GenerateDocumentChangelogPayload.Changelog(childComplexity), true
case "GenerateFrameworkStateOfApplicabilityPayload.data":
if e.complexity.GenerateFrameworkStateOfApplicabilityPayload.Data == nil {
break
}
return e.complexity.GenerateFrameworkStateOfApplicabilityPayload.Data(childComplexity), true
case "GetTrustCenterFilePayload.trustCenterFile": case "GetTrustCenterFilePayload.trustCenterFile":
if e.complexity.GetTrustCenterFilePayload.TrustCenterFile == nil { if e.complexity.GetTrustCenterFilePayload.TrustCenterFile == nil {
break break
@@ -6182,17 +6155,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
} }
return e.complexity.Mutation.GenerateDocumentChangelog(childComplexity, args["input"].(types.GenerateDocumentChangelogInput)), true return e.complexity.Mutation.GenerateDocumentChangelog(childComplexity, args["input"].(types.GenerateDocumentChangelogInput)), true
case "Mutation.generateFrameworkStateOfApplicability":
if e.complexity.Mutation.GenerateFrameworkStateOfApplicability == nil {
break
}
args, err := ec.field_Mutation_generateFrameworkStateOfApplicability_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.GenerateFrameworkStateOfApplicability(childComplexity, args["input"].(types.GenerateFrameworkStateOfApplicabilityInput)), true
case "Mutation.getTrustCenterFile": case "Mutation.getTrustCenterFile":
if e.complexity.Mutation.GetTrustCenterFile == nil { if e.complexity.Mutation.GetTrustCenterFile == nil {
break break
@@ -10419,7 +10381,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputExportTransferImpactAssessmentsPDFInput, ec.unmarshalInputExportTransferImpactAssessmentsPDFInput,
ec.unmarshalInputFrameworkOrder, ec.unmarshalInputFrameworkOrder,
ec.unmarshalInputGenerateDocumentChangelogInput, ec.unmarshalInputGenerateDocumentChangelogInput,
ec.unmarshalInputGenerateFrameworkStateOfApplicabilityInput,
ec.unmarshalInputGetTrustCenterFileInput, ec.unmarshalInputGetTrustCenterFileInput,
ec.unmarshalInputImportFrameworkInput, ec.unmarshalInputImportFrameworkInput,
ec.unmarshalInputImportMeasureInput, ec.unmarshalInputImportMeasureInput,
@@ -11627,14 +11588,6 @@ enum DataClassification
) )
} }
enum ControlStatus
@goModel(model: "go.probo.inc/probo/pkg/coredata.ControlStatus") {
INCLUDED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ControlStatusIncluded")
EXCLUDED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ControlStatusExcluded")
}
enum AuditOrderField enum AuditOrderField
@goModel(model: "go.probo.inc/probo/pkg/coredata.AuditOrderField") { @goModel(model: "go.probo.inc/probo/pkg/coredata.AuditOrderField") {
CREATED_AT CREATED_AT
@@ -12648,8 +12601,6 @@ type Control implements Node {
sectionTitle: String! sectionTitle: String!
name: String! name: String!
description: String description: String
status: ControlStatus!
exclusionJustification: String
bestPractice: Boolean! bestPractice: Boolean!
regulatory: Boolean! @goField(forceResolver: true) regulatory: Boolean! @goField(forceResolver: true)
contractual: Boolean! @goField(forceResolver: true) contractual: Boolean! @goField(forceResolver: true)
@@ -13884,9 +13835,6 @@ type Mutation {
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload! importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload!
deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload! deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload!
generateFrameworkStateOfApplicability(
input: GenerateFrameworkStateOfApplicabilityInput!
): GenerateFrameworkStateOfApplicabilityPayload!
exportFramework(input: ExportFrameworkInput!): ExportFrameworkPayload! exportFramework(input: ExportFrameworkInput!): ExportFrameworkPayload!
# Control mutations # Control mutations
createControl(input: CreateControlInput!): CreateControlPayload! createControl(input: CreateControlInput!): CreateControlPayload!
@@ -14173,14 +14121,6 @@ type Mutation {
} }
# Input Types # Input Types
input GenerateFrameworkStateOfApplicabilityInput {
frameworkId: ID!
}
type GenerateFrameworkStateOfApplicabilityPayload {
data: String!
}
input UpdateOrganizationContextInput { input UpdateOrganizationContextInput {
organizationId: ID! organizationId: ID!
summary: String @goField(omittable: true) summary: String @goField(omittable: true)
@@ -14743,8 +14683,6 @@ input CreateControlInput {
sectionTitle: String! sectionTitle: String!
name: String! name: String!
description: String description: String
status: ControlStatus!
exclusionJustification: String
bestPractice: Boolean! bestPractice: Boolean!
} }
@@ -14753,8 +14691,6 @@ input UpdateControlInput {
sectionTitle: String sectionTitle: String
name: String name: String
description: String @goField(omittable: true) description: String @goField(omittable: true)
status: ControlStatus
exclusionJustification: String
bestPractice: Boolean bestPractice: Boolean
} }
@@ -17835,17 +17771,6 @@ func (ec *executionContext) field_Mutation_generateDocumentChangelog_args(ctx co
return args, nil return args, nil
} }
func (ec *executionContext) field_Mutation_generateFrameworkStateOfApplicability_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNGenerateFrameworkStateOfApplicabilityInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateFrameworkStateOfApplicabilityInput)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_getTrustCenterFile_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { func (ec *executionContext) field_Mutation_getTrustCenterFile_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error var err error
args := map[string]any{} args := map[string]any{}
@@ -20211,10 +20136,6 @@ func (ec *executionContext) fieldContext_ApplicabilityStatement_control(_ contex
return ec.fieldContext_Control_name(ctx, field) return ec.fieldContext_Control_name(ctx, field)
case "description": case "description":
return ec.fieldContext_Control_description(ctx, field) return ec.fieldContext_Control_description(ctx, field)
case "status":
return ec.fieldContext_Control_status(ctx, field)
case "exclusionJustification":
return ec.fieldContext_Control_exclusionJustification(ctx, field)
case "bestPractice": case "bestPractice":
return ec.fieldContext_Control_bestPractice(ctx, field) return ec.fieldContext_Control_bestPractice(ctx, field)
case "regulatory": case "regulatory":
@@ -23225,64 +23146,6 @@ func (ec *executionContext) fieldContext_Control_description(_ context.Context,
return fc, nil return fc, nil
} }
func (ec *executionContext) _Control_status(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Control_status,
func(ctx context.Context) (any, error) {
return obj.Status, nil
},
nil,
ec.marshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus,
true,
true,
)
}
func (ec *executionContext) fieldContext_Control_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Control",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ControlStatus does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Control_exclusionJustification(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Control_exclusionJustification,
func(ctx context.Context) (any, error) {
return obj.ExclusionJustification, nil
},
nil,
ec.marshalOString2ᚖstring,
true,
false,
)
}
func (ec *executionContext) fieldContext_Control_exclusionJustification(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Control",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Control_bestPractice(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) { func (ec *executionContext) _Control_bestPractice(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -23960,10 +23823,6 @@ func (ec *executionContext) fieldContext_ControlEdge_node(_ context.Context, fie
return ec.fieldContext_Control_name(ctx, field) return ec.fieldContext_Control_name(ctx, field)
case "description": case "description":
return ec.fieldContext_Control_description(ctx, field) return ec.fieldContext_Control_description(ctx, field)
case "status":
return ec.fieldContext_Control_status(ctx, field)
case "exclusionJustification":
return ec.fieldContext_Control_exclusionJustification(ctx, field)
case "bestPractice": case "bestPractice":
return ec.fieldContext_Control_bestPractice(ctx, field) return ec.fieldContext_Control_bestPractice(ctx, field)
case "regulatory": case "regulatory":
@@ -32598,35 +32457,6 @@ func (ec *executionContext) fieldContext_GenerateDocumentChangelogPayload_change
return fc, nil return fc, nil
} }
func (ec *executionContext) _GenerateFrameworkStateOfApplicabilityPayload_data(ctx context.Context, field graphql.CollectedField, obj *types.GenerateFrameworkStateOfApplicabilityPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_GenerateFrameworkStateOfApplicabilityPayload_data,
func(ctx context.Context) (any, error) {
return obj.Data, nil
},
nil,
ec.marshalNString2string,
true,
true,
)
}
func (ec *executionContext) fieldContext_GenerateFrameworkStateOfApplicabilityPayload_data(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "GenerateFrameworkStateOfApplicabilityPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _GetTrustCenterFilePayload_trustCenterFile(ctx context.Context, field graphql.CollectedField, obj *types.GetTrustCenterFilePayload) (ret graphql.Marshaler) { func (ec *executionContext) _GetTrustCenterFilePayload_trustCenterFile(ctx context.Context, field graphql.CollectedField, obj *types.GetTrustCenterFilePayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -35189,51 +35019,6 @@ func (ec *executionContext) fieldContext_Mutation_deleteFramework(ctx context.Co
return fc, nil return fc, nil
} }
func (ec *executionContext) _Mutation_generateFrameworkStateOfApplicability(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Mutation_generateFrameworkStateOfApplicability,
func(ctx context.Context) (any, error) {
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().GenerateFrameworkStateOfApplicability(ctx, fc.Args["input"].(types.GenerateFrameworkStateOfApplicabilityInput))
},
nil,
ec.marshalNGenerateFrameworkStateOfApplicabilityPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateFrameworkStateOfApplicabilityPayload,
true,
true,
)
}
func (ec *executionContext) fieldContext_Mutation_generateFrameworkStateOfApplicability(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "data":
return ec.fieldContext_GenerateFrameworkStateOfApplicabilityPayload_data(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type GenerateFrameworkStateOfApplicabilityPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_generateFrameworkStateOfApplicability_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_exportFramework(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_exportFramework(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -53944,10 +53729,6 @@ func (ec *executionContext) fieldContext_UpdateControlPayload_control(_ context.
return ec.fieldContext_Control_name(ctx, field) return ec.fieldContext_Control_name(ctx, field)
case "description": case "description":
return ec.fieldContext_Control_description(ctx, field) return ec.fieldContext_Control_description(ctx, field)
case "status":
return ec.fieldContext_Control_status(ctx, field)
case "exclusionJustification":
return ec.fieldContext_Control_exclusionJustification(ctx, field)
case "bestPractice": case "bestPractice":
return ec.fieldContext_Control_bestPractice(ctx, field) return ec.fieldContext_Control_bestPractice(ctx, field)
case "regulatory": case "regulatory":
@@ -63141,7 +62922,7 @@ func (ec *executionContext) unmarshalInputCreateControlInput(ctx context.Context
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"frameworkId", "sectionTitle", "name", "description", "status", "exclusionJustification", "bestPractice"} fieldsInOrder := [...]string{"frameworkId", "sectionTitle", "name", "description", "bestPractice"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -63176,20 +62957,6 @@ func (ec *executionContext) unmarshalInputCreateControlInput(ctx context.Context
return it, err return it, err
} }
it.Description = data it.Description = data
case "status":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
data, err := ec.unmarshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx, v)
if err != nil {
return it, err
}
it.Status = data
case "exclusionJustification":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("exclusionJustification"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.ExclusionJustification = data
case "bestPractice": case "bestPractice":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bestPractice")) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bestPractice"))
data, err := ec.unmarshalNBoolean2bool(ctx, v) data, err := ec.unmarshalNBoolean2bool(ctx, v)
@@ -66924,33 +66691,6 @@ func (ec *executionContext) unmarshalInputGenerateDocumentChangelogInput(ctx con
return it, nil return it, nil
} }
func (ec *executionContext) unmarshalInputGenerateFrameworkStateOfApplicabilityInput(ctx context.Context, obj any) (types.GenerateFrameworkStateOfApplicabilityInput, error) {
var it types.GenerateFrameworkStateOfApplicabilityInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"frameworkId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "frameworkId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("frameworkId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.FrameworkID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputGetTrustCenterFileInput(ctx context.Context, obj any) (types.GetTrustCenterFileInput, error) { func (ec *executionContext) unmarshalInputGetTrustCenterFileInput(ctx context.Context, obj any) (types.GetTrustCenterFileInput, error) {
var it types.GetTrustCenterFileInput var it types.GetTrustCenterFileInput
asMap := map[string]any{} asMap := map[string]any{}
@@ -68231,7 +67971,7 @@ func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"id", "sectionTitle", "name", "description", "status", "exclusionJustification", "bestPractice"} fieldsInOrder := [...]string{"id", "sectionTitle", "name", "description", "bestPractice"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -68266,20 +68006,6 @@ func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context
return it, err return it, err
} }
it.Description = graphql.OmittableOf(data) it.Description = graphql.OmittableOf(data)
case "status":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
data, err := ec.unmarshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx, v)
if err != nil {
return it, err
}
it.Status = data
case "exclusionJustification":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("exclusionJustification"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.ExclusionJustification = data
case "bestPractice": case "bestPractice":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bestPractice")) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bestPractice"))
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
@@ -72533,13 +72259,6 @@ func (ec *executionContext) _Control(ctx context.Context, sel ast.SelectionSet,
} }
case "description": case "description":
out.Values[i] = ec._Control_description(ctx, field, obj) out.Values[i] = ec._Control_description(ctx, field, obj)
case "status":
out.Values[i] = ec._Control_status(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "exclusionJustification":
out.Values[i] = ec._Control_exclusionJustification(ctx, field, obj)
case "bestPractice": case "bestPractice":
out.Values[i] = ec._Control_bestPractice(ctx, field, obj) out.Values[i] = ec._Control_bestPractice(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
@@ -79243,45 +78962,6 @@ func (ec *executionContext) _GenerateDocumentChangelogPayload(ctx context.Contex
return out return out
} }
var generateFrameworkStateOfApplicabilityPayloadImplementors = []string{"GenerateFrameworkStateOfApplicabilityPayload"}
func (ec *executionContext) _GenerateFrameworkStateOfApplicabilityPayload(ctx context.Context, sel ast.SelectionSet, obj *types.GenerateFrameworkStateOfApplicabilityPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, generateFrameworkStateOfApplicabilityPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("GenerateFrameworkStateOfApplicabilityPayload")
case "data":
out.Values[i] = ec._GenerateFrameworkStateOfApplicabilityPayload_data(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var getTrustCenterFilePayloadImplementors = []string{"GetTrustCenterFilePayload"} var getTrustCenterFilePayloadImplementors = []string{"GetTrustCenterFilePayload"}
func (ec *executionContext) _GetTrustCenterFilePayload(ctx context.Context, sel ast.SelectionSet, obj *types.GetTrustCenterFilePayload) graphql.Marshaler { func (ec *executionContext) _GetTrustCenterFilePayload(ctx context.Context, sel ast.SelectionSet, obj *types.GetTrustCenterFilePayload) graphql.Marshaler {
@@ -80277,13 +79957,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ out.Invalids++
} }
case "generateFrameworkStateOfApplicability":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_generateFrameworkStateOfApplicability(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "exportFramework": case "exportFramework":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_exportFramework(ctx, field) return ec._Mutation_exportFramework(ctx, field)
@@ -93049,34 +92722,6 @@ var (
} }
) )
func (ec *executionContext) unmarshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx context.Context, v any) (coredata.ControlStatus, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx context.Context, sel ast.SelectionSet, v coredata.ControlStatus) graphql.Marshaler {
_ = sel
res := graphql.MarshalString(marshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
}
return res
}
var (
unmarshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus = map[string]coredata.ControlStatus{
"INCLUDED": coredata.ControlStatusIncluded,
"EXCLUDED": coredata.ControlStatusExcluded,
}
marshalNControlStatus2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus = map[coredata.ControlStatus]string{
coredata.ControlStatusIncluded: "INCLUDED",
coredata.ControlStatusExcluded: "EXCLUDED",
}
)
func (ec *executionContext) unmarshalNCountryCode2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCode(ctx context.Context, v any) (coredata.CountryCode, error) { func (ec *executionContext) unmarshalNCountryCode2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCode(ctx context.Context, v any) (coredata.CountryCode, error) {
tmp, err := graphql.UnmarshalString(v) tmp, err := graphql.UnmarshalString(v)
res := unmarshalNCountryCode2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCode[tmp] res := unmarshalNCountryCode2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCode[tmp]
@@ -96474,25 +96119,6 @@ func (ec *executionContext) marshalNGenerateDocumentChangelogPayload2ᚖgoᚗpro
return ec._GenerateDocumentChangelogPayload(ctx, sel, v) return ec._GenerateDocumentChangelogPayload(ctx, sel, v)
} }
func (ec *executionContext) unmarshalNGenerateFrameworkStateOfApplicabilityInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateFrameworkStateOfApplicabilityInput(ctx context.Context, v any) (types.GenerateFrameworkStateOfApplicabilityInput, error) {
res, err := ec.unmarshalInputGenerateFrameworkStateOfApplicabilityInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNGenerateFrameworkStateOfApplicabilityPayload2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateFrameworkStateOfApplicabilityPayload(ctx context.Context, sel ast.SelectionSet, v types.GenerateFrameworkStateOfApplicabilityPayload) graphql.Marshaler {
return ec._GenerateFrameworkStateOfApplicabilityPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNGenerateFrameworkStateOfApplicabilityPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateFrameworkStateOfApplicabilityPayload(ctx context.Context, sel ast.SelectionSet, v *types.GenerateFrameworkStateOfApplicabilityPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._GenerateFrameworkStateOfApplicabilityPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNGetTrustCenterFileInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGetTrustCenterFileInput(ctx context.Context, v any) (types.GetTrustCenterFileInput, error) { func (ec *executionContext) unmarshalNGetTrustCenterFileInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGetTrustCenterFileInput(ctx context.Context, v any) (types.GetTrustCenterFileInput, error) {
res, err := ec.unmarshalInputGetTrustCenterFileInput(ctx, v) res, err := ec.unmarshalInputGetTrustCenterFileInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -101595,36 +101221,6 @@ func (ec *executionContext) unmarshalOControlOrder2ᚖgoᚗproboᚗincᚋprobo
return &res, graphql.ErrorOnPath(ctx, err) return &res, graphql.ErrorOnPath(ctx, err)
} }
func (ec *executionContext) unmarshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx context.Context, v any) (*coredata.ControlStatus, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus(ctx context.Context, sel ast.SelectionSet, v *coredata.ControlStatus) graphql.Marshaler {
if v == nil {
return graphql.Null
}
_ = sel
_ = ctx
res := graphql.MarshalString(marshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus[*v])
return res
}
var (
unmarshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus = map[string]coredata.ControlStatus{
"INCLUDED": coredata.ControlStatusIncluded,
"EXCLUDED": coredata.ControlStatusExcluded,
}
marshalOControlStatus2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐControlStatus = map[coredata.ControlStatus]string{
coredata.ControlStatusIncluded: "INCLUDED",
coredata.ControlStatusExcluded: "EXCLUDED",
}
)
func (ec *executionContext) unmarshalOCountryCode2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCodeᚄ(ctx context.Context, v any) ([]coredata.CountryCode, error) { func (ec *executionContext) unmarshalOCountryCode2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐCountryCodeᚄ(ctx context.Context, v any) ([]coredata.CountryCode, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil

View File

@@ -57,13 +57,11 @@ func NewControl(control *coredata.Control) *Control {
Framework: &Framework{ Framework: &Framework{
ID: control.FrameworkID, ID: control.FrameworkID,
}, },
SectionTitle: control.SectionTitle, SectionTitle: control.SectionTitle,
Name: control.Name, Name: control.Name,
Description: control.Description, Description: control.Description,
Status: control.Status, BestPractice: control.BestPractice,
ExclusionJustification: control.ExclusionJustification, CreatedAt: control.CreatedAt,
BestPractice: control.BestPractice, UpdatedAt: control.UpdatedAt,
CreatedAt: control.CreatedAt,
UpdatedAt: control.UpdatedAt,
} }
} }

View File

@@ -179,26 +179,24 @@ type ContinualImprovementFilter struct {
} }
type Control struct { type Control struct {
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
Organization *Organization `json:"organization,omitempty"` Organization *Organization `json:"organization,omitempty"`
SectionTitle string `json:"sectionTitle"` SectionTitle string `json:"sectionTitle"`
Name string `json:"name"` Name string `json:"name"`
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
Status coredata.ControlStatus `json:"status"` BestPractice bool `json:"bestPractice"`
ExclusionJustification *string `json:"exclusionJustification,omitempty"` Regulatory bool `json:"regulatory"`
BestPractice bool `json:"bestPractice"` Contractual bool `json:"contractual"`
Regulatory bool `json:"regulatory"` RiskAssessment bool `json:"riskAssessment"`
Contractual bool `json:"contractual"` Framework *Framework `json:"framework"`
RiskAssessment bool `json:"riskAssessment"` Measures *MeasureConnection `json:"measures"`
Framework *Framework `json:"framework"` Documents *DocumentConnection `json:"documents"`
Measures *MeasureConnection `json:"measures"` Audits *AuditConnection `json:"audits"`
Documents *DocumentConnection `json:"documents"` Obligations *ObligationConnection `json:"obligations"`
Audits *AuditConnection `json:"audits"` Snapshots *SnapshotConnection `json:"snapshots"`
Obligations *ObligationConnection `json:"obligations"` CreatedAt time.Time `json:"createdAt"`
Snapshots *SnapshotConnection `json:"snapshots"` UpdatedAt time.Time `json:"updatedAt"`
CreatedAt time.Time `json:"createdAt"` Permission bool `json:"permission"`
UpdatedAt time.Time `json:"updatedAt"`
Permission bool `json:"permission"`
} }
func (Control) IsNode() {} func (Control) IsNode() {}
@@ -288,13 +286,11 @@ type CreateControlDocumentMappingPayload struct {
} }
type CreateControlInput struct { type CreateControlInput struct {
FrameworkID gid.GID `json:"frameworkId"` FrameworkID gid.GID `json:"frameworkId"`
SectionTitle string `json:"sectionTitle"` SectionTitle string `json:"sectionTitle"`
Name string `json:"name"` Name string `json:"name"`
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
Status coredata.ControlStatus `json:"status"` BestPractice bool `json:"bestPractice"`
ExclusionJustification *string `json:"exclusionJustification,omitempty"`
BestPractice bool `json:"bestPractice"`
} }
type CreateControlMeasureMappingInput struct { type CreateControlMeasureMappingInput struct {
@@ -1334,14 +1330,6 @@ type GenerateDocumentChangelogPayload struct {
Changelog string `json:"changelog"` Changelog string `json:"changelog"`
} }
type GenerateFrameworkStateOfApplicabilityInput struct {
FrameworkID gid.GID `json:"frameworkId"`
}
type GenerateFrameworkStateOfApplicabilityPayload struct {
Data string `json:"data"`
}
type GetTrustCenterFileInput struct { type GetTrustCenterFileInput struct {
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
} }
@@ -1994,13 +1982,11 @@ type UpdateContinualImprovementPayload struct {
} }
type UpdateControlInput struct { type UpdateControlInput struct {
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
SectionTitle *string `json:"sectionTitle,omitempty"` SectionTitle *string `json:"sectionTitle,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Description graphql.Omittable[*string] `json:"description,omitempty"` Description graphql.Omittable[*string] `json:"description,omitempty"`
Status *coredata.ControlStatus `json:"status,omitempty"` BestPractice *bool `json:"bestPractice,omitempty"`
ExclusionJustification *string `json:"exclusionJustification,omitempty"`
BestPractice *bool `json:"bestPractice,omitempty"`
} }
type UpdateControlPayload struct { type UpdateControlPayload struct {

View File

@@ -2511,28 +2511,6 @@ func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.Dele
}, nil }, nil
} }
// GenerateFrameworkStateOfApplicability is the resolver for the generateFrameworkStateOfApplicability field.
func (r *mutationResolver) GenerateFrameworkStateOfApplicability(ctx context.Context, input types.GenerateFrameworkStateOfApplicabilityInput) (*types.GenerateFrameworkStateOfApplicabilityPayload, error) {
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkStateOfApplicabilityGenerate); err != nil {
return nil, err
}
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
soa, err := prb.Frameworks.StateOfApplicability(ctx, input.FrameworkID)
if err != nil {
// TODO no panic use gqlutils.InternalError
panic(fmt.Errorf("cannot generate framework SOA: %w", err))
}
return &types.GenerateFrameworkStateOfApplicabilityPayload{
Data: fmt.Sprintf(
"data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,%s",
base64.StdEncoding.EncodeToString(soa),
),
}, nil
}
// ExportFramework is the resolver for the exportFramework field. // ExportFramework is the resolver for the exportFramework field.
func (r *mutationResolver) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) { func (r *mutationResolver) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) {
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkExport); err != nil { if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkExport); err != nil {
@@ -2569,13 +2547,11 @@ func (r *mutationResolver) CreateControl(ctx context.Context, input types.Create
control, err := prb.Controls.Create( control, err := prb.Controls.Create(
ctx, ctx,
probo.CreateControlRequest{ probo.CreateControlRequest{
FrameworkID: input.FrameworkID, FrameworkID: input.FrameworkID,
Name: input.Name, Name: input.Name,
Description: input.Description, Description: input.Description,
SectionTitle: input.SectionTitle, SectionTitle: input.SectionTitle,
Status: &input.Status, BestPractice: input.BestPractice,
ExclusionJustification: input.ExclusionJustification,
BestPractice: input.BestPractice,
}, },
) )
if err != nil { if err != nil {
@@ -2603,13 +2579,11 @@ func (r *mutationResolver) UpdateControl(ctx context.Context, input types.Update
control, err := prb.Controls.Update( control, err := prb.Controls.Update(
ctx, ctx,
probo.UpdateControlRequest{ probo.UpdateControlRequest{
ID: input.ID, ID: input.ID,
Name: input.Name, Name: input.Name,
Description: gqlutils.UnwrapOmittable(input.Description), Description: gqlutils.UnwrapOmittable(input.Description),
SectionTitle: input.SectionTitle, SectionTitle: input.SectionTitle,
Status: input.Status, BestPractice: input.BestPractice,
ExclusionJustification: input.ExclusionJustification,
BestPractice: input.BestPractice,
}, },
) )

View File

@@ -1182,12 +1182,10 @@ func (r *Resolver) AddControlTool(ctx context.Context, req *mcp.CallToolRequest,
control, err := svc.Controls.Create( control, err := svc.Controls.Create(
ctx, ctx,
probo.CreateControlRequest{ probo.CreateControlRequest{
FrameworkID: input.FrameworkID, FrameworkID: input.FrameworkID,
Name: input.Name, Name: input.Name,
Description: input.Description, Description: input.Description,
SectionTitle: input.SectionTitle, SectionTitle: input.SectionTitle,
Status: input.Status,
ExclusionJustification: input.ExclusionJustification,
}, },
) )
if err != nil { if err != nil {
@@ -1207,12 +1205,10 @@ func (r *Resolver) UpdateControlTool(ctx context.Context, req *mcp.CallToolReque
control, err := svc.Controls.Update( control, err := svc.Controls.Update(
ctx, ctx,
probo.UpdateControlRequest{ probo.UpdateControlRequest{
ID: input.ID, ID: input.ID,
Name: input.Name, Name: input.Name,
Description: UnwrapOmittable(input.Description), Description: UnwrapOmittable(input.Description),
SectionTitle: input.SectionTitle, SectionTitle: input.SectionTitle,
Status: input.Status,
ExclusionJustification: input.ExclusionJustification,
}, },
) )
if err != nil { if err != nil {

View File

@@ -2758,13 +2758,6 @@ components:
audit: audit:
$ref: "#/components/schemas/Audit" $ref: "#/components/schemas/Audit"
ControlStatus:
type: string
enum:
- INCLUDED
- EXCLUDED
go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.ControlStatus
ControlOrderField: ControlOrderField:
type: string type: string
enum: enum:
@@ -2793,7 +2786,6 @@ components:
- framework_id - framework_id
- section_title - section_title
- name - name
- status
- created_at - created_at
- updated_at - updated_at
properties: properties:
@@ -2817,14 +2809,6 @@ components:
- string - string
- "null" - "null"
description: Control description description: Control description
status:
$ref: "#/components/schemas/ControlStatus"
description: Control status
exclusion_justification:
type:
- string
- "null"
description: Exclusion justification
created_at: created_at:
type: string type: string
format: date-time format: date-time
@@ -2914,12 +2898,6 @@ components:
description: description:
type: string type: string
description: Control description description: Control description
status:
$ref: "#/components/schemas/ControlStatus"
description: Control status
exclusion_justification:
type: string
description: Exclusion justification
AddControlOutput: AddControlOutput:
type: object type: object
@@ -2947,16 +2925,6 @@ components:
type: ["string", "null"] type: ["string", "null"]
description: Control description description: Control description
go.probo.inc/mcpgen/omittable: true go.probo.inc/mcpgen/omittable: true
status:
anyOf:
- $ref: "#/components/schemas/ControlStatus"
description: Control status
- type: "null"
description: No status
description: Control status
exclusion_justification:
type: string
description: Exclusion justification
UpdateControlOutput: UpdateControlOutput:
type: object type: object

View File

@@ -20,16 +20,14 @@ import (
func NewControl(c *coredata.Control) *Control { func NewControl(c *coredata.Control) *Control {
return &Control{ return &Control{
ID: c.ID, ID: c.ID,
OrganizationID: c.OrganizationID, OrganizationID: c.OrganizationID,
SectionTitle: c.SectionTitle, SectionTitle: c.SectionTitle,
FrameworkID: c.FrameworkID, FrameworkID: c.FrameworkID,
Name: c.Name, Name: c.Name,
Description: c.Description, Description: c.Description,
Status: c.Status, CreatedAt: c.CreatedAt,
ExclusionJustification: c.ExclusionJustification, UpdatedAt: c.UpdatedAt,
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
} }
} }

View File

@@ -21,8 +21,8 @@ var (
AddAuditToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"audit":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"description":"Audit name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED","REJECTED","OUTDATED"]},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"},"valid_from":{"description":"Valid from date","format":"date-time"},"valid_until":{"description":"Valid until date","format":"date-time"}},"required":["id","organization_id","framework_id","state","trust_center_visibility","created_at","updated_at"]}},"required":["audit"]}`) AddAuditToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"audit":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"description":"Audit name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED","REJECTED","OUTDATED"]},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"},"valid_from":{"description":"Valid from date","format":"date-time"},"valid_until":{"description":"Valid until date","format":"date-time"}},"required":["id","organization_id","framework_id","state","trust_center_visibility","created_at","updated_at"]}},"required":["audit"]}`)
AddContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"type":"string","description":"Description"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"description":"Priority","anyOf":[{"type":"string","enum":["LOW","MEDIUM","HIGH"]},{"type":"null","description":"No priority"}]},"reference_id":{"type":"string","description":"Reference ID"},"source":{"type":"string","description":"Source"},"status":{"description":"Status","anyOf":[{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},{"type":"null","description":"No status"}]},"target_date":{"type":"string","description":"Target date","format":"date-time"}},"required":["organization_id","reference_id","owner_id"]}`) AddContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"type":"string","description":"Description"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"description":"Priority","anyOf":[{"type":"string","enum":["LOW","MEDIUM","HIGH"]},{"type":"null","description":"No priority"}]},"reference_id":{"type":"string","description":"Reference ID"},"source":{"type":"string","description":"Source"},"status":{"description":"Status","anyOf":[{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},{"type":"null","description":"No status"}]},"target_date":{"type":"string","description":"Target date","format":"date-time"}},"required":["organization_id","reference_id","owner_id"]}`)
AddContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`) AddContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`)
AddControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"type":"string","description":"Control description"},"exclusion_justification":{"type":"string","description":"Exclusion justification"},"framework_id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"status":{"type":"string","enum":["INCLUDED","EXCLUDED"]}},"required":["organization_id","framework_id","section_title","name"]}`) AddControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"type":"string","description":"Control description"},"framework_id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"}},"required":["organization_id","framework_id","section_title","name"]}`)
AddControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"exclusion_justification":{"description":"Exclusion justification"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"status":{"type":"string","enum":["INCLUDED","EXCLUDED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","status","created_at","updated_at"]}},"required":["control"]}`) AddControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","created_at","updated_at"]}},"required":["control"]}`)
AddDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"vendor_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Vendor IDs"}},"required":["organization_id","name","data_classification","owner_id"]}`) AddDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"vendor_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Vendor IDs"}},"required":["organization_id","name","data_classification","owner_id"]}`)
AddDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`) AddDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`)
AddDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"approver_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Approver IDs"},"classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"content":{"type":"string","description":"Document content"},"document_type":{"type":"string","enum":["OTHER","ISMS","POLICY","PROCEDURE"]},"organization_id":{"type":"string","format":"string"},"title":{"type":"string","description":"Document title"},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]}},"required":["organization_id","title","content","approver_ids","classification","document_type"]}`) AddDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"approver_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Approver IDs"},"classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"content":{"type":"string","description":"Document content"},"document_type":{"type":"string","enum":["OTHER","ISMS","POLICY","PROCEDURE"]},"organization_id":{"type":"string","format":"string"},"title":{"type":"string","description":"Document title"},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]}},"required":["organization_id","title","content","approver_ids","classification","document_type"]}`)
@@ -54,11 +54,11 @@ var (
DeleteDraftDocumentVersionToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"document_version_id":{"type":"string","format":"string"}},"required":["document_version_id"]}`) DeleteDraftDocumentVersionToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"document_version_id":{"type":"string","format":"string"}},"required":["document_version_id"]}`)
DeleteDraftDocumentVersionToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_document_version_id":{"type":"string","format":"string"}},"required":["deleted_document_version_id"]}`) DeleteDraftDocumentVersionToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_document_version_id":{"type":"string","format":"string"}},"required":["deleted_document_version_id"]}`)
DeleteMeetingToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) DeleteMeetingToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
DeleteTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
DeleteTaskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_task_id":{"type":"string","format":"string"}},"required":["deleted_task_id"]}`)
DeleteMeetingToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_meeting_id":{"type":"string","format":"string"}},"required":["deleted_meeting_id"]}`) DeleteMeetingToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_meeting_id":{"type":"string","format":"string"}},"required":["deleted_meeting_id"]}`)
DeleteRiskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) DeleteRiskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
DeleteRiskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_risk_id":{"type":"string","format":"string"}},"required":["deleted_risk_id"]}`) DeleteRiskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_risk_id":{"type":"string","format":"string"}},"required":["deleted_risk_id"]}`)
DeleteTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
DeleteTaskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"deleted_task_id":{"type":"string","format":"string"}},"required":["deleted_task_id"]}`)
GetAssetToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetAssetToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
GetAssetToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"asset":{"type":"object","properties":{"amount":{"type":"integer","description":"Asset amount"},"asset_type":{"type":"string","enum":["PHYSICAL","VIRTUAL"]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_types_stored":{"type":"string","description":"Data types stored"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Asset name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","amount","owner_id","asset_type","data_types_stored","created_at","updated_at"]}},"required":["asset"]}`) GetAssetToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"asset":{"type":"object","properties":{"amount":{"type":"integer","description":"Asset amount"},"asset_type":{"type":"string","enum":["PHYSICAL","VIRTUAL"]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_types_stored":{"type":"string","description":"Data types stored"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Asset name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","amount","owner_id","asset_type","data_types_stored","created_at","updated_at"]}},"required":["asset"]}`)
GetAuditToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetAuditToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
@@ -66,7 +66,7 @@ var (
GetContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
GetContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`) GetContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`)
GetControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
GetControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"exclusion_justification":{"description":"Exclusion justification"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"status":{"type":"string","enum":["INCLUDED","EXCLUDED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","status","created_at","updated_at"]}},"required":["control"]}`) GetControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","created_at","updated_at"]}},"required":["control"]}`)
GetDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
GetDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`) GetDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`)
GetDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`) GetDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"id":{"type":"string","format":"string"}},"required":["id"]}`)
@@ -108,7 +108,7 @@ var (
ListContinualImprovementsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","REFERENCE_ID","TARGET_DATE","STATUS","PRIORITY"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`) ListContinualImprovementsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","REFERENCE_ID","TARGET_DATE","STATUS","PRIORITY"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`)
ListContinualImprovementsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvements":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["continual_improvements"]}`) ListContinualImprovementsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvements":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["continual_improvements"]}`)
ListControlsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"query":{"type":"string","description":"Search query"}}},"framework_id":{"type":"string","format":"string"},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","SECTION_TITLE"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`) ListControlsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"query":{"type":"string","description":"Search query"}}},"framework_id":{"type":"string","format":"string"},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","SECTION_TITLE"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`)
ListControlsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"controls":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"exclusion_justification":{"description":"Exclusion justification"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"status":{"type":"string","enum":["INCLUDED","EXCLUDED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","status","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["controls"]}`) ListControlsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"controls":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["controls"]}`)
ListDataToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","NAME","DATA_CLASSIFICATION"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`) ListDataToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","NAME","DATA_CLASSIFICATION"]}},"required":["field","direction"]},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}},"required":["organization_id"]}`)
ListDataToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["data"]}`) ListDataToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"next_cursor":{"type":"string","format":"string"}},"required":["data"]}`)
ListDocumentVersionSignaturesToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"document_version_id":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"active_contract":{"type":"boolean","description":"Signatory contract status"},"states":{"type":"array","items":{"type":"string","enum":["REQUESTED","SIGNED"]},"description":"Signature states"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","SIGNED_AT"]}},"required":["field","direction"]},"size":{"type":"integer","description":"Page size"}},"required":["document_version_id"]}`) ListDocumentVersionSignaturesToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"cursor":{"type":"string","format":"string"},"document_version_id":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"active_contract":{"type":"boolean","description":"Signatory contract status"},"states":{"type":"array","items":{"type":"string","enum":["REQUESTED","SIGNED"]},"description":"Signature states"}}},"order_by":{"type":"object","properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","SIGNED_AT"]}},"required":["field","direction"]},"size":{"type":"integer","description":"Page size"}},"required":["document_version_id"]}`)
@@ -163,8 +163,8 @@ var (
UpdateAuditToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"audit":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"description":"Audit name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED","REJECTED","OUTDATED"]},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"},"valid_from":{"description":"Valid from date","format":"date-time"},"valid_until":{"description":"Valid until date","format":"date-time"}},"required":["id","organization_id","framework_id","state","trust_center_visibility","created_at","updated_at"]}},"required":["audit"]}`) UpdateAuditToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"audit":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"description":"Audit name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED","REJECTED","OUTDATED"]},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"},"valid_from":{"description":"Valid from date","format":"date-time"},"valid_until":{"description":"Valid until date","format":"date-time"}},"required":["id","organization_id","framework_id","state","trust_center_visibility","created_at","updated_at"]}},"required":["audit"]}`)
UpdateContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"description":"Description"},"id":{"type":"string","format":"string"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"priority":{"description":"Priority","anyOf":[{"type":"string","enum":["LOW","MEDIUM","HIGH"]},{"type":"null","description":"No priority"}]},"reference_id":{"type":"string","description":"Reference ID"},"source":{"description":"Source"},"status":{"description":"Status","anyOf":[{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},{"type":"null","description":"No status"}]},"target_date":{"description":"Target date","format":"date-time"}},"required":["id"]}`) UpdateContinualImprovementToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"description":"Description"},"id":{"type":"string","format":"string"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"priority":{"description":"Priority","anyOf":[{"type":"string","enum":["LOW","MEDIUM","HIGH"]},{"type":"null","description":"No priority"}]},"reference_id":{"type":"string","description":"Reference ID"},"source":{"description":"Source"},"status":{"description":"Status","anyOf":[{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},{"type":"null","description":"No status"}]},"target_date":{"description":"Target date","format":"date-time"}},"required":["id"]}`)
UpdateContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`) UpdateContinualImprovementToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"continual_improvement":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Description"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"priority":{"type":"string","enum":["LOW","MEDIUM","HIGH"]},"reference_id":{"type":"string","description":"Reference ID"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"target_date":{"description":"Target date","format":"date-time"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","reference_id","owner_id","status","priority","created_at","updated_at"]}},"required":["continual_improvement"]}`)
UpdateControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"description":"Control description"},"exclusion_justification":{"type":"string","description":"Exclusion justification"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"section_title":{"type":"string","description":"Section title"},"status":{"description":"Control status","anyOf":[{"type":"string","enum":["INCLUDED","EXCLUDED"]},{"type":"null","description":"No status"}]}},"required":["id"]}`) UpdateControlToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"description":{"description":"Control description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"section_title":{"type":"string","description":"Section title"}},"required":["id"]}`)
UpdateControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"exclusion_justification":{"description":"Exclusion justification"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"status":{"type":"string","enum":["INCLUDED","EXCLUDED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","status","created_at","updated_at"]}},"required":["control"]}`) UpdateControlToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"control":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Control description"},"framework_id":{"type":"string","format":"string"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Control name"},"organization_id":{"type":"string","format":"string"},"section_title":{"type":"string","description":"Section title"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","framework_id","section_title","name","created_at","updated_at"]}},"required":["control"]}`)
UpdateDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"vendor_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Vendor IDs"}},"required":["id"]}`) UpdateDatumToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"vendor_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Vendor IDs"}},"required":["id"]}`)
UpdateDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`) UpdateDatumToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"datum":{"type":"object","properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"data_classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Datum name"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}},"required":["id","organization_id","name","data_classification","owner_id","created_at","updated_at"]}},"required":["datum"]}`)
UpdateDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"approver_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Approver IDs"},"classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"document_type":{"type":"string","enum":["OTHER","ISMS","POLICY","PROCEDURE"]},"id":{"type":"string","format":"string"},"title":{"type":"string","description":"Document title"},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]}},"required":["id"]}`) UpdateDocumentToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","properties":{"approver_ids":{"type":"array","items":{"type":"string","format":"string"},"description":"Approver IDs"},"classification":{"type":"string","enum":["PUBLIC","INTERNAL","CONFIDENTIAL","SECRET"]},"document_type":{"type":"string","enum":["OTHER","ISMS","POLICY","PROCEDURE"]},"id":{"type":"string","format":"string"},"title":{"type":"string","description":"Document title"},"trust_center_visibility":{"type":"string","enum":["NONE","PRIVATE","PUBLIC"]}},"required":["id"]}`)
@@ -564,8 +564,6 @@ type AddContinualImprovementOutput struct {
type AddControlInput struct { type AddControlInput struct {
// Control description // Control description
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
// Exclusion justification
ExclusionJustification *string `json:"exclusion_justification,omitempty"`
// Framework ID // Framework ID
FrameworkID gid.GID `json:"framework_id"` FrameworkID gid.GID `json:"framework_id"`
// Control name // Control name
@@ -574,8 +572,6 @@ type AddControlInput struct {
OrganizationID gid.GID `json:"organization_id"` OrganizationID gid.GID `json:"organization_id"`
// Section title // Section title
SectionTitle string `json:"section_title"` SectionTitle string `json:"section_title"`
// Control status
Status *coredata.ControlStatus `json:"status,omitempty"`
} }
// AddControlOutput represents the schema // AddControlOutput represents the schema
@@ -975,8 +971,6 @@ type Control struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
// Control description // Control description
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
// Exclusion justification
ExclusionJustification *string `json:"exclusion_justification,omitempty"`
// Framework ID // Framework ID
FrameworkID gid.GID `json:"framework_id"` FrameworkID gid.GID `json:"framework_id"`
// Control ID // Control ID
@@ -987,8 +981,6 @@ type Control struct {
OrganizationID gid.GID `json:"organization_id"` OrganizationID gid.GID `json:"organization_id"`
// Section title // Section title
SectionTitle string `json:"section_title"` SectionTitle string `json:"section_title"`
// Control status
Status coredata.ControlStatus `json:"status"`
// Update timestamp // Update timestamp
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
@@ -1088,6 +1080,18 @@ type DeleteRiskOutput struct {
DeletedRiskID gid.GID `json:"deleted_risk_id"` DeletedRiskID gid.GID `json:"deleted_risk_id"`
} }
// DeleteTaskInput represents the schema
type DeleteTaskInput struct {
// Task ID
ID gid.GID `json:"id"`
}
// DeleteTaskOutput represents the schema
type DeleteTaskOutput struct {
// Deleted task ID
DeletedTaskID gid.GID `json:"deleted_task_id"`
}
// Document represents the schema // Document represents the schema
type Document struct { type Document struct {
// Approver IDs // Approver IDs
@@ -2171,18 +2175,6 @@ type UnassignTaskOutput struct {
Task *Task `json:"task"` Task *Task `json:"task"`
} }
// DeleteTaskInput represents the schema
type DeleteTaskInput struct {
// Task ID
ID gid.GID `json:"id"`
}
// DeleteTaskOutput represents the schema
type DeleteTaskOutput struct {
// Deleted task ID
DeletedTaskID gid.GID `json:"deleted_task_id"`
}
// UnlinkControlAuditInput represents the schema // UnlinkControlAuditInput represents the schema
type UnlinkControlAuditInput struct { type UnlinkControlAuditInput struct {
// Audit ID // Audit ID
@@ -2304,16 +2296,12 @@ type UpdateContinualImprovementOutput struct {
type UpdateControlInput struct { type UpdateControlInput struct {
// Control description // Control description
Description mcp.Omittable[*string] `json:"description,omitempty"` Description mcp.Omittable[*string] `json:"description,omitempty"`
// Exclusion justification
ExclusionJustification *string `json:"exclusion_justification,omitempty"`
// Control ID // Control ID
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
// Control name // Control name
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
// Section title // Section title
SectionTitle *string `json:"section_title,omitempty"` SectionTitle *string `json:"section_title,omitempty"`
// Control status
Status *coredata.ControlStatus `json:"status,omitempty"`
} }
// UpdateControlOutput represents the schema // UpdateControlOutput represents the schema

View File

@@ -1,56 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import "github.com/xuri/excelize/v2"
type Applicability struct {
Value string
IsApplicable bool
}
func NewApplicability(value string, isApplicable bool) Applicability {
return Applicability{
Value: value,
IsApplicable: isApplicable,
}
}
func (a Applicability) String() string {
return a.Value
}
func (a Applicability) MarshalExcel() ExcelValue {
color := "FFB6C1" // Light red for not applicable
if a.IsApplicable {
color = "90EE90" // Light green for applicable
}
return ExcelValue{
Value: a.Value,
Style: &excelize.Style{
Border: []excelize.Border{
{Type: "left", Color: "000000", Style: 1},
{Type: "top", Color: "000000", Style: 1},
{Type: "bottom", Color: "000000", Style: 1},
{Type: "right", Color: "000000", Style: 1},
},
Fill: excelize.Fill{Type: "pattern", Color: []string{color}, Pattern: 1},
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
},
Validation: []string{"Yes", "No"},
Width: 12,
}
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import "github.com/xuri/excelize/v2"
type ExcelValue struct {
Value interface{}
Style *excelize.Style
Validation []string
Width float64
}
type ExcelMarshaler interface {
MarshalExcel() ExcelValue
}

View File

@@ -1,101 +0,0 @@
// Copyright (c) 2025 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.
package soagen
type FieldConfiguration struct {
Field string
Columns []string
FilterColumns []string // Specific columns that should have filters (subset of Columns)
Width []float64 // Width for each column
DefaultWidth float64 // Default width if not specified
HasFilter bool // Whether to enable auto-filter
}
var (
soaFieldConfigs = []FieldConfiguration{
{
Field: "SectionTitle",
Columns: []string{"A"},
FilterColumns: []string{},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: false,
},
{
Field: "ControlName",
Columns: []string{"B"},
FilterColumns: []string{},
Width: []float64{35},
DefaultWidth: 35,
HasFilter: false,
},
{
Field: "Applicability",
Columns: []string{"C"},
FilterColumns: []string{"C"},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: true,
},
{
Field: "ExclusionJustification",
Columns: []string{"D"},
FilterColumns: []string{},
Width: []float64{25},
DefaultWidth: 25,
HasFilter: false,
},
{
Field: "Regulatory",
Columns: []string{"E"},
FilterColumns: []string{},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: false,
},
{
Field: "Contractual",
Columns: []string{"F"},
FilterColumns: []string{},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: false,
},
{
Field: "BestPractice",
Columns: []string{"G"},
FilterColumns: []string{},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: false,
},
{
Field: "RiskAssessment",
Columns: []string{"H"},
FilterColumns: []string{},
Width: []float64{12},
DefaultWidth: 12,
HasFilter: false,
},
{
Field: "SecurityMeasures",
Columns: []string{"I"},
FilterColumns: []string{},
Width: []float64{40},
DefaultWidth: 40,
HasFilter: false,
},
}
)

View File

@@ -1,319 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import (
"fmt"
"strings"
"github.com/xuri/excelize/v2"
)
func GenerateSOAExcel(data SOAData) ([]byte, error) {
f := excelize.NewFile()
defer func() { _ = f.Close() }()
sheetName := "State of Applicability"
_, err := f.NewSheet(sheetName)
if err != nil {
return nil, fmt.Errorf("cannot create sheet: %w", err)
}
if err := f.DeleteSheet("Sheet1"); err != nil {
return nil, fmt.Errorf("cannot delete sheet: %w", err)
}
if err := setupSOAHeader(f, sheetName); err != nil {
return nil, fmt.Errorf("cannot setup Excel header: %w", err)
}
if err := populateSOAData(f, sheetName, data.Rows); err != nil {
return nil, fmt.Errorf("cannot populate Excel data: %w", err)
}
if err := applySOAFinalFormatting(f, sheetName, len(data.Rows)); err != nil {
return nil, fmt.Errorf("cannot apply final formatting: %w", err)
}
buf, err := f.WriteToBuffer()
if err != nil {
return nil, fmt.Errorf("cannot write Excel file to buffer: %w", err)
}
return buf.Bytes(), nil
}
func setupSOAHeader(f *excelize.File, sheetName string) error {
headerStyle, err := f.NewStyle(getHeaderStyle())
if err != nil {
return err
}
cellStyle, err := f.NewStyle(getCellStyle())
if err != nil {
return err
}
return applyHeaderLayout(f, sheetName, getSOAHeaderLayout(), headerStyle, cellStyle)
}
func populateSOAData(f *excelize.File, sheetName string, rows []SOARowData) error {
dataStartRow := 8
for i, rowData := range rows {
isFirstRow := i == 0
filterColumns, err := writeSOARow(f, sheetName, dataStartRow+i, rowData, isFirstRow)
if err != nil {
return fmt.Errorf("cannot write row %d: %w", dataStartRow+i, err)
}
if isFirstRow && len(filterColumns) > 0 {
if err := applySOAAutoFilter(f, sheetName, filterColumns); err != nil {
return fmt.Errorf("cannot apply auto filter: %w", err)
}
}
}
return nil
}
func writeSOARow(f *excelize.File, sheetName string, row int, data SOARowData, isFirstRow bool) ([]string, error) {
var allFilterColumns []string
fields := []struct {
name string
value interface{}
}{
{"SectionTitle", data.SectionTitle},
{"ControlName", data.ControlName},
{"Applicability", data.Applicability},
{"Regulatory", data.Regulatory},
{"Contractual", data.Contractual},
{"BestPractice", data.BestPractice},
{"RiskAssessment", data.RiskAssessment},
{"ExclusionJustification", data.ExclusionJustification},
{"SecurityMeasures", data.SecurityMeasures},
}
for _, field := range fields {
fieldConfig := getSOAFieldConfig(field.name)
if fieldConfig == nil {
continue
}
filterColumns, err := processField(f, sheetName, row, field.value, *fieldConfig, isFirstRow)
if err != nil {
return nil, fmt.Errorf("cannot write field %s: %w", field.name, err)
}
allFilterColumns = append(allFilterColumns, filterColumns...)
}
return allFilterColumns, nil
}
func getSOAFieldConfig(fieldName string) *FieldConfiguration {
for _, config := range soaFieldConfigs {
if config.Field == fieldName {
return &config
}
}
return nil
}
func applySOAAutoFilter(f *excelize.File, sheetName string, filterColumns []string) error {
if len(filterColumns) == 0 {
return nil
}
firstCol, lastCol := filterColumns[0], filterColumns[0]
for _, col := range filterColumns {
if col < firstCol {
firstCol = col
}
if col > lastCol {
lastCol = col
}
}
filterRange := fmt.Sprintf("%s7:%s1000", firstCol, lastCol)
return f.AutoFilter(sheetName, filterRange, []excelize.AutoFilterOptions{})
}
func applySOAFinalFormatting(f *excelize.File, sheetName string, dataRowCount int) error {
if dataRowCount > 0 {
headerRowHeight := 30.0
_ = f.SetRowHeight(sheetName, 6, headerRowHeight)
_ = f.SetRowHeight(sheetName, 7, headerRowHeight)
return f.SetPanes(sheetName, &excelize.Panes{
Freeze: true,
XSplit: 0,
YSplit: 7,
TopLeftCell: "A8",
})
}
return nil
}
func processField(f *excelize.File, sheetName string, row int, value interface{}, config FieldConfiguration, isFirstRow bool) ([]string, error) {
switch v := value.(type) {
case ExcelMarshaler:
marshaler := v
excelValue := marshaler.MarshalExcel()
styleID, err := createCellStyle(f, excelValue.Style)
if err != nil {
return nil, err
}
return writeSingleColumnField(f, sheetName, row, excelValue, &config, styleID, isFirstRow)
case string:
if len(config.Columns) == 0 {
return []string{}, nil
}
col := config.Columns[0]
cellRef := fmt.Sprintf("%s%d", col, row)
if err := f.SetCellValue(sheetName, cellRef, v); err != nil {
return nil, fmt.Errorf("cannot set cell value: %w", err)
}
textStyleID, err := createCellStyle(f, getTextStyle())
if err != nil {
return nil, fmt.Errorf("cannot create text style: %w", err)
}
if err := f.SetCellStyle(sheetName, cellRef, cellRef, textStyleID); err != nil {
return nil, fmt.Errorf("cannot set cell style: %w", err)
}
if isFirstRow {
width := config.DefaultWidth
if len(config.Width) > 0 {
width = config.Width[0]
}
if err := f.SetColWidth(sheetName, col, col, width); err != nil {
return nil, fmt.Errorf("cannot set column width: %w", err)
}
}
if config.HasFilter {
if len(config.FilterColumns) > 0 {
return config.FilterColumns, nil
}
return []string{col}, nil
}
return []string{}, nil
case []string:
var formattedLines []string
for _, item := range v {
lines := strings.Split(item, "\n")
for _, line := range lines {
if strings.TrimSpace(line) != "" {
formattedLines = append(formattedLines, "• "+strings.TrimSpace(line))
}
}
}
joinedValue := strings.Join(formattedLines, "\n")
if len(config.Columns) == 0 {
return []string{}, nil
}
col := config.Columns[0]
cellRef := fmt.Sprintf("%s%d", col, row)
if err := f.SetCellValue(sheetName, cellRef, joinedValue); err != nil {
return nil, fmt.Errorf("cannot set cell value: %w", err)
}
textStyleID, err := createCellStyle(f, getTextStyle())
if err != nil {
return nil, fmt.Errorf("cannot create text style: %w", err)
}
if err := f.SetCellStyle(sheetName, cellRef, cellRef, textStyleID); err != nil {
return nil, fmt.Errorf("cannot set cell style: %w", err)
}
if isFirstRow {
width := config.DefaultWidth
if len(config.Width) > 0 {
width = config.Width[0]
}
if err := f.SetColWidth(sheetName, col, col, width); err != nil {
return nil, fmt.Errorf("cannot set column width: %w", err)
}
}
if config.HasFilter {
if len(config.FilterColumns) > 0 {
return config.FilterColumns, nil
}
return []string{col}, nil
}
return []string{}, nil
case *bool:
yesNoValue := boolToYesNo(v)
excelValue := yesNoValue.MarshalExcel()
styleID, err := createCellStyle(f, excelValue.Style)
if err != nil {
return nil, err
}
return writeSingleColumnField(f, sheetName, row, excelValue, &config, styleID, isFirstRow)
default:
return nil, fmt.Errorf("no handler found for field type: %T", value)
}
}
func GenerateExcel(data SOAData) ([]byte, error) {
return GenerateSOAExcel(data)
}
func writeSingleColumnField(f *excelize.File, sheetName string, row int, excelValue ExcelValue, colDef *FieldConfiguration, styleID int, isFirstRow bool) ([]string, error) {
if len(colDef.Columns) == 0 {
return []string{}, nil
}
col := colDef.Columns[0]
cellRef := fmt.Sprintf("%s%d", col, row)
_ = f.SetCellValue(sheetName, cellRef, excelValue.Value)
_ = f.SetCellStyle(sheetName, cellRef, cellRef, styleID)
if isFirstRow {
if err := applyDataValidation(f, sheetName, col, row, excelValue.Validation); err != nil {
return nil, err
}
if err := setColumnWidth(f, sheetName, col, excelValue.Width); err != nil {
return nil, err
}
}
if colDef.HasFilter {
if len(colDef.FilterColumns) > 0 {
return colDef.FilterColumns, nil
}
return []string{col}, nil
}
return []string{}, nil
}

View File

@@ -1,134 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import (
"fmt"
"time"
"github.com/xuri/excelize/v2"
)
type HeaderCell struct {
Cell string
Value string
Style string // "header" or "cell"
}
type MergedCell struct {
StartCell string
EndCell string
}
type HeaderLayout struct {
InfoHeader []HeaderCell
InfoData []HeaderCell
MainHeader []HeaderCell
SubHeader []HeaderCell
Merges []MergedCell
}
func getSOAHeaderLayout() HeaderLayout {
return HeaderLayout{
InfoHeader: []HeaderCell{
{"A2", "Version", "header"},
{"C2", "Date", "header"},
{"D2", "Comment", "header"},
{"E2", "Author", "header"},
{"F2", "Approver", "header"},
},
InfoData: []HeaderCell{
{"A3", "1.0", "cell"},
{"C3", time.Now().Format("01/02/2006"), "cell"},
{"D3", "Initial SoA", "cell"},
{"E3", "System Admin", "cell"},
{"F3", "Security Manager", "cell"},
},
MainHeader: []HeaderCell{
{"A6", "Control", "header"},
{"B6", "Control name", "header"},
{"C6", "Applicability", "header"},
{"D6", "Justification for exclusion", "header"},
{"E6", "Justification for inclusion", "header"},
{"F6", "Justification for inclusion", "header"},
{"G6", "Justification for inclusion", "header"},
{"H6", "Justification for inclusion", "header"},
{"I6", "List of security measure or policy", "header"},
},
SubHeader: []HeaderCell{
{"A7", "Control", "header"},
{"B7", "Control name", "header"},
{"C7", "Applicability", "header"},
{"D7", "Justification for exclusion", "header"},
{"E7", "Regulatory", "header"},
{"F7", "Contractual", "header"},
{"G7", "Best practice", "header"},
{"H7", "Risk assessment", "header"},
{"I7", "List of security measure or policy", "header"},
},
Merges: []MergedCell{
{"A6", "A7"},
{"B6", "B7"},
{"C6", "C7"},
{"D6", "D7"},
{"E6", "H6"},
{"I6", "I7"},
},
}
}
func applyHeaderLayout(f *excelize.File, sheetName string, layout HeaderLayout, headerStyle, cellStyle int) error {
if err := applyCells(f, sheetName, layout.InfoHeader, headerStyle, cellStyle); err != nil {
return err
}
if err := applyCells(f, sheetName, layout.InfoData, headerStyle, cellStyle); err != nil {
return err
}
if err := applyCells(f, sheetName, layout.MainHeader, headerStyle, cellStyle); err != nil {
return err
}
if err := applyCells(f, sheetName, layout.SubHeader, headerStyle, cellStyle); err != nil {
return err
}
for _, merge := range layout.Merges {
if err := f.MergeCell(sheetName, merge.StartCell, merge.EndCell); err != nil {
return err
}
}
return nil
}
func applyCells(f *excelize.File, sheetName string, cells []HeaderCell, headerStyle, cellStyle int) error {
for _, cell := range cells {
if err := f.SetCellValue(sheetName, cell.Cell, cell.Value); err != nil {
return fmt.Errorf("cannot set cell value: %w", err)
}
style := cellStyle
if cell.Style == "header" {
style = headerStyle
}
if err := f.SetCellStyle(sheetName, cell.Cell, cell.Cell, style); err != nil {
return fmt.Errorf("cannot set cell style: %w", err)
}
}
return nil
}

View File

@@ -1,33 +0,0 @@
// Copyright (c) 2025 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.
package soagen
// SOARowData represents a single row in the State of Applicability Excel
type SOARowData struct {
SectionTitle string
ControlName string
Applicability Applicability
Regulatory *bool
Contractual *bool
BestPractice *bool
RiskAssessment *bool
ExclusionJustification string
SecurityMeasures []string
}
// SOAData contains all the data needed for State of Applicability generation
type SOAData struct {
Rows []SOARowData
}

View File

@@ -1,95 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import (
"fmt"
"github.com/xuri/excelize/v2"
)
// getTextStyle returns the standard text style for string fields
func getTextStyle() *excelize.Style {
return &excelize.Style{
Border: []excelize.Border{
{Type: "left", Color: "#000000", Style: 1},
{Type: "top", Color: "#000000", Style: 1},
{Type: "bottom", Color: "#000000", Style: 1},
{Type: "right", Color: "#000000", Style: 1},
},
Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true},
}
}
// getHeaderStyle returns the standard header style
func getHeaderStyle() *excelize.Style {
return &excelize.Style{
Font: &excelize.Font{Bold: true, Size: 10, Color: "#000000"},
Fill: excelize.Fill{Type: "pattern", Color: []string{"#D9D9D9"}, Pattern: 1},
Border: []excelize.Border{
{Type: "left", Color: "#000000", Style: 1},
{Type: "top", Color: "#000000", Style: 1},
{Type: "bottom", Color: "#000000", Style: 1},
{Type: "right", Color: "#000000", Style: 1},
},
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
}
}
// getCellStyle returns the standard cell style
func getCellStyle() *excelize.Style {
return &excelize.Style{
Border: []excelize.Border{
{Type: "left", Color: "#000000", Style: 1},
{Type: "top", Color: "#000000", Style: 1},
{Type: "bottom", Color: "#000000", Style: 1},
{Type: "right", Color: "#000000", Style: 1},
},
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
}
}
func createCellStyle(f *excelize.File, style *excelize.Style) (int, error) {
styleID, err := f.NewStyle(style)
if err != nil {
return 0, fmt.Errorf("cannot create style: %w", err)
}
return styleID, nil
}
func applyDataValidation(f *excelize.File, sheetName, col string, row int, validation []string) error {
if len(validation) == 0 {
return nil
}
dv := excelize.NewDataValidation(true)
dv.Sqref = fmt.Sprintf("%s%d:%s1000", col, row, col) // Apply to reasonable range
_ = dv.SetDropList(validation)
dv.SetError(excelize.DataValidationErrorStyleStop, "Invalid Input", "Please select from the dropdown list.")
if err := f.AddDataValidation(sheetName, dv); err != nil {
return fmt.Errorf("cannot add data validation: %w", err)
}
return nil
}
func setColumnWidth(f *excelize.File, sheetName, col string, width float64) error {
if width > 0 {
if err := f.SetColWidth(sheetName, col, col, width); err != nil {
return fmt.Errorf("cannot set column width: %w", err)
}
}
return nil
}

View File

@@ -1,60 +0,0 @@
// Copyright (c) 2025 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.
package soagen
import "github.com/xuri/excelize/v2"
// YesNo represents a YES/NO/Empty value
type YesNo string
const (
Yes YesNo = "YES"
No YesNo = "NO"
Empty YesNo = ""
)
// String returns the string representation of YesNo
func (yn YesNo) String() string {
return string(yn)
}
// MarshalExcel implements ExcelMarshaler for YesNo
func (yn YesNo) MarshalExcel() ExcelValue {
return ExcelValue{
Value: yn.String(),
Style: &excelize.Style{
Border: []excelize.Border{
{Type: "left", Color: "#000000", Style: 1},
{Type: "top", Color: "#000000", Style: 1},
{Type: "bottom", Color: "#000000", Style: 1},
{Type: "right", Color: "#000000", Style: 1},
},
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
},
Validation: []string{string(Yes), string(No), string(Empty)},
Width: 12,
}
}
// boolToYesNo converts *bool to YesNo type for Excel output
func boolToYesNo(b *bool) YesNo {
if b == nil {
return Empty
}
if *b {
return Yes
}
return No
}

View File

@@ -154,8 +154,7 @@ func TestValidationErrors_Methods(t *testing.T) {
first := errors.First() first := errors.First()
if first == nil { if first == nil {
t.Fatal("expected first error") t.Fatal("expected first error")
} } else if first.Field != "email" {
if first.Field != "email" {
t.Errorf("expected first field to be 'email', got '%s'", first.Field) t.Errorf("expected first field to be 'email', got '%s'", first.Field)
} }
}) })

View File

@@ -40,8 +40,7 @@ func TestMinItems(t *testing.T) {
err := MinItems(2)(&items) err := MinItems(2)(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error") t.Fatal("expected validation error")
} } else if err.Code != ErrorCodeOutOfRange {
if err.Code != ErrorCodeOutOfRange {
t.Errorf("expected error code %s, got %s", ErrorCodeOutOfRange, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeOutOfRange, err.Code)
} }
}) })
@@ -85,8 +84,7 @@ func TestMaxItems(t *testing.T) {
err := MaxItems(2)(&items) err := MaxItems(2)(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error") t.Fatal("expected validation error")
} } else if err.Code != ErrorCodeOutOfRange {
if err.Code != ErrorCodeOutOfRange {
t.Errorf("expected error code %s, got %s", ErrorCodeOutOfRange, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeOutOfRange, err.Code)
} }
}) })
@@ -114,8 +112,7 @@ func TestUniqueItems(t *testing.T) {
err := UniqueItems()(&items) err := UniqueItems()(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error") t.Fatal("expected validation error")
} } else if err.Code != ErrorCodeInvalidFormat {
if err.Code != ErrorCodeInvalidFormat {
t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code)
} }
}) })
@@ -157,12 +154,13 @@ func TestUniqueItems(t *testing.T) {
err := UniqueItems()(&items) err := UniqueItems()(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error for non-comparable type") t.Fatal("expected validation error for non-comparable type")
} } else {
if err.Code != ErrorCodeInvalidFormat { if err.Code != ErrorCodeInvalidFormat {
t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code)
} }
if err.Message != "cannot validate uniqueness for non-comparable types" { if err.Message != "cannot validate uniqueness for non-comparable types" {
t.Errorf("unexpected error message: %s", err.Message) t.Errorf("unexpected error message: %s", err.Message)
}
} }
}) })
@@ -171,8 +169,7 @@ func TestUniqueItems(t *testing.T) {
err := UniqueItems()(&items) err := UniqueItems()(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error for non-comparable type") t.Fatal("expected validation error for non-comparable type")
} } else if err.Code != ErrorCodeInvalidFormat {
if err.Code != ErrorCodeInvalidFormat {
t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code)
} }
}) })
@@ -185,8 +182,7 @@ func TestUniqueItems(t *testing.T) {
err := UniqueItems()(&items) err := UniqueItems()(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error for non-comparable type") t.Fatal("expected validation error for non-comparable type")
} } else if err.Code != ErrorCodeInvalidFormat {
if err.Code != ErrorCodeInvalidFormat {
t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code)
} }
}) })
@@ -212,8 +208,7 @@ func TestUniqueItems(t *testing.T) {
err := UniqueItems()(&items) err := UniqueItems()(&items)
if err == nil { if err == nil {
t.Fatal("expected validation error for duplicate comparable structs") t.Fatal("expected validation error for duplicate comparable structs")
} } else if err.Code != ErrorCodeInvalidFormat {
if err.Code != ErrorCodeInvalidFormat {
t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeInvalidFormat, err.Code)
} }
}) })

View File

@@ -103,8 +103,7 @@ func TestRequired(t *testing.T) {
err := Required()(&str) err := Required()(&str)
if err == nil { if err == nil {
t.Fatal("expected validation error") t.Fatal("expected validation error")
} } else if err.Code != ErrorCodeRequired {
if err.Code != ErrorCodeRequired {
t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code)
} }
}) })
@@ -193,8 +192,7 @@ func TestRequired(t *testing.T) {
err := Required()(slice) err := Required()(slice)
if err == nil { if err == nil {
t.Fatal("expected validation error for empty []string slice") t.Fatal("expected validation error for empty []string slice")
} } else if err.Code != ErrorCodeRequired {
if err.Code != ErrorCodeRequired {
t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code)
} }
}) })
@@ -212,8 +210,7 @@ func TestRequired(t *testing.T) {
err := Required()(slice) err := Required()(slice)
if err == nil { if err == nil {
t.Fatal("expected validation error for empty []int slice") t.Fatal("expected validation error for empty []int slice")
} } else if err.Code != ErrorCodeRequired {
if err.Code != ErrorCodeRequired {
t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code)
} }
}) })
@@ -234,8 +231,7 @@ func TestRequired(t *testing.T) {
err := Required()(slice) err := Required()(slice)
if err == nil { if err == nil {
t.Fatal("expected validation error for empty custom type slice") t.Fatal("expected validation error for empty custom type slice")
} } else if err.Code != ErrorCodeRequired {
if err.Code != ErrorCodeRequired {
t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code) t.Errorf("expected error code %s, got %s", ErrorCodeRequired, err.Code)
} }
}) })