Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,61 +27,39 @@

var _ mocks.MockRegistrar = (*WindowsEnrollmentStatusPageMock)(nil)

func (m *WindowsEnrollmentStatusPageMock) RegisterMocks() {

Check failure on line 30 in internal/services/resources/device_management/graph_beta/windows_enrollment_status_page/mocks/responders.go

View workflow job for this annotation

GitHub Actions / ✨ Run golangci-lint

cyclomatic complexity 33 of func `(*WindowsEnrollmentStatusPageMock).RegisterMocks` is high (> 30) (gocyclo)
mockState.Lock()
mockState.enrollmentStatusPages = make(map[string]map[string]any)
mockState.Unlock()

// Mock the mobile apps endpoint for validation
httpmock.RegisterResponder("GET", `=~^https://graph\.microsoft\.com/beta/deviceAppManagement/mobileApps.*`, func(req *http.Request) (*http.Response, error) {
// Return mock mobile apps that include the test app IDs used in unit tests
mockApps := map[string]any{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceAppManagement/mobileApps",
"@odata.count": 5,
"value": []any{
map[string]any{
"@odata.type": "#microsoft.graph.win32LobApp",
"id": "12345678-1234-1234-1234-123456789012",
"displayName": "Test App 1",
"description": "Test application 1 for unit testing",
"publisher": "Test Publisher",
"publishingState": "published",
},
map[string]any{
"@odata.type": "#microsoft.graph.winGetApp",
"id": "87654321-4321-4321-4321-210987654321",
"displayName": "Test App 2",
"description": "Test application 2 for unit testing",
"publisher": "Test Publisher",
"publishingState": "published",
},
map[string]any{
"@odata.type": "#microsoft.graph.win32LobApp",
"id": "e4938228-aab3-493b-a9d5-8250aa8e9d55",
"displayName": "Test App 3",
"description": "Test application 3 for unit testing",
"publisher": "Test Publisher",
"publishingState": "published",
},
map[string]any{
"@odata.type": "#microsoft.graph.win32LobApp",
"id": "e83d36e1-3ff2-4567-90d9-940919184ad5",
"displayName": "Test App 4",
"description": "Test application 4 for unit testing",
"publisher": "Test Publisher",
"publishingState": "published",
},
map[string]any{
"@odata.type": "#microsoft.graph.win32LobApp",
"id": "cd4486df-05cc-42bd-8c34-67ac20e10166",
"displayName": "Test App 5",
"description": "Test application 5 for unit testing",
"publisher": "Test Publisher",
"publishingState": "published",
},
},
// Define mock apps used in tests
mockApps := map[string]string{
"12345678-1234-1234-1234-123456789012": "#microsoft.graph.win32LobApp",
"87654321-4321-4321-4321-210987654321": "#microsoft.graph.winGetApp",
"e4938228-aab3-493b-a9d5-8250aa8e9d55": "#microsoft.graph.win32LobApp",
"e83d36e1-3ff2-4567-90d9-940919184ad5": "#microsoft.graph.win32LobApp",
"cd4486df-05cc-42bd-8c34-67ac20e10166": "#microsoft.graph.win32LobApp",
}

// Mock individual mobile app lookup by ID
httpmock.RegisterResponder("GET", `=~^https://graph\.microsoft\.com/beta/deviceAppManagement/mobileApps/[0-9a-fA-F-]+$`, func(req *http.Request) (*http.Response, error) {
parts := strings.Split(req.URL.Path, "/")
appId := parts[len(parts)-1]

if odataType, ok := mockApps[appId]; ok {
return httpmock.NewJsonResponse(200, map[string]any{
"@odata.type": odataType,
"id": appId,
})
}
return httpmock.NewJsonResponse(200, mockApps)

// Return 404 for unknown app IDs
return httpmock.NewJsonResponse(404, map[string]any{
"error": map[string]any{
"code": "ResourceNotFound",
"message": "The requested resource does not exist.",
},
})
})

httpmock.RegisterResponder("GET", "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations", func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -318,6 +296,16 @@
mockState.enrollmentStatusPages = make(map[string]map[string]any)
mockState.Unlock()

// Mock individual mobile app lookup by ID for error scenarios - always return 404
httpmock.RegisterResponder("GET", `=~^https://graph\.microsoft\.com/beta/deviceAppManagement/mobileApps/[0-9a-fA-F-]+$`, func(req *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(404, map[string]any{
"error": map[string]any{
"code": "ResourceNotFound",
"message": "The requested resource does not exist.",
},
})
})

httpmock.RegisterResponder("GET", "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations", func(req *http.Request) (*http.Response, error) {
jsonStr, _ := helpers.ParseJSONFile("../tests/responses/validate_get/get_windows_enrollment_status_pages_list.json")
var responseObj map[string]any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
msgraphbetasdk "github.com/microsoftgraph/msgraph-beta-sdk-go"
"github.com/microsoftgraph/msgraph-beta-sdk-go/deviceappmanagement"
graphmodels "github.com/microsoftgraph/msgraph-beta-sdk-go/models"
)

// validateRequest validates the entire request payload
Expand Down Expand Up @@ -38,7 +38,7 @@
guidRegex := regexp.MustCompile(constants.GuidRegex)
for _, appId := range appIdStrings {
if !guidRegex.MatchString(appId.ValueString()) {
return fmt.Errorf("invalid application ID format: %s. Must be a valid UUID", appId.ValueString())

Check failure on line 41 in internal/services/resources/device_management/graph_beta/windows_enrollment_status_page/validate.go

View workflow job for this annotation

GitHub Actions / ✨ Run golangci-lint

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"invalid application ID format: %s. Must be a valid UUID\", appId.ValueString())" (err113)
}
}

Expand All @@ -48,60 +48,77 @@
return nil
}

// Get all Windows app types from Microsoft Graph
filter := "isof('microsoft.graph.windowsAppX') or isof('microsoft.graph.windowsMobileMSI') or isof('microsoft.graph.windowsUniversalAppX') or isof('microsoft.graph.officeSuiteApp') or isof('microsoft.graph.windowsMicrosoftEdgeApp') or isof('microsoft.graph.winGetApp') or isof('microsoft.graph.win32LobApp') or isof('microsoft.graph.win32CatalogApp')"
orderby := "displayname"
top := int32(250)

requestConfig := &deviceappmanagement.MobileAppsRequestBuilderGetRequestConfiguration{
QueryParameters: &deviceappmanagement.MobileAppsRequestBuilderGetQueryParameters{
Filter: &filter,
Orderby: []string{orderby},
Top: &top,
},
}

mobileApps, err := client.
DeviceAppManagement().
MobileApps().
Get(ctx, requestConfig)

if err != nil {
tflog.Error(ctx, "Failed to retrieve mobile apps for validation", map[string]any{
"error": err.Error(),
})
return fmt.Errorf("failed to validate mobile app IDs: unable to retrieve available apps from Microsoft Graph")
}
for _, appId := range appIdStrings {
appIdValue := appId.ValueString()

// Create a map of valid app IDs for quick lookup
validAppIds := make(map[string]string) // ID -> DisplayName
validAppTypes := make(map[string]string) // ID -> AppType
// Query the specific app by ID
app, err := client.
DeviceAppManagement().
MobileApps().
ByMobileAppId(appIdValue).
Get(ctx, nil)

if err != nil {
tflog.Error(ctx, "Failed to retrieve mobile app for validation", map[string]any{
"appId": appIdValue,
"error": err.Error(),
})
return fmt.Errorf("supplied app ID '%s' does not match any valid Windows app types. Valid app types include: windowsAppX, windowsMobileMSI, windowsUniversalAppX, officeSuiteApp, windowsMicrosoftEdgeApp, winGetApp, win32LobApp, win32CatalogApp", appIdValue)

Check failure on line 66 in internal/services/resources/device_management/graph_beta/windows_enrollment_status_page/validate.go

View workflow job for this annotation

GitHub Actions / ✨ Run golangci-lint

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"supplied app ID '%s' does not match any valid Windows app types. Valid app types include: windowsAppX, windowsMobileMSI, windowsUniversalAppX, officeSuiteApp, windowsMicrosoftEdgeApp, winGetApp, win32LobApp, win32CatalogApp\", appIdValue)" (err113)
}

if mobileApps.GetValue() != nil {
for _, app := range mobileApps.GetValue() {
if app.GetId() != nil && app.GetDisplayName() != nil && app.GetOdataType() != nil {
validAppIds[*app.GetId()] = *app.GetDisplayName()
validAppTypes[*app.GetId()] = *app.GetOdataType()
// Validate the app type using SDK type assertions
isValidType := false
var appTypeName string

switch app.(type) {
case *graphmodels.WindowsAppX:
isValidType = true
appTypeName = "windowsAppX"
case *graphmodels.WindowsMobileMSI:
isValidType = true
appTypeName = "windowsMobileMSI"
case *graphmodels.WindowsUniversalAppX:
isValidType = true
appTypeName = "windowsUniversalAppX"
case *graphmodels.OfficeSuiteApp:
isValidType = true
appTypeName = "officeSuiteApp"
case *graphmodels.WindowsMicrosoftEdgeApp:
isValidType = true
appTypeName = "windowsMicrosoftEdgeApp"
case *graphmodels.WinGetApp:
isValidType = true
appTypeName = "winGetApp"
case *graphmodels.Win32LobApp:
isValidType = true
appTypeName = "win32LobApp"
case *graphmodels.Win32CatalogApp:
isValidType = true
appTypeName = "win32CatalogApp"
default:
if odataType := app.GetOdataType(); odataType != nil {
appTypeName = *odataType
} else {
appTypeName = "unknown"
}
}
}

// Validate each provided app ID
for _, appId := range appIdStrings {
appIdValue := appId.ValueString()
displayName, exists := validAppIds[appIdValue]
if !isValidType {
return fmt.Errorf("supplied app ID '%s' has type '%s' which is not a valid Windows app type. Valid app types include: windowsAppX, windowsMobileMSI, windowsUniversalAppX, officeSuiteApp, windowsMicrosoftEdgeApp, winGetApp, win32LobApp, win32CatalogApp", appIdValue, appTypeName)

Check failure on line 107 in internal/services/resources/device_management/graph_beta/windows_enrollment_status_page/validate.go

View workflow job for this annotation

GitHub Actions / ✨ Run golangci-lint

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"supplied app ID '%s' has type '%s' which is not a valid Windows app type. Valid app types include: windowsAppX, windowsMobileMSI, windowsUniversalAppX, officeSuiteApp, windowsMicrosoftEdgeApp, winGetApp, win32LobApp, win32CatalogApp\", appIdValue, appTypeName)" (err113)
}

if !exists {
return fmt.Errorf("supplied app ID '%s' does not match any valid Windows app types. Valid app types include: windowsAppX, windowsMobileMSI, windowsUniversalAppX, officeSuiteApp, windowsMicrosoftEdgeApp, winGetApp, win32LobApp, win32CatalogApp", appIdValue)
displayName := ""
if app.GetDisplayName() != nil {
displayName = *app.GetDisplayName()
}

tflog.Debug(ctx, "Validated mobile app", map[string]any{
"appId": appIdValue,
"displayName": displayName,
"appType": validAppTypes[appIdValue],
"appType": appTypeName,
})
}

tflog.Debug(ctx, fmt.Sprintf("Validated %d mobile app IDs against %d available Windows apps", len(appIdStrings), len(validAppIds)))
tflog.Debug(ctx, fmt.Sprintf("Successfully validated %d mobile app IDs", len(appIdStrings)))
return nil
}
Loading