{
/>
-
+ field="Compliance.allowPartnerToCollectIosCertificateMetadata"
+ compareType="is"
+ compareValue={true}
+ action="disable"
+ >
+
+
From ae7341d592e078e60ad9f2baa3211bcf44596e98 Mon Sep 17 00:00:00 2001
From: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Date: Thu, 25 Jun 2026 17:20:34 +0800
Subject: [PATCH 13/22] Update standards.json
---
src/data/standards.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/data/standards.json b/src/data/standards.json
index 209e7d29c17d..6df63fcb9c65 100644
--- a/src/data/standards.json
+++ b/src/data/standards.json
@@ -378,8 +378,8 @@
"cat": "Global Standards",
"tag": ["CIS M365 7.0.0 (1.3.6)", "CustomerLockBoxEnabled"],
"appliesToTest": ["CIS_1_3_6"],
- "helpText": "**Requires Entra ID P2.** Enables Customer Lockbox that offers an approval process for Microsoft support to access organization data",
- "docsDescription": "**Requires Entra ID P2.** Customer Lockbox ensures that Microsoft can't access your content to do service operations without your explicit approval. Customer Lockbox ensures only authorized requests allow access to your organizations data.",
+ "helpText": "**Requires CustomerLockbox (E5, E7, A5, Purview Addon for BP, EDU or FL)** Enables Customer Lockbox that offers an approval process for Microsoft support to access organization data",
+ "docsDescription": "**Requires CustomerLockbox (E5, E7, A5, Purview Addon for BP, EDU or FL)** Customer Lockbox ensures that Microsoft can't access your content to do service operations without your explicit approval. Customer Lockbox ensures only authorized requests allow access to your organizations data.",
"executiveText": "Requires explicit organizational approval before Microsoft support staff can access company data for service operations. This provides an additional layer of data protection and ensures the organization maintains control over who can access sensitive business information, even during technical support scenarios.",
"addedComponent": [],
"label": "Enable Customer Lockbox",
From 56756d4352a05c8290c93961438aa4e221f2f98b Mon Sep 17 00:00:00 2001
From: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Date: Thu, 25 Jun 2026 22:00:20 +0800
Subject: [PATCH 14/22] ISO 639-1 and ISO 3166-1 autocomplete options
---
.../CippComponents/CippFormComponent.jsx | 137 ++++++++++++------
src/data/standards.json | 12 +-
2 files changed, 94 insertions(+), 55 deletions(-)
diff --git a/src/components/CippComponents/CippFormComponent.jsx b/src/components/CippComponents/CippFormComponent.jsx
index 628a9aa0dafc..d8b2f9d48443 100644
--- a/src/components/CippComponents/CippFormComponent.jsx
+++ b/src/components/CippComponents/CippFormComponent.jsx
@@ -25,6 +25,25 @@ import { CippDataTable } from "../CippTable/CippDataTable";
import React from "react";
import { CloudUpload } from "@mui/icons-material";
import { Stack } from "@mui/system";
+import countryList from "../../data/countryList";
+import languageList from "../../data/languageList";
+
+// ISO 3166-1 alpha-2 country/region codes (uppercase), used by the CountryCodeMultiSelect type.
+const countryCodeOptions = countryList
+ .map((c) => ({ label: `${c.Name} (${c.Code})`, value: c.Code }))
+ .sort((a, b) => a.label.localeCompare(b.label));
+
+// ISO 639-1 alpha-2 language codes (lowercase), used by the LanguageCodeMultiSelect type.
+// Derived from the locale tags in languageList.json, deduplicated to the two-letter primary subtag (e.g. "en-US" -> "en").
+const languageCodeOptions = Object.values(
+ languageList.reduce((acc, entry) => {
+ const code = entry.tag?.split("-")[0]?.toLowerCase();
+ if (code && code.length === 2 && !acc[code]) {
+ acc[code] = { label: `${entry.language} (${code})`, value: code };
+ }
+ return acc;
+ }, {}),
+).sort((a, b) => a.label.localeCompare(b.label));
// The tiptap / prosemirror / mui-tiptap editor tree is large and only used by `richText` fields.
// Load it on demand via next/dynamic so it is code-split into an async chunk instead of being
@@ -87,6 +106,59 @@ export const CippFormComponent = (props) => {
}
};
+ // Shared renderer for autoComplete-backed fields (autoComplete + the ISO-code multiselects).
+ const renderAutoCompleteField = (autoCompleteProps) => {
+ // Resolve options if it's a function
+ const resolvedOptions =
+ typeof autoCompleteProps.options === "function"
+ ? autoCompleteProps.options(row)
+ : autoCompleteProps.options;
+
+ // Wrap validate function to pass row as third parameter
+ const resolvedValidators = validators
+ ? {
+ ...validators,
+ validate:
+ typeof validators.validate === "function"
+ ? (value, formValues) => validators.validate(value, formValues, row)
+ : validators.validate,
+ }
+ : validators;
+
+ return (
+
+ (
+ field.onChange(value)}
+ onBlur={field.onBlur}
+ />
+ )}
+ />
+
+ {get(errors, convertedName, {})?.message && (
+
+ {get(errors, convertedName, {})?.message}
+
+ )}
+ {helperText && (
+
+ {helperText}
+
+ )}
+
+ );
+ };
+
switch (type) {
case "heading":
return (
@@ -434,55 +506,26 @@ export const CippFormComponent = (props) => {
>
);
- case "autoComplete": {
- // Resolve options if it's a function
- const resolvedOptions =
- typeof other.options === "function" ? other.options(row) : other.options;
-
- // Wrap validate function to pass row as third parameter
- const resolvedValidators = validators
- ? {
- ...validators,
- validate:
- typeof validators.validate === "function"
- ? (value, formValues) => validators.validate(value, formValues, row)
- : validators.validate,
- }
- : validators;
+ case "autoComplete":
+ return renderAutoCompleteField(other);
- return (
-
- (
- field.onChange(value)}
- onBlur={field.onBlur}
- />
- )}
- />
+ // ISO 3166-1 alpha-2 region/country code multiselect (e.g. Spam Filter RegionBlockList).
+ case "CountryCodeMultiSelect":
+ return renderAutoCompleteField({
+ ...other,
+ options: countryCodeOptions,
+ multiple: true,
+ creatable: false,
+ });
- {get(errors, convertedName, {})?.message && (
-
- {get(errors, convertedName, {})?.message}
-
- )}
- {helperText && (
-
- {helperText}
-
- )}
-
- );
- }
+ // ISO 639-1 alpha-2 language code multiselect (e.g. Spam Filter LanguageBlockList).
+ case "LanguageCodeMultiSelect":
+ return renderAutoCompleteField({
+ ...other,
+ options: languageCodeOptions,
+ multiple: true,
+ creatable: false,
+ });
case "richText": {
return (
diff --git a/src/data/standards.json b/src/data/standards.json
index 6df63fcb9c65..6552e8000429 100644
--- a/src/data/standards.json
+++ b/src/data/standards.json
@@ -4157,12 +4157,10 @@
"defaultValue": false
},
{
- "type": "autoComplete",
- "multiple": true,
- "creatable": true,
+ "type": "LanguageCodeMultiSelect",
"required": false,
"name": "standards.SpamFilterPolicy.LanguageBlockList",
- "label": "Languages to block (uppercase ISO 639-1 two-letter)",
+ "label": "Languages to block (ISO 639-1 two-letter)",
"condition": {
"field": "standards.SpamFilterPolicy.EnableLanguageBlockList",
"compareType": "is",
@@ -4176,12 +4174,10 @@
"defaultValue": false
},
{
- "type": "autoComplete",
- "multiple": true,
- "creatable": true,
+ "type": "CountryCodeMultiSelect",
"required": false,
"name": "standards.SpamFilterPolicy.RegionBlockList",
- "label": "Regions to block (uppercase ISO 3166-1 two-letter)",
+ "label": "Regions to block (ISO 3166-1 two-letter)",
"condition": {
"field": "standards.SpamFilterPolicy.EnableRegionBlockList",
"compareType": "is",
From 28178b0df2214522af9648aae33b029a3f52caa5 Mon Sep 17 00:00:00 2001
From: Zacgoose <107489668+Zacgoose@users.noreply.github.com>
Date: Fri, 26 Jun 2026 14:22:43 +0800
Subject: [PATCH 15/22] Permission repair improvements
---
.../CippAppPermissionBuilder.jsx | 149 +++++++++---------
.../super-admin/sam-app-permissions.js | 66 +++++++-
2 files changed, 134 insertions(+), 81 deletions(-)
diff --git a/src/components/CippComponents/CippAppPermissionBuilder.jsx b/src/components/CippComponents/CippAppPermissionBuilder.jsx
index 07d21613fb84..013fe843096a 100644
--- a/src/components/CippComponents/CippAppPermissionBuilder.jsx
+++ b/src/components/CippComponents/CippAppPermissionBuilder.jsx
@@ -462,10 +462,11 @@ const CippAppPermissionBuilder = ({
if (appTable !== undefined && appTable?.length === 0) {
setAppTable(
spPermissions?.applicationPermissions
- ?.sort((a, b) => a.value.localeCompare(b.value))
+ ?.sort((a, b) => (a.value ?? "").localeCompare(b.value ?? ""))
?.map((perm) => ({
id: perm.id,
value: perm.value,
+ required: perm.required ?? false,
description: spInfo?.Results?.appRoles.find((role) => role.id === perm.id)
?.description,
})),
@@ -474,10 +475,11 @@ const CippAppPermissionBuilder = ({
if (delegatedTable !== undefined && delegatedTable.length === 0) {
setDelegatedTable(
spPermissions?.delegatedPermissions
- ?.sort((a, b) => a.value.localeCompare(b.value))
+ ?.sort((a, b) => (a.value ?? "").localeCompare(b.value ?? ""))
?.map((perm) => ({
id: perm.id,
value: perm.value,
+ required: perm.required ?? false,
description:
spInfo?.Results?.publishedPermissionScopes.find((scope) => scope.id === perm.id)
?.userConsentDescription ?? "Manually added",
@@ -625,6 +627,7 @@ const CippAppPermissionBuilder = ({
label: "Delete Permission",
icon: ,
noConfirm: true,
+ condition: (row) => !row.required,
customFunction: (row) => handleRemoveRow("applicationPermissions", row),
},
]}
@@ -690,6 +693,7 @@ const CippAppPermissionBuilder = ({
label: "Delete Permission",
icon: ,
noConfirm: true,
+ condition: (row) => !row.required,
customFunction: (row) => handleRemoveRow("delegatedPermissions", row),
},
]}
@@ -788,7 +792,7 @@ const CippAppPermissionBuilder = ({
-
+