Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4d09517
feat(mem): use tooltip-enabled policy details in compare view
kris6673 Apr 30, 2026
17077aa
feat(compare): add null safety
kris6673 Apr 30, 2026
1bcf7bd
feat(intune): show administrative template policy details
kris6673 Apr 30, 2026
0ba8d57
Pass tenant filter to alerts endpoint
Zacgoose May 4, 2026
7189fe6
updates CIS
KelvinTegelaar May 4, 2026
fbc092d
Allow the tenant filter to be populated with tenant id or initial domain
Zacgoose May 4, 2026
0b1ba6c
feat: add Dutch (Belgium) language
JohnDuprey May 4, 2026
9ece1d2
fix: quarantine action issues
JohnDuprey May 4, 2026
e776575
feat: add AllTenant support to groups
JohnDuprey May 4, 2026
3488384
feat: PR check on fork
JohnDuprey May 4, 2026
7140778
fix: pdf/csv export missing columns if first row does not have the de…
JohnDuprey May 4, 2026
5828c00
update standards.json for SMB1001
KelvinTegelaar May 5, 2026
8469fae
deviations count
Zacgoose May 5, 2026
35eff10
fix: Support IPv6 in GeoIP lookup
JohnDuprey May 6, 2026
8818d4b
pass utc to api for nice response message
Zacgoose May 6, 2026
efa060a
Correct support for all tenant mode in the tenant backup page
Zacgoose May 6, 2026
f0b5468
Fix removing row in bulk add user removing the wrong row
Zacgoose May 6, 2026
68331c4
Update CippWizardCSVImport.jsx
Zacgoose May 6, 2026
0ac68ab
public group standard
KelvinTegelaar May 6, 2026
1e668ec
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP into dev
KelvinTegelaar May 6, 2026
27af9a2
Empty AllowList Standard for CIS
KelvinTegelaar May 6, 2026
4b2c909
add teasm ZAP standard
KelvinTegelaar May 6, 2026
cdcde9b
standards improvements
KelvinTegelaar May 6, 2026
4832593
Ensure that collaboration invitations are sent to allowed domains only
KelvinTegelaar May 6, 2026
344acd1
Enable reporting for standard AutoAddProxy
Zacgoose May 7, 2026
43bec67
tag and standard updates
KelvinTegelaar May 7, 2026
d8aa246
TAP audit log prebuilt alert
Zacgoose May 7, 2026
d3c75d8
more test suite tags
KelvinTegelaar May 7, 2026
d53745f
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP into dev
KelvinTegelaar May 7, 2026
7c05747
Add Usage Location field to JIT Admin and template forms (#5910)
joaadvi May 7, 2026
b898428
Merge pull request #5951 from kris6673/admin-templates
KelvinTegelaar May 7, 2026
397d0c9
add purview section
KelvinTegelaar May 7, 2026
1b51746
feat: add AutoDiscover data retrieval to CippDomainCards
kris6673 May 7, 2026
038c9f6
Add Investigate status to custom tests
Zacgoose May 8, 2026
b0661ac
Update AuditLogTemplates.json
Zacgoose May 8, 2026
f2d78d1
Merge pull request #5974 from kris6673/issue5972
KelvinTegelaar May 8, 2026
922be32
Merge pull request #5971 from joaadvi/feat/jit-admin-usage-location
KelvinTegelaar May 8, 2026
406b2d5
Merge pull request #5950 from kris6673/feat/compare-intune-policy-too…
KelvinTegelaar May 8, 2026
182f0c8
pushing new compliance menus
KelvinTegelaar May 8, 2026
78fa718
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP into dev
KelvinTegelaar May 8, 2026
2a59c79
feat: add manager and sponsor properties to user patching
kris6673 May 8, 2026
ad8ca14
Merge pull request #5976 from kris6673/5933
KelvinTegelaar May 8, 2026
d251423
fix(jit-admin): submit TAP lifetime within policy bounds
kris6673 May 8, 2026
6e1466a
Merge pull request #5977 from kris6673/5965
KelvinTegelaar May 8, 2026
ed9d0f9
Disable all tenant support for message trace
Zacgoose May 8, 2026
8e09f22
add make to portals list
rvdwegen May 8, 2026
3f7ed1f
feat: add Indirect Reseller Link component and integrate into onboard…
JohnDuprey May 8, 2026
3878e5c
fix typo
JohnDuprey May 8, 2026
f482fa8
fix: minor tweaks
JohnDuprey May 8, 2026
64a5439
chore: bump version to 10.4.4
JohnDuprey May 8, 2026
ff61271
Merge pull request #5985 from KelvinTegelaar/dev
JohnDuprey May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions .github/workflows/pr_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
# Only process fork PRs with specific branch conditions
# Must be a fork AND (source is main/master OR target is main/master)
if: |
github.event.pull_request.head.repo.fork == true &&
github.event.pull_request.head.repo.fork == true &&
((github.event.pull_request.head.ref == 'main' || github.event.pull_request.head.ref == 'master') ||
(github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master'))
uses: actions/github-script@v9
Expand All @@ -31,7 +31,31 @@ jobs:
script: |
let message = '';

// Check if the fork has open PRs (indicates pull bot or similar is active)
const forkOwner = context.payload.pull_request.head.repo.owner.login;
const forkRepo = context.payload.pull_request.head.repo.name;
const forkPullsUrl = context.payload.pull_request.head.repo.html_url + '/pulls';

let openPRs = [];
try {
const { data: prs } = await github.rest.pulls.list({
owner: forkOwner,
repo: forkRepo,
state: 'open',
per_page: 5
});
openPRs = prs;
} catch (e) {
// Can't read fork PRs — skip
}

message += '🔄 If you are attempting to update your CIPP repo please follow the instructions at: https://docs.cipp.app/setup/self-hosting-guide/updating. Are you a sponsor? Contact the helpdesk for direct assistance with updating to the latest version.';

if (openPRs.length > 0) {
message += ` It looks like you may already have a pending update PR on your fork — check your [open pull requests](${forkPullsUrl}) to accept it.`;
} else {
message += ` You can enable [Pull Bot](https://github.com/apps/pull) or [Repo Sync](https://github.com/apps/repo-sync) to automatically keep your fork up to date.`;
}
message += '\n\n';

// Check if PR is targeting main/master
Expand All @@ -40,7 +64,7 @@ jobs:
}

// Check if PR is from a fork's main/master branch
if (context.payload.pull_request.head.repo.fork &&
if (context.payload.pull_request.head.repo.fork &&
(context.payload.pull_request.head.ref === 'main' || context.payload.pull_request.head.ref === 'master')) {
message += '⚠️ This PR cannot be merged because it originates from your fork\'s main/master branch. If you are attempting to contribute code please PR from your dev branch or another non-main/master branch.\n\n';
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cipp",
"version": "10.4.3",
"version": "10.4.4",
"author": "CIPP Contributors",
"homepage": "https://cipp.app/",
"bugs": {
Expand Down
7 changes: 7 additions & 0 deletions public/languageList.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@
"languageTag": "Danish (da-DK)",
"LCID": "1030"
},
{
"language": "Dutch",
"Geographic area": "Belgium",
"tag": "nl-BE",
"languageTag": "Dutch (nl-BE)",
"LCID": "2067"
},
{
"language": "Dutch",
"Geographic area": "Netherlands",
Expand Down
2 changes: 1 addition & 1 deletion public/version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "10.4.3"
"version": "10.4.4"
}
27 changes: 27 additions & 0 deletions src/components/CippCards/CippDomainCards.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,13 @@ export const CippDomainCards = ({ domain: propDomain = "", fullwidth = false })
waiting: !!domain,
});

const { data: autoDiscoverData, isFetching: autoDiscoverLoading } = ApiGetCall({
url: "/api/ListDomainHealth",
queryKey: `autodiscover-${domain}`,
data: { Domain: domain, Action: "ReadAutoDiscover" },
waiting: !!domain,
});

const { data: httpsData, isFetching: httpsLoading } = ApiGetCall({
url: "/api/ListDomainHealth",
queryKey: `https-${domain}-${subdomains}`,
Expand Down Expand Up @@ -684,6 +691,26 @@ export const CippDomainCards = ({ domain: propDomain = "", fullwidth = false })
}
/>
</Grid>
<Grid size={{ md: gridItemSize, xs: 12 }}>
<DomainResultCard
title="AutoDiscover"
data={autoDiscoverData}
isFetching={autoDiscoverLoading}
info={
<div>
<p>
AutoDiscover ({autoDiscoverData?.RecordType || "None"}):
</p>
<CippCodeBlock code={autoDiscoverData?.Record || "No record found"} />
<ResultList
passes={autoDiscoverData?.ValidationPasses}
warns={autoDiscoverData?.ValidationWarns}
fails={autoDiscoverData?.ValidationFails}
/>
</div>
}
/>
</Grid>
{enableHttps && (
<Grid size={{ md: gridItemSize, xs: 12 }}>
<DomainResultCard
Expand Down
4 changes: 3 additions & 1 deletion src/components/CippComponents/CippBulkUserDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export const CippBulkUserDrawer = ({
const handleRemoveItem = (row) => {
if (row === undefined) return false;
const currentData = formControl.getValues("bulkUser") || [];
const index = currentData.findIndex((item) => item === row);
const rowKey = JSON.stringify(row);
const index = currentData.findIndex((item) => JSON.stringify(item) === rowKey);
if (index === -1) return false;
const newData = [...currentData];
newData.splice(index, 1);
formControl.setValue("bulkUser", newData, { shouldValidate: true });
Expand Down
259 changes: 259 additions & 0 deletions src/components/CippComponents/CippDeployCompliancePolicyDrawer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
import React, { useEffect, useState } from "react";
import { Button, Divider, Stack } from "@mui/material";
import { Grid } from "@mui/system";
import { useForm, useFormState, useWatch } from "react-hook-form";
import { RocketLaunch } from "@mui/icons-material";
import { CippOffCanvas } from "./CippOffCanvas";
import CippFormComponent from "./CippFormComponent";
import { CippFormTenantSelector } from "./CippFormTenantSelector";
import { CippApiResults } from "./CippApiResults";
import { ApiPostCall } from "../../api/ApiCall";

const MODE_CONFIG = {
DlpCompliancePolicy: {
title: "Deploy DLP Compliance Policy",
buttonLabel: "Deploy DLP Policy",
postUrl: "/api/AddDlpCompliancePolicy",
listTemplatesUrl: "/api/ListDlpCompliancePolicyTemplates",
templateQueryKey: "TemplateListDlpCompliancePolicy",
relatedQueryKeys: ["ListDlpCompliancePolicy", "ListDlpCompliancePolicyTemplates"],
placeholder: `{
"Name": "Block Credit Card data",
"Comment": "Blocks documents containing credit card numbers",
"Mode": "Enable",
"ExchangeLocation": "All",
"SharePointLocation": "All",
"OneDriveLocation": "All",
"RuleParams": {
"Name": "Block Credit Card data Rule",
"ContentContainsSensitiveInformation": [{ "name": "Credit Card Number", "minCount": "1" }],
"BlockAccess": true
}
}`,
},
RetentionCompliancePolicy: {
title: "Deploy Retention Compliance Policy",
buttonLabel: "Deploy Retention Policy",
postUrl: "/api/AddRetentionCompliancePolicy",
listTemplatesUrl: "/api/ListRetentionCompliancePolicyTemplates",
templateQueryKey: "TemplateListRetentionCompliancePolicy",
relatedQueryKeys: [
"ListRetentionCompliancePolicy",
"ListRetentionCompliancePolicyTemplates",
],
placeholder: `{
"Name": "7-year Email Retention",
"Comment": "Retain Exchange mail for 7 years",
"ExchangeLocation": "All",
"Enabled": true,
"RuleParams": {
"Name": "7-year Email Retention Rule",
"RetentionDuration": 2555,
"RetentionComplianceAction": "Keep",
"ExpirationDateOption": "ModificationAgeInDays"
}
}`,
},
SensitivityLabel: {
title: "Deploy Sensitivity Label",
buttonLabel: "Deploy Sensitivity Label",
postUrl: "/api/AddSensitivityLabel",
listTemplatesUrl: "/api/ListSensitivityLabelTemplates",
templateQueryKey: "TemplateListSensitivityLabel",
relatedQueryKeys: ["ListSensitivityLabel", "ListSensitivityLabelTemplates"],
placeholder: `{
"Name": "Confidential",
"DisplayName": "Confidential",
"Tooltip": "Confidential data, do not share externally",
"Comment": "Internal-only confidential classification",
"ContentType": "File, Email",
"EncryptionEnabled": true,
"EncryptionProtectionType": "Template",
"ContentMarkingHeaderEnabled": true,
"ContentMarkingHeaderText": "Confidential - Internal Use Only",
"PolicyParams": {
"Name": "Confidential Label Policy",
"ExchangeLocation": "All",
"Settings": [
["mandatory", "false"],
["disablemandatoryinoutlook", "true"]
]
}
}`,
},
SensitiveInfoType: {
title: "Deploy Sensitive Information Type",
buttonLabel: "Deploy SIT",
postUrl: "/api/AddSensitiveInfoType",
listTemplatesUrl: "/api/ListSensitiveInfoTypeTemplates",
templateQueryKey: "TemplateListSensitiveInfoType",
relatedQueryKeys: ["ListSensitiveInfoType", "ListSensitiveInfoTypeTemplates"],
placeholder: `{
"Name": "Custom Employee ID",
"Description": "Internal Employee ID format EMP-NNNNN",
"Pattern": "EMP-\\\\d{5}",
"Confidence": "High",
"Recommended": true
}

// Or with a base64-encoded XML rule pack:
// {
// "Name": "Custom Rule Pack",
// "FileDataBase64": "<BASE64 encoded XML rule pack>"
// }`,
},
};

export const CippDeployCompliancePolicyDrawer = ({
mode,
buttonText,
requiredPermissions = [],
PermissionButton = Button,
}) => {
const config = MODE_CONFIG[mode];

const [drawerVisible, setDrawerVisible] = useState(false);

const formControl = useForm({
mode: "onChange",
defaultValues: {
selectedTenants: [],
TemplateList: null,
PowerShellCommand: "",
},
});

const { isValid } = useFormState({ control: formControl.control });

const templateListVal = useWatch({ control: formControl.control, name: "TemplateList" });

useEffect(() => {
if (templateListVal?.value) {
formControl.setValue("PowerShellCommand", JSON.stringify(templateListVal.value));
}
}, [templateListVal, formControl]);

const deployPolicy = ApiPostCall({
urlFromData: true,
relatedQueryKeys: config?.relatedQueryKeys ?? [],
});

useEffect(() => {
if (deployPolicy.isSuccess) {
formControl.reset({
selectedTenants: [],
TemplateList: null,
PowerShellCommand: "",
});
}
}, [deployPolicy.isSuccess, formControl]);

if (!config) {
return null;
}

const handleSubmit = () => {
formControl.trigger();
if (!isValid) return;
deployPolicy.mutate({
url: config.postUrl,
data: formControl.getValues(),
});
};

const handleCloseDrawer = () => {
setDrawerVisible(false);
formControl.reset({
selectedTenants: [],
TemplateList: null,
PowerShellCommand: "",
});
};

return (
<>
<PermissionButton
requiredPermissions={requiredPermissions}
onClick={() => setDrawerVisible(true)}
startIcon={<RocketLaunch />}
>
{buttonText ?? config.buttonLabel}
</PermissionButton>
<CippOffCanvas
title={config.title}
visible={drawerVisible}
onClose={handleCloseDrawer}
size="lg"
footer={
<Stack direction="row" spacing={2} justifyContent="flex-start">
<Button
variant="contained"
color="primary"
onClick={handleSubmit}
disabled={deployPolicy.isLoading || !isValid}
>
{deployPolicy.isLoading
? "Deploying..."
: deployPolicy.isSuccess
? "Deploy Another"
: "Deploy"}
</Button>
<Button variant="outlined" onClick={handleCloseDrawer}>
Close
</Button>
</Stack>
}
>
<Grid container spacing={2} sx={{ mb: 2 }}>
<Grid size={{ xs: 12 }}>
<CippFormTenantSelector
label="Select Tenants"
formControl={formControl}
name="selectedTenants"
type="multiple"
allTenants={true}
preselectedEnabled={true}
validators={{ required: "At least one tenant must be selected" }}
/>
</Grid>

<Divider sx={{ my: 1, width: "100%" }} />

<Grid size={{ xs: 12 }}>
<CippFormComponent
type="autoComplete"
label="Select a template (optional)"
name="TemplateList"
formControl={formControl}
multiple={false}
api={{
queryKey: config.templateQueryKey,
labelField: "name",
valueField: (option) => option,
url: config.listTemplatesUrl,
}}
placeholder="Select a template or enter PowerShell JSON manually"
/>
</Grid>

<Divider sx={{ my: 1, width: "100%" }} />

<Grid size={{ xs: 12 }}>
<CippFormComponent
type="textField"
label="Parameters (JSON)"
name="PowerShellCommand"
formControl={formControl}
multiline
rows={12}
validators={{ required: "Please enter the PowerShell parameters as JSON." }}
placeholder={config.placeholder}
/>
</Grid>

<CippApiResults apiObject={deployPolicy} />
</Grid>
</CippOffCanvas>
</>
);
};
Loading