Skip to content

fix: validate merged profiles on PATCH - #1404

Open
sinchubhat wants to merge 1 commit into
mainfrom
issue1261-console-4.1.1
Open

sinchubhat wants to merge 1 commit into
mainfrom
issue1261-console-4.1.1

Conversation

@sinchubhat

@sinchubhat sinchubhat commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Addresses #1261

Addresses Point No 1 of 4.1 Console defects https://github.com/device-management-toolkit/console/wiki/ConsoleRPS-vs-StandaloneRPS-API--Gap-Analysis

Create test data

TOKEN=$(curl -sk https://localhost:8181/api/v1/authorize -H "Content-Type: application/json" -d '{"username":"<username>","password":"<password>"}' | jq -r '.token') 

BASE=https://127.0.0.1:8181/api/v1/admin
NAME="patch1261$(date +%s)"
WIFI="wifi1261$(date +%s)"
curl --noproxy '*' -skS -i -X POST "$BASE/wirelessconfigs" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$WIFI\",\"authenticationMethod\":6,\"encryptionMethod\":4,\"ssid\":\"TestWiFi\",\"pskPassphrase\":\"Testpass1\"}"

Output:

HTTP/2 201 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 156
date: Thu, 12 Nov 2026 04:11:44 GMT

{"profileName":"wifi12611794456697","authenticationMethod":6,"encryptionMethod":4,"ssid":"TestWiFi","pskValue":0,"linkPolicy":[],"tenantId":"","version":""}
```bash

```bash
curl --noproxy '*' -skS -i -X POST "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"ccmactivate\",\"amtPassword\":\"P@ssw0rd\",\"dhcpEnabled\":true,\"wifiConfigs\":[{\"profileName\":\"$WIFI\",\"priority\":1}]}"

Output:

HTTP/2 201 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 428
date: Thu, 12 Nov 2026 04:12:14 GMT

{"profileName":"patch12611794456697","generateRandomPassword":false,"activation":"ccmactivate","generateRandomMEBxPassword":false,"tags":[""],"dhcpEnabled":true,"ipSyncEnabled":false,"localWifiSyncEnabled":false,"wifiConfigs":[{"priority":1,"profileName":"wifi12611794456697","profileProfileName":"","tenantId":""}],"tenantId":"","tlsMode":0,"iderEnabled":false,"kvmEnabled":false,"solEnabled":false,"uefiWifiSyncEnabled":false}

Test PATCH

Each of these should return 400:

Invalid activation

curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"activate\"}"

Output:

HTTP/2 400 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 207
date: Thu, 12 Nov 2026 04:22:25 GMT

{"error":"Key: 'Profile.Activation' Error:Field validation for 'Activation' failed on the 'oneof' tag","message":"Key: 'Profile.Activation' Error:Field validation for 'Activation' failed on the 'oneof' tag"}

Weak password

curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"amtPassword\":\"Intel123\"}"

Output:

HTTP/2 400 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 243
date: Thu, 12 Nov 2026 04:23:21 GMT

{"error":"Key: 'Profile.AMTPassword' Error:Field validation for 'AMTPassword' failed on the 'amtpasswordcomplexity' tag","message":"Key: 'Profile.AMTPassword' Error:Field validation for 'AMTPassword' failed on the 'amtpasswordcomplexity' tag"}
curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"ccmactivate\"}"

Output:

HTTP/2 200 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 447
date: Thu, 12 Nov 2026 04:25:34 GMT

{"profileName":"patch12611794457322","generateRandomPassword":false,"activation":"ccmactivate","generateRandomMEBxPassword":false,"tags":[""],"dhcpEnabled":true,"ipSyncEnabled":false,"localWifiSyncEnabled":false,"wifiConfigs":[{"priority":1,"profileName":"wifi12611794457322","profileProfileName":"patch12611794457322","tenantId":""}],"tenantId":"","tlsMode":0,"iderEnabled":false,"kvmEnabled":false,"solEnabled":false,"uefiWifiSyncEnabled":false}

ACM without a MEBx password

curl --noproxy '*' -skS -i "$BASE/profiles"  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"acmactivate\"}"

Output:

HTTP/2 400 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 175
date: Thu, 12 Nov 2026 04:13:34 GMT

{"error":"Invalid input: amtPassword is required when generateRandomPassword is false","message":"Invalid input: amtPassword is required when generateRandomPassword is false"}

DHCP cannot be disabled while the profile has Wi-Fi links
Expected: 400

curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"dhcpEnabled\":false}"

Output:

HTTP/2 400 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 217
date: Thu, 12 Nov 2026 04:13:56 GMT

{"error":"Key: 'Profile.WiFiConfigs' Error:Field validation for 'WiFiConfigs' failed on the 'wifidhcp' tag","message":"Key: 'Profile.WiFiConfigs' Error:Field validation for 'WiFiConfigs' failed on the 'wifidhcp' tag"}

A valid partial update without a password should return 200:

curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"kvmEnabled\":true}"

Output:

HTTP/2 200 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 446
date: Thu, 12 Nov 2026 04:14:21 GMT

{"profileName":"patch12611794456697","generateRandomPassword":false,"activation":"ccmactivate","generateRandomMEBxPassword":false,"tags":[""],"dhcpEnabled":true,"ipSyncEnabled":false,"localWifiSyncEnabled":false,"wifiConfigs":[{"priority":1,"profileName":"wifi12611794456697","profileProfileName":"patch12611794456697","tenantId":""}],"tenantId":"","tlsMode":0,"iderEnabled":false,"kvmEnabled":true,"solEnabled":false,"uefiWifiSyncEnabled":false}

Check persisted state:

curl --noproxy '*' -skS -i "$BASE/profiles/$NAME" -H "Authorization: Bearer $TOKEN"
Output:
HTTP/2 200 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 446
date: Thu, 12 Nov 2026 04:16:24 GMT

{"profileName":"patch12611794456697","generateRandomPassword":false,"activation":"ccmactivate","generateRandomMEBxPassword":false,"tags":[""],"dhcpEnabled":true,"ipSyncEnabled":false,"localWifiSyncEnabled":false,"wifiConfigs":[{"priority":1,"profileName":"wifi12611794456697","profileProfileName":"patch12611794456697","tenantId":""}],"tenantId":"","tlsMode":0,"iderEnabled":false,"kvmEnabled":true,"solEnabled":false,"uefiWifiSyncEnabled":false}

Clean up

curl --noproxy '*' -skS -i -X DELETE "$BASE/profiles/$NAME" -H "Authorization: Bearer $TOKEN"

Output:

HTTP/2 204 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
date: Thu, 12 Nov 2026 04:17:23 GMT
curl --noproxy '*' -skS -i -X DELETE "$BASE/wirelessconfigs/$WIFI" -H "Authorization: Bearer $TOKEN"

Output:

HTTP/2 204 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
date: Thu, 12 Nov 2026 04:17:38 GMT

Create a CCM profile, then PATCH it to ACM without a MEBx password. The PATCH should return 400.

Create CCM profile: expect 201

curl --noproxy '*' -skS -i -X POST "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"ccmactivate\",\"amtPassword\":\"P@ssw0rd\"}"

Output:

HTTP/2 201 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 325
date: Thu, 12 Nov 2026 04:28:57 GMT

{"profileName":"patch12611794457322","generateRandomPassword":false,"activation":"ccmactivate","generateRandomMEBxPassword":false,"tags":[""],"dhcpEnabled":false,"ipSyncEnabled":false,"localWifiSyncEnabled":false,"tenantId":"","tlsMode":0,"iderEnabled":false,"kvmEnabled":false,"solEnabled":false,"uefiWifiSyncEnabled":false}

PATCH to ACM without MEBx password: expect 400

curl --noproxy '*' -skS -i -X PATCH "$BASE/profiles" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"profileName\":\"$NAME\",\"activation\":\"acmactivate\"}"

Output:

HTTP/2 400 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
content-length: 245
date: Thu, 12 Nov 2026 04:29:15 GMT

{"error":"Invalid input: mebxPassword is required when activation is acmactivate and generateRandomMEBxPassword is false","message":"Invalid input: mebxPassword is required when activation is acmactivate and generateRandomMEBxPassword is false"}

Clean up: expect 204

curl --noproxy '*' -skS -i -X DELETE "$BASE/profiles/$NAME" \
  -H "Authorization: Bearer $TOKEN"

Output:

HTTP/2 204 
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
date: Thu, 12 Nov 2026 04:29:30 GMT

@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.46%. Comparing base (70b2f40) to head (eb0b071).

Files with missing lines Patch % Lines
internal/entity/dto/v1/profile.go 90.00% 1 Missing ⚠️
internal/usecase/profiles/usecase.go 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1404      +/-   ##
==========================================
+ Coverage   62.32%   62.46%   +0.14%     
==========================================
  Files         159      159              
  Lines       13435    13452      +17     
==========================================
+ Hits         8373     8403      +30     
+ Misses       5062     5049      -13     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The affected PATCH integration assertions still expect outdated validation errors and will fail until aligned with the merged-profile validation behavior.

1 open issue
What changed in this PR

This PR addresses the profile PATCH validation gap tracked in #1261 by validating merged profile state before persistence, while preserving valid partial updates that omit passwords.

Changes:

  • Reuses profile validators across HTTP binding and use-case validation.
  • Checks merged PATCH profiles against field constraints and password requirements.
  • Adds regression coverage for invalid updates and preserved stored values.
File Description
internal/​usecase/​profiles/​usecase.go Validates merged profiles and shares password-required checks.
internal/​usecase/​profiles/​usecase_test.go Tests merged-state validation and password-preserving updates.
internal/​entity/​dto/​v1/​profile.go Centralizes registration of profile validators.
internal/​entity/​dto/​v1/​profile_test.go Tests shared validator registration and constraints.
internal/​controller/​httpapi/​v1/​profiles.go Uses the shared validator registration helper.
internal/​controller/​httpapi/​v1/​profiles_test.go Tests PATCH rejection responses and route validator registration.

Review effort: Balanced

Comment thread internal/usecase/profiles/usecase.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are recorded for the profile PATCH validation change.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@sinchubhat
sinchubhat marked this pull request as ready for review November 12, 2026 06:38
@sinchubhat
sinchubhat requested a review from a team as a code owner November 12, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants