diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml
index a23d2a5d..c2e7ba8b 100644
--- a/.github/workflows/generate-docs.yml
+++ b/.github/workflows/generate-docs.yml
@@ -45,7 +45,8 @@ jobs:
- name: Generate tf docs
run: |
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
- tfplugindocs generate --examples-dir examples
+ cd $GITHUB_WORKSPACE
+ tfplugindocs generate --examples-dir $GITHUB_WORKSPACE/examples
- name: Check for changes in generated Go docs and formatted Terraform files
id: go-gen-check
diff --git a/.github/workflows/provider-release.yml b/.github/workflows/provider-release.yml
index 57fe93f2..793d9620 100644
--- a/.github/workflows/provider-release.yml
+++ b/.github/workflows/provider-release.yml
@@ -4,6 +4,12 @@ on:
push:
tags:
- 'v*'
+ workflow_dispatch:
+ inputs:
+ release_version:
+ description: 'TF Provider Release version to publish'
+ required: true
+ default: 'v0.0.0'
permissions:
contents: write
diff --git a/docs/index.md b/docs/index.md
index f74af795..e6a6a6d4 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -213,7 +213,7 @@ terraform {
required_providers {
microsoft365 = {
source = "deploymenttheory/terraform-provider-microsoft365"
- version = "~> 1.0.0"
+ version = "~> 1.0.0"
}
}
}
@@ -227,16 +227,16 @@ provider "microsoft365" {
debug_mode = var.debug_mode
entra_id_options = {
- client_id = var.client_id
- client_secret = var.client_secret
- client_certificate = var.client_certificate
- client_certificate_password = var.client_certificate_password
- send_certificate_chain = var.send_certificate_chain
- username = var.username
- password = var.password
- disable_instance_discovery = var.disable_instance_discovery
- additionally_allowed_tenants = var.additionally_allowed_tenants
- redirect_url = var.redirect_url
+ client_id = var.client_id
+ client_secret = var.client_secret
+ client_certificate = var.client_certificate
+ client_certificate_password = var.client_certificate_password
+ send_certificate_chain = var.send_certificate_chain
+ username = var.username
+ password = var.password
+ disable_instance_discovery = var.disable_instance_discovery
+ additionally_allowed_tenants = var.additionally_allowed_tenants
+ redirect_url = var.redirect_url
}
client_options = {
diff --git a/docs/resources/graph_beta_device_and_app_management_macos_platform_script.md b/docs/resources/graph_beta_device_and_app_management_macos_platform_script.md
index be5be185..7d192cdf 100644
--- a/docs/resources/graph_beta_device_and_app_management_macos_platform_script.md
+++ b/docs/resources/graph_beta_device_and_app_management_macos_platform_script.md
@@ -115,6 +115,6 @@ Import is supported using the following syntax:
```shell
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_device_shell_script.example device-shell-script-id
+terraform import microsoft365_graph_beta_device_and_app_management_device_shell_script.example device-shell-script-id
```
diff --git a/docs/resources/graph_beta_device_and_app_management_settings_catalog.md b/docs/resources/graph_beta_device_and_app_management_settings_catalog.md
index 8cff4c79..3ba04045 100644
--- a/docs/resources/graph_beta_device_and_app_management_settings_catalog.md
+++ b/docs/resources/graph_beta_device_and_app_management_settings_catalog.md
@@ -494,6 +494,6 @@ Import is supported using the following syntax:
```shell
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_settings_catalog.example settings-catalog-id
+terraform import microsoft365_graph_beta_device_and_app_management_settings_catalog.example settings-catalog-id
```
diff --git a/docs/resources/graph_beta_device_and_app_management_windows_platform_script.md b/docs/resources/graph_beta_device_and_app_management_windows_platform_script.md
index 30bba17f..795b5fb9 100644
--- a/docs/resources/graph_beta_device_and_app_management_windows_platform_script.md
+++ b/docs/resources/graph_beta_device_and_app_management_windows_platform_script.md
@@ -106,6 +106,6 @@ Import is supported using the following syntax:
```shell
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_device_management_script.example device-management-script-id
+terraform import microsoft365_graph_beta_device_and_app_management_device_management_script.example device-management-script-id
```
diff --git a/docs/resources/graph_beta_identity_and_access_conditional_access_policy.md b/docs/resources/graph_beta_identity_and_access_conditional_access_policy.md
index 70477bed..b04778c6 100644
--- a/docs/resources/graph_beta_identity_and_access_conditional_access_policy.md
+++ b/docs/resources/graph_beta_identity_and_access_conditional_access_policy.md
@@ -1,7 +1,6 @@
---
-# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "microsoft365_graph_beta_identity_and_access_conditional_access_policy Resource - terraform-provider-microsoft365"
-subcategory: ""
+subcategory: "Identity & Access: Conditional Access Policy"
description: |-
---
@@ -10,7 +9,110 @@ description: |-
-
+## Example Usage
+
+```terraform
+resource "microsoft365_graph_beta_identity_and_access_conditional_access_policy" "example_policy" {
+ display_name = "test"
+ state = "disabled"
+
+ conditions = {
+ applications = {
+ include_applications = ["All"]
+ exclude_applications = []
+ include_user_actions = []
+ application_filter = null
+ }
+
+ users = {
+ include_users = ["All"]
+ exclude_users = ["11111111-1111-1111-1111-111111111111"]
+ include_groups = []
+ exclude_groups = ["11111111-1111-1111-1111-111111111111"]
+ exclude_roles = [
+ "11111111-1111-1111-1111-111111111111",
+ "11111111-1111-1111-1111-111111111111"
+ ]
+ exclude_guests_or_external_users = {
+ guest_or_external_user_types = ["b2bCollaborationGuest", "b2bCollaborationMember"]
+ external_tenants = {
+ membership_kind = "all"
+ }
+ }
+ }
+
+ platforms = {
+ include_platforms = ["iOS", "windows", "windowsPhone"]
+ exclude_platforms = []
+ }
+
+ locations = {
+ include_locations = [
+ "11111111-1111-1111-1111-111111111111",
+ "11111111-1111-1111-1111-111111111111"
+ ]
+ exclude_locations = []
+ }
+
+ client_app_types = ["browser", "mobileAppsAndDesktopClients", "exchangeActiveSync", "other"]
+
+ devices = {
+ device_filter = {
+ mode = "include"
+ rule = "device.deviceId -eq \"thing\""
+ }
+ include_devices = []
+ exclude_devices = []
+ }
+
+ user_risk_levels = ["high"]
+ sign_in_risk_levels = ["none"]
+
+ authentication_flows = {
+ transfer_methods = ["deviceCodeFlow", "authenticationTransfer"]
+ }
+ }
+
+ grant_controls = {
+ operator = "AND"
+ built_in_controls = ["mfa", "approvedApplication"]
+ }
+
+ session_controls = {
+ cloud_app_security = {
+ is_enabled = true
+ cloud_app_security_type = "monitorOnly"
+ }
+
+ sign_in_frequency = {
+ is_enabled = true
+ type = "hours"
+ value = 5
+ frequency_interval = "timeBased"
+ authentication_type = "primaryAndSecondaryAuthentication"
+ }
+
+ persistent_browser = {
+ is_enabled = true
+ mode = "always"
+ }
+
+ continuous_access_evaluation = {
+ mode = "strictLocation"
+ }
+
+ disable_resilience_defaults = true
+ }
+
+ # Optional: Define custom timeouts
+ timeouts = {
+ create = "30m"
+ read = "10m"
+ update = "30m"
+ delete = "30m"
+ }
+}
+```
## Schema
@@ -96,7 +198,7 @@ Optional:
Required:
-- `guest_or_external_user_types` (String) Indicates internal guests or external user types. Possible values are: none, internalGuest, b2bCollaborationGuest, b2bCollaborationMember, b2bDirectConnectUser, otherExternalUser, serviceProvider, unknownFutureValue.
+- `guest_or_external_user_types` (List of String) Indicates internal guests or external user types. Possible values are: none, internalGuest, b2bCollaborationGuest, b2bCollaborationMember, b2bDirectConnectUser, otherExternalUser, serviceProvider, unknownFutureValue.
Optional:
@@ -116,7 +218,7 @@ Required:
Required:
-- `guest_or_external_user_types` (String) Indicates internal guests or external user types. Possible values are: none, internalGuest, b2bCollaborationGuest, b2bCollaborationMember, b2bDirectConnectUser, otherExternalUser, serviceProvider, unknownFutureValue.
+- `guest_or_external_user_types` (List of String) Indicates internal guests or external user types. Possible values are: none, internalGuest, b2bCollaborationGuest, b2bCollaborationMember, b2bDirectConnectUser, otherExternalUser, serviceProvider, unknownFutureValue.
Optional:
@@ -137,7 +239,7 @@ Required:
Optional:
-- `transfer_methods` (String) Represents the transfer methods in scope for the policy. The possible values are: none, deviceCodeFlow, authenticationTransfer, unknownFutureValue.
+- `transfer_methods` (List of String) Represents the transfer methods in scope for the policy. The possible values are: none, deviceCodeFlow, authenticationTransfer, unknownFutureValue.
@@ -174,9 +276,7 @@ Optional:
Optional:
- `device_filter` (Attributes) Filter that defines the dynamic-device-syntax rule to include/exclude devices. A filter can use device properties (such as extension attributes) to include/exclude them. Cannot be set if includeDevices or excludeDevices is set. (see [below for nested schema](#nestedatt--conditions--devices--device_filter))
-- `exclude_device_states` (List of String, Deprecated) (Deprecated) States excluded from the scope of the policy. Possible values: 'Compliant', 'DomainJoined'.
- `exclude_devices` (List of String) States excluded from the scope of the policy. Possible values: 'Compliant', 'DomainJoined'. Cannot be set if deviceFilter is set.
-- `include_device_states` (List of String, Deprecated) (Deprecated) States in the scope of the policy. 'All' is the only allowed value.
- `include_devices` (List of String) States in the scope of the policy. 'All' is the only allowed value. Cannot be set if deviceFilter is set.
@@ -321,3 +421,13 @@ Optional:
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Using the provider-default project ID, the import ID is:
+# {resource_id}
+terraform import microsoft365_graph_beta_identity_and_access_conditional_access_policy.example conditional-access-policy-id
+```
\ No newline at end of file
diff --git a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_macos_platform_script/import.sh b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_macos_platform_script/import.sh
index eb371aa8..9537ecaa 100644
--- a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_macos_platform_script/import.sh
+++ b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_macos_platform_script/import.sh
@@ -1,4 +1,4 @@
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_device_shell_script.example device-shell-script-id
+terraform import microsoft365_graph_beta_device_and_app_management_device_shell_script.example device-shell-script-id
diff --git a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_settings_catalog/import.sh b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_settings_catalog/import.sh
index 38a24ceb..72ccba78 100644
--- a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_settings_catalog/import.sh
+++ b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_settings_catalog/import.sh
@@ -1,4 +1,4 @@
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_settings_catalog.example settings-catalog-id
+terraform import microsoft365_graph_beta_device_and_app_management_settings_catalog.example settings-catalog-id
diff --git a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_windows_platform_script/import.sh b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_windows_platform_script/import.sh
index 67d3bc59..7009d17d 100644
--- a/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_windows_platform_script/import.sh
+++ b/examples/microsoft365_graph_beta/microsoft365_graph_beta_device_and_app_management_windows_platform_script/import.sh
@@ -1,4 +1,4 @@
# Using the provider-default project ID, the import ID is:
# {resource_id}
-terraform terraform import microsoft365_graph_beta_device_and_app_management_device_management_script.example device-management-script-id
+terraform import microsoft365_graph_beta_device_and_app_management_device_management_script.example device-management-script-id
diff --git a/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/import.sh b/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/import.sh
new file mode 100644
index 00000000..8ff28f1d
--- /dev/null
+++ b/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/import.sh
@@ -0,0 +1,4 @@
+# Using the provider-default project ID, the import ID is:
+# {resource_id}
+terraform import microsoft365_graph_beta_identity_and_access_conditional_access_policy.example conditional-access-policy-id
+
diff --git a/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/resource.tf b/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/resource.tf
index e32a9141..5b07841f 100644
--- a/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/resource.tf
+++ b/examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/resource.tf
@@ -1,95 +1,81 @@
resource "microsoft365_graph_beta_identity_and_access_conditional_access_policy" "example_policy" {
- display_name = "Example Conditional Access Policy"
- state = "enabled"
+ display_name = "test"
+ state = "disabled"
conditions = {
applications = {
include_applications = ["All"]
- exclude_applications = ["MicrosoftAdminPortals"]
- application_filter = {
- mode = "include"
- rule = "(appId -eq '11111111-1111-1111-1111-111111111111')"
- }
- include_user_actions = ["urn:user:registersecurityinfo"]
- }
-
- authentication_flows = {
- transfer_methods = "deviceCodeFlow"
+ exclude_applications = []
+ include_user_actions = []
+ application_filter = null
}
users = {
include_users = ["All"]
exclude_users = ["11111111-1111-1111-1111-111111111111"]
- include_groups = ["22222222-2222-2222-2222-222222222222"]
- }
-
- client_applications = {
- include_service_principals = ["ServicePrincipalsInMyTenant"]
- exclude_service_principals = ["33333333-3333-3333-3333-333333333333"]
- service_principal_filter = {
- mode = "include"
- rule = "(servicePrincipalId -eq '44444444-4444-4444-4444-444444444444')"
+ include_groups = []
+ exclude_groups = ["11111111-1111-1111-1111-111111111111"]
+ exclude_roles = [
+ "11111111-1111-1111-1111-111111111111",
+ "11111111-1111-1111-1111-111111111111"
+ ]
+ exclude_guests_or_external_users = {
+ guest_or_external_user_types = ["b2bCollaborationGuest", "b2bCollaborationMember"]
+ external_tenants = {
+ membership_kind = "all"
+ }
}
}
- client_app_types = ["all"]
-
- locations = {
- include_locations = ["All"]
- exclude_locations = ["55555555-5555-5555-5555-555555555555"]
- }
-
platforms = {
- include_platforms = ["android", "iOS"]
- exclude_platforms = ["windows"]
+ include_platforms = ["iOS", "windows", "windowsPhone"]
+ exclude_platforms = []
}
- device_states = {
- include_states = ["All"]
- exclude_states = ["Compliant"]
+ locations = {
+ include_locations = [
+ "11111111-1111-1111-1111-111111111111",
+ "11111111-1111-1111-1111-111111111111"
+ ]
+ exclude_locations = []
}
+ client_app_types = ["browser", "mobileAppsAndDesktopClients", "exchangeActiveSync", "other"]
+
devices = {
- include_devices = ["All"]
- exclude_devices = ["DomainJoined"]
device_filter = {
- mode = "exclude"
- rule = "(device.deviceId -eq '66666666-6666-6666-6666-666666666666')"
+ mode = "include"
+ rule = "device.deviceId -eq \"thing\""
}
+ include_devices = []
+ exclude_devices = []
}
- sign_in_risk_levels = ["medium", "high"]
- user_risk_levels = ["low", "medium"]
+ user_risk_levels = ["high"]
+ sign_in_risk_levels = ["none"]
+
+ authentication_flows = {
+ transfer_methods = ["deviceCodeFlow", "authenticationTransfer"]
+ }
}
grant_controls = {
- operator = "OR"
- built_in_controls = ["mfa", "compliantDevice"]
- custom_authentication_factors = ["77777777-7777-7777-7777-777777777777"]
- terms_of_use = ["88888888-8888-8888-8888-888888888888"]
-
- authentication_strength = {
- id = "99999999-9999-9999-9999-999999999999"
- display_name = "Example Authentication Strength"
- description = "A description for the authentication strength."
- policy_type = "required"
- requirements_satisfied = "mfa"
- allowed_combinations = ["password", "biometric"]
- }
+ operator = "AND"
+ built_in_controls = ["mfa", "approvedApplication"]
}
session_controls = {
- application_enforced_restrictions = {
- is_enabled = true
- }
-
cloud_app_security = {
is_enabled = true
cloud_app_security_type = "monitorOnly"
}
- continuous_access_evaluation = {
- mode = "strictEnforcement"
+ sign_in_frequency = {
+ is_enabled = true
+ type = "hours"
+ value = 5
+ frequency_interval = "timeBased"
+ authentication_type = "primaryAndSecondaryAuthentication"
}
persistent_browser = {
@@ -97,20 +83,13 @@ resource "microsoft365_graph_beta_identity_and_access_conditional_access_policy"
mode = "always"
}
- sign_in_frequency = {
- is_enabled = true
- type = "days"
- value = 1
- authentication_type = "primaryAndSecondaryAuthentication"
- frequency_interval = "timeBased"
+ continuous_access_evaluation = {
+ mode = "strictLocation"
}
- disable_resilience_defaults = false
-
- secure_sign_in_session = {
- is_enabled = true
- }
+ disable_resilience_defaults = true
}
+
# Optional: Define custom timeouts
timeouts = {
create = "30m"
@@ -118,4 +97,4 @@ resource "microsoft365_graph_beta_identity_and_access_conditional_access_policy"
update = "30m"
delete = "30m"
}
-}
+}
\ No newline at end of file
diff --git a/internal/resources/_resource_template/crud.go b/internal/resources/_resource_template/crud.go
index 19657ef0..ac0067a7 100644
--- a/internal/resources/_resource_template/crud.go
+++ b/internal/resources/_resource_template/crud.go
@@ -3,7 +3,6 @@ package graphVersionResourceTemplate
import (
"context"
"fmt"
- "sync"
"time"
"github.com/deploymenttheory/terraform-provider-microsoft365/internal/resources/common/crud"
@@ -11,18 +10,13 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
)
-// Create requires a mutex need to lock Create requests during parallel runs
-var mu sync.Mutex
-
// Create handles the Create operation.
func (r *ResourceTemplateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan ResourceTemplateResourceModel
- mu.Lock()
- defer mu.Unlock()
-
tflog.Debug(ctx, fmt.Sprintf("Starting creation of resource: %s_%s", r.ProviderTypeName, r.TypeName))
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
@@ -57,13 +51,33 @@ func (r *ResourceTemplateResource) Create(ctx context.Context, req resource.Crea
plan.ID = types.StringValue(*resource.GetId())
- MapRemoteStateToTerraform(ctx, &plan, resource)
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+ resp.Diagnostics.Append(resp.State.Set(ctx, &object)...)
if resp.Diagnostics.HasError() {
return
}
+ err = retry.RetryContext(ctx, retryTimeout, func() *retry.RetryError {
+ readResp := &resource.ReadResponse{State: resp.State}
+ r.Read(ctx, resource.ReadRequest{
+ State: resp.State,
+ ProviderMeta: req.ProviderMeta,
+ }, readResp)
+
+ if readResp.Diagnostics.HasError() {
+ return retry.NonRetryableError(fmt.Errorf("error reading resource state after Create Method: %s", readResp.Diagnostics.Errors()))
+ }
+
+ resp.State = readResp.State
+ return nil
+ })
+
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error waiting for resource creation",
+ fmt.Sprintf("Failed to verify resource creation: %s", err),
+ )
+ return
+ }
tflog.Debug(ctx, fmt.Sprintf("Finished Create Method: %s_%s", r.ProviderTypeName, r.TypeName))
}
@@ -140,12 +154,30 @@ func (r *ResourceTemplateResource) Update(ctx context.Context, req resource.Upda
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
+ err = retry.RetryContext(ctx, retryTimeout, func() *retry.RetryError {
+ readResp := &resource.ReadResponse{State: resp.State}
+ r.Read(ctx, resource.ReadRequest{
+ State: resp.State,
+ ProviderMeta: req.ProviderMeta,
+ }, readResp)
+
+ if readResp.Diagnostics.HasError() {
+ return retry.NonRetryableError(fmt.Errorf("error reading resource state after Update Method: %s", readResp.Diagnostics.Errors()))
+ }
+
+ resp.State = readResp.State
+ return nil
+ })
+
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error waiting for resource update",
+ fmt.Sprintf("Failed to verify resource update: %s", err),
+ )
return
}
@@ -176,7 +208,7 @@ func (r *ResourceTemplateResource) Delete(ctx context.Context, req resource.Dele
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/common/errors/error_handling.go b/internal/resources/common/errors/error_handling.go
index 8c9565c6..76102299 100644
--- a/internal/resources/common/errors/error_handling.go
+++ b/internal/resources/common/errors/error_handling.go
@@ -86,13 +86,20 @@ func HandleGraphError(ctx context.Context, err error, resp interface{}, operatio
constructErrorDetail(errorDesc.Detail, errorInfo.ErrorMessage))
case 401, 403:
- if operation == "Read" {
- tflog.Warn(ctx, "Permission error on read operation, check required Graph permissions")
- handlePermissionError(ctx, errorInfo, resp, operation, requiredPermissions)
- return
+ tflog.Warn(ctx, fmt.Sprintf("Permission error on %s operation, check required Graph permissions", operation))
+
+ var requiredPermissionsToReport []string
+ switch operation {
+ case "Read":
+ requiredPermissionsToReport = requiredPermissions
+ case "Create", "Update", "Delete":
+ requiredPermissionsToReport = requiredPermissions
+ default:
+ requiredPermissionsToReport = []string{}
}
- addErrorToDiagnostics(ctx, resp, errorDesc.Summary,
- constructErrorDetail(errorDesc.Detail, errorInfo.ErrorMessage))
+
+ handlePermissionError(ctx, errorInfo, resp, operation, requiredPermissionsToReport)
+ return
case 404:
if operation == "Read" {
diff --git a/internal/resources/device_and_app_management/beta/assignment_filter/crud.go b/internal/resources/device_and_app_management/beta/assignment_filter/crud.go
index 0fb613e7..8cc784d5 100644
--- a/internal/resources/device_and_app_management/beta/assignment_filter/crud.go
+++ b/internal/resources/device_and_app_management/beta/assignment_filter/crud.go
@@ -172,7 +172,7 @@ func (r *AssignmentFilterResource) Update(ctx context.Context, req resource.Upda
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -231,7 +231,7 @@ func (r *AssignmentFilterResource) Delete(ctx context.Context, req resource.Dele
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/browser_site/crud.go b/internal/resources/device_and_app_management/beta/browser_site/crud.go
index 6cf642eb..d90f0003 100644
--- a/internal/resources/device_and_app_management/beta/browser_site/crud.go
+++ b/internal/resources/device_and_app_management/beta/browser_site/crud.go
@@ -156,7 +156,7 @@ func (r *BrowserSiteResource) Update(ctx context.Context, req resource.UpdateReq
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -198,7 +198,7 @@ func (r *BrowserSiteResource) Delete(ctx context.Context, req resource.DeleteReq
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/browser_site_list/crud.go b/internal/resources/device_and_app_management/beta/browser_site_list/crud.go
index 40f9d504..edb0a7fa 100644
--- a/internal/resources/device_and_app_management/beta/browser_site_list/crud.go
+++ b/internal/resources/device_and_app_management/beta/browser_site_list/crud.go
@@ -138,7 +138,7 @@ func (r *BrowserSiteListResource) Update(ctx context.Context, req resource.Updat
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -176,7 +176,7 @@ func (r *BrowserSiteListResource) Delete(ctx context.Context, req resource.Delet
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/device_management_template/crud.go b/internal/resources/device_and_app_management/beta/device_management_template/crud.go
index 4b3f3aed..e8ef2d4d 100644
--- a/internal/resources/device_and_app_management/beta/device_management_template/crud.go
+++ b/internal/resources/device_and_app_management/beta/device_management_template/crud.go
@@ -363,7 +363,7 @@ func (r *DeviceManagementTemplateResource) Delete(ctx context.Context, req resou
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/endpoint_privilege_management/crud.go b/internal/resources/device_and_app_management/beta/endpoint_privilege_management/crud.go
index c145e8d4..a04b24b0 100644
--- a/internal/resources/device_and_app_management/beta/endpoint_privilege_management/crud.go
+++ b/internal/resources/device_and_app_management/beta/endpoint_privilege_management/crud.go
@@ -363,7 +363,7 @@ func (r *EndpointPrivilegeManagementResource) Delete(ctx context.Context, req re
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/linux_platform_script/crud.go b/internal/resources/device_and_app_management/beta/linux_platform_script/crud.go
index 5803031a..986ec204 100644
--- a/internal/resources/device_and_app_management/beta/linux_platform_script/crud.go
+++ b/internal/resources/device_and_app_management/beta/linux_platform_script/crud.go
@@ -283,7 +283,7 @@ package graphBetaLinuxPlatformScript
// err = client.SendCustomPutRequestByResourceId(ctx, r.client.GetAdapter(), putRequest)
// if err != nil {
-// errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+// errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
// return
// }
@@ -361,7 +361,7 @@ package graphBetaLinuxPlatformScript
// Delete(ctx, nil)
// if err != nil {
-// errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+// errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
// return
// }
diff --git a/internal/resources/device_and_app_management/beta/m365_apps_installation_options/crud.go b/internal/resources/device_and_app_management/beta/m365_apps_installation_options/crud.go
index 5b7e5983..909b4c5e 100644
--- a/internal/resources/device_and_app_management/beta/m365_apps_installation_options/crud.go
+++ b/internal/resources/device_and_app_management/beta/m365_apps_installation_options/crud.go
@@ -135,7 +135,7 @@ func (r *M365AppsInstallationOptionsResource) Update(ctx context.Context, req re
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/macos_pkg_app/crud.go b/internal/resources/device_and_app_management/beta/macos_pkg_app/crud.go
index cac7f131..f191166e 100644
--- a/internal/resources/device_and_app_management/beta/macos_pkg_app/crud.go
+++ b/internal/resources/device_and_app_management/beta/macos_pkg_app/crud.go
@@ -151,7 +151,7 @@ func (r *MacOSPkgAppResource) Update(ctx context.Context, req resource.UpdateReq
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -198,7 +198,7 @@ func (r *MacOSPkgAppResource) Delete(ctx context.Context, req resource.DeleteReq
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/macos_platform_script/crud.go b/internal/resources/device_and_app_management/beta/macos_platform_script/crud.go
index ec7abecf..52418969 100644
--- a/internal/resources/device_and_app_management/beta/macos_platform_script/crud.go
+++ b/internal/resources/device_and_app_management/beta/macos_platform_script/crud.go
@@ -303,7 +303,7 @@ func (r *MacOSPlatformScriptResource) Delete(ctx context.Context, req resource.D
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/mobile_app_assignment/crud.go b/internal/resources/device_and_app_management/beta/mobile_app_assignment/crud.go
index f728ae38..b9e391b0 100644
--- a/internal/resources/device_and_app_management/beta/mobile_app_assignment/crud.go
+++ b/internal/resources/device_and_app_management/beta/mobile_app_assignment/crud.go
@@ -163,7 +163,7 @@ func (r *MobileAppAssignmentResource) Update(ctx context.Context, req resource.U
Post(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -199,7 +199,7 @@ func (r *MobileAppAssignmentResource) Delete(ctx context.Context, req resource.D
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/role_definition/crud.go b/internal/resources/device_and_app_management/beta/role_definition/crud.go
index bad12344..fb2caeb6 100644
--- a/internal/resources/device_and_app_management/beta/role_definition/crud.go
+++ b/internal/resources/device_and_app_management/beta/role_definition/crud.go
@@ -252,7 +252,7 @@ func (r *RoleDefinitionResource) Delete(ctx context.Context, req resource.Delete
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/role_scope_tag/crud.go b/internal/resources/device_and_app_management/beta/role_scope_tag/crud.go
index a1ad2171..22024898 100644
--- a/internal/resources/device_and_app_management/beta/role_scope_tag/crud.go
+++ b/internal/resources/device_and_app_management/beta/role_scope_tag/crud.go
@@ -317,7 +317,7 @@ func (r *RoleScopeTagResource) Delete(ctx context.Context, req resource.DeleteRe
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/windows_platform_script/crud.go b/internal/resources/device_and_app_management/beta/windows_platform_script/crud.go
index 24ab57c4..3da3163e 100644
--- a/internal/resources/device_and_app_management/beta/windows_platform_script/crud.go
+++ b/internal/resources/device_and_app_management/beta/windows_platform_script/crud.go
@@ -3,7 +3,6 @@ package graphBetaWindowsPlatformScript
import (
"context"
"fmt"
- "sync"
"time"
"github.com/deploymenttheory/terraform-provider-microsoft365/internal/resources/common/crud"
@@ -13,19 +12,9 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog"
)
-var (
- // mutex needed to lock Create requests during parallel runs to avoid overwhelming api and resulting in stating issues
- mu sync.Mutex
-
- // object is the resource model for the device management script resource
- object WindowsPlatformScriptResourceModel
-)
-
// Create handles the Create operation.
func (r *WindowsPlatformScriptResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
-
- mu.Lock()
- defer mu.Unlock()
+ var object WindowsPlatformScriptResourceModel
tflog.Debug(ctx, fmt.Sprintf("Starting creation of resource: %s_%s", r.ProviderTypeName, r.TypeName))
@@ -132,7 +121,7 @@ func (r *WindowsPlatformScriptResource) Create(ctx context.Context, req resource
// are properly read and mapped into the Terraform state, providing a complete view
// of the resource's current configuration on the server.
func (r *WindowsPlatformScriptResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
-
+ var object WindowsPlatformScriptResourceModel
tflog.Debug(ctx, fmt.Sprintf("Starting Read method for: %s_%s", r.ProviderTypeName, r.TypeName))
resp.Diagnostics.Append(req.State.Get(ctx, &object)...)
@@ -198,6 +187,7 @@ func (r *WindowsPlatformScriptResource) Read(ctx context.Context, req resource.R
// Produces 400 ODATA errors when attempting to update the resource settings using PATCH.
// Tested with custom PUT, SDK PATCH and custom POST requests, all failed.
func (r *WindowsPlatformScriptResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var object WindowsPlatformScriptResourceModel
tflog.Debug(ctx, fmt.Sprintf("Starting Update of resource: %s_%s", r.ProviderTypeName, r.TypeName))
// Get current state
@@ -321,7 +311,7 @@ func (r *WindowsPlatformScriptResource) Update(ctx context.Context, req resource
//
// All assignments and settings associated with the resource are automatically removed as part of the deletion.
func (r *WindowsPlatformScriptResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
-
+ var object WindowsPlatformScriptResourceModel
tflog.Debug(ctx, fmt.Sprintf("Starting deletion of resource: %s_%s", r.ProviderTypeName, r.TypeName))
resp.Diagnostics.Append(req.State.Get(ctx, &object)...)
@@ -342,7 +332,7 @@ func (r *WindowsPlatformScriptResource) Delete(ctx context.Context, req resource
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/beta/winget_app/crud.go b/internal/resources/device_and_app_management/beta/winget_app/crud.go
index dd6b351d..66642708 100644
--- a/internal/resources/device_and_app_management/beta/winget_app/crud.go
+++ b/internal/resources/device_and_app_management/beta/winget_app/crud.go
@@ -222,7 +222,7 @@ func (r *WinGetAppResource) Delete(ctx context.Context, req resource.DeleteReque
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/v1.0/cloud_pc_device_image/crud.go b/internal/resources/device_and_app_management/v1.0/cloud_pc_device_image/crud.go
index 77b7d9ca..d6a1dcc3 100644
--- a/internal/resources/device_and_app_management/v1.0/cloud_pc_device_image/crud.go
+++ b/internal/resources/device_and_app_management/v1.0/cloud_pc_device_image/crud.go
@@ -137,7 +137,7 @@ func (r *CloudPcDeviceImageResource) Update(ctx context.Context, req resource.Up
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -174,7 +174,7 @@ func (r *CloudPcDeviceImageResource) Delete(ctx context.Context, req resource.De
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/v1.0/cloud_pc_provisioning_policy/crud.go b/internal/resources/device_and_app_management/v1.0/cloud_pc_provisioning_policy/crud.go
index c09ee35a..6da2ef7a 100644
--- a/internal/resources/device_and_app_management/v1.0/cloud_pc_provisioning_policy/crud.go
+++ b/internal/resources/device_and_app_management/v1.0/cloud_pc_provisioning_policy/crud.go
@@ -137,7 +137,7 @@ func (r *CloudPcProvisioningPolicyResource) Update(ctx context.Context, req reso
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -174,7 +174,7 @@ func (r *CloudPcProvisioningPolicyResource) Delete(ctx context.Context, req reso
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/device_and_app_management/v1.0/cloud_pc_user_setting/crud.go b/internal/resources/device_and_app_management/v1.0/cloud_pc_user_setting/crud.go
index 48f805b0..1459aafe 100644
--- a/internal/resources/device_and_app_management/v1.0/cloud_pc_user_setting/crud.go
+++ b/internal/resources/device_and_app_management/v1.0/cloud_pc_user_setting/crud.go
@@ -136,7 +136,7 @@ func (r *CloudPcUserSettingResource) Update(ctx context.Context, req resource.Up
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -173,7 +173,7 @@ func (r *CloudPcUserSettingResource) Delete(ctx context.Context, req resource.De
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
resp.State.RemoveResource(ctx)
diff --git a/internal/resources/device_and_app_management/v1.0/role_definition/crud.go b/internal/resources/device_and_app_management/v1.0/role_definition/crud.go
index a088ac48..f90a1d4f 100644
--- a/internal/resources/device_and_app_management/v1.0/role_definition/crud.go
+++ b/internal/resources/device_and_app_management/v1.0/role_definition/crud.go
@@ -134,7 +134,7 @@ func (r *RoleDefinitionResource) Update(ctx context.Context, req resource.Update
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
@@ -172,7 +172,7 @@ func (r *RoleDefinitionResource) Delete(ctx context.Context, req resource.Delete
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Delete", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/identity_and_access/beta/conditional_access_policy/construct.go b/internal/resources/identity_and_access/beta/conditional_access_policy/construct.go
index 3adc4254..0a821a3d 100644
--- a/internal/resources/identity_and_access/beta/conditional_access_policy/construct.go
+++ b/internal/resources/identity_and_access/beta/conditional_access_policy/construct.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
+ "strings"
"github.com/deploymenttheory/terraform-provider-microsoft365/internal/resources/common/construct"
"github.com/hashicorp/terraform-plugin-log/tflog"
@@ -11,7 +12,7 @@ import (
"github.com/microsoftgraph/msgraph-beta-sdk-go/models"
)
-// constructResource maps the Terraform schema to the graph beta SDK model
+// constructResource maps the Terraform schema values to the graph beta SDK model and sets the values for the request to the Graph API
func constructResource(ctx context.Context, data *ConditionalAccessPolicyResourceModel) (*models.ConditionalAccessPolicy, error) {
tflog.Debug(ctx, fmt.Sprintf("Constructing %s resource from model", ResourceName))
@@ -75,7 +76,7 @@ func constructResource(ctx context.Context, data *ConditionalAccessPolicyResourc
return requestBody, nil
}
-// Helper functions to construct nested objects
+// constructConditions constructs the ConditionalAccessConditionSet object
func constructConditions(data *ConditionalAccessConditionsModel) (*models.ConditionalAccessConditionSet, error) {
if data == nil {
return nil, nil
@@ -257,6 +258,7 @@ func constructConditions(data *ConditionalAccessConditionsModel) (*models.Condit
return conditions, nil
}
+// constructApplications constructs the ConditionalAccessApplicationsable object
func constructApplications(data *ConditionalAccessApplicationsModel) (models.ConditionalAccessApplicationsable, error) {
if data == nil {
return nil, nil
@@ -288,9 +290,41 @@ func constructApplications(data *ConditionalAccessApplicationsModel) (models.Con
applications.SetIncludeUserActions(userActions)
}
+ if len(data.IncludeAuthenticationContextClassReferences) > 0 {
+ authRefs := make([]string, len(data.IncludeAuthenticationContextClassReferences))
+ for i, ref := range data.IncludeAuthenticationContextClassReferences {
+ authRefs[i] = ref.ValueString()
+ }
+ applications.SetIncludeAuthenticationContextClassReferences(authRefs)
+ }
+
+ if data.ApplicationFilter != nil {
+ filter := models.NewConditionalAccessFilter()
+ if !data.ApplicationFilter.Mode.IsNull() {
+ modeStr := data.ApplicationFilter.Mode.ValueString()
+ modeAny, err := models.ParseFilterMode(modeStr)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing filter mode: %v", err)
+ }
+ if modeAny != nil {
+ mode := modeAny.(*models.FilterMode)
+ filter.SetMode(mode)
+ }
+ }
+ if !data.ApplicationFilter.Rule.IsNull() {
+ rule := data.ApplicationFilter.Rule.ValueString()
+ filter.SetRule(&rule)
+ }
+ applications.SetApplicationFilter(filter)
+ }
+
+ additionalData := make(map[string]interface{})
+ applications.SetAdditionalData(additionalData)
+
return applications, nil
}
+// constructAuthenticationFlows constructs the ConditionalAccessAuthenticationFlowsable object
func constructAuthenticationFlows(data *ConditionalAccessAuthenticationFlowsModel) (models.ConditionalAccessAuthenticationFlowsable, error) {
if data == nil {
return nil, nil
@@ -298,20 +332,27 @@ func constructAuthenticationFlows(data *ConditionalAccessAuthenticationFlowsMode
authFlows := models.NewConditionalAccessAuthenticationFlows()
- if !data.TransferMethods.IsNull() {
- transferMethodsStr := data.TransferMethods.ValueString()
- transferMethods, err := models.ParseConditionalAccessTransferMethods(transferMethodsStr)
- if err != nil {
- return nil, fmt.Errorf("error parsing transfer methods: %v", err)
- }
- if transferMethods != nil {
- authFlows.SetTransferMethods(transferMethods.(*models.ConditionalAccessTransferMethods))
+ if len(data.TransferMethods) > 0 {
+ // Create a combined transfer methods value
+ var combinedMethods models.ConditionalAccessTransferMethods
+ for i, method := range data.TransferMethods {
+ methodAny, err := models.ParseConditionalAccessTransferMethods(method.ValueString())
+ if err != nil {
+ return nil, fmt.Errorf("error parsing transfer methods: %v", err)
+ }
+ if methodAny != nil {
+ if i == 0 {
+ combinedMethods = *methodAny.(*models.ConditionalAccessTransferMethods)
+ } else {
+ combinedMethods |= *methodAny.(*models.ConditionalAccessTransferMethods)
+ }
+ }
}
+ authFlows.SetTransferMethods(&combinedMethods)
}
return authFlows, nil
}
-
func constructUsers(data *ConditionalAccessUsersModel) (models.ConditionalAccessUsersable, error) {
if data == nil {
return nil, nil
@@ -386,6 +427,46 @@ func constructUsers(data *ConditionalAccessUsersModel) (models.ConditionalAccess
return users, nil
}
+// constructGuestsOrExternalUsers constructs a ConditionalAccessGuestsOrExternalUsers object
+// for the Microsoft Graph SDK based on the data provided from the Terraform model.
+//
+// This function processes the HCL input for `exclude_guests_or_external_users` or
+// `include_guests_or_external_users` and maps the list of `guest_or_external_user_types`
+// into a comma-separated string. The string is parsed using the Microsoft Graph SDK's
+// `ParseConditionalAccessGuestOrExternalUserTypes` function, which combines the individual
+// flags into a single bitmask value.
+//
+// Parameters:
+// - data: *ConditionalAccessGuestsOrExternalUsersModel
+// The Terraform model containing the input data for GuestOrExternalUserTypes
+// and ExternalTenants.
+//
+// Returns:
+// - models.ConditionalAccessGuestsOrExternalUsersable: The constructed object
+// that can be sent to the Microsoft Graph API.
+// - error: If an error occurs while parsing the guest or external user types.
+//
+// Behavior:
+// - If `guest_or_external_user_types` contains a list of strings (e.g., ["b2bCollaborationGuest", "b2bCollaborationMember"]),
+// they are combined into a single comma-separated string and parsed into the corresponding SDK enum bitmask.
+// - If `external_tenants` is provided, it is mapped using the helper function `constructConditionalAccessExternalTenants`.
+// - Handles cases where no data is provided for `guest_or_external_user_types` or `external_tenants` by safely returning nil.
+//
+// Example Input (HCL):
+//
+// exclude_guests_or_external_users = {
+// guest_or_external_user_types = ["b2bCollaborationGuest", "b2bCollaborationMember"]
+// external_tenants = {
+// membership_kind = "all"
+// }
+// }
+//
+// Errors:
+// - Returns an error if a value in `guest_or_external_user_types` cannot be parsed into a valid enum.
+//
+// Notes:
+// - The Microsoft Graph SDK uses a bitmask-based enum for GuestOrExternalUserTypes.
+// - This implementation ensures that Terraform's list input aligns correctly with the SDK's expected format.
func constructGuestsOrExternalUsers(data *ConditionalAccessGuestsOrExternalUsersModel) (models.ConditionalAccessGuestsOrExternalUsersable, error) {
if data == nil {
return nil, nil
@@ -393,17 +474,25 @@ func constructGuestsOrExternalUsers(data *ConditionalAccessGuestsOrExternalUsers
guestsOrExternalUsers := models.NewConditionalAccessGuestsOrExternalUsers()
- if !data.GuestOrExternalUserTypes.IsNull() {
- userTypesAny, err := models.ParseConditionalAccessGuestOrExternalUserTypes(data.GuestOrExternalUserTypes.ValueString())
+ if len(data.GuestOrExternalUserTypes) > 0 {
+ var userTypesStrings []string
+ for _, userType := range data.GuestOrExternalUserTypes {
+ userTypesStrings = append(userTypesStrings, userType.ValueString())
+ }
+
+ combinedTypesString := strings.Join(userTypesStrings, ",")
+
+ parsedAny, err := models.ParseConditionalAccessGuestOrExternalUserTypes(combinedTypesString)
if err != nil {
return nil, fmt.Errorf("error parsing guest or external user types: %v", err)
}
- if userTypesAny != nil {
- userTypes, ok := userTypesAny.(*models.ConditionalAccessGuestOrExternalUserTypes)
+
+ if parsedAny != nil {
+ parsedType, ok := parsedAny.(*models.ConditionalAccessGuestOrExternalUserTypes)
if !ok {
- return nil, fmt.Errorf("unexpected type for guest or external user types: %T", userTypesAny)
+ return nil, fmt.Errorf("unexpected type for guest or external user types: %T", parsedAny)
}
- guestsOrExternalUsers.SetGuestOrExternalUserTypes(userTypes)
+ guestsOrExternalUsers.SetGuestOrExternalUserTypes(parsedType)
}
}
@@ -491,23 +580,23 @@ func constructDevices(data *ConditionalAccessDevicesModel) (models.ConditionalAc
devices.SetExcludeDevices(excludeDevices)
}
- if data.IncludeStates != nil {
- if len(data.IncludeStates) > 0 {
- includeStates := make([]string, len(data.IncludeStates))
- for i, state := range data.IncludeStates {
- includeStates[i] = state.ValueString()
- }
- devices.SetIncludeDeviceStates(includeStates)
- }
-
- if len(data.ExcludeStates) > 0 {
- excludeStates := make([]string, len(data.ExcludeStates))
- for i, state := range data.ExcludeStates {
- excludeStates[i] = state.ValueString()
- }
- devices.SetExcludeDeviceStates(excludeStates)
- }
- }
+ // if data.IncludeStates != nil {
+ // if len(data.IncludeStates) > 0 {
+ // includeStates := make([]string, len(data.IncludeStates))
+ // for i, state := range data.IncludeStates {
+ // includeStates[i] = state.ValueString()
+ // }
+ // devices.SetIncludeDeviceStates(includeStates)
+ // }
+
+ // if len(data.ExcludeStates) > 0 {
+ // excludeStates := make([]string, len(data.ExcludeStates))
+ // for i, state := range data.ExcludeStates {
+ // excludeStates[i] = state.ValueString()
+ // }
+ // devices.SetExcludeDeviceStates(excludeStates)
+ // }
+ // }
if data.DeviceFilter != nil {
filter := models.NewConditionalAccessFilter()
diff --git a/internal/resources/identity_and_access/beta/conditional_access_policy/crud.go b/internal/resources/identity_and_access/beta/conditional_access_policy/crud.go
index da3674ac..ab5ec8e4 100644
--- a/internal/resources/identity_and_access/beta/conditional_access_policy/crud.go
+++ b/internal/resources/identity_and_access/beta/conditional_access_policy/crud.go
@@ -10,9 +10,22 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
)
-// Create handles the Create operation.
+// Create handles the Create operation for Conditional Access Policy resources.
+//
+// - Retrieves the planned configuration from the create request
+// - Constructs the resource request body from the plan
+// - Sends POST request to create the base resource and settings
+// - Captures the new resource ID from the response
+// - Sets initial state with planned values
+// - Calls Read operation to fetch the latest state from the API with retry
+// - Updates the final state with the fresh data from the API
+//
+// The function ensures that both the Conditional Access Policy profile and its assignments
+// (if specified) are created properly. The settings must be defined during creation
+// as they are required for a successful deployment, while assignments are optional.
func (r *ConditionalAccessPolicyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var object ConditionalAccessPolicyResourceModel
@@ -29,6 +42,9 @@ func (r *ConditionalAccessPolicyResource) Create(ctx context.Context, req resour
}
defer cancel()
+ deadline, _ := ctx.Deadline()
+ retryTimeout := time.Until(deadline) - time.Second
+
requestBody, err := constructResource(ctx, &object)
if err != nil {
resp.Diagnostics.AddError(
@@ -51,13 +67,33 @@ func (r *ConditionalAccessPolicyResource) Create(ctx context.Context, req resour
object.ID = types.StringValue(*conditionalAccessPolicy.GetId())
- MapRemoteStateToTerraform(ctx, &object, conditionalAccessPolicy)
-
resp.Diagnostics.Append(resp.State.Set(ctx, &object)...)
if resp.Diagnostics.HasError() {
return
}
+ err = retry.RetryContext(ctx, retryTimeout, func() *retry.RetryError {
+ readResp := &resource.ReadResponse{State: resp.State}
+ r.Read(ctx, resource.ReadRequest{
+ State: resp.State,
+ ProviderMeta: req.ProviderMeta,
+ }, readResp)
+
+ if readResp.Diagnostics.HasError() {
+ return retry.NonRetryableError(fmt.Errorf("error reading resource state after Create Method: %s", readResp.Diagnostics.Errors()))
+ }
+
+ resp.State = readResp.State
+ return nil
+ })
+
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error waiting for resource creation",
+ fmt.Sprintf("Failed to verify resource creation: %s", err),
+ )
+ return
+ }
tflog.Debug(ctx, fmt.Sprintf("Finished Create Method: %s_%s", r.ProviderTypeName, r.TypeName))
}
@@ -103,7 +139,17 @@ func (r *ConditionalAccessPolicyResource) Read(ctx context.Context, req resource
tflog.Debug(ctx, fmt.Sprintf("Finished Read Method: %s_%s", r.ProviderTypeName, r.TypeName))
}
-// Update handles the Update operation.
+// Update handles the Update operation for Conditional Access Policy resources.
+//
+// - Retrieves the planned changes from the update request
+// - Constructs the resource request body from the plan
+// - Sends PATCH request to update the base resource and settings
+// - Sets initial state with planned values
+// - Calls Read operation to fetch the latest state from the API with retry
+// - Updates the final state with the fresh data from the API
+//
+// The function ensures that both the settings and assignments are updated atomically,
+// and the final state reflects the actual state of the resource on the server.
func (r *ConditionalAccessPolicyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var object ConditionalAccessPolicyResourceModel
@@ -120,6 +166,9 @@ func (r *ConditionalAccessPolicyResource) Update(ctx context.Context, req resour
}
defer cancel()
+ deadline, _ := ctx.Deadline()
+ retryTimeout := time.Until(deadline) - time.Second
+
requestBody, err := constructResource(ctx, &object)
if err != nil {
resp.Diagnostics.AddError(
@@ -129,7 +178,7 @@ func (r *ConditionalAccessPolicyResource) Update(ctx context.Context, req resour
return
}
- conditionalAccessPolicy, err := r.client.
+ _, err = r.client.
Identity().
ConditionalAccess().
Policies().
@@ -137,14 +186,30 @@ func (r *ConditionalAccessPolicyResource) Update(ctx context.Context, req resour
Patch(ctx, requestBody, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Update", r.WritePermissions)
return
}
- MapRemoteStateToTerraform(ctx, &object, conditionalAccessPolicy)
+ err = retry.RetryContext(ctx, retryTimeout, func() *retry.RetryError {
+ readResp := &resource.ReadResponse{State: resp.State}
+ r.Read(ctx, resource.ReadRequest{
+ State: resp.State,
+ ProviderMeta: req.ProviderMeta,
+ }, readResp)
- resp.Diagnostics.Append(resp.State.Set(ctx, &object)...)
- if resp.Diagnostics.HasError() {
+ if readResp.Diagnostics.HasError() {
+ return retry.NonRetryableError(fmt.Errorf("error reading resource state after Update Method: %s", readResp.Diagnostics.Errors()))
+ }
+
+ resp.State = readResp.State
+ return nil
+ })
+
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error waiting for resource update",
+ fmt.Sprintf("Failed to verify resource update: %s", err),
+ )
return
}
@@ -176,7 +241,7 @@ func (r *ConditionalAccessPolicyResource) Delete(ctx context.Context, req resour
Delete(ctx, nil)
if err != nil {
- errors.HandleGraphError(ctx, err, resp, "Update", r.ReadPermissions)
+ errors.HandleGraphError(ctx, err, resp, "Delete", r.WritePermissions)
return
}
diff --git a/internal/resources/identity_and_access/beta/conditional_access_policy/model.go b/internal/resources/identity_and_access/beta/conditional_access_policy/model.go
index 8e2724d6..852759b7 100644
--- a/internal/resources/identity_and_access/beta/conditional_access_policy/model.go
+++ b/internal/resources/identity_and_access/beta/conditional_access_policy/model.go
@@ -36,10 +36,11 @@ type ConditionalAccessConditionsModel struct {
}
type ConditionalAccessApplicationsModel struct {
- IncludeApplications []types.String `tfsdk:"include_applications"`
- ExcludeApplications []types.String `tfsdk:"exclude_applications"`
- ApplicationFilter *ConditionalAccessFilterModel `tfsdk:"application_filter"`
- IncludeUserActions []types.String `tfsdk:"include_user_actions"`
+ IncludeApplications []types.String `tfsdk:"include_applications"`
+ ExcludeApplications []types.String `tfsdk:"exclude_applications"`
+ ApplicationFilter *ConditionalAccessFilterModel `tfsdk:"application_filter"`
+ IncludeUserActions []types.String `tfsdk:"include_user_actions"`
+ IncludeAuthenticationContextClassReferences []types.String `tfsdk:"include_authentication_context_class_references"`
}
type ConditionalAccessUsersModel struct {
@@ -55,7 +56,7 @@ type ConditionalAccessUsersModel struct {
type ConditionalAccessGuestsOrExternalUsersModel struct {
ExternalTenants *ConditionalAccessExternalTenantsModel `tfsdk:"external_tenants"`
- GuestOrExternalUserTypes types.String `tfsdk:"guest_or_external_user_types"`
+ GuestOrExternalUserTypes []types.String `tfsdk:"guest_or_external_user_types"` // Change to a slice
}
type ConditionalAccessExternalTenantsModel struct {
@@ -74,11 +75,11 @@ type ConditionalAccessDeviceStatesModel struct {
}
type ConditionalAccessDevicesModel struct {
- IncludeDevices []types.String `tfsdk:"include_devices"`
- ExcludeDevices []types.String `tfsdk:"exclude_devices"`
- IncludeStates []types.String `tfsdk:"include_states"` // TODO - validate this. sdk different to msft docs
- ExcludeStates []types.String `tfsdk:"exclude_states"` // TODO - validate this. sdk different to msft docs
- DeviceFilter *ConditionalAccessFilterModel `tfsdk:"device_filter"`
+ IncludeDevices []types.String `tfsdk:"include_devices"`
+ ExcludeDevices []types.String `tfsdk:"exclude_devices"`
+ //IncludeStates []types.String `tfsdk:"include_device_states"` // TODO - validate this. sdk different to msft docs
+ //ExcludeStates []types.String `tfsdk:"exclude_device_states"` // TODO - validate this. sdk different to msft docs
+ DeviceFilter *ConditionalAccessFilterModel `tfsdk:"device_filter"`
}
type ConditionalAccessLocationsModel struct {
@@ -92,7 +93,7 @@ type ConditionalAccessPlatformsModel struct {
}
type ConditionalAccessAuthenticationFlowsModel struct {
- TransferMethods types.String `tfsdk:"transfer_methods"`
+ TransferMethods []types.String `tfsdk:"transfer_methods"`
}
type ConditionalAccessFilterModel struct {
diff --git a/internal/resources/identity_and_access/beta/conditional_access_policy/resource.go b/internal/resources/identity_and_access/beta/conditional_access_policy/resource.go
index d8da97e2..ff19e356 100644
--- a/internal/resources/identity_and_access/beta/conditional_access_policy/resource.go
+++ b/internal/resources/identity_and_access/beta/conditional_access_policy/resource.go
@@ -274,15 +274,18 @@ func (r *ConditionalAccessPolicyResource) conditionalAccessApplicationsSchema()
func (r *ConditionalAccessPolicyResource) conditionalAccessAuthenticationFlowsSchema() map[string]schema.Attribute {
return map[string]schema.Attribute{
- "transfer_methods": schema.StringAttribute{
+ "transfer_methods": schema.ListAttribute{
Optional: true,
Description: "Represents the transfer methods in scope for the policy. The possible values are: none, deviceCodeFlow, authenticationTransfer, unknownFutureValue.",
- Validators: []validator.String{
- stringvalidator.OneOf(
- "none",
- "deviceCodeFlow",
- "authenticationTransfer",
- "unknownFutureValue",
+ ElementType: types.StringType,
+ Validators: []validator.List{
+ listvalidator.ValueStringsAre(
+ stringvalidator.OneOf(
+ "none",
+ "deviceCodeFlow",
+ "authenticationTransfer",
+ "unknownFutureValue",
+ ),
),
},
},
@@ -457,29 +460,29 @@ func (r *ConditionalAccessPolicyResource) conditionalAccessDevicesSchema() map[s
"device_filter": filterSchema(
"Filter that defines the dynamic-device-syntax rule to include/exclude devices. A filter can use device properties (such as extension attributes) to include/exclude them. Cannot be set if includeDevices or excludeDevices is set.",
),
- "include_device_states": schema.ListAttribute{
- Optional: true,
- Description: "(Deprecated) States in the scope of the policy. 'All' is the only allowed value.",
- DeprecationMessage: "This field is deprecated. Use include_devices instead.",
- ElementType: types.StringType,
- Validators: []validator.List{
- listvalidator.SizeAtMost(1),
- listvalidator.ValueStringsAre(
- stringvalidator.OneOf("All"),
- ),
- },
- },
- "exclude_device_states": schema.ListAttribute{
- Optional: true,
- Description: "(Deprecated) States excluded from the scope of the policy. Possible values: 'Compliant', 'DomainJoined'.",
- DeprecationMessage: "This field is deprecated. Use exclude_devices instead.",
- ElementType: types.StringType,
- Validators: []validator.List{
- listvalidator.ValueStringsAre(
- stringvalidator.OneOf("Compliant", "DomainJoined"),
- ),
- },
- },
+ // "include_device_states": schema.ListAttribute{
+ // Optional: true,
+ // Description: "(Deprecated) States in the scope of the policy. 'All' is the only allowed value.",
+ // DeprecationMessage: "This field is deprecated. Use include_devices instead.",
+ // ElementType: types.StringType,
+ // Validators: []validator.List{
+ // listvalidator.SizeAtMost(1),
+ // listvalidator.ValueStringsAre(
+ // stringvalidator.OneOf("All"),
+ // ),
+ // },
+ // },
+ // "exclude_device_states": schema.ListAttribute{
+ // Optional: true,
+ // Description: "(Deprecated) States excluded from the scope of the policy. Possible values: 'Compliant', 'DomainJoined'.",
+ // DeprecationMessage: "This field is deprecated. Use exclude_devices instead.",
+ // ElementType: types.StringType,
+ // Validators: []validator.List{
+ // listvalidator.ValueStringsAre(
+ // stringvalidator.OneOf("Compliant", "DomainJoined"),
+ // ),
+ // },
+ // },
}
}
@@ -562,19 +565,22 @@ func (r *ConditionalAccessPolicyResource) conditionalAccessGuestsOrExternalUsers
},
},
},
- "guest_or_external_user_types": schema.StringAttribute{
+ "guest_or_external_user_types": schema.ListAttribute{
Required: true,
Description: "Indicates internal guests or external user types. Possible values are: none, internalGuest, b2bCollaborationGuest, b2bCollaborationMember, b2bDirectConnectUser, otherExternalUser, serviceProvider, unknownFutureValue.",
- Validators: []validator.String{
- stringvalidator.OneOf(
- "none",
- "internalGuest",
- "b2bCollaborationGuest",
- "b2bCollaborationMember",
- "b2bDirectConnectUser",
- "otherExternalUser",
- "serviceProvider",
- "unknownFutureValue",
+ ElementType: types.StringType,
+ Validators: []validator.List{
+ listvalidator.ValueStringsAre(
+ stringvalidator.OneOf(
+ "none",
+ "internalGuest",
+ "b2bCollaborationGuest",
+ "b2bCollaborationMember",
+ "b2bDirectConnectUser",
+ "otherExternalUser",
+ "serviceProvider",
+ "unknownFutureValue",
+ ),
),
},
},
diff --git a/internal/resources/identity_and_access/beta/conditional_access_policy/state.go b/internal/resources/identity_and_access/beta/conditional_access_policy/state.go
index f4a8b902..d37f39ab 100644
--- a/internal/resources/identity_and_access/beta/conditional_access_policy/state.go
+++ b/internal/resources/identity_and_access/beta/conditional_access_policy/state.go
@@ -2,6 +2,7 @@ package graphBetaConditionalAccessPolicy
import (
"context"
+ "strings"
"github.com/deploymenttheory/terraform-provider-microsoft365/internal/resources/common/state"
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -154,19 +155,21 @@ func mapAuthenticationFlows(ctx context.Context, authFlows models.ConditionalAcc
tflog.Debug(ctx, "Starting to map authentication flows")
- var transferMethodsString string
+ var transferMethods []types.String
if authFlows.GetTransferMethods() != nil {
- transferMethodsString = authFlows.GetTransferMethods().String()
- } else {
- transferMethodsString = ""
+ methods := authFlows.GetTransferMethods()
+ // TransferMethods is a bitmask enum: split into separate methods
+ for _, method := range methods.String() {
+ transferMethods = append(transferMethods, types.StringValue(string(method)))
+ }
}
result := &ConditionalAccessAuthenticationFlowsModel{
- TransferMethods: types.StringValue(transferMethodsString),
+ TransferMethods: transferMethods,
}
tflog.Debug(ctx, "Finished mapping authentication flows", map[string]interface{}{
- "transferMethods": result.TransferMethods.ValueString(),
+ "transferMethodsCount": len(result.TransferMethods),
})
return result
@@ -180,21 +183,26 @@ func mapGuestsOrExternalUsers(ctx context.Context, guestsOrExternalUsers models.
tflog.Debug(ctx, "Starting to map guests or external users")
- var guestOrExternalUserTypesString string
+ // Extract and split GuestOrExternalUserTypes into a list of strings
+ var guestOrExternalUserTypes []types.String
if guestsOrExternalUsers.GetGuestOrExternalUserTypes() != nil {
- guestOrExternalUserTypesString = guestsOrExternalUsers.GetGuestOrExternalUserTypes().String()
- } else {
- guestOrExternalUserTypesString = ""
+ typesString := guestsOrExternalUsers.GetGuestOrExternalUserTypes().String() // Returns a comma-separated string
+ for _, userType := range strings.Split(typesString, ",") {
+ guestOrExternalUserTypes = append(guestOrExternalUserTypes, types.StringValue(strings.TrimSpace(userType)))
+ }
}
+ // Map ExternalTenants
+ externalTenants := mapExternalTenants(ctx, guestsOrExternalUsers.GetExternalTenants())
+
result := &ConditionalAccessGuestsOrExternalUsersModel{
- ExternalTenants: mapExternalTenants(ctx, guestsOrExternalUsers.GetExternalTenants()),
- GuestOrExternalUserTypes: types.StringValue(guestOrExternalUserTypesString),
+ ExternalTenants: externalTenants,
+ GuestOrExternalUserTypes: guestOrExternalUserTypes,
}
tflog.Debug(ctx, "Finished mapping guests or external users", map[string]interface{}{
- "guestOrExternalUserTypes": result.GuestOrExternalUserTypes.ValueString(),
- "hasExternalTenants": result.ExternalTenants != nil,
+ "guestOrExternalUserTypesCount": len(result.GuestOrExternalUserTypes),
+ "hasExternalTenants": result.ExternalTenants != nil,
})
return result
@@ -260,17 +268,17 @@ func mapDevices(ctx context.Context, devices models.ConditionalAccessDevicesable
result := &ConditionalAccessDevicesModel{
IncludeDevices: state.SliceToTypeStringSlice(devices.GetIncludeDevices()),
ExcludeDevices: state.SliceToTypeStringSlice(devices.GetExcludeDevices()),
- IncludeStates: state.SliceToTypeStringSlice(devices.GetIncludeDeviceStates()),
- ExcludeStates: state.SliceToTypeStringSlice(devices.GetExcludeDeviceStates()),
- DeviceFilter: mapFilter(ctx, devices.GetDeviceFilter()),
+ //IncludeStates: state.SliceToTypeStringSlice(devices.GetIncludeDeviceStates()),
+ //ExcludeStates: state.SliceToTypeStringSlice(devices.GetExcludeDeviceStates()),
+ DeviceFilter: mapFilter(ctx, devices.GetDeviceFilter()),
}
tflog.Debug(ctx, "Finished mapping devices", map[string]interface{}{
"includeDevicesCount": len(result.IncludeDevices),
"excludeDevicesCount": len(result.ExcludeDevices),
- "includeStatesCount": len(result.IncludeStates),
- "excludeStatesCount": len(result.ExcludeStates),
- "hasDeviceFilter": result.DeviceFilter != nil,
+ //"includeStatesCount": len(result.IncludeStates),
+ //"excludeStatesCount": len(result.ExcludeStates),
+ "hasDeviceFilter": result.DeviceFilter != nil,
})
return result
diff --git a/templates/resources/graph_beta_identity_and_access_conditional_access_policy.md.tmpl b/templates/resources/graph_beta_identity_and_access_conditional_access_policy.md.tmpl
new file mode 100644
index 00000000..8b7e3383
--- /dev/null
+++ b/templates/resources/graph_beta_identity_and_access_conditional_access_policy.md.tmpl
@@ -0,0 +1,22 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
+subcategory: "Identity & Access: Conditional Access Policy"
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+## Example Usage
+
+{{ tffile "examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/resource.tf" }}
+
+{{ .SchemaMarkdown | trimspace }}
+
+## Import
+
+Import is supported using the following syntax:
+
+{{ codefile "shell" "examples/microsoft365_graph_beta/microsoft365_graph_beta_identity_and_access_conditional_access_policy/import.sh" }}
\ No newline at end of file