diff --git a/opencti-platform/opencti-front/lang/back/de.json b/opencti-platform/opencti-front/lang/back/de.json index 2255a2c64ed1..0929d75d7026 100644 --- a/opencti-platform/opencti-front/lang/back/de.json +++ b/opencti-platform/opencti-front/lang/back/de.json @@ -334,6 +334,7 @@ "Is family": "Ist Familie", "Is live": "Ist live", "Is read": "Wird gelesen", + "Is sensitive changes allowed": "Sind sensible Änderungen erlaubt?", "Issuer": "Ausgeber", "Issuer alternative name": "Alternativer Name des Ausstellers", "Job title": "Berufsbezeichnung", diff --git a/opencti-platform/opencti-front/lang/back/en.json b/opencti-platform/opencti-front/lang/back/en.json index 951b85adad51..c0c8d1589035 100644 --- a/opencti-platform/opencti-front/lang/back/en.json +++ b/opencti-platform/opencti-front/lang/back/en.json @@ -334,6 +334,7 @@ "Is family": "Is family", "Is live": "Is live", "Is read": "Is read", + "Is sensitive changes allowed": "Is sensitive changes allowed", "Issuer": "Issuer", "Issuer alternative name": "Issuer alternative name", "Job title": "Job title", diff --git a/opencti-platform/opencti-front/lang/back/es.json b/opencti-platform/opencti-front/lang/back/es.json index 6da6d57ed0bf..f502c512de97 100644 --- a/opencti-platform/opencti-front/lang/back/es.json +++ b/opencti-platform/opencti-front/lang/back/es.json @@ -334,6 +334,7 @@ "Is family": "Es familia", "Is live": "Está vivo", "Is read": "Se lee", + "Is sensitive changes allowed": "¿Se permiten cambios sensibles?", "Issuer": "Emisor", "Issuer alternative name": "Nombre alternativo del emisor", "Job title": "Cargo", diff --git a/opencti-platform/opencti-front/lang/back/fr.json b/opencti-platform/opencti-front/lang/back/fr.json index 45a5f3230d93..06875c052ff3 100644 --- a/opencti-platform/opencti-front/lang/back/fr.json +++ b/opencti-platform/opencti-front/lang/back/fr.json @@ -334,6 +334,7 @@ "Is family": "Est la famille", "Is live": "Est en direct", "Is read": "Est lu", + "Is sensitive changes allowed": "Les modifications sensibles sont-elles autorisées ?", "Issuer": "Émetteur", "Issuer alternative name": "Nom alternatif de l'émetteur", "Job title": "Titre du poste", diff --git a/opencti-platform/opencti-front/lang/back/ja.json b/opencti-platform/opencti-front/lang/back/ja.json index 5da3dba908dc..1d4636890a59 100644 --- a/opencti-platform/opencti-front/lang/back/ja.json +++ b/opencti-platform/opencti-front/lang/back/ja.json @@ -334,6 +334,7 @@ "Is family": "アーキテクチャの実行環境", "Is live": "ライブ", "Is read": "ユーザー", + "Is sensitive changes allowed": "センシティブな変更は許されるか", "Issuer": "発行者", "Issuer alternative name": "発行者別名", "Job title": "配偶者の有無", diff --git a/opencti-platform/opencti-front/lang/back/ko.json b/opencti-platform/opencti-front/lang/back/ko.json index 18d004fd8d47..ebbdfccccfd8 100644 --- a/opencti-platform/opencti-front/lang/back/ko.json +++ b/opencti-platform/opencti-front/lang/back/ko.json @@ -334,6 +334,7 @@ "Is family": "가족 여부", "Is live": "실시간 여부", "Is read": "읽음 여부", + "Is sensitive changes allowed": "민감한 변경이 허용되나요?", "Issuer": "발행자", "Issuer alternative name": "발행자 대체 이름", "Job title": "직책", diff --git a/opencti-platform/opencti-front/lang/back/zh.json b/opencti-platform/opencti-front/lang/back/zh.json index 1c46f2ab3381..14498a4f6528 100644 --- a/opencti-platform/opencti-front/lang/back/zh.json +++ b/opencti-platform/opencti-front/lang/back/zh.json @@ -334,6 +334,7 @@ "Is family": "是否属于", "Is live": "已激活", "Is read": "已读", + "Is sensitive changes allowed": "是否允许敏感变化", "Issuer": "签发人", "Issuer alternative name": "签发人替代名称", "Job title": "职位", diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 60a740e70255..b773077161c3 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -136,6 +136,7 @@ "All types of relationship": "Alle Arten von Beziehungen", "All types of target": "Alle Arten von Ziel", "All years": "Alle Jahre", + "Allow modification of sensitive configuration": "Änderung der sensiblen Konfiguration zulassen", "Allowed marking definitions": "Erlaubte Markierungsdefinitionen", "Allowed markings": "Erlaubte Markierungen", "Already in plat.": "Bereits in plat.", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index ace73c49956b..5eaa1504014c 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -136,6 +136,7 @@ "All types of relationship": "All types of relationship", "All types of target": "All types of target", "All years": "All years", + "Allow modification of sensitive configuration": "Allow modification of sensitive configuration", "Allowed marking definitions": "Allowed marking definitions", "Allowed markings": "Allowed markings", "Already in plat.": "Already in plat.", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index b31c847c8d8c..3f327d321f65 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -136,6 +136,7 @@ "All types of relationship": "Todos los tipos de relación", "All types of target": "Todo los tipos de objetivo", "All years": "Todos los años", + "Allow modification of sensitive configuration": "Permitir la modificación de la configuración sensible", "Allowed marking definitions": "Definiciones de marcado permitidas", "Allowed markings": "Marcas permitidas", "Already in plat.": "Ya está en la plataforma.", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index f6f47f30dcd7..11ab94282e58 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -136,6 +136,7 @@ "All types of relationship": "Tous les types de relation", "All types of target": "Tous les types de cible", "All years": "Toutes les années", + "Allow modification of sensitive configuration": "Permettre la modification d'une configuration sensible", "Allowed marking definitions": "Définitions de marquage autorisées", "Allowed markings": "Marquages autorisés", "Already in plat.": "Déjà dans la plat.", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index e62358fb0be7..85a8680e584f 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -136,6 +136,7 @@ "All types of relationship": "全てのリレーションシップの種別", "All types of target": "あらゆる種類のターゲット", "All years": "すべての年", + "Allow modification of sensitive configuration": "機密設定の変更を許可する", "Allowed marking definitions": "許可されたマーキング定義", "Allowed markings": "許可されるマーキング", "Already in plat.": "すでにプラットフォームに存在します", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index 9226c6bceddf..486b9837f369 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -136,6 +136,7 @@ "All types of relationship": "모든 관계 유형", "All types of target": "모든 대상 유형", "All years": "모든 연도", + "Allow modification of sensitive configuration": "민감한 구성의 수정 허용", "Allowed marking definitions": "허용된 마킹 정의", "Allowed markings": "허용된 마킹", "Already in plat.": "이미 플랫폼에 있음", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index 44cb7e03391d..ad842c726141 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -136,6 +136,7 @@ "All types of relationship": "关系的所有类型", "All types of target": "所有类型的目标", "All years": "所有年份", + "Allow modification of sensitive configuration": "允许修改敏感配置", "Allowed marking definitions": "允许的标记定义", "Allowed markings": "允许的标记", "Already in plat.": "已经在平台", diff --git a/opencti-platform/opencti-front/src/private/Root.tsx b/opencti-platform/opencti-front/src/private/Root.tsx index 9fba89c5d75f..c603cefac7d3 100644 --- a/opencti-platform/opencti-front/src/private/Root.tsx +++ b/opencti-platform/opencti-front/src/private/Root.tsx @@ -141,6 +141,7 @@ const meUserFragment = graphql` id name } + can_manage_sensitive_config } `; diff --git a/opencti-platform/opencti-front/src/private/components/settings/Policies.tsx b/opencti-platform/opencti-front/src/private/components/settings/Policies.tsx index 2accf9401b66..32193e40f934 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/Policies.tsx +++ b/opencti-platform/opencti-front/src/private/components/settings/Policies.tsx @@ -37,6 +37,7 @@ import useEnterpriseEdition from '../../../utils/hooks/useEnterpriseEdition'; import ItemBoolean from '../../../components/ItemBoolean'; import Breadcrumbs from '../../../components/Breadcrumbs'; import useApiMutation from '../../../utils/hooks/useApiMutation'; +import useSensitiveModifications from '../../../utils/hooks/useSensitiveModifications'; import Transition from '../../../components/Transition'; // Deprecated - https://mui.com/system/styles/basics/ @@ -124,6 +125,7 @@ const PoliciesComponent: FunctionComponent = ({ queryRef, }) => { const isEnterpriseEdition = useEnterpriseEdition(); + const { ffenabled, isPlatformOrgaModificationAllowed } = useSensitiveModifications(); const [openPlatformOrganizationChanges, setOpenPlatformOrganizationChanges] = useState(false); const data = usePreloadedQuery(policiesQuery, queryRef); @@ -201,7 +203,7 @@ const PoliciesComponent: FunctionComponent = ({ setOpenPlatformOrganizationChanges(true)} style={{ width: '100%', marginTop: 20 }} diff --git a/opencti-platform/opencti-front/src/private/components/settings/groups/Group.tsx b/opencti-platform/opencti-front/src/private/components/settings/groups/Group.tsx index bcac75be9cc5..bb0603b735bc 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/groups/Group.tsx +++ b/opencti-platform/opencti-front/src/private/components/settings/groups/Group.tsx @@ -30,6 +30,7 @@ import ItemIcon from '../../../../components/ItemIcon'; import GroupHiddenTypesChipList from './GroupHiddenTypesChipList'; import ExpandableMarkdown from '../../../../components/ExpandableMarkdown'; import { checkIsMarkingAllowed } from '../../../../utils/markings/markingsFiltering'; +import useSensitiveModifications from '../../../../utils/hooks/useSensitiveModifications'; // Deprecated - https://mui.com/system/styles/basics/ // Do not use it for new code. @@ -62,6 +63,7 @@ const groupFragment = graphql` rolesOrderMode: { type: "OrderingMode", defaultValue: asc } ) { id + standard_id entity_type name default_assignation @@ -123,6 +125,7 @@ const Group = ({ groupData }: { groupData: Group_group$key }) => { const classes = useStyles(); const { t_i18n } = useFormatter(); const group = useFragment(groupFragment, groupData); + const { ffenabled, isGroupEditionAllowed } = useSensitiveModifications(); const markingsSort = R.sortWith([ R.ascend(R.propOr('TLP', 'definition_type')), R.descend(R.propOr(0, 'x_opencti_order')), @@ -153,9 +156,19 @@ const Group = ({ groupData }: { groupData: Group_group$key }) => { > {group.name} -
- -
+ {ffenabled && ( + isGroupEditionAllowed(group.standard_id) + ?
+ +
+ : <> + )} + {!ffenabled && ( +
+ +
+ ) + }
{ - + {ffenabled && ( + isGroupEditionAllowed(group.standard_id) + ?
+ +
+ : <> + )} + {!ffenabled && ( +
+ +
+ ) + }
); }; diff --git a/opencti-platform/opencti-front/src/private/components/settings/roles/CapabilitiesList.tsx b/opencti-platform/opencti-front/src/private/components/settings/roles/CapabilitiesList.tsx index 3e2f6b2bfdc6..add8cd946cf1 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/roles/CapabilitiesList.tsx +++ b/opencti-platform/opencti-front/src/private/components/settings/roles/CapabilitiesList.tsx @@ -9,6 +9,7 @@ import { roleEditionCapabilitiesLinesSearch } from './RoleEditionCapabilities'; import { RoleEditionCapabilitiesLinesSearchQuery } from './__generated__/RoleEditionCapabilitiesLinesSearchQuery.graphql'; import { Role_role$data } from './__generated__/Role_role.graphql'; import ItemIcon from '../../../../components/ItemIcon'; +import useSensitiveModifications from '../../../../utils/hooks/useSensitiveModifications'; interface CapabilitiesListProps { queryRef: PreloadedQuery; @@ -27,8 +28,23 @@ const CapabilitiesList: FunctionComponent = ({ roleEditionCapabilitiesLinesSearch, queryRef, ); + const { ffenabled, isRoleWithManageSensitiveConfig } = useSensitiveModifications(); + return ( + {ffenabled && isRoleWithManageSensitiveConfig(role) && ( + + + + + + + )} {capabilities?.edges?.map((edge, i) => { const capability = edge?.node; if (capability) { diff --git a/opencti-platform/opencti-front/src/private/components/settings/roles/Role.tsx b/opencti-platform/opencti-front/src/private/components/settings/roles/Role.tsx index 525dad9df88d..926331d5f881 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/roles/Role.tsx +++ b/opencti-platform/opencti-front/src/private/components/settings/roles/Role.tsx @@ -24,6 +24,7 @@ import { groupsSearchQuery } from '../Groups'; import { GroupsSearchQuery } from '../__generated__/GroupsSearchQuery.graphql'; import ItemIcon from '../../../../components/ItemIcon'; import ExpandableMarkdown from '../../../../components/ExpandableMarkdown'; +import useSensitiveModifications from '../../../../utils/hooks/useSensitiveModifications'; // Deprecated - https://mui.com/system/styles/basics/ // Do not use it for new code. @@ -52,6 +53,7 @@ const useStyles = makeStyles(() => ({ const roleFragment = graphql` fragment Role_role on Role { id + standard_id name description created_at @@ -61,6 +63,7 @@ const roleFragment = graphql` name description } + can_manage_sensitive_config } `; @@ -81,6 +84,7 @@ const Role = ({ : null)) .filter((n) => n !== null && n !== undefined); }; + const { ffenabled, isRoleEditionAllowed } = useSensitiveModifications(); const role = useFragment(roleFragment, roleData); const queryRef = useQueryLoading( roleEditionCapabilitiesLinesSearch, @@ -96,10 +100,20 @@ const Role = ({ > {role.name} -
- -
-
+ {ffenabled && ( + isRoleEditionAllowed(role.standard_id) + ?
+ +
+ : <> + )} + {!ffenabled && ( +
+ +
+ ) + } +
{ if (props && props.role) { + if (ffenabled) { + return ( + isRoleEditionAllowed(role.standard_id) + ? + : <> + ); + } return ( , @@ -101,9 +116,46 @@ const RoleEditionCapabilitiesComponent: FunctionComponent, + ) => { + const roleId = role.id; + commitPatchAllowSensitiveConf({ + variables: { + id: roleId, + input: { + key: 'can_manage_sensitive_config', + value: event.target.checked, + }, + }, + }); + // And invalid me ?? or invalidSession + }; + + const { ffenabled } = useSensitiveModifications(); + if (capabilities && capabilities.edges) { return ( + {ffenabled && ( + + + + + + + handleSensitiveToggle(event)} + checked={role.can_manage_sensitive_config ?? true} + disabled={false} + /> + + + )} {capabilities.edges.map((edge) => { const capability = edge?.node; if (capability) { @@ -155,6 +207,7 @@ const RoleEditionCapabilities = createFragmentContainer( role: graphql` fragment RoleEditionCapabilities_role on Role { id + can_manage_sensitive_config capabilities { id name diff --git a/opencti-platform/opencti-front/src/schema/relay.schema.graphql b/opencti-platform/opencti-front/src/schema/relay.schema.graphql index 4e9f7707f735..963806d87a83 100644 --- a/opencti-platform/opencti-front/src/schema/relay.schema.graphql +++ b/opencti-platform/opencti-front/src/schema/relay.schema.graphql @@ -1608,6 +1608,7 @@ type MeUser implements BasicObject & InternalObject { submenu_show_icons: Boolean submenu_auto_collapse: Boolean monochrome_labels: Boolean + can_manage_sensitive_config: Boolean } type SessionDetail { @@ -1694,6 +1695,7 @@ type Role implements BasicObject & InternalObject { updated_at: DateTime! capabilities: [Capability] editContext: [EditUserContext!] + can_manage_sensitive_config: Boolean } input RoleAddInput { diff --git a/opencti-platform/opencti-front/src/utils/hooks/useSensitiveModifications.ts b/opencti-platform/opencti-front/src/utils/hooks/useSensitiveModifications.ts new file mode 100644 index 000000000000..25f103f194da --- /dev/null +++ b/opencti-platform/opencti-front/src/utils/hooks/useSensitiveModifications.ts @@ -0,0 +1,56 @@ +import { Role_role$data } from '@components/settings/roles/__generated__/Role_role.graphql'; +import useAuth from './useAuth'; +import useHelper from './useHelper'; + +const PROTECT_SENSITIVE_CHANGES_FF = 'PROTECT_SENSITIVE_CHANGES'; + +const ADMINISTRATORS_GROUP_ID = 'group--1d9d9a2a-d7e1-5a22-8e90-572d597750ac'; +const CONNECTORS_GROUP_ID = 'group--599fc7ab-02f4-50c1-94f9-4b68da122010'; +const DEFAULT_GROUP_ID = 'group--a7991a4f-6192-59a4-87d3-d006d2c41cc8'; +const PROTECTED_GROUPS_IDS = [ADMINISTRATORS_GROUP_ID, CONNECTORS_GROUP_ID, DEFAULT_GROUP_ID]; + +const ADMINISTRATOR_ROLE_ID = 'role--22abb1ff-6ea9-5833-8bf1-aea5c4c971ce'; +const CONNECTOR_ROLE_ID = 'role--b375ed46-a11c-56d5-a2d4-0c654f61eeee'; +const DEFAULT_ROLE_ID = 'role--a7991a4f-6192-59a4-87d3-d006d2c41cc8'; +const PROTECTED_ROLES_IDS = [ADMINISTRATOR_ROLE_ID, CONNECTOR_ROLE_ID, DEFAULT_ROLE_ID]; + +const useSensitiveModifications = () => { + const { me } = useAuth(); + const { isFeatureEnable } = useHelper(); + const isGroupEditionAllowed = (groupStandardId: string) => { + if (me.can_manage_sensitive_config) { + return true; + } + return !PROTECTED_GROUPS_IDS.includes(groupStandardId); + }; + + /** + * Return true when current user has the fake capa can_manage_sensitive_config enabled. + * @param roleStandardId + */ + const isRoleEditionAllowed = (roleStandardId: string) => { + if (me.can_manage_sensitive_config) { + return true; + } + return !PROTECTED_ROLES_IDS.includes(roleStandardId); + }; + + /** + * True when a role has the fake capa can_manage_sensitive_config enabled, false if not. + * when can_manage_sensitive_config undefined => true. + * @param role + */ + const isRoleWithManageSensitiveConfig = (role: Role_role$data) => { + return role.can_manage_sensitive_config ?? true; + }; + + return { + ffenabled: isFeatureEnable(PROTECT_SENSITIVE_CHANGES_FF), + isGroupEditionAllowed, + isRoleEditionAllowed, + isRoleWithManageSensitiveConfig, + isPlatformOrgaModificationAllowed: me.can_manage_sensitive_config ?? true, + }; +}; + +export default useSensitiveModifications; diff --git a/opencti-platform/opencti-graphql/config/default.json b/opencti-platform/opencti-graphql/config/default.json index 998cc081d4c5..c739050970c9 100644 --- a/opencti-platform/opencti-graphql/config/default.json +++ b/opencti-platform/opencti-graphql/config/default.json @@ -11,7 +11,8 @@ "NEW_IMPORT_SCREENS", "FILIGRAN_LOADER", "CONTAINERS_AUTHORIZED_MEMBERS", - "TELEMETRY_COUNT_ACTIVE_USERS" + "TELEMETRY_COUNT_ACTIVE_USERS", + "PROTECT_SENSITIVE_CHANGES" ], "https_cert": { "ca": [], diff --git a/opencti-platform/opencti-graphql/config/schema/opencti.graphql b/opencti-platform/opencti-graphql/config/schema/opencti.graphql index 10e732102a24..7566654197d1 100644 --- a/opencti-platform/opencti-graphql/config/schema/opencti.graphql +++ b/opencti-platform/opencti-graphql/config/schema/opencti.graphql @@ -1542,6 +1542,7 @@ type MeUser implements BasicObject & InternalObject { submenu_show_icons: Boolean submenu_auto_collapse: Boolean monochrome_labels: Boolean + can_manage_sensitive_config: Boolean } type SessionDetail { id: ID! @@ -1624,6 +1625,7 @@ type Role implements BasicObject & InternalObject { updated_at: DateTime! capabilities: [Capability] editContext: [EditUserContext!] + can_manage_sensitive_config: Boolean } input RoleAddInput { name: String! @constraint(minLength: 2, format: "not-blank") diff --git a/opencti-platform/opencti-graphql/src/database/data-initialization.js b/opencti-platform/opencti-graphql/src/database/data-initialization.js index 693110ca46f7..2f2de70bbf24 100644 --- a/opencti-platform/opencti-graphql/src/database/data-initialization.js +++ b/opencti-platform/opencti-graphql/src/database/data-initialization.js @@ -1,4 +1,4 @@ -import { logApp } from '../config/conf'; +import { isFeatureEnabled, logApp } from '../config/conf'; import { addSettings } from '../domain/settings'; import { BYPASS, ROLE_ADMINISTRATOR, ROLE_DEFAULT, SYSTEM_USER } from '../utils/access'; import { initCreateEntitySettings } from '../modules/entitySetting/entitySetting-domain'; @@ -10,7 +10,7 @@ import { VocabularyCategory } from '../generated/graphql'; import { builtInOv, openVocabularies } from '../modules/vocabulary/vocabulary-utils'; import { addVocabulary } from '../modules/vocabulary/vocabulary-domain'; import { addAllowedMarkingDefinition } from '../domain/markingDefinition'; -import { addCapability, addGroup, addRole } from '../domain/grant'; +import { addCapability, addGroup, addRole, PROTECT_SENSITIVE_CHANGES_FF } from '../domain/grant'; import { GROUP_DEFAULT, groupAddRelation } from '../domain/group'; import { TAXIIAPI } from '../domain/user'; import { KNOWLEDGE_COLLABORATION, KNOWLEDGE_DELETE, KNOWLEDGE_MANAGE_AUTH_MEMBERS, KNOWLEDGE_UPDATE } from '../schema/general'; @@ -241,18 +241,52 @@ export const createCapabilities = async (context, capabilities, parentName = '') const createBasicRolesAndCapabilities = async (context) => { // Create capabilities await createCapabilities(context, CAPABILITIES); - // Create roles + + // Create Default(s) Role and Group const defaultRole = await addRole(context, SYSTEM_USER, { name: ROLE_DEFAULT, description: 'Default role associated to the default group', capabilities: [KNOWLEDGE_CAPABILITY], }); - await addRole(context, SYSTEM_USER, { + + const defaultGroup = await addGroup(context, SYSTEM_USER, { + name: GROUP_DEFAULT, + description: 'Default group associated to all users', + default_assignation: true, + }); + const defaultRoleRelationInput = { + toId: defaultRole.id, + relationship_type: 'has-role', + }; + await groupAddRelation(context, SYSTEM_USER, defaultGroup.id, defaultRoleRelationInput); + + // Create Administrator(s) Role and Group + let administratorRoleInput = { name: ROLE_ADMINISTRATOR, description: 'Administrator role that bypass every capabilities', capabilities: [BYPASS], + }; + if (isFeatureEnabled((PROTECT_SENSITIVE_CHANGES_FF))) { + administratorRoleInput = { + ...administratorRoleInput, + can_manage_sensitive_config: false + }; + } + const administratorRole = await addRole(context, SYSTEM_USER, administratorRoleInput); + + const administratorGroup = await addGroup(context, SYSTEM_USER, { + name: 'Administrators', + description: 'Administrator group', + auto_new_marking: true, }); - const connectorRole = await addRole(context, SYSTEM_USER, { + const administratorRoleRelationInput = { + toId: administratorRole.id, + relationship_type: 'has-role', + }; + await groupAddRelation(context, SYSTEM_USER, administratorGroup.id, administratorRoleRelationInput); + + // Create Connector(s) Role and Group + let connectorRoleInput = { name: 'Connector', description: 'Connector role that has the recommended capabilities', capabilities: [ @@ -270,18 +304,18 @@ const createBasicRolesAndCapabilities = async (context) => { 'SETTINGS_SETMARKINGS', 'SETTINGS_SETLABELS', ], - }); - // Create default group with default role - const defaultGroup = await addGroup(context, SYSTEM_USER, { - name: GROUP_DEFAULT, - description: 'Default group associated to all users', - default_assignation: true, - }); - const defaultRoleRelationInput = { - toId: defaultRole.id, - relationship_type: 'has-role', }; - await groupAddRelation(context, SYSTEM_USER, defaultGroup.id, defaultRoleRelationInput); + + if (isFeatureEnabled((PROTECT_SENSITIVE_CHANGES_FF))) { + connectorRoleInput = { + ...connectorRoleInput, + can_manage_sensitive_config: false + }; + } + + const connectorRole = await addRole(context, SYSTEM_USER, connectorRoleInput); + // Create default group with default role + // Create connector group with connector role const connectorGroup = await addGroup(context, SYSTEM_USER, { name: 'Connectors', diff --git a/opencti-platform/opencti-graphql/src/domain/grant.js b/opencti-platform/opencti-graphql/src/domain/grant.js index 0e1bfea7b192..eb7debc4f63b 100644 --- a/opencti-platform/opencti-graphql/src/domain/grant.js +++ b/opencti-platform/opencti-graphql/src/domain/grant.js @@ -5,6 +5,9 @@ import { ENTITY_TYPE_CAPABILITY, ENTITY_TYPE_GROUP, ENTITY_TYPE_ROLE } from '../ import { RELATION_HAS_CAPABILITY } from '../schema/internalRelationship'; import { generateStandardId } from '../schema/identifier'; import { publishUserAction } from '../listener/UserActionListener'; +import { isFeatureEnabled } from '../config/conf'; + +export const PROTECT_SENSITIVE_CHANGES_FF = 'PROTECT_SENSITIVE_CHANGES'; export const addCapability = async (context, user, capability) => { return createEntity(context, user, capability, ENTITY_TYPE_CAPABILITY); @@ -16,7 +19,19 @@ export const addRole = async (context, user, role) => { assoc('description', role.description ? role.description : ''), dissoc('capabilities'), )(role); - const { element, isCreation } = await createEntity(context, user, roleToCreate, ENTITY_TYPE_ROLE, { complete: true }); + + let completeRoleToCreate; + if (isFeatureEnabled(PROTECT_SENSITIVE_CHANGES_FF)) { + completeRoleToCreate = { + ...roleToCreate, + can_manage_sensitive_config: role.can_manage_sensitive_config ?? false, // default when undefined is false + }; + } else { + completeRoleToCreate = { + ...roleToCreate + }; + } + const { element, isCreation } = await createEntity(context, user, completeRoleToCreate, ENTITY_TYPE_ROLE, { complete: true }); const relationPromises = capabilities.map(async (capabilityName) => { const generateToId = generateStandardId(ENTITY_TYPE_CAPABILITY, { name: capabilityName }); return createRelation(context, user, { fromId: element.id, toId: generateToId, relationship_type: RELATION_HAS_CAPABILITY }); diff --git a/opencti-platform/opencti-graphql/src/domain/user.js b/opencti-platform/opencti-graphql/src/domain/user.js index 9952e1091d57..86cf4a6106e7 100644 --- a/opencti-platform/opencti-graphql/src/domain/user.js +++ b/opencti-platform/opencti-graphql/src/domain/user.js @@ -10,9 +10,10 @@ import { BUS_TOPICS, DEFAULT_ACCOUNT_STATUS, ENABLED_DEMO_MODE, + isFeatureEnabled, logApp, OPENCTI_SESSION, - PLATFORM_VERSION, + PLATFORM_VERSION } from '../config/conf'; import { AuthenticationFailure, DatabaseError, ForbiddenAccess, FunctionalError, UnsupportedError } from '../config/errors'; import { getEntitiesListFromCache, getEntitiesMapFromCache, getEntityFromCache, resetCacheForEntity } from '../database/cache'; @@ -62,7 +63,7 @@ import { } from '../utils/access'; import { ASSIGNEE_FILTER, CREATOR_FILTER, PARTICIPANT_FILTER } from '../utils/filtering/filtering-constants'; import { now, utcDate } from '../utils/format'; -import { addGroup } from './grant'; +import { addGroup, PROTECT_SENSITIVE_CHANGES_FF } from './grant'; import { defaultMarkingDefinitionsFromGroups, findAll as findGroups } from './group'; import { addIndividual } from './individual'; import { ENTITY_TYPE_IDENTITY_ORGANIZATION } from '../modules/organization/organization-types'; @@ -1281,6 +1282,14 @@ const getStackTrace = () => { Error.captureStackTrace(obj, getStackTrace); return obj.stack; }; + +export const isSensitiveChangesAllowed = (userId, roles) => { + if (userId === OPENCTI_ADMIN_UUID) { + return true; + } + return roles.some((role) => role.can_manage_sensitive_config !== false); +}; + export const buildCompleteUser = async (context, client) => { if (!client) { return undefined; @@ -1331,8 +1340,14 @@ export const buildCompleteUser = async (context, client) => { const no_creators = groups.filter((g) => g.no_creators).length === groups.length; const restrict_delete = !isByPass && groups.filter((g) => g.restrict_delete).length === groups.length; + let canManageSensitiveConfig = null; + if (isFeatureEnabled(PROTECT_SENSITIVE_CHANGES_FF)) { + canManageSensitiveConfig = { can_manage_sensitive_config: isSensitiveChangesAllowed(client.id, roles) }; + } + return { ...client, + ...canManageSensitiveConfig, roles, capabilities, default_hidden_types, diff --git a/opencti-platform/opencti-graphql/src/generated/graphql.ts b/opencti-platform/opencti-graphql/src/generated/graphql.ts index 9309000d7371..d370221d5a1d 100644 --- a/opencti-platform/opencti-graphql/src/generated/graphql.ts +++ b/opencti-platform/opencti-graphql/src/generated/graphql.ts @@ -12747,6 +12747,7 @@ export type MeUser = BasicObject & InternalObject & { administrated_organizations: Array; allowed_marking?: Maybe>; api_token: Scalars['String']['output']; + can_manage_sensitive_config?: Maybe; capabilities: Array; default_dashboard?: Maybe; default_dashboards: Array; @@ -22311,6 +22312,7 @@ export enum RetentionUnit { export type Role = BasicObject & InternalObject & { __typename?: 'Role'; + can_manage_sensitive_config?: Maybe; capabilities?: Maybe>>; created_at: Scalars['DateTime']['output']; description?: Maybe; @@ -35655,6 +35657,7 @@ export type MeUserResolvers, ParentType, ContextType>; allowed_marking?: Resolver>, ParentType, ContextType>; api_token?: Resolver; + can_manage_sensitive_config?: Resolver, ParentType, ContextType>; capabilities?: Resolver, ParentType, ContextType>; default_dashboard?: Resolver, ParentType, ContextType>; default_dashboards?: Resolver, ParentType, ContextType>; @@ -37821,6 +37824,7 @@ export type RetentionRuleEditMutationsResolvers; export type RoleResolvers = ResolversObject<{ + can_manage_sensitive_config?: Resolver, ParentType, ContextType>; capabilities?: Resolver>>, ParentType, ContextType>; created_at?: Resolver; description?: Resolver, ParentType, ContextType>; diff --git a/opencti-platform/opencti-graphql/src/modules/attributes/internalObject-registrationAttributes.ts b/opencti-platform/opencti-graphql/src/modules/attributes/internalObject-registrationAttributes.ts index 671a86675870..dcd46e1be5fd 100644 --- a/opencti-platform/opencti-graphql/src/modules/attributes/internalObject-registrationAttributes.ts +++ b/opencti-platform/opencti-graphql/src/modules/attributes/internalObject-registrationAttributes.ts @@ -348,6 +348,7 @@ const internalObjectsAttributes: { [k: string]: Array } = { [ENTITY_TYPE_ROLE]: [ { name: 'name', label: 'Name', type: 'string', format: 'short', mandatoryType: 'external', editDefault: true, multiple: false, upsert: false, isFilterable: true }, { name: 'description', label: 'Description', type: 'string', format: 'text', mandatoryType: 'no', editDefault: false, multiple: false, upsert: false, isFilterable: true }, + { name: 'can_manage_sensitive_config', label: 'Is sensitive changes allowed', type: 'boolean', mandatoryType: 'no', editDefault: false, multiple: false, upsert: false, isFilterable: false, featureFlag: 'PROTECT_SENSITIVE_CHANGES' }, ], [ENTITY_TYPE_RULE]: [ { name: 'active', label: 'Status', type: 'boolean', mandatoryType: 'no', editDefault: false, multiple: false, upsert: true, isFilterable: true } diff --git a/opencti-platform/opencti-graphql/tests/01-unit/domain/user-test.ts b/opencti-platform/opencti-graphql/tests/01-unit/domain/user-test.ts index edc8f017ed9f..8f8b59161fe5 100644 --- a/opencti-platform/opencti-graphql/tests/01-unit/domain/user-test.ts +++ b/opencti-platform/opencti-graphql/tests/01-unit/domain/user-test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { testContext } from '../../utils/testQuery'; -import { checkPasswordInlinePolicy } from '../../../src/domain/user'; +import { checkPasswordInlinePolicy, isSensitiveChangesAllowed } from '../../../src/domain/user'; +import { OPENCTI_ADMIN_UUID } from '../../../src/schema/general'; describe('password checker', () => { it('should no policy applied', async () => { @@ -75,3 +76,242 @@ describe('password checker', () => { expect(checkPasswordInlinePolicy(testContext, policy03, 'ju!lA').length).toBe(0); }); }); + +describe('isSensitiveChangesAllowed use case coverage', () => { + const NOT_INFRA_ADMIN_USER_ID = '1c0925fe-ab65-42a1-8e96-ee6dc7fab4fa'; + + it('should user with one role and not can_manage_sensitive_config set be allow change sensitive conf', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z' + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role without can_manage_sensitive_config field should be isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should user with one role can_manage_sensitive_config=true be allow change sensitive conf', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: true + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role with can_manage_sensitive_config field true should be isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should user with one role can_manage_sensitive_config=false not be allow change sensitive conf', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role with can_manage_sensitive_config field false should be isSensitiveChangesAllowed=false').toBeFalsy(); + }); + + it('should user with 2 roles one without can_manage_sensitive_config, the other is false', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + }, + { + _index: 'opencti_internal_objects-000001', + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role with one can_manage_sensitive_config true should be isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should user with 2 roles one without can_manage_sensitive_config, the other is true', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + }, + { + _index: 'opencti_internal_objects-000001', + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: true + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role with one can_manage_sensitive_config true should be isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should user with 2 roles all with can_manage_sensitive_config set to false', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + }, + { + _index: 'opencti_internal_objects-000001', + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + } + ]; + + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'Role with all can_manage_sensitive_config field false should be isSensitiveChangesAllowed=false').toBeFalsy(); + }); + + it('should INFRA admin bypass sensitive conf', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + }, + { + _index: 'opencti_internal_objects-000001', + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: false + } + ]; + + const result = isSensitiveChangesAllowed(OPENCTI_ADMIN_UUID, roles); + expect(result, 'OPENCTI_ADMIN_UUID should be always isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should INFRA user with 2 roles one without can_manage_sensitive_config, the other is true', async () => { + // subset of role data + const roles = [{ + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + }, + { + _index: 'opencti_internal_objects-000001', + base_type: 'ENTITY', + confidence: 100, + created_at: '2024-08-06T13:30:04.478Z', + description: 'Administrator role that bypass every capabilities', + entity_type: 'Role', + id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + internal_id: '57312f0e-f276-44f8-97d3-88191ee57e1a', + name: 'Administrator', + updated_at: '2024-08-06T13:30:04.478Z', + can_manage_sensitive_config: true + } + ]; + + const result = isSensitiveChangesAllowed(OPENCTI_ADMIN_UUID, roles); + expect(result, 'OPENCTI_ADMIN_UUID should be always isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should INFRA admin bypass sensitive conf with zero role', async () => { + // subset of role data + const roles: any[] = []; + const result = isSensitiveChangesAllowed(OPENCTI_ADMIN_UUID, roles); + expect(result, 'OPENCTI_ADMIN_UUID should be always isSensitiveChangesAllowed=true').toBeTruthy(); + }); + + it('should a user with zero role be isSensitiveChangesAllowed=false', async () => { + // subset of role data + const roles: any[] = []; + const result = isSensitiveChangesAllowed(NOT_INFRA_ADMIN_USER_ID, roles); + expect(result, 'A user with no role should be isSensitiveChangesAllowed=false').toBeFalsy(); + }); +}); diff --git a/opencti-platform/opencti-graphql/tests/02-integration/01-database/data-initialization-test.ts b/opencti-platform/opencti-graphql/tests/02-integration/01-database/data-initialization-test.ts index 6ea79e06fe63..fbe009cf2d76 100644 --- a/opencti-platform/opencti-graphql/tests/02-integration/01-database/data-initialization-test.ts +++ b/opencti-platform/opencti-graphql/tests/02-integration/01-database/data-initialization-test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; import { listAllEntities } from '../../../src/database/middleware-loader'; -import { ENTITY_TYPE_CAPABILITY } from '../../../src/schema/internalObject'; +import {ENTITY_TYPE_CAPABILITY, ENTITY_TYPE_GROUP, ENTITY_TYPE_ROLE} from '../../../src/schema/internalObject'; import { ADMIN_USER, testContext } from '../../utils/testQuery'; import type { BasicStoreEntity } from '../../../src/types/store'; @@ -51,4 +51,22 @@ describe('Data initialization test', () => { ]; expect(capabilitiesNames).toEqual(allExpectedNames); }); + + it('should create all initial roles', async () => { + const allRoles = await listAllEntities(testContext, ADMIN_USER, [ENTITY_TYPE_ROLE]); + const allRolesNames = allRoles.map((role) => role.name).sort(); + const allExpectedRoles = ['Administrator', 'Connector', 'Default']; + for (let i = 0; i < allExpectedRoles.length; i = i+1) { + expect(allRolesNames, `${allExpectedRoles[i]} Role is missing from initialization`).toContain(allExpectedRoles[i]); + } + }); + + it('should create all initial Groups', async () => { + const allGroups = await listAllEntities(testContext, ADMIN_USER, [ENTITY_TYPE_GROUP]); + const allGroupsNames = allGroups.map((group) => group.name).sort(); + const allExpectedGroups = ['Administrators', 'Connectors', 'Default']; + for (let i = 0; i < allExpectedGroups.length; i = i+1) { + expect(allGroupsNames, `${allExpectedGroups[i]} Group is missing from initialization`).toContain(allExpectedGroups[i]); + } + }); }); diff --git a/opencti-platform/opencti-graphql/tests/02-integration/01-database/elasticSearch-test.js b/opencti-platform/opencti-graphql/tests/02-integration/01-database/elasticSearch-test.js index da2ab4801ba2..e42555730f8b 100644 --- a/opencti-platform/opencti-graphql/tests/02-integration/01-database/elasticSearch-test.js +++ b/opencti-platform/opencti-graphql/tests/02-integration/01-database/elasticSearch-test.js @@ -404,7 +404,7 @@ describe('Elasticsearch pagination', () => { it('should entity paginate everything', async () => { const data = await elPaginate(testContext, ADMIN_USER, READ_ENTITIES_INDICES, { first: ES_MAX_PAGINATION }); expect(data).not.toBeNull(); - expect(data.edges.length).toEqual(537); + expect(data.edges.length).toEqual(520 + TESTING_USERS.length + TESTING_ROLES.length + TESTING_GROUPS.length); const filterBaseTypes = R.uniq(R.map((e) => e.node.base_type, data.edges)); expect(filterBaseTypes.length).toEqual(1); expect(R.head(filterBaseTypes)).toEqual('ENTITY'); @@ -500,7 +500,7 @@ describe('Elasticsearch pagination', () => { filterGroups: [], }; const data = await elPaginate(testContext, ADMIN_USER, READ_ENTITIES_INDICES, { filters, first: ES_MAX_PAGINATION }); - expect(data.edges.length).toEqual(526); + expect(data.edges.length).toEqual(527); }); it('should entity paginate with field exist filter', async () => { const filters = { @@ -581,7 +581,7 @@ describe('Elasticsearch pagination', () => { orderMode: 'asc', first: ES_MAX_PAGINATION }); - expect(data.edges.length).toEqual(519 + TESTING_USERS.length + TESTING_ROLES.length + TESTING_GROUPS.length); + expect(data.edges.length).toEqual(520 + TESTING_USERS.length + TESTING_ROLES.length + TESTING_GROUPS.length); const createdDates = R.map((e) => e.node.created, data.edges); let previousCreatedDate = null; for (let index = 0; index < createdDates.length; index += 1) { @@ -632,7 +632,7 @@ describe('Elasticsearch pagination', () => { orderBy: 'group_confidence_level', orderMode: 'desc', }); - expect(data.edges.length).toEqual(TESTING_GROUPS.length + 2); // there are 2 built-in groups in initialization + expect(data.edges.length).toEqual(TESTING_GROUPS.length + 3); // there are 3 built-in groups in initialization let previousConfidenceLevel = 100; for (let i = 0; i < data.edges.length; i += 1) { @@ -659,7 +659,7 @@ describe('Elasticsearch pagination', () => { orderBy: 'group_confidence_level', orderMode: 'asc', }); - expect(data.edges.length).toEqual(TESTING_GROUPS.length + 2); // there are 2 built-in groups in initialization + expect(data.edges.length).toEqual(TESTING_GROUPS.length + 3); // there are 3 built-in groups in initialization let previousConfidenceLevel = 0; for (let i = 0; i < data.edges.length; i += 1) { @@ -679,7 +679,7 @@ describe('Elasticsearch pagination', () => { let data = await elPaginate(testContext, ADMIN_USER, READ_RELATIONSHIPS_INDICES, { includeAuthorities: true }); expect(data).not.toBeNull(); const groupByIndices = R.groupBy((e) => e.node._index, data.edges); - expect(groupByIndices[`${ES_INDEX_PREFIX}_internal_relationships-000001`].length).toEqual(94); + expect(groupByIndices[`${ES_INDEX_PREFIX}_internal_relationships-000001`].length).toEqual(106); expect(groupByIndices[`${ES_INDEX_PREFIX}_stix_core_relationships-000001`].length).toEqual(24); expect(groupByIndices[`${ES_INDEX_PREFIX}_stix_meta_relationships-000001`].length).toEqual(129); expect(groupByIndices[`${ES_INDEX_PREFIX}_stix_sighting_relationships-000001`].length).toEqual(2); @@ -691,14 +691,14 @@ describe('Elasticsearch pagination', () => { expect(metaByEntityType['external-reference'].length).toEqual(7); expect(metaByEntityType['object-marking'].length).toEqual(28); expect(metaByEntityType['kill-chain-phase'].length).toEqual(3); - expect(data.edges.length).toEqual(249); + expect(data.edges.length).toEqual(261); let filterBaseTypes = R.uniq(R.map((e) => e.node.base_type, data.edges)); expect(filterBaseTypes.length).toEqual(1); expect(R.head(filterBaseTypes)).toEqual('RELATION'); // Same query with no pagination data = await elPaginate(testContext, ADMIN_USER, READ_RELATIONSHIPS_INDICES, { connectionFormat: false }); expect(data).not.toBeNull(); - expect(data.length).toEqual(249); + expect(data.length).toEqual(261); filterBaseTypes = R.uniq(R.map((e) => e.base_type, data)); expect(filterBaseTypes.length).toEqual(1); expect(R.head(filterBaseTypes)).toEqual('RELATION'); diff --git a/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/role-test.js b/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/role-test.js index 705c47cdf3d0..625c273219b9 100644 --- a/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/role-test.js +++ b/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/role-test.js @@ -4,6 +4,8 @@ import { ADMIN_USER, testContext, queryAsAdmin, TESTING_ROLES } from '../../util import { elLoadById } from '../../../src/database/engine'; import { ENTITY_TYPE_CAPABILITY } from '../../../src/schema/internalObject'; import { generateStandardId } from '../../../src/schema/identifier'; +import {isFeatureEnabled} from '../../../src/config/conf'; +import {PROTECT_SENSITIVE_CHANGES_FF} from '../../../src/domain/grant'; const LIST_QUERY = gql` query roles($first: Int, $after: ID, $orderBy: RolesOrdering, $orderMode: OrderingMode, $search: String) { @@ -39,6 +41,7 @@ describe('Role resolver standard behavior', () => { id name description + can_manage_sensitive_config } } `; @@ -56,6 +59,12 @@ describe('Role resolver standard behavior', () => { expect(role).not.toBeNull(); expect(role.data.roleAdd).not.toBeNull(); expect(role.data.roleAdd.name).toEqual('Role'); + if(isFeatureEnabled(PROTECT_SENSITIVE_CHANGES_FF)){ + expect(role.data.roleAdd.can_manage_sensitive_config).toBeFalsy('New role should have the can_manage_sensitive_config to false by default'); + } else { + expect(role.data.roleAdd.can_manage_sensitive_config).toBeUndefined('New role should not have the can_manage_sensitive_config when it is not enabled'); + } + roleInternalId = role.data.roleAdd.id; }); it('should role loaded by internal id', async () => { diff --git a/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/user-test.js b/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/user-test.js index fd8c4737c713..a74156bf78c9 100644 --- a/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/user-test.js +++ b/opencti-platform/opencti-graphql/tests/02-integration/02-resolvers/user-test.js @@ -613,9 +613,9 @@ describe('User resolver standard behavior', () => { describe('User list members query behavior', () => { it('Should user lists all members', async () => { const queryResult = await editorQuery({ query: LIST_MEMBERS_QUERY }); - expect(queryResult.data.members.edges.length).toEqual(23); + expect(queryResult.data.members.edges.length).toEqual(24); expect(queryResult.data.members.edges.filter(({ node: { entity_type } }) => entity_type === ENTITY_TYPE_USER).length).toEqual(TESTING_USERS.length + 1); // +1 = Plus admin user - expect(queryResult.data.members.edges.filter(({ node: { entity_type } }) => entity_type === ENTITY_TYPE_GROUP).length).toEqual(TESTING_GROUPS.length + 2); // 2 built-in groups + expect(queryResult.data.members.edges.filter(({ node: { entity_type } }) => entity_type === ENTITY_TYPE_GROUP).length).toEqual(TESTING_GROUPS.length + 3); // 3 built-in groups expect(queryResult.data.members.edges.filter(({ node: { entity_type } }) => entity_type === ENTITY_TYPE_IDENTITY_ORGANIZATION).length).toEqual(8); }); });