diff --git a/CopilotStudioUtils/CompromisedBotReport/CompromisedBotReport_1_0_0_6.zip b/CopilotStudioUtils/CompromisedBotReport/CompromisedBotReport_1_0_0_6.zip new file mode 100644 index 00000000..bdc837f7 Binary files /dev/null and b/CopilotStudioUtils/CompromisedBotReport/CompromisedBotReport_1_0_0_6.zip differ diff --git a/CopilotStudioUtils/CompromisedBotReport/README.MD b/CopilotStudioUtils/CompromisedBotReport/README.MD new file mode 100644 index 00000000..d95fe90c --- /dev/null +++ b/CopilotStudioUtils/CompromisedBotReport/README.MD @@ -0,0 +1,99 @@ +# Generate an at-risk copilot report ahead of MC699716 + +Microsoft Copilot Studio allows [adding copilots to Teams](https://learn.microsoft.com/en-us/microsoft-copilot-studio/publication-add-bot-to-microsoft-teams) using a number of methods: by sharing a direct link to the copilot, sharing the copilot with specific users or by sharing the copilot with the user's organization. + +Makers and users sometimes also "sideload" copilots in Teams, by uploading the copilot's manifest as a custom app. + +As per [MC699716](https://admin.microsoft.com/Adminportal/Home?#/MessageCenter/:/messages/MC699716), on January 31st, 2024, the ability to chat on Teams with copilots that are either shared via link or sideloaded, will be blocked for users who are not under a policy that allows uploading custom apps. + +

+ MC699716 +
+ Message MC699716 +

+ +## Impact for Copilot Studio customers + +Following the breaking change, copilots that have the Teams channel "Turned on", and are only shared via link will no longer be accessible to users. Moreover, users will no longer be able to chat with copilots that have been sideloaded (uploaded as a custom app by a non-admin user). + +Copilots that have been shared with specific users or submitted and published to the organization's Teams app catalog, will continue to work as expected. + +

+ Safe and unsafe methods +
+ Safe and unsafe methods +

+ +## What do you need to do to prepare + +To provide Power Platform admins with tenant-wide visibility into the potential impact of this change, we are sharing a template for a Power Automate Cloud flow that will generate a list of all the at-risk copilots in a customer's tenant. + +We encourage Power Platform admins to use this automated report to identify copilots that are at a risk of breaking and then work with copilot makers to publish copilots using one of the safe methods specified above. + +When published using one of the "safe methods", copilots will appear in Teams either under "Built with Power Platform" (when shared with specific users) or under "Built for your org" (when shared with the entire organization). + +**Please note:** the copilot app manifest which can be downloaded as a zip file, can be shared with a Teams admin and safely published to the Teams app catalog ("Built for your org"). The "Download as .zip" option is marked as unsafe, as it is also used for sideloading. + +## Import the cloud flow and generate a list of at-risk copilots + +After successfully importing and running the cloud flow, it will generate a list of at-risk copilots. The cloud flow retrieves all the copilots in a tenant that have the Teams channel "Turned on", and then performs two checks: whether the copilot is available in the Power Platform store ("Built with Power Platform") and whether it has been published to the Teams app catalog ("Built for your org"). If the copilot is missing from both catalogs, it is marked as at-risk, as it is expected to break with the upcoming change. + +A CSV file with the list of at-risk copilots will be generated by the cloud flow and shared with the user who initiated the flow run. The CSV includes the following fields: + +- Copilot name +- Copilot ID +- Environment ID +- Copilot owner name +- Copilot owner email + +## Setting up the necessary permissions, importing the cloud flow and generating the report + +Before importing the solution, make sure the following prerequisites are satisfied: + +- The user importing and later running the solution should have the Power Platform administrator role assigned +- Before importing the solution, an app registration should be created to allow reading from the Teams app catalog. Make sure you have the necessary permissions to create an app registration +- Verify the target tenant has sufficient licensing that allows using premium connectors in a standalone Power Automate flow + +Follow the steps below to set up the app registration and import the solution + +### Step 1 - Create an app registration + + +1. Login to Azure Portal. Create an app registration with the AppCatalog.Read.All permission, and grant admin consent for this app. + +

+ API Permissions +
+ API Permissions +

+ +2. Create a secret for the app + +3. Save your registered app's Application (client) ID & secret value for later + +4. Still in Azure Portal, navigate to the [tenant properties page](https://portal.azure.com/#view/Microsoft_AAD_IAM/TenantProperties.ReactView) and copy your tenant ID. + +### Step 2 - Import the solution + +1. Download the [solution file](./CompromisedBotReport_1_0_0_6.zip) +2. Sign in to [Power Automate](https://make.powerautomate.com/), and navigate to the solutions page +3. Select the Power Platform environment where the solution should be installed. A good choice would be the same environment where the CoE Starter Kit is installed. +4. Click on "Import solution" and select the solution file that was downloaded in (1) +5. Create the necessary connections for: Office 365, Power Platform for Admins and Microsoft Dataverse +6. When asked to populate the environment variables, provide the values documented in (step 1): Tenant ID, Application (Client) ID & Secret +7. Complete importing the solution + +### Step 3 - Run the report + +1. Once the solution has been successfully imported, you should see a flow called "Generate Compromised Bot Report" in your environment + +

+ Compromised Bot Report +
+ The Cloud Flow +

+ +2. Run the flow, and wait for it to complete. On a successful run, you should receive an email message with the list of compromised copilots attached. + +## Questions and issues +In case of questions and feedback regarding the cloud flow template, open an issue in this repository diff --git a/CopilotStudioUtils/CompromisedBotReport/images/appRegistration.png b/CopilotStudioUtils/CompromisedBotReport/images/appRegistration.png new file mode 100644 index 00000000..236c7061 Binary files /dev/null and b/CopilotStudioUtils/CompromisedBotReport/images/appRegistration.png differ diff --git a/CopilotStudioUtils/CompromisedBotReport/images/flow.png b/CopilotStudioUtils/CompromisedBotReport/images/flow.png new file mode 100644 index 00000000..f7e438af Binary files /dev/null and b/CopilotStudioUtils/CompromisedBotReport/images/flow.png differ diff --git a/CopilotStudioUtils/CompromisedBotReport/images/greenRedMethods.png b/CopilotStudioUtils/CompromisedBotReport/images/greenRedMethods.png new file mode 100644 index 00000000..54fd47bd Binary files /dev/null and b/CopilotStudioUtils/CompromisedBotReport/images/greenRedMethods.png differ diff --git a/CopilotStudioUtils/CompromisedBotReport/images/messageCenter.png b/CopilotStudioUtils/CompromisedBotReport/images/messageCenter.png new file mode 100644 index 00000000..6d3edac3 Binary files /dev/null and b/CopilotStudioUtils/CompromisedBotReport/images/messageCenter.png differ diff --git a/SharePointSSOComponent/.eslintrc.js b/SharePointSSOComponent/.eslintrc.js index ef68d0e9..f6e5edb0 100644 --- a/SharePointSSOComponent/.eslintrc.js +++ b/SharePointSSOComponent/.eslintrc.js @@ -12,8 +12,9 @@ module.exports = { 'sourceType': 'module' }, rules: { + '@typescript-eslint/no-empty-function': 0, // Prevent usage of the JavaScript null value, while allowing code to access existing APIs that may require null. https://www.npmjs.com/package/@rushstack/eslint-plugin - '@rushstack/no-new-null': 1, + '@rushstack/no-new-null': 0, // Require Jest module mocking APIs to be called before any other statements in their code block. https://www.npmjs.com/package/@rushstack/eslint-plugin '@rushstack/hoist-jest-mock': 1, // Require regular expressions to be constructed from string constants rather than dynamically building strings at runtime. https://www.npmjs.com/package/@rushstack/eslint-plugin-security @@ -60,7 +61,7 @@ module.exports = { // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/explicit-function-return-type': [ - 1, + 0, { 'allowExpressions': true, 'allowTypedFunctionExpressions': true, @@ -79,7 +80,7 @@ module.exports = { // This rule should be suppressed only in very special cases such as JSON.stringify() // where the type really can be anything. Even if the type is flexible, another type // may be more appropriate such as "unknown", "{}", or "Record". - '@typescript-eslint/no-explicit-any': 1, + '@typescript-eslint/no-explicit-any': 0, // RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch() // handler. Thus wherever a Promise arises, the code must either append a catch handler, // or else return the object to a caller (who assumes this responsibility). Unterminated @@ -323,7 +324,7 @@ module.exports = { // ==================================================================== '@microsoft/spfx/import-requires-chunk-name': 1, '@microsoft/spfx/no-require-ensure': 2, - '@microsoft/spfx/pair-react-dom-render-unmount': 1 + '@microsoft/spfx/pair-react-dom-render-unmount': 0 } }, { diff --git a/SharePointSSOComponent/.gitignore b/SharePointSSOComponent/.gitignore index 51ca7b9e..564d87f3 100644 --- a/SharePointSSOComponent/.gitignore +++ b/SharePointSSOComponent/.gitignore @@ -12,7 +12,6 @@ lib release solution temp -*.sppkg .heft # Coverage directory used by tools like istanbul diff --git a/SharePointSSOComponent/Configure-McsForSite.ps1 b/SharePointSSOComponent/Configure-McsForSite.ps1 new file mode 100644 index 00000000..d8ee1b39 --- /dev/null +++ b/SharePointSSOComponent/Configure-McsForSite.ps1 @@ -0,0 +1,38 @@ +param ( + [Parameter(Mandatory=$true)] + [string]$siteUrl, + + [Parameter(Mandatory=$true)] + [string]$botUrl, + + [Parameter(Mandatory=$true)] + [string]$botName, + + [Parameter(Mandatory=$true)] + [string]$customScope, + + [Parameter(Mandatory=$true)] + [string]$clientId, + + [Parameter(Mandatory=$true)] + [string]$authority, + + [Parameter(Mandatory=$true)] + [string]$buttonLabel +) + +Connect-PnPOnline -Url $siteUrl -Interactive +$action = (Get-PnPCustomAction | Where-Object { $_.Title -eq "PvaSso" })[0] + +$action.ClientSideComponentProperties = @{ + "botURL" = $botUrl + "customScope" = $customScope + "clientID" = $clientId + "authority" = $authority + "greet" = $true + "buttonLabel" = $buttonLabel + "botName" = $botName +} | ConvertTo-Json -Compress + +$action.Update() +Invoke-PnPQuery \ No newline at end of file