@burdenoff/fluidgrids-fe-sdk 2026.1113.11 → 2026.1114.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AiStudioPage-BP2cLXEK.js → AiStudioPage-C040XZyS.js} +4 -4
- package/dist/{DataSinkDashboardPage-CiFi9YXQ.js → DataSinkDashboardPage-BoyLrZnt.js} +1 -1
- package/dist/{ExecutionDetailPage-BfFrWnBj.js → ExecutionDetailPage-C0lNp122.js} +5 -5
- package/dist/{ExecutionsListPage-BRvj71Nd.js → ExecutionsListPage-BpHBy1JU.js} +4 -4
- package/dist/{FluidGridsProvider-Dxehlm-2.js → FluidGridsProvider-CPLfIarV.js} +2 -2
- package/dist/{HistoryPage-CjtgUOZr.js → HistoryPage-CCZS-hPw.js} +1 -1
- package/dist/{InsightsPage-BsGqBpUO.js → InsightsPage-C-Nm9YNI.js} +1 -1
- package/dist/{NodesPage-B8fqXtey.js → NodesPage-C3sh0aL9.js} +1 -1
- package/dist/{PaidTemplateConfirm-BUBCnbP0.js → PaidTemplateConfirm-D20JFNCb.js} +1 -1
- package/dist/{QuotaExhaustedDialog-BEsj0A-I.js → QuotaExhaustedDialog-DTpI0jfj.js} +1 -1
- package/dist/{SettingsPage-DpBhx95x.js → SettingsPage-CmIa107C.js} +828 -8
- package/dist/{TaskQueuesPage-DLzuumGp.js → TaskQueuesPage-BNoe05qF.js} +16 -2
- package/dist/{TemplateCard-DD3vJ3a5.js → TemplateCard-C_YMW80k.js} +44 -34
- package/dist/{TemplateConfigurationModal-BtzI-4fr.js → TemplateConfigurationModal-DmM7s1zk.js} +1 -1
- package/dist/{TemplateDetailPanel-BxFNnlXm.js → TemplateDetailPanel-k0esV8pr.js} +12 -15
- package/dist/{TemplatePreview-Ca7df91b.js → TemplatePreview-aKYt0Kad.js} +4 -4
- package/dist/{TemplatesPage-BSMLtMnf.js → TemplatesPage-DIVghCB6.js} +12 -10
- package/dist/{WorkflowBuilder-Bok_WtPQ.js → WorkflowBuilder-BsDvbIpS.js} +6 -6
- package/dist/{WorkflowBuilder-Dh8MYfZJ.js → WorkflowBuilder-knGFBAAk.js} +4 -4
- package/dist/{WorkflowSearchRedirect-bcWo68LY.js → WorkflowSearchRedirect-DFsQzQw9.js} +1 -1
- package/dist/{WorkflowsList-DURQu2ZD.js → WorkflowsList-DEN-0uQe.js} +6 -6
- package/dist/{agentTools-B4BDCe57.js → agentTools-BTld9unj.js} +3 -3
- package/dist/{app-BIsCEL65.js → app-4Qdv2_5b.js} +4 -4
- package/dist/{attach-node-helpers-CCWFS75V.js → attach-node-helpers-4d-YMaBH.js} +1 -1
- package/dist/{canvasNoteTools-CLMZ6u5m.js → canvasNoteTools-C9vJMuXY.js} +2 -2
- package/dist/executions.js +2 -2
- package/dist/{flow-builder-CIvz3sOr.js → flow-builder-ConlP_db.js} +60 -48
- package/dist/history.js +1 -1
- package/dist/{index-BDN8AK1D.d.ts → index-BVCOwqsN.d.ts} +90 -59
- package/dist/index.d.ts +2 -2
- package/dist/index.js +45 -45
- package/dist/{label-CDy86rIZ.js → label-BMVzJ2yW.js} +2 -2
- package/dist/{logs-panel-_Dl5Nrdn.js → logs-panel-BgGt_dFm.js} +1 -1
- package/dist/{node-detail-view-Dz1ZCIzV.js → node-detail-view-C4jNBsfW.js} +9 -9
- package/dist/{node-editor-tab-body-D5ybpm-b.js → node-editor-tab-body-CYeFTQr6.js} +3 -3
- package/dist/{node-operation-selection-bFx9s45-.js → node-operation-selection-DHbtGNrG.js} +9 -9
- package/dist/node-type-icon-DEAztACh.js +28 -0
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/{popover-ClSWhtja.js → popover-DhwmsszC.js} +4 -4
- package/dist/{quick-config-panel-iDMk4TT5.js → quick-config-panel-c8JQlXuc.js} +5 -5
- package/dist/{schedule-panel-DzkTZm2q.js → schedule-panel-CBab8kSL.js} +5 -5
- package/dist/settings.js +1 -1
- package/dist/{sidebar-node-editor-C16VnTzr.js → sidebar-node-editor-Bo_XRHJs.js} +5 -5
- package/dist/store-icon-BOiBSHY6.js +100 -0
- package/dist/template-preview-BpP8QMAe.js +32 -0
- package/dist/templates.js +2 -2
- package/dist/{useAgentDefinitions-akQ6WwzD.js → useAgentDefinitions-Bs_ci53W.js} +1 -1
- package/dist/{useDurableParity-fZcATZHI.js → useDurableParity-DrahdkaR.js} +1 -1
- package/dist/{useExecutions-lRqeXDYS.js → useExecutions-6P7ohzlh.js} +1 -1
- package/dist/{useGlobalStoreClient-BOI2kYRv.js → useGlobalStoreClient-B42oOe9Q.js} +1 -1
- package/dist/{useObservability-CBFLQBQO.js → useObservability-BSLLLev9.js} +1 -1
- package/dist/{useRunHistory-DSDD_ha3.js → useRunHistory-DuKiGSuF.js} +1 -1
- package/dist/{useWorkflowCodeExport-qGat2KNz.js → useWorkflowCodeExport-D80HIo-F.js} +1 -1
- package/dist/{useWorkflows-CXwXQg74.js → useWorkflows-B5kFIfrZ.js} +1 -1
- package/dist/workflow-builder.js +5 -5
- package/dist/workflow-pages.d.ts +1 -1
- package/dist/workflow-pages.js +15 -15
- package/dist/workflow-preview.js +1 -1
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
- package/dist/node-type-icon-D28t8I64.js +0 -35
- package/dist/template-preview-C01KV277.js +0 -29
|
@@ -6,22 +6,22 @@ import { n as useManagedAiPolicyAuthority } from "./ManagedAiPolicyAuthorityCont
|
|
|
6
6
|
import { c as budgetInputValue, d as withBudgetMode, f as EffectBadge, m as useActionPolicies, n as checkCodecServerUrl, p as effectLabel, s as BUDGET_DIMENSIONS, u as withBudgetLimit } from "./codec-client-CAYl6j46.js";
|
|
7
7
|
import { i as isAutonomyLevel, o as useAutonomyLevelCopy, t as AUTONOMY_LEVELS } from "./run-mode-Du-fvjtE.js";
|
|
8
8
|
import { n as getFluidGridsClient } from "./client-Ctl4jmY3.js";
|
|
9
|
-
import { o as throwIfResultError, t as describeOperationError } from "./errors-xPZ-IbQd.js";
|
|
9
|
+
import { o as throwIfResultError, r as isForbiddenError, t as describeOperationError } from "./errors-xPZ-IbQd.js";
|
|
10
10
|
import { d as useFluidGridsFlag, m as usePhaseCFlags, t as FLUIDGRIDS_FLAGS, u as useDurableParityEnabled } from "./feature-flags-B_b8PJ6Z.js";
|
|
11
|
+
import { QI as WorkflowSecuritySeverity, XI as WorkflowSearchAttributeType, ZI as WorkflowSecurityCheck } from "./graphql-types-D82O-0XY.js";
|
|
11
12
|
import { M as saveCodecServerSettings, _ as fetchPauseRules, a as createPauseRule, c as deletePauseRule, f as fetchArchiveSettings, g as fetchCodecServerSettings, j as saveArchiveSettings, l as deleteSearchAttribute, o as createSearchAttribute, r as clearArchiveSettings, x as fetchSearchAttributes } from "./api-CEnNq15C.js";
|
|
12
13
|
import { i as NativeSelect, o as StatusPill, t as FieldError, u as useResource } from "./shared-C0LCTtyh.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { a as useLogStreamDestinations, i as useLogStreamDestinationActions } from "./useObservability-CBFLQBQO.js";
|
|
14
|
+
import { A as useFlowStore } from "./node-operation-selection-DHbtGNrG.js";
|
|
15
|
+
import { Tt as useSaveStatusStore, Yt as findSaveConflict } from "./FluidGridsProvider-CPLfIarV.js";
|
|
16
|
+
import { a as useLogStreamDestinations, i as useLogStreamDestinationActions } from "./useObservability-BSLLLev9.js";
|
|
17
17
|
import { n as useConnections } from "./useConnections-BlB0gbOB.js";
|
|
18
|
-
import { Nt as useUpdateWorkflowDefinitionMutation, Rt as useWorkflowDefinitionQuery, Vt as useWorkflowDefinitionsQuery, n as useAgentDefinitions } from "./useAgentDefinitions-
|
|
18
|
+
import { Nt as useUpdateWorkflowDefinitionMutation, Rt as useWorkflowDefinitionQuery, Vt as useWorkflowDefinitionsQuery, n as useAgentDefinitions } from "./useAgentDefinitions-Bs_ci53W.js";
|
|
19
19
|
import { a as formToInput$2, i as emptyAgentForm, n as agentToForm, o as grantDays, r as describeRule, t as AgentFormError } from "./agent-form-D0uLvzx4.js";
|
|
20
20
|
import { r as getFluidGridsConfig } from "./config-X97zrIvn.js";
|
|
21
21
|
import { n as getGlobalStoreClient } from "./global-client-DP_Wxe5t.js";
|
|
22
22
|
import { t as FluidGridsDocsLink } from "./FluidGridsDocsLink-JxkBpOeb.js";
|
|
23
23
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
24
|
-
import { useNavigate, useParams } from "react-router";
|
|
24
|
+
import { Link, useNavigate, useParams } from "react-router";
|
|
25
25
|
import { Icon } from "@iconify/react";
|
|
26
26
|
import { cn } from "@burdenoff/fe-libs/utils";
|
|
27
27
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -712,6 +712,264 @@ const WorkflowNotificationSettingsDocument = {
|
|
|
712
712
|
}]
|
|
713
713
|
};
|
|
714
714
|
|
|
715
|
+
// src/generated/documents/wspace/WorkspaceSecurityReportDocument.ts
|
|
716
|
+
const WorkspaceSecurityReportDocument = {
|
|
717
|
+
"kind": "Document",
|
|
718
|
+
"definitions": [{
|
|
719
|
+
"kind": "OperationDefinition",
|
|
720
|
+
"operation": "query",
|
|
721
|
+
"name": {
|
|
722
|
+
"kind": "Name",
|
|
723
|
+
"value": "WorkspaceSecurityReport"
|
|
724
|
+
},
|
|
725
|
+
"variableDefinitions": [{
|
|
726
|
+
"kind": "VariableDefinition",
|
|
727
|
+
"variable": {
|
|
728
|
+
"kind": "Variable",
|
|
729
|
+
"name": {
|
|
730
|
+
"kind": "Name",
|
|
731
|
+
"value": "input"
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
"type": {
|
|
735
|
+
"kind": "NamedType",
|
|
736
|
+
"name": {
|
|
737
|
+
"kind": "Name",
|
|
738
|
+
"value": "WorkspaceSecurityReportInput"
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
"directives": []
|
|
742
|
+
}],
|
|
743
|
+
"directives": [],
|
|
744
|
+
"selectionSet": {
|
|
745
|
+
"kind": "SelectionSet",
|
|
746
|
+
"selections": [{
|
|
747
|
+
"kind": "Field",
|
|
748
|
+
"name": {
|
|
749
|
+
"kind": "Name",
|
|
750
|
+
"value": "workspaceSecurityReport"
|
|
751
|
+
},
|
|
752
|
+
"arguments": [{
|
|
753
|
+
"kind": "Argument",
|
|
754
|
+
"name": {
|
|
755
|
+
"kind": "Name",
|
|
756
|
+
"value": "input"
|
|
757
|
+
},
|
|
758
|
+
"value": {
|
|
759
|
+
"kind": "Variable",
|
|
760
|
+
"name": {
|
|
761
|
+
"kind": "Name",
|
|
762
|
+
"value": "input"
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}],
|
|
766
|
+
"directives": [],
|
|
767
|
+
"selectionSet": {
|
|
768
|
+
"kind": "SelectionSet",
|
|
769
|
+
"selections": [
|
|
770
|
+
{
|
|
771
|
+
"kind": "Field",
|
|
772
|
+
"name": {
|
|
773
|
+
"kind": "Name",
|
|
774
|
+
"value": "generatedAt"
|
|
775
|
+
},
|
|
776
|
+
"arguments": [],
|
|
777
|
+
"directives": []
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
"kind": "Field",
|
|
781
|
+
"name": {
|
|
782
|
+
"kind": "Name",
|
|
783
|
+
"value": "checks"
|
|
784
|
+
},
|
|
785
|
+
"arguments": [],
|
|
786
|
+
"directives": []
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
"kind": "Field",
|
|
790
|
+
"name": {
|
|
791
|
+
"kind": "Name",
|
|
792
|
+
"value": "workflowsScanned"
|
|
793
|
+
},
|
|
794
|
+
"arguments": [],
|
|
795
|
+
"directives": []
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
"kind": "Field",
|
|
799
|
+
"name": {
|
|
800
|
+
"kind": "Name",
|
|
801
|
+
"value": "truncated"
|
|
802
|
+
},
|
|
803
|
+
"arguments": [],
|
|
804
|
+
"directives": []
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
"kind": "Field",
|
|
808
|
+
"name": {
|
|
809
|
+
"kind": "Name",
|
|
810
|
+
"value": "notes"
|
|
811
|
+
},
|
|
812
|
+
"arguments": [],
|
|
813
|
+
"directives": []
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
"kind": "Field",
|
|
817
|
+
"name": {
|
|
818
|
+
"kind": "Name",
|
|
819
|
+
"value": "counts"
|
|
820
|
+
},
|
|
821
|
+
"arguments": [],
|
|
822
|
+
"directives": [],
|
|
823
|
+
"selectionSet": {
|
|
824
|
+
"kind": "SelectionSet",
|
|
825
|
+
"selections": [{
|
|
826
|
+
"kind": "Field",
|
|
827
|
+
"name": {
|
|
828
|
+
"kind": "Name",
|
|
829
|
+
"value": "check"
|
|
830
|
+
},
|
|
831
|
+
"arguments": [],
|
|
832
|
+
"directives": []
|
|
833
|
+
}, {
|
|
834
|
+
"kind": "Field",
|
|
835
|
+
"name": {
|
|
836
|
+
"kind": "Name",
|
|
837
|
+
"value": "count"
|
|
838
|
+
},
|
|
839
|
+
"arguments": [],
|
|
840
|
+
"directives": []
|
|
841
|
+
}]
|
|
842
|
+
}
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
"kind": "Field",
|
|
846
|
+
"name": {
|
|
847
|
+
"kind": "Name",
|
|
848
|
+
"value": "findings"
|
|
849
|
+
},
|
|
850
|
+
"arguments": [],
|
|
851
|
+
"directives": [],
|
|
852
|
+
"selectionSet": {
|
|
853
|
+
"kind": "SelectionSet",
|
|
854
|
+
"selections": [
|
|
855
|
+
{
|
|
856
|
+
"kind": "Field",
|
|
857
|
+
"name": {
|
|
858
|
+
"kind": "Name",
|
|
859
|
+
"value": "check"
|
|
860
|
+
},
|
|
861
|
+
"arguments": [],
|
|
862
|
+
"directives": []
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
"kind": "Field",
|
|
866
|
+
"name": {
|
|
867
|
+
"kind": "Name",
|
|
868
|
+
"value": "severity"
|
|
869
|
+
},
|
|
870
|
+
"arguments": [],
|
|
871
|
+
"directives": []
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
"kind": "Field",
|
|
875
|
+
"name": {
|
|
876
|
+
"kind": "Name",
|
|
877
|
+
"value": "workflowKey"
|
|
878
|
+
},
|
|
879
|
+
"arguments": [],
|
|
880
|
+
"directives": []
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
"kind": "Field",
|
|
884
|
+
"name": {
|
|
885
|
+
"kind": "Name",
|
|
886
|
+
"value": "workflowName"
|
|
887
|
+
},
|
|
888
|
+
"arguments": [],
|
|
889
|
+
"directives": []
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
"kind": "Field",
|
|
893
|
+
"name": {
|
|
894
|
+
"kind": "Name",
|
|
895
|
+
"value": "version"
|
|
896
|
+
},
|
|
897
|
+
"arguments": [],
|
|
898
|
+
"directives": []
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
"kind": "Field",
|
|
902
|
+
"name": {
|
|
903
|
+
"kind": "Name",
|
|
904
|
+
"value": "active"
|
|
905
|
+
},
|
|
906
|
+
"arguments": [],
|
|
907
|
+
"directives": []
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
"kind": "Field",
|
|
911
|
+
"name": {
|
|
912
|
+
"kind": "Name",
|
|
913
|
+
"value": "nodeId"
|
|
914
|
+
},
|
|
915
|
+
"arguments": [],
|
|
916
|
+
"directives": []
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
"kind": "Field",
|
|
920
|
+
"name": {
|
|
921
|
+
"kind": "Name",
|
|
922
|
+
"value": "nodeType"
|
|
923
|
+
},
|
|
924
|
+
"arguments": [],
|
|
925
|
+
"directives": []
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
"kind": "Field",
|
|
929
|
+
"name": {
|
|
930
|
+
"kind": "Name",
|
|
931
|
+
"value": "nodeLabel"
|
|
932
|
+
},
|
|
933
|
+
"arguments": [],
|
|
934
|
+
"directives": []
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
"kind": "Field",
|
|
938
|
+
"name": {
|
|
939
|
+
"kind": "Name",
|
|
940
|
+
"value": "message"
|
|
941
|
+
},
|
|
942
|
+
"arguments": [],
|
|
943
|
+
"directives": []
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
"kind": "Field",
|
|
947
|
+
"name": {
|
|
948
|
+
"kind": "Name",
|
|
949
|
+
"value": "connectionId"
|
|
950
|
+
},
|
|
951
|
+
"arguments": [],
|
|
952
|
+
"directives": []
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
"kind": "Field",
|
|
956
|
+
"name": {
|
|
957
|
+
"kind": "Name",
|
|
958
|
+
"value": "latestVersion"
|
|
959
|
+
},
|
|
960
|
+
"arguments": [],
|
|
961
|
+
"directives": []
|
|
962
|
+
}
|
|
963
|
+
]
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
]
|
|
967
|
+
}
|
|
968
|
+
}]
|
|
969
|
+
}
|
|
970
|
+
}]
|
|
971
|
+
};
|
|
972
|
+
|
|
715
973
|
// src/modules/action-policies/utils/policy-form.ts
|
|
716
974
|
const POLICY_EFFECTS = [
|
|
717
975
|
"REQUIRE_APPROVAL",
|
|
@@ -3108,6 +3366,555 @@ function WorkflowNotificationsTab({ workflowKey }) {
|
|
|
3108
3366
|
});
|
|
3109
3367
|
}
|
|
3110
3368
|
|
|
3369
|
+
// src/modules/settings/hooks/useWorkspaceSecurityReport.ts
|
|
3370
|
+
/**
|
|
3371
|
+
* The workspace security report (BOFF-9747) for Settings → Security report.
|
|
3372
|
+
*
|
|
3373
|
+
* `workspaceSecurityReport` is computed on demand from the stored workflow
|
|
3374
|
+
* definitions and is for workspace admins only: the gateway answers anyone
|
|
3375
|
+
* else with FORBIDDEN, which the hook reports as `forbidden` rather than as a
|
|
3376
|
+
* load failure, so the screen can say who may see the report.
|
|
3377
|
+
*/
|
|
3378
|
+
async function fetchWorkspaceSecurityReport() {
|
|
3379
|
+
const result = await getFluidGridsClient().query({
|
|
3380
|
+
query: WorkspaceSecurityReportDocument,
|
|
3381
|
+
variables: {},
|
|
3382
|
+
fetchPolicy: "network-only"
|
|
3383
|
+
});
|
|
3384
|
+
throwIfResultError(result);
|
|
3385
|
+
const report = result.data?.workspaceSecurityReport;
|
|
3386
|
+
if (!report) throw new Error("The security report did not come back.");
|
|
3387
|
+
return report;
|
|
3388
|
+
}
|
|
3389
|
+
const LOADING = {
|
|
3390
|
+
report: null,
|
|
3391
|
+
error: null,
|
|
3392
|
+
forbidden: false,
|
|
3393
|
+
loading: true
|
|
3394
|
+
};
|
|
3395
|
+
function useWorkspaceSecurityReport() {
|
|
3396
|
+
const [state, setState] = useState(LOADING);
|
|
3397
|
+
const [generation, setGeneration] = useState(0);
|
|
3398
|
+
useEffect(() => {
|
|
3399
|
+
let cancelled = false;
|
|
3400
|
+
const load = async () => {
|
|
3401
|
+
try {
|
|
3402
|
+
const report = await fetchWorkspaceSecurityReport();
|
|
3403
|
+
if (!cancelled) setState({
|
|
3404
|
+
report,
|
|
3405
|
+
error: null,
|
|
3406
|
+
forbidden: false,
|
|
3407
|
+
loading: false
|
|
3408
|
+
});
|
|
3409
|
+
} catch (err) {
|
|
3410
|
+
if (!cancelled) setState((current) => ({
|
|
3411
|
+
report: current.report,
|
|
3412
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
3413
|
+
forbidden: isForbiddenError(err),
|
|
3414
|
+
loading: false
|
|
3415
|
+
}));
|
|
3416
|
+
}
|
|
3417
|
+
};
|
|
3418
|
+
load();
|
|
3419
|
+
return () => {
|
|
3420
|
+
cancelled = true;
|
|
3421
|
+
};
|
|
3422
|
+
}, [generation]);
|
|
3423
|
+
const refresh = useCallback(() => {
|
|
3424
|
+
setState((current) => ({
|
|
3425
|
+
...current,
|
|
3426
|
+
error: null,
|
|
3427
|
+
loading: true
|
|
3428
|
+
}));
|
|
3429
|
+
setGeneration((value) => value + 1);
|
|
3430
|
+
}, []);
|
|
3431
|
+
return {
|
|
3432
|
+
...state,
|
|
3433
|
+
refresh
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
// src/modules/settings/utils/security-report.ts
|
|
3438
|
+
/** Every check the service runs, in the order the screen lists them. */
|
|
3439
|
+
const SECURITY_CHECKS = [
|
|
3440
|
+
"PUBLIC_TRIGGER_WITHOUT_AUTH",
|
|
3441
|
+
"CODE_EXECUTION",
|
|
3442
|
+
"HTTP_TO_PRIVATE_ADDRESS",
|
|
3443
|
+
"SQL_WITH_EXPRESSIONS",
|
|
3444
|
+
"OUTDATED_STORE_NODE"
|
|
3445
|
+
];
|
|
3446
|
+
/** Severities, most serious first. */
|
|
3447
|
+
const SECURITY_SEVERITIES = [
|
|
3448
|
+
"HIGH",
|
|
3449
|
+
"MEDIUM",
|
|
3450
|
+
"LOW"
|
|
3451
|
+
];
|
|
3452
|
+
/** The filter value that keeps every check or severity. */
|
|
3453
|
+
const ALL = "ALL";
|
|
3454
|
+
const CHECK_SET = new Set(SECURITY_CHECKS);
|
|
3455
|
+
const SEVERITY_SET = new Set(SECURITY_SEVERITIES);
|
|
3456
|
+
/** A select's value as a check filter; anything unknown keeps every check. */
|
|
3457
|
+
function toCheckFilter(value) {
|
|
3458
|
+
return SECURITY_CHECKS.find((check) => check === value) ?? "ALL";
|
|
3459
|
+
}
|
|
3460
|
+
/** A select's value as a severity filter; anything unknown keeps every severity. */
|
|
3461
|
+
function toSeverityFilter(value) {
|
|
3462
|
+
return SECURITY_SEVERITIES.find((severity) => severity === value) ?? "ALL";
|
|
3463
|
+
}
|
|
3464
|
+
/**
|
|
3465
|
+
* One row per known check, in screen order, with the service's count (taken
|
|
3466
|
+
* before the findings list is cut, so it can be larger than the findings
|
|
3467
|
+
* shown). Checks that did not run show 0 and `ran: false`.
|
|
3468
|
+
*/
|
|
3469
|
+
function summarizeChecks(report) {
|
|
3470
|
+
const ran = new Set(report.checks);
|
|
3471
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3472
|
+
for (const entry of report.counts) counts.set(entry.check, entry.count);
|
|
3473
|
+
return SECURITY_CHECKS.map((check) => ({
|
|
3474
|
+
check,
|
|
3475
|
+
count: counts.get(check) ?? 0,
|
|
3476
|
+
ran: ran.has(check)
|
|
3477
|
+
}));
|
|
3478
|
+
}
|
|
3479
|
+
/** The findings that match both filters, in the service's order (most severe first). */
|
|
3480
|
+
function filterFindings(findings, filter) {
|
|
3481
|
+
return findings.filter((finding) => (filter.check === "ALL" || finding.check === filter.check) && (filter.severity === "ALL" || finding.severity === filter.severity));
|
|
3482
|
+
}
|
|
3483
|
+
/** The badge tone for a severity; an unknown value reads as neutral. */
|
|
3484
|
+
function severityTone(severity) {
|
|
3485
|
+
if (!SEVERITY_SET.has(severity)) return "neutral";
|
|
3486
|
+
if (severity === String("HIGH")) return "danger";
|
|
3487
|
+
if (severity === String("MEDIUM")) return "warning";
|
|
3488
|
+
return "neutral";
|
|
3489
|
+
}
|
|
3490
|
+
/** True for a check this SDK knows a label for. */
|
|
3491
|
+
function isKnownCheck(check) {
|
|
3492
|
+
return CHECK_SET.has(check);
|
|
3493
|
+
}
|
|
3494
|
+
/**
|
|
3495
|
+
* Where a finding opens: the builder on the finding's workflow version. The
|
|
3496
|
+
* builder has no node deep link, so the node is named in the row instead.
|
|
3497
|
+
* Relative to the Settings page, like its "Back to Workflows" link.
|
|
3498
|
+
*/
|
|
3499
|
+
function findingBuilderPath(finding) {
|
|
3500
|
+
return `../workflow/${encodeURIComponent(finding.workflowKey)}/${encodeURIComponent(finding.version)}`;
|
|
3501
|
+
}
|
|
3502
|
+
/** The node's name for a row: its label, else its id. */
|
|
3503
|
+
function findingNodeName(finding) {
|
|
3504
|
+
const label = finding.nodeLabel?.trim();
|
|
3505
|
+
return label ? label : finding.nodeId;
|
|
3506
|
+
}
|
|
3507
|
+
/** A stable key for a finding row. */
|
|
3508
|
+
function findingKey(finding) {
|
|
3509
|
+
return [
|
|
3510
|
+
finding.check,
|
|
3511
|
+
finding.workflowKey,
|
|
3512
|
+
finding.version,
|
|
3513
|
+
finding.nodeId,
|
|
3514
|
+
finding.connectionId ?? ""
|
|
3515
|
+
].join("|");
|
|
3516
|
+
}
|
|
3517
|
+
/**
|
|
3518
|
+
* One unique key per finding row. Two findings with the same check, workflow,
|
|
3519
|
+
* version, node and connection would collide on {@link findingKey}; later
|
|
3520
|
+
* repeats get a `#n` suffix so React keys stay unique.
|
|
3521
|
+
*/
|
|
3522
|
+
function uniqueFindingKeys(findings) {
|
|
3523
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3524
|
+
return findings.map((finding) => {
|
|
3525
|
+
const key = findingKey(finding);
|
|
3526
|
+
const count = seen.get(key) ?? 0;
|
|
3527
|
+
seen.set(key, count + 1);
|
|
3528
|
+
return count === 0 ? key : `${key}#${count}`;
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3532
|
+
// src/modules/settings/utils/security-report-labels.ts
|
|
3533
|
+
const TONE_CLASSES$1 = {
|
|
3534
|
+
danger: "bg-status-error-bg-subtle text-status-error-text border-status-error-border",
|
|
3535
|
+
warning: "bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border",
|
|
3536
|
+
neutral: "bg-surface text-text-secondary border-border-default"
|
|
3537
|
+
};
|
|
3538
|
+
function checkLabel(tr, check) {
|
|
3539
|
+
if (!isKnownCheck(check)) return check;
|
|
3540
|
+
return {
|
|
3541
|
+
["PUBLIC_TRIGGER_WITHOUT_AUTH"]: tr("fluidgrids.settings.securityReport.check.publicTrigger", "Public trigger without auth"),
|
|
3542
|
+
["CODE_EXECUTION"]: tr("fluidgrids.settings.securityReport.check.codeExecution", "Code execution"),
|
|
3543
|
+
["HTTP_TO_PRIVATE_ADDRESS"]: tr("fluidgrids.settings.securityReport.check.httpPrivate", "HTTP to a private address"),
|
|
3544
|
+
["SQL_WITH_EXPRESSIONS"]: tr("fluidgrids.settings.securityReport.check.sqlExpressions", "SQL built from expressions"),
|
|
3545
|
+
["OUTDATED_STORE_NODE"]: tr("fluidgrids.settings.securityReport.check.outdatedNode", "Outdated Node Store node")
|
|
3546
|
+
}[check];
|
|
3547
|
+
}
|
|
3548
|
+
function severityLabel(tr, severity) {
|
|
3549
|
+
return {
|
|
3550
|
+
["HIGH"]: tr("fluidgrids.settings.securityReport.severity.high", "High"),
|
|
3551
|
+
["MEDIUM"]: tr("fluidgrids.settings.securityReport.severity.medium", "Medium"),
|
|
3552
|
+
["LOW"]: tr("fluidgrids.settings.securityReport.severity.low", "Low")
|
|
3553
|
+
}[severity];
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
// src/modules/settings/components/SecurityReportParts.tsx
|
|
3557
|
+
/**
|
|
3558
|
+
* Sections of Settings → Security report (BOFF-9747), split out of
|
|
3559
|
+
* SecurityReportTab so each part stays small.
|
|
3560
|
+
*/
|
|
3561
|
+
function SeverityBadge({ severity, label }) {
|
|
3562
|
+
return /* @__PURE__ */ jsx(Badge, {
|
|
3563
|
+
variant: "outline",
|
|
3564
|
+
className: cn("text-xs", TONE_CLASSES$1[severityTone(severity)]),
|
|
3565
|
+
children: label
|
|
3566
|
+
});
|
|
3567
|
+
}
|
|
3568
|
+
function FindingRow({ finding, tr }) {
|
|
3569
|
+
return /* @__PURE__ */ jsxs("tr", {
|
|
3570
|
+
className: "border-t border-border-default align-top",
|
|
3571
|
+
"data-testid": "security-report-finding",
|
|
3572
|
+
"data-check": finding.check,
|
|
3573
|
+
"data-severity": finding.severity,
|
|
3574
|
+
children: [
|
|
3575
|
+
/* @__PURE__ */ jsx("td", {
|
|
3576
|
+
className: "px-3 py-2",
|
|
3577
|
+
children: /* @__PURE__ */ jsx(SeverityBadge, {
|
|
3578
|
+
severity: finding.severity,
|
|
3579
|
+
label: severityLabel(tr, finding.severity)
|
|
3580
|
+
})
|
|
3581
|
+
}),
|
|
3582
|
+
/* @__PURE__ */ jsx("td", {
|
|
3583
|
+
className: "px-3 py-2 text-text-primary",
|
|
3584
|
+
children: checkLabel(tr, finding.check)
|
|
3585
|
+
}),
|
|
3586
|
+
/* @__PURE__ */ jsxs("td", {
|
|
3587
|
+
className: "px-3 py-2",
|
|
3588
|
+
children: [/* @__PURE__ */ jsx(Link, {
|
|
3589
|
+
to: findingBuilderPath(finding),
|
|
3590
|
+
className: "font-medium text-text-primary underline-offset-2 hover:underline",
|
|
3591
|
+
"data-testid": "security-report-finding-link",
|
|
3592
|
+
children: finding.workflowName || finding.workflowKey
|
|
3593
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3594
|
+
className: "text-xs text-text-muted",
|
|
3595
|
+
children: [
|
|
3596
|
+
tr("fluidgrids.settings.securityReport.versionLabel", "Version"),
|
|
3597
|
+
" ",
|
|
3598
|
+
finding.version,
|
|
3599
|
+
finding.active ? ` · ${tr("fluidgrids.settings.securityReport.activeLabel", "Active")}` : ` · ${tr("fluidgrids.settings.securityReport.draftLabel", "Draft")}`
|
|
3600
|
+
]
|
|
3601
|
+
})]
|
|
3602
|
+
}),
|
|
3603
|
+
/* @__PURE__ */ jsxs("td", {
|
|
3604
|
+
className: "px-3 py-2",
|
|
3605
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
3606
|
+
className: "text-text-primary",
|
|
3607
|
+
children: findingNodeName(finding)
|
|
3608
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3609
|
+
className: "text-xs text-text-muted",
|
|
3610
|
+
children: finding.nodeType
|
|
3611
|
+
})]
|
|
3612
|
+
}),
|
|
3613
|
+
/* @__PURE__ */ jsxs("td", {
|
|
3614
|
+
className: "px-3 py-2 text-text-secondary",
|
|
3615
|
+
children: [finding.message, finding.latestVersion ? /* @__PURE__ */ jsx("div", {
|
|
3616
|
+
className: "text-xs text-text-muted",
|
|
3617
|
+
children: tr("fluidgrids.settings.securityReport.latestVersion", "Newest version: {{version}}", { version: finding.latestVersion })
|
|
3618
|
+
}) : null]
|
|
3619
|
+
})
|
|
3620
|
+
]
|
|
3621
|
+
});
|
|
3622
|
+
}
|
|
3623
|
+
function ReportForbidden({ tr }) {
|
|
3624
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3625
|
+
className: "flex items-center gap-2 rounded-lg border border-border-default bg-surface p-3",
|
|
3626
|
+
"data-testid": "security-report-forbidden",
|
|
3627
|
+
role: "note",
|
|
3628
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
3629
|
+
icon: "mdi:shield-lock-outline",
|
|
3630
|
+
width: 18,
|
|
3631
|
+
className: "shrink-0 text-text-secondary"
|
|
3632
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3633
|
+
className: "text-sm text-text-secondary",
|
|
3634
|
+
children: tr("fluidgrids.settings.securityReport.adminsOnly", "Only workspace admins can see this report.")
|
|
3635
|
+
})]
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
function ReportLoadFailed({ tr, error, onRetry }) {
|
|
3639
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3640
|
+
className: "space-y-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle p-3",
|
|
3641
|
+
"data-testid": "security-report-error",
|
|
3642
|
+
role: "alert",
|
|
3643
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
3644
|
+
className: "text-sm text-status-error-text",
|
|
3645
|
+
children: [
|
|
3646
|
+
tr("fluidgrids.settings.securityReport.loadFailed", "Could not load the security report."),
|
|
3647
|
+
" ",
|
|
3648
|
+
error.message
|
|
3649
|
+
]
|
|
3650
|
+
}), /* @__PURE__ */ jsx(Button$1, {
|
|
3651
|
+
variant: "outline",
|
|
3652
|
+
size: "sm",
|
|
3653
|
+
onClick: onRetry,
|
|
3654
|
+
children: tr("fluidgrids.settings.securityReport.retry", "Try again")
|
|
3655
|
+
})]
|
|
3656
|
+
});
|
|
3657
|
+
}
|
|
3658
|
+
function ReportLoading({ tr }) {
|
|
3659
|
+
return /* @__PURE__ */ jsx("p", {
|
|
3660
|
+
className: "text-sm text-text-secondary",
|
|
3661
|
+
"data-testid": "security-report-loading",
|
|
3662
|
+
children: tr("fluidgrids.settings.securityReport.loading", "Checking the workspace's workflows…")
|
|
3663
|
+
});
|
|
3664
|
+
}
|
|
3665
|
+
function ReportHeader({ tr, report, loading, onRefresh }) {
|
|
3666
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3667
|
+
className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
|
|
3668
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
3669
|
+
className: "flex items-start gap-2",
|
|
3670
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
3671
|
+
icon: "mdi:shield-search",
|
|
3672
|
+
width: 18,
|
|
3673
|
+
className: "mt-0.5 shrink-0 text-text-secondary"
|
|
3674
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
3675
|
+
className: "text-sm text-text-secondary",
|
|
3676
|
+
children: tr("fluidgrids.settings.securityReport.intro", "Risky workflows of this workspace, checked from their saved definitions. Only workspace admins see this report.")
|
|
3677
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3678
|
+
className: "mt-1 text-xs text-text-muted",
|
|
3679
|
+
"data-testid": "security-report-meta",
|
|
3680
|
+
children: tr("fluidgrids.settings.securityReport.meta", "{{count}} workflows checked · {{time}}", {
|
|
3681
|
+
count: report.workflowsScanned,
|
|
3682
|
+
time: new Date(report.generatedAt).toLocaleString()
|
|
3683
|
+
})
|
|
3684
|
+
})] })]
|
|
3685
|
+
}), /* @__PURE__ */ jsxs(Button$1, {
|
|
3686
|
+
variant: "outline",
|
|
3687
|
+
size: "sm",
|
|
3688
|
+
onClick: onRefresh,
|
|
3689
|
+
disabled: loading,
|
|
3690
|
+
"data-testid": "security-report-refresh",
|
|
3691
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
3692
|
+
icon: "mdi:refresh",
|
|
3693
|
+
className: "mr-2",
|
|
3694
|
+
width: 16
|
|
3695
|
+
}), tr("fluidgrids.settings.securityReport.refresh", "Run again")]
|
|
3696
|
+
})]
|
|
3697
|
+
});
|
|
3698
|
+
}
|
|
3699
|
+
function ReportTruncatedNote({ tr }) {
|
|
3700
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3701
|
+
className: "flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle p-3",
|
|
3702
|
+
"data-testid": "security-report-truncated",
|
|
3703
|
+
role: "note",
|
|
3704
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
3705
|
+
icon: "mdi:alert-outline",
|
|
3706
|
+
width: 18,
|
|
3707
|
+
className: "mt-0.5 shrink-0 text-status-warning-text"
|
|
3708
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3709
|
+
className: "text-sm text-status-warning-text",
|
|
3710
|
+
children: tr("fluidgrids.settings.securityReport.truncated", "This report is incomplete: some workflows or findings were left out because the report is bounded. Counts still include them.")
|
|
3711
|
+
})]
|
|
3712
|
+
});
|
|
3713
|
+
}
|
|
3714
|
+
function CheckSummary({ tr, summary, check, onCheck }) {
|
|
3715
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3716
|
+
className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5",
|
|
3717
|
+
"data-testid": "security-report-summary",
|
|
3718
|
+
children: summary.map((entry) => /* @__PURE__ */ jsxs("button", {
|
|
3719
|
+
type: "button",
|
|
3720
|
+
onClick: () => onCheck(check === entry.check ? "ALL" : toCheckFilter(entry.check)),
|
|
3721
|
+
"aria-pressed": check === entry.check,
|
|
3722
|
+
className: cn("rounded-lg border bg-surface p-3 text-left", check === entry.check ? "border-border-strong" : "border-border-default"),
|
|
3723
|
+
"data-testid": `security-report-count-${entry.check}`,
|
|
3724
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
3725
|
+
className: "text-2xl font-semibold text-text-primary",
|
|
3726
|
+
children: entry.ran ? entry.count : "–"
|
|
3727
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3728
|
+
className: "text-xs text-text-secondary",
|
|
3729
|
+
children: checkLabel(tr, entry.check)
|
|
3730
|
+
})]
|
|
3731
|
+
}, entry.check))
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3734
|
+
function ReportFilters({ tr, check, severity, onCheck, onSeverity }) {
|
|
3735
|
+
const allLabel = tr("fluidgrids.settings.securityReport.filterAll", "All");
|
|
3736
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3737
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
3738
|
+
children: [/* @__PURE__ */ jsxs(Select, {
|
|
3739
|
+
value: check,
|
|
3740
|
+
onValueChange: (value) => onCheck(toCheckFilter(value)),
|
|
3741
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
3742
|
+
className: "w-full bg-surface border-border-default sm:w-[260px]",
|
|
3743
|
+
"aria-label": tr("fluidgrids.settings.securityReport.checkFilter", "Check"),
|
|
3744
|
+
"data-testid": "security-report-check-filter",
|
|
3745
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
3746
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [/* @__PURE__ */ jsx(SelectItem, {
|
|
3747
|
+
value: "ALL",
|
|
3748
|
+
children: allLabel
|
|
3749
|
+
}), SECURITY_CHECKS.map((value) => /* @__PURE__ */ jsx(SelectItem, {
|
|
3750
|
+
value,
|
|
3751
|
+
children: checkLabel(tr, value)
|
|
3752
|
+
}, value))] })]
|
|
3753
|
+
}), /* @__PURE__ */ jsxs(Select, {
|
|
3754
|
+
value: severity,
|
|
3755
|
+
onValueChange: (value) => onSeverity(toSeverityFilter(value)),
|
|
3756
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
3757
|
+
className: "w-full bg-surface border-border-default sm:w-[180px]",
|
|
3758
|
+
"aria-label": tr("fluidgrids.settings.securityReport.severityFilter", "Severity"),
|
|
3759
|
+
"data-testid": "security-report-severity-filter",
|
|
3760
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
3761
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [/* @__PURE__ */ jsx(SelectItem, {
|
|
3762
|
+
value: "ALL",
|
|
3763
|
+
children: allLabel
|
|
3764
|
+
}), SECURITY_SEVERITIES.map((value) => /* @__PURE__ */ jsx(SelectItem, {
|
|
3765
|
+
value,
|
|
3766
|
+
children: severityLabel(tr, value)
|
|
3767
|
+
}, value))] })]
|
|
3768
|
+
})]
|
|
3769
|
+
});
|
|
3770
|
+
}
|
|
3771
|
+
function FindingsTable({ tr, findings, hasAnyFindings }) {
|
|
3772
|
+
if (findings.length === 0) return /* @__PURE__ */ jsxs("div", {
|
|
3773
|
+
className: "flex items-center gap-2 rounded-lg border border-border-default bg-surface-sunken p-4",
|
|
3774
|
+
"data-testid": "security-report-empty",
|
|
3775
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
3776
|
+
icon: "mdi:shield-check-outline",
|
|
3777
|
+
width: 18,
|
|
3778
|
+
className: "shrink-0 text-text-secondary"
|
|
3779
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3780
|
+
className: "text-sm text-text-secondary",
|
|
3781
|
+
children: !hasAnyFindings ? tr("fluidgrids.settings.securityReport.noFindings", "No risky workflows found.") : tr("fluidgrids.settings.securityReport.noMatches", "No findings match these filters.")
|
|
3782
|
+
})]
|
|
3783
|
+
});
|
|
3784
|
+
const rowKeys = uniqueFindingKeys(findings);
|
|
3785
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3786
|
+
className: "overflow-x-auto rounded-lg border border-border-default bg-surface",
|
|
3787
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
3788
|
+
className: "w-full min-w-[720px] text-sm",
|
|
3789
|
+
"data-testid": "security-report-table",
|
|
3790
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
3791
|
+
className: "bg-surface-sunken text-left text-xs text-text-muted",
|
|
3792
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
3793
|
+
/* @__PURE__ */ jsx("th", {
|
|
3794
|
+
className: "px-3 py-2 font-medium",
|
|
3795
|
+
children: tr("fluidgrids.settings.securityReport.severityColumn", "Severity")
|
|
3796
|
+
}),
|
|
3797
|
+
/* @__PURE__ */ jsx("th", {
|
|
3798
|
+
className: "px-3 py-2 font-medium",
|
|
3799
|
+
children: tr("fluidgrids.settings.securityReport.checkColumn", "Check")
|
|
3800
|
+
}),
|
|
3801
|
+
/* @__PURE__ */ jsx("th", {
|
|
3802
|
+
className: "px-3 py-2 font-medium",
|
|
3803
|
+
children: tr("fluidgrids.settings.securityReport.workflowColumn", "Workflow")
|
|
3804
|
+
}),
|
|
3805
|
+
/* @__PURE__ */ jsx("th", {
|
|
3806
|
+
className: "px-3 py-2 font-medium",
|
|
3807
|
+
children: tr("fluidgrids.settings.securityReport.nodeColumn", "Node")
|
|
3808
|
+
}),
|
|
3809
|
+
/* @__PURE__ */ jsx("th", {
|
|
3810
|
+
className: "px-3 py-2 font-medium",
|
|
3811
|
+
children: tr("fluidgrids.settings.securityReport.detailsColumn", "What to do")
|
|
3812
|
+
})
|
|
3813
|
+
] })
|
|
3814
|
+
}), /* @__PURE__ */ jsx("tbody", { children: findings.map((finding, index) => /* @__PURE__ */ jsx(FindingRow, {
|
|
3815
|
+
finding,
|
|
3816
|
+
tr
|
|
3817
|
+
}, rowKeys[index])) })]
|
|
3818
|
+
})
|
|
3819
|
+
});
|
|
3820
|
+
}
|
|
3821
|
+
function ReportNotes({ tr, notes }) {
|
|
3822
|
+
if (notes.length === 0) return null;
|
|
3823
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3824
|
+
"data-testid": "security-report-notes",
|
|
3825
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3826
|
+
className: "mb-1 text-sm font-semibold text-text-primary",
|
|
3827
|
+
children: tr("fluidgrids.settings.securityReport.notesTitle", "About this report")
|
|
3828
|
+
}), /* @__PURE__ */ jsx("ul", {
|
|
3829
|
+
className: "list-disc space-y-1 pl-5 text-xs text-text-secondary",
|
|
3830
|
+
children: [...new Set(notes)].map((note) => /* @__PURE__ */ jsx("li", { children: note }, note))
|
|
3831
|
+
})]
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
function ReportRefreshFailed({ tr, error }) {
|
|
3835
|
+
return /* @__PURE__ */ jsxs("p", {
|
|
3836
|
+
className: "text-sm text-status-error-text",
|
|
3837
|
+
"data-testid": "security-report-refresh-failed",
|
|
3838
|
+
role: "alert",
|
|
3839
|
+
children: [
|
|
3840
|
+
tr("fluidgrids.settings.securityReport.refreshFailed", "Could not run the report again. This is the last report."),
|
|
3841
|
+
" ",
|
|
3842
|
+
error.message
|
|
3843
|
+
]
|
|
3844
|
+
});
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
// src/modules/settings/components/SecurityReportTab.tsx
|
|
3848
|
+
/**
|
|
3849
|
+
* Settings → Security report (BOFF-9747): the workspace's risky workflows, the
|
|
3850
|
+
* FluidGrids counterpart of `n8n audit`. Public triggers without auth, code
|
|
3851
|
+
* execution, HTTP calls to private addresses, SQL built from expressions and
|
|
3852
|
+
* outdated Node Store nodes, computed on demand by `workspaceSecurityReport`.
|
|
3853
|
+
*
|
|
3854
|
+
* Workspace admins only: anyone else sees a short note, not an error.
|
|
3855
|
+
*/
|
|
3856
|
+
function SecurityReportTab() {
|
|
3857
|
+
const tr = useTr();
|
|
3858
|
+
const { report, loading, error, forbidden, refresh } = useWorkspaceSecurityReport();
|
|
3859
|
+
const [check, setCheck] = useState("ALL");
|
|
3860
|
+
const [severity, setSeverity] = useState("ALL");
|
|
3861
|
+
const summary = useMemo(() => report ? summarizeChecks(report) : [], [report]);
|
|
3862
|
+
const findings = useMemo(() => report ? filterFindings(report.findings, {
|
|
3863
|
+
check,
|
|
3864
|
+
severity
|
|
3865
|
+
}) : [], [
|
|
3866
|
+
report,
|
|
3867
|
+
check,
|
|
3868
|
+
severity
|
|
3869
|
+
]);
|
|
3870
|
+
if (forbidden) return /* @__PURE__ */ jsx(ReportForbidden, { tr });
|
|
3871
|
+
if (error && !report) return /* @__PURE__ */ jsx(ReportLoadFailed, {
|
|
3872
|
+
tr,
|
|
3873
|
+
error,
|
|
3874
|
+
onRetry: refresh
|
|
3875
|
+
});
|
|
3876
|
+
if (!report) return /* @__PURE__ */ jsx(ReportLoading, { tr });
|
|
3877
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3878
|
+
className: "space-y-6",
|
|
3879
|
+
"data-testid": "security-report",
|
|
3880
|
+
children: [
|
|
3881
|
+
/* @__PURE__ */ jsx(ReportHeader, {
|
|
3882
|
+
tr,
|
|
3883
|
+
report,
|
|
3884
|
+
loading,
|
|
3885
|
+
onRefresh: refresh
|
|
3886
|
+
}),
|
|
3887
|
+
error ? /* @__PURE__ */ jsx(ReportRefreshFailed, {
|
|
3888
|
+
tr,
|
|
3889
|
+
error
|
|
3890
|
+
}) : null,
|
|
3891
|
+
report.truncated ? /* @__PURE__ */ jsx(ReportTruncatedNote, { tr }) : null,
|
|
3892
|
+
/* @__PURE__ */ jsx(CheckSummary, {
|
|
3893
|
+
tr,
|
|
3894
|
+
summary,
|
|
3895
|
+
check,
|
|
3896
|
+
onCheck: setCheck
|
|
3897
|
+
}),
|
|
3898
|
+
/* @__PURE__ */ jsx(ReportFilters, {
|
|
3899
|
+
tr,
|
|
3900
|
+
check,
|
|
3901
|
+
severity,
|
|
3902
|
+
onCheck: setCheck,
|
|
3903
|
+
onSeverity: setSeverity
|
|
3904
|
+
}),
|
|
3905
|
+
/* @__PURE__ */ jsx(FindingsTable, {
|
|
3906
|
+
tr,
|
|
3907
|
+
findings,
|
|
3908
|
+
hasAnyFindings: report.findings.length > 0
|
|
3909
|
+
}),
|
|
3910
|
+
/* @__PURE__ */ jsx(ReportNotes, {
|
|
3911
|
+
tr,
|
|
3912
|
+
notes: report.notes
|
|
3913
|
+
})
|
|
3914
|
+
]
|
|
3915
|
+
});
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3111
3918
|
// src/modules/settings/components/RunControlTab.tsx
|
|
3112
3919
|
/**
|
|
3113
3920
|
* Settings → Run control (BOFF-9906, Phase C): the workspace's activity pause
|
|
@@ -6697,6 +7504,15 @@ function SettingsPage({ workflowKey: workflowKeyProp } = {}) {
|
|
|
6697
7504
|
width: 16
|
|
6698
7505
|
}), tr("fluidgrids.settings.page.mcpTab", "MCP")]
|
|
6699
7506
|
}),
|
|
7507
|
+
/* @__PURE__ */ jsxs(TabsTrigger, {
|
|
7508
|
+
value: "security-report",
|
|
7509
|
+
className: "gap-1.5",
|
|
7510
|
+
"data-testid": "fluidgrids-settings-security-report-tab",
|
|
7511
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
7512
|
+
icon: "mdi:shield-search",
|
|
7513
|
+
width: 16
|
|
7514
|
+
}), tr("fluidgrids.settings.page.securityReportTab", "Security report")]
|
|
7515
|
+
}),
|
|
6700
7516
|
/* @__PURE__ */ jsxs(TabsTrigger, {
|
|
6701
7517
|
value: "notifications",
|
|
6702
7518
|
className: "gap-1.5",
|
|
@@ -6755,6 +7571,10 @@ function SettingsPage({ workflowKey: workflowKeyProp } = {}) {
|
|
|
6755
7571
|
value: "mcp",
|
|
6756
7572
|
children: /* @__PURE__ */ jsx(McpGatewayTab, { workflowKey })
|
|
6757
7573
|
}),
|
|
7574
|
+
/* @__PURE__ */ jsx(TabsContent, {
|
|
7575
|
+
value: "security-report",
|
|
7576
|
+
children: /* @__PURE__ */ jsx(SecurityReportTab, {})
|
|
7577
|
+
}),
|
|
6758
7578
|
/* @__PURE__ */ jsx(TabsContent, {
|
|
6759
7579
|
value: "notifications",
|
|
6760
7580
|
children: /* @__PURE__ */ jsx(WorkflowNotificationsTab, { workflowKey })
|
|
@@ -6772,4 +7592,4 @@ function SettingsPage({ workflowKey: workflowKeyProp } = {}) {
|
|
|
6772
7592
|
});
|
|
6773
7593
|
}
|
|
6774
7594
|
|
|
6775
|
-
export {
|
|
7595
|
+
export { ManagedAiWorkspacePolicyDocument as a, UpdateManagedAiWorkspacePolicyDocument as c, WorkflowNotificationSettingsDocument as i, UpdateDurableHistoryCapsDocument as l, SettingsPage_exports as n, DurableHistoryCapsDocument as o, WorkspaceSecurityReportDocument as r, UpdateWorkflowNotificationSettingsDocument as s, SettingsPage as t };
|