Skip to content

[Change Safety] Az.Accounts: AutoRest AcquirePolicyToken pipeline step (Stage A) - #29840

Merged
Yabo Hu (VeryEarly) merged 11 commits into
Azure:mainfrom
YangAn-microsoft:feature/change-safety-autorest-accounts
Aug 11, 2026
Merged

Yabo Hu (VeryEarly) merged 11 commits into
Azure:mainfrom
YangAn-microsoft:feature/change-safety-autorest-accounts

Conversation

@YangAn-microsoft

@YangAn-microsoft YangAn-microsoft commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Change Safety for AutoRest-generated cmdlets — the Az.Accounts (processing) half. Adds a VTable slot AddChangeSafetyPolicyTokenHandler (delegate type ChangeSafetyPolicyTokenDelegate) that the generated module invokes right after OnNewRequest. ContextAdapter.AddChangeSafetyPolicyTokenHandler(invocationInfo, appendStep) reads -AcquirePolicyToken / -ChangeReference from the cmdlet's BoundParameters and, when requested, appends a single step that calls the shared PolicyTokenAcquirer and stamps the x-ms-policy-external-evaluations header on write requests.

AutoRest cmdlets don't inherit AzurePSCmdlet, so the handler is injected centrally via the Register-AzModule VTable, mirroring how auth, telemetry, and completers are wired. The generator (Azure/autorest.powershell#1549) surfaces the two parameters via an inline IDynamicParameters implementation; their values flow to this step through BoundParameters.

  • Guarded no-op. When neither parameter is bound, no step is added (zero per-request cost); acquisition fails closed. Under -WhatIf the write cmdlet's ShouldProcess gate skips the HTTP call.
  • Separate VTable wiring. RegisterAzModule registers the slot alongside OnNewRequest (un-combined).
  • Contract pin test. Asserts the two parameter names + help text stay in sync with the literals the AutoRest generator emits (no compile-time link across repos).

Scope

  • src/Accounts/Accounts/CommonModule/VTable.csChangeSafetyPolicyTokenDelegate alias + AddChangeSafetyPolicyTokenHandler slot.
  • src/Accounts/Accounts/CommonModule/ContextAdapter.cs — the single AddChangeSafetyPolicyTokenHandler(invocationInfo, appendStep) method that reads BoundParameters and conditionally appends the acquire step (gating core; no separate wrapper).
  • src/Accounts/Accounts/CommonModule/RegisterAzModule.cs — wires the delegate as a separate VTable slot.
  • src/Accounts/Accounts.Test/UnitTest/AcquirePolicyTokenHandlerTests.cs, ChangeSafetyParameterContractTests.cs — tests.
  • tools/Common.Netcore.Dependencies.targets, src/Accounts/Accounts/ChangeLog.md — bump common to 1.3.114-preview.

Tests

10 unit tests pass locally:

  • AcquirePolicyTokenHandlerTests — step-append gating from the cmdlet's bound parameters: no step when the feature is off (parameters absent/null, -AcquirePolicyToken:$false, or empty/whitespace -ChangeReference); a single step when -AcquirePolicyToken is present, -ChangeReference is set, or both (dedup to one). Tests drive the handler through an InvocationInfo built with its bound parameters. Write-verb gate and header/wire behavior are covered by PolicyTokenAcquirer tests in azure-powershell-common.
  • ChangeSafetyParameterContractTests — pins the parameter names and help text to the values the generator emits.

Paired generator output check (Azure/autorest.powershell#1549): a fresh regen + build-module.ps1 of Az.ManagedServiceIdentity (exit 0) confirms the write cmdlets surface -AcquirePolicyToken (SwitchParameter) / -ChangeReference (string) — the values this handler reads from BoundParameters — while read (Get-*) cmdlets do not. Parameter names/help match this PR's ChangeSafetyParameters (kept in sync by ChangeSafetyParameterContractTests).

Live end-to-end test (real Azure)

Re-validated on the latest upstream/main (merged into this branch) after rebuilding this Stage A Az.Accounts. Ran against an opted-in AutoRest module (Az.ManagedServiceIdentity) regenerated by the paired generator PR (Azure/autorest.powershell#1549) with enable-change-safety.

Command

New-AzUserAssignedIdentity -ResourceGroupName rg-cs-e2e -Name mi-cs-e2e -Location eastus -AcquirePolicyToken -Confirm:$false

-AcquirePolicyToken bound and flowed into BoundParameters; the AddChangeSafetyPolicyTokenHandler VTable slot appended the acquire step, which stamped x-ms-policy-external-evaluations on the write. The identity was created (HTTP 200/201).

Pipeline trace (temporary token-safe debug hook in ContextAdapter; only metadata + a one-way SHA-256 hash of the stamped header are logged — never the raw token)

[PolicyTokenAcquirer] Intercept PUT .../userAssignedIdentities/mi-cs-e2e?api-version=2023-01-31
[PolicyTokenAcquirer] Payload prepared.
[PolicyTokenAcquirer] POST acquirePolicyToken .../Microsoft.Authorization/acquirePolicyToken?api-version=2025-03-01
[PolicyTokenAcquirer] Response 200 OK
[PolicyTokenAcquirer] Token acquired and header added.
writeRequest: PUT .../userAssignedIdentities/mi-cs-e2e?api-version=2023-01-31
  x-ms-policy-external-evaluations: sha256=789ed4cc92f969d73c3ad6d5004def21fdf381dce8998f822fd81802c1c7efb7 (len=4538)
  writeBody: { "location": "eastus" }

Acquisition fails closed (StampPolicyTokenAsync throws before the write on any non-200 / missing token), so a successful write proves a valid token was obtained and stamped.

Note: the AutoRest -Debug dump prints the request at BeforeCall, before the appended step runs, so x-ms-policy-external-evaluations is not visible in that dump (the Authorization header is likewise absent yet the call authenticates). The in-step trace above confirms the stamp. Token safety: only metadata + a SHA-256 hash are ever logged, and the header is in AuthorizationHeaderNames so it's dropped from request logs. Subscription/tenant IDs are redacted; test resources are provisioned in a BAMI subscription and removed after validation.

Dependencies

Copilot AI lite review requested due to automatic review settings July 13, 2026 13:18
@azure-client-tools-bot-prd

Copy link
Copy Markdown
Thanks for your contribution! The pull request validation has started. Please revisit this comment for updated status.

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.

Pull request overview

This PR extends the Az.Accounts “Change Safety” infrastructure to AutoRest-generated cmdlets by wiring new runtime hooks into the generated cmdlet VTable and HTTP pipeline, and adding unit tests plus release notes to document the groundwork.

Changes:

  • Adds a conditional HTTP pipeline step that stamps an Azure Policy token onto outgoing write requests when Change Safety parameters are bound.
  • Introduces a new VTable delegate for supplying Change Safety dynamic parameters and wires it through Register-AzModule.
  • Adds unit tests for pipeline-step gating and dynamic-parameter gating, and updates the Accounts changelog.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Accounts/Accounts/CommonModule/VTable.cs Adds a new GetDynamicParameters delegate contract for Stage C generated modules.
src/Accounts/Accounts/CommonModule/RegisterAzModule.cs Wires the new GetDynamicParameters delegate from ContextAdapter into the exported VTable.
src/Accounts/Accounts/CommonModule/ContextAdapter.cs Appends the conditional AcquirePolicyToken pipeline step and implements Change Safety dynamic parameter building/gating.
src/Accounts/Accounts/ChangeLog.md Documents upcoming Change Safety plumbing for AutoRest cmdlets.
src/Accounts/Accounts.Test/UnitTest/AcquirePolicyTokenHandlerTests.cs Adds unit coverage for step-append gating based on bound Change Safety parameters.
src/Accounts/Accounts.Test/ChangeSafetyDynamicParametersTests.cs Adds tests for dynamic parameter exposure on write verbs and exclusion on read verbs.

Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs Outdated
Comment thread src/Accounts/Accounts/ChangeLog.md Outdated
Comment thread src/Accounts/Accounts/CommonModule/VTable.cs Outdated
Copilot AI review requested due to automatic review settings July 15, 2026 00:48

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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/Accounts/Accounts/CommonModule/VTable.cs Outdated
Comment thread src/Accounts/Accounts/ChangeLog.md Outdated
Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs Outdated
Comment thread src/Accounts/Accounts/ChangeLog.md Outdated
Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs Outdated
Copilot AI review requested due to automatic review settings July 16, 2026 07:03

@VeryEarly Yabo Hu (VeryEarly) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

you can keep trying this direction, but I have a concern about this design:

Essentially, we will get delegates at runtime to:

  • function to add dynamic parameters
  • http pipeline step to add dynamic parameter values to header

But for generated modules, in order to expose dynamic parameters, the public object GetDynamicParameters() need to be implemented in each cmdlet instance, which will be injected in generator logic. And in order to get that value, the cmdlet needs to call the call the getparametervalue delegate explicitly by name which will also be injected in generator logic. That will make codegen logic depends on a runtime wired delegate. Which is not generally the best practice. And I'll argue whether this increased or decreased the complexity.

Keeping the http pipeline step is fine, because it append/prepend the step into pipeline in module level, no cmdlet level changes required.

Please consider my concern unless you plan to do it differently.

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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/Accounts/Accounts/ChangeLog.md Outdated
Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs Outdated
@YangAn-microsoft

YangAn-microsoft commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

you can keep trying this direction, but I have a concern about this design:

Essentially, we will get delegates at runtime to:

  • function to add dynamic parameters
  • http pipeline step to add dynamic parameter values to header

But for generated modules, in order to expose dynamic parameters, the public object GetDynamicParameters() need to be implemented in each cmdlet instance, which will be injected in generator logic. And in order to get that value, the cmdlet needs to call the call the getparametervalue delegate explicitly by name which will also be injected in generator logic. That will make codegen logic depends on a runtime wired delegate. Which is not generally the best practice. And I'll argue whether this increased or decreased the complexity.

Keeping the http pipeline step is fine, because it append/prepend the step into pipeline in module level, no cmdlet level changes required.

Please consider my concern unless you plan to do it differently.

I will explore and compare with changing generator to generate self-contained static parameters on write cmdlets

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI review requested due to automatic review settings July 17, 2026 00:45

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs
Comment thread src/Accounts/Accounts/ChangeLog.md Outdated
@YangAn-microsoft YangAn-microsoft changed the title [Change Safety] Az.Accounts: AutoRest AcquirePolicyToken pipeline step + dynamic-parameter delegate (Stages A+B) [Change Safety] Az.Accounts: AutoRest AcquirePolicyToken pipeline step (Stage A) Jul 17, 2026
Copilot AI review requested due to automatic review settings July 17, 2026 03:38

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs
Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs
Copilot AI review requested due to automatic review settings July 17, 2026 03:57

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs Outdated
Comment thread src/Accounts/Accounts/CommonModule/ContextAdapter.cs
Comment thread src/Accounts/Accounts.Test/UnitTest/AcquirePolicyTokenHandlerTests.cs Outdated

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Match the generated module VTable slot rename and the Add...Handler naming convention. Delegate alias AcquirePolicyTokenDelegate -> ChangeSafetyPolicyTokenDelegate; ContextAdapter wrapper method renamed to match. Also add missing using for MemoryDataStore in the change-safety unit test.
Copilot AI review requested due to automatic review settings August 3, 2026 03:12
@a0x1ab

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 3 pipeline(s).

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 3, 2026 03:17
@a0x1ab

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 3 pipeline(s).

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Merge AddChangeSafetyPolicyTokenHandler and AddAcquirePolicyTokenHandler into a single InvocationInfo-based method, and update unit tests to construct an InvocationInfo via its non-public BoundParameters setter.
Copilot AI review requested due to automatic review settings August 11, 2026 00:39

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

src/Accounts/Accounts/ChangeLog.md:26

  • This dependency bump belongs under the "## Upcoming Release" section per the changelog header instructions. Leaving it under "## Version 5.5.2" makes the changelog misleading about what changed in that already-versioned release section.
## Version 5.5.2
* Upgraded `Azure.Core` dependency from 1.56.0 to 1.57.0.
* Upgraded `System.ClientModel` dependency from 1.12.0 to 1.13.0.
* Upgraded common library to `1.3.114-preview`.

@a0x1ab

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 3 pipeline(s).

Copilot AI review requested due to automatic review settings August 11, 2026 00:46
@a0x1ab

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 3 pipeline(s).

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Accounts/Accounts/ChangeLog.md:26

  • The change log guidance at the top of this file says changes for the next release should go under "## Upcoming Release", but this new entry is currently filed under "## Version 5.5.2" (which reads like a past release). Please move the common-library upgrade bullet into the Upcoming Release section so the release notes remain chronologically accurate.

## Version 5.5.2
* Upgraded `Azure.Core` dependency from 1.56.0 to 1.57.0.
* Upgraded `System.ClientModel` dependency from 1.12.0 to 1.13.0.
* Upgraded common library to `1.3.114-preview`.

@VeryEarly
Yabo Hu (VeryEarly) merged commit 96d8749 into Azure:main Aug 11, 2026
12 checks passed
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.

4 participants