Skip to content

feat(adr): add policy revoke-issuer & device CRUD/revoke commands with restructured tests - #782

Closed
Hangyi (HangyiWang) wants to merge 40 commits into
release/cms_public_preview_refreshfrom
users/hangyiwang/public-review-refresh
Closed

Hangyi (HangyiWang) wants to merge 40 commits into
release/cms_public_preview_refreshfrom
users/hangyiwang/public-review-refresh

Conversation

@HangyiWang

@HangyiWang Hangyi (HangyiWang) commented Feb 22, 2026 •

Copy link
Copy Markdown
Contributor

New Commands

az iot adr ns policy revoke-issuer

Revokes the current CA (issuer) certificate on a credential policy and triggers ICA rotation. After revocation, a new CA certificate is generated automatically. All device credentials issued by the old CA must be re-issued.

For BYOR policies, revocation transitions the policy back to PendingActivation with a new CSR that must be re-signed and re-activated via activate-byor.

az iot adr ns device list

Lists all devices in an ADR namespace.

az iot adr ns device show

Shows details of a specific device.

az iot adr ns device update

Updates device properties including enabled state, policy association, OS version, and attributes.

az iot adr ns device revoke

Revokes all active credentials for a device, forcing re-authentication.

Integration Test Restructuring

Refactored ADR integration tests from 3 monolithic files into 5 focused modules with shared helpers:

File Tests Covers
test_adr_crud_int.py 1 Namespace create/show/list/update/delete, credential CRUD, policy create/show/list/update/delete
test_adr_infra_int.py 1 Full pipeline smoke: UAMI → namespace → Hub Gen2 → DPS → enrollment → credential sync → hub cert verification
test_adr_device_int.py 1 Device provisioning via DPS+CSR, device list/show/update (enable/disable), 6 revoke scenarios
test_adr_byor_int.py 8 BYOR create, activate, sync-to-hub, revoke+reactivate rotation, edge cases (standard policy guard, mismatched chain, pre-activation revoke)
test_adr_policy_revoke_int.py 3 Standard policy revoke-issuer E2E with ICA rotation, single-policy-per-credential limit, nonexistent policy revoke
yxftpj6jfn1 yxftpj6jfn2 yxftpj6jfn3 yxftpj6jfn4 yxftpj6jfn5 yxftpj6jfn6 yxftpj6jfn7 yxftpj6jfn8

Ryan K (c-ryan-k) and others added 30 commits October 21, 2025 16:12
* Eventhub sdk add

* monitoring changes

* event changes

* add discovery logic

* remove unused code

* test changes

* Add fixes for integration tests

* remove readme file

* Remove uamqp usage in the code entirely

* Replace uampq from docs to pyamqp

* Fix failing unit tests

* Fix args compatibility issue

* Fix linting errors

* Addressing comments

* Fix linting issues

* Addressed comments

* Add right exception

* remove unwanted exception

---------

Co-authored-by: Ketki <ketkinaik@microsoft.com>
* fix: move base64 validation inside validate block for passthrough cases

When parsing connection strings with redacted SharedAccessKey=*** values
(e.g., from IoT Hub properties), the base64 validation would fail since
the redacted value is not valid base64.

Move the validation inside the 'if validate:' block so it only runs when
full validation is requested. Passthrough cases that only need to extract
other properties (like EntityPath, Endpoint) will no longer fail.

* fix: skip base64 validation for redacted SharedAccessKey (****) values

* Remove defensive check

---------

Co-authored-by: Ketki <ketkinaik@microsoft.com>
* Create release data

* Improve formatting and remove internal changes

---------

Co-authored-by: Ketki <ketkinaik@microsoft.com>
* fix: win/MSI pipeline fixes

* fix conditional compile-time/runtime logic issue

* fix windows extension path

* test: try to repro windows install issue by reordering pipeline stages

* fixup

* revert pipeline testing changes for now

* revert separation of python setup and dev requirements for now
Co-authored-by: Ketki <ketkinaik@microsoft.com>
Co-authored-by: Ketki <ketkinaik@microsoft.com>
Co-authored-by: Ketki <ketkinaik@microsoft.com>
Co-authored-by: Ketki <ketkinaik@microsoft.com>
* Try requirements options

* Add range

---------

Co-authored-by: Ketki <ketkinaik@microsoft.com>
Co-authored-by: Ketki <ketkinaik@microsoft.com>
@HangyiWang

Copy link
Copy Markdown
Contributor Author

Copilot could you review the PR and list the advice/actions/TODOs one by one

Copilot AI commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Hangyi (@HangyiWang) I've opened a new pull request, #783, to work on those changes. Once the pull request is ready, I'll request review from you.

* Remove all uampq occurences

* Addressed comments and fixed linting errors

---------

Co-authored-by: Ketki <ketkinaik@microsoft.com>
@HangyiWang
Hangyi (HangyiWang) marked this pull request as ready for review March 3, 2026 02:58
@@ -0,0 +1,46 @@
# coding=utf-8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are there async operations being used anywhere? If not why include anything from aio?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nope - let me remove all aio folder, we only consume operations

Comment thread azext_iot/adr/providers/credential.py Outdated
)
return wait_for_terminal_state(poller, **kwargs)
result = wait_for_terminal_state(poller, **kwargs)
return result.serialize(keep_readonly=True) if result else result

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the reason for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was changed a while ago, I don’t recall the exact reason, but I believe I needed to serialize it at the time to get some tests passing. If there are any objections, we can revert it.

try:
result = wait_for_terminal_state(poller, **kwargs)
except HttpResponseError as e:
# The backend returns 200 OK with an empty body when the LRO completes,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Has this been raised with the service team?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not yet - this is a workaround for a while also, let me see if I can reproduce it and file a bug to them.

Comment thread azext_iot/adr/providers/credential.py Outdated
try:
return self.client.credentials.get(resource_group_name=resource_group_name, namespace_name=namespace_name)
result = self.client.credentials.get(resource_group_name=resource_group_name, namespace_name=namespace_name)
return result.serialize(keep_readonly=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Another usage of result.serialize I'd like to grok

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah I can't recall exact reasons

Comment thread azext_iot/adr/providers/device.py Outdated
if attributes is not None:
properties["attributes"] = attributes
if policy_resource_id is not None:
properties["policy"] = {"resource_id": policy_resource_id}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How many of the above properties can be deleted or empty? For example, tags. For those that can, we should ensure update can support that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sotags attributes os_version can be deleted, not sure about policy_resource_id

@@ -0,0 +1,8243 @@
# coding=utf-8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we using models in our own clients ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because generated SDK methods require them as typed request bodies? Not necessary but it's more convenient pattern in other places.

@@ -0,0 +1,30 @@
# coding=utf-8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't include this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

okay

Comment thread docs/sdk-generation-guide.md
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.

5 participants