[Change Safety] Generator: emit inline IDynamicParameters (-AcquirePolicyToken/-ChangeReference) on write cmdlets (Stage D) - #1549
Conversation
… to VTable dynamic-parameter delegate) Emit -AcquirePolicyToken (switch) and -ChangeReference (string) as static [Parameter] properties on azure write-verb cmdlets, categorized Azure. No IDynamicParameters, no Module.cs/VTable delegate wiring; the module-level HTTP pipeline step reads the values from BoundParameters by name.
…eters Gate implementChangeSafetyParameters on !endpointResourceIdKeyName (the generator's canonical data-plane signal, matching isDataPlane in module-class.ts), so only management-plane (ARM) write-verb cmdlets get -AcquirePolicyToken/-ChangeReference.
…meters) Use the exact parameter names and help messages defined in azure-powershell-common ChangeSafetyParameters so AutoRest and SDK cmdlets present identically to users.
…flag Add a change-safety project flag (default false) read from the module readme. implementChangeSafetyParameters only emits -AcquirePolicyToken/-ChangeReference when it is true, so the ~180-module rollout is deliberate (a module opts in alongside bumping its Az.Accounts minimum) rather than triggered by any unrelated regeneration.
Yabo Hu (VeryEarly)
left a comment
There was a problem hiding this comment.
I think the wiring of the runtime delegate to add headers is missing from this PR
…le-change-safety Address review feedback on Azure#1549: - Gate the -AcquirePolicyToken/-ChangeReference emission on the PowerShell verb instead of sniffing the HTTP method off requests[0]. A cmdlet's callGraph can hold multiple operations (e.g. GetPut Update = GET + PUT) and one operation can carry multiple requests, so requests[0] was unreliable. The verb also correctly treats POST list-style operations (surfaced as Get) as reads. - Rename the opt-in config key change-safety -> enable-change-safety (and the Project.changeSafety property -> enableChangeSafety) so it reads as a toggle.
|
Yabo Hu (@VeryEarly) re: "the wiring of the runtime delegate to add headers is missing from this PR" — that is intentional in this design. This is the static-parameter approach that replaced #1548 (which used a runtime-wired VTable delegate). Here the generator only emits the static |
…s (Stage D) Switch the generator from emitting static -AcquirePolicyToken/-ChangeReference [Parameter] properties to an inline IDynamicParameters.GetDynamicParameters() implementation on azure management-plane write-verb cmdlets. This matches the dynamic-parameter mechanism SDK cmdlets use (AzurePSCmdlet/ChangeSafetyParameters), so SDK and AutoRest cmdlets are indistinguishable. The generated method builds the RuntimeDefinedParameterDictionary locally with names + help text mirroring azure-powershell-common's ChangeSafetyParameters (kept in sync by the Accounts.Test contract pin test); no runtime-wired VTable delegate. All gating (opt-in enable-change-safety flag, azure-only, data-plane excluded, verb-based write gating) is unchanged.
There was a problem hiding this comment.
Pull request overview
Adds opt-in support to emit Change Safety dynamic parameters (-AcquirePolicyToken, -ChangeReference) on generated Azure management-plane write-verb cmdlets by generating an inline IDynamicParameters implementation directly in each cmdlet (avoiding any Module/VTable runtime wiring), controlled by a new enable-change-safety configuration flag.
Changes:
- Introduces
enable-change-safety(defaultfalse) as a per-module configuration flag, exposed asProject.enableChangeSafety. - Adds a PowerShell declarations entry for
System.Management.Automation.IDynamicParameters. - Updates cmdlet generation to (when gated conditions are met) implement
IDynamicParametersand emitGetDynamicParameters()that returns a locally-builtRuntimeDefinedParameterDictionarycontaining the two Change Safety parameters.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| powershell/internal/project.ts | Adds enableChangeSafety and loads enable-change-safety config (default off) to gate emission. |
| powershell/internal/powershell-declarations.ts | Declares IDynamicParameters so generated cmdlets can implement it. |
| powershell/cmdlets/class.ts | Emits inline IDynamicParameters.GetDynamicParameters() for eligible Azure management-plane write-verb cmdlets, adding the two dynamic parameters. |
…nNewRequest Adds a dedicated AcquirePolicyTokenDelegate type and a PolicyTokenHandler property on the generated Module, invoked in CreatePipeline right after OnNewRequest (append-only). Emitted and mapped in the .psm1 only when enable-change-safety is set (azure management-plane), decoupling the change-safety step from OnNewRequest instead of composing into it.
… invoke The AcquirePolicyTokenDelegate type, the Module PolicyTokenHandler property, and the .psm1 VTable mapping are now emitted for every management-plane module (like the other always-on delegates). Only the CreatePipeline invoke (and the per-cmdlet params) stay gated on enable-change-safety, so the plumbing is inert until a module opts in.
feef16a to
87c5059
Compare
…ndler Align the Change Safety pipeline delegate with the existing Add...Handler VTable naming convention and give it a change-safety-qualified name. Delegate type AcquirePolicyTokenDelegate -> ChangeSafetyPolicyTokenDelegate.
AutoRest proxy functions use a static param() block, so the inline IDynamicParameters emitted on the private cmdlet never surfaced on the public proxy. Emit a dynamicparam block (only when a wrapped cmdlet implements IDynamicParameters) that forwards the private cmdlet's dynamic parameters, mirroring PowerShell's canonical ProxyCommand pattern. Self-gating: cmdlets without dynamic parameters get no block (zero diff).
…baselines Option B: the AddChangeSafetyPolicyTokenHandler VTable delegate/property, its Module.cs alias, and the psm1 mapping are now emitted only when project.enableChangeSafety is set. Non-opted management-plane modules therefore have zero Module.cs/Az.*.psm1 diff. The always-present build-time runtime sources (ExportProxyCmdlet.cs dynamicparam forwarding + PsProxyOutputs.cs DynamicParamOutput) still change in every baseline. This baseline refresh also sweeps up the pre-existing Context.cs comment typo fix (PSBoundParamters -> PSBoundParameters, Azure#1514) whose baselines were last regenerated in Azure#1421.
…ty-generator-static
…k (address review) Move the AddChangeSafetyPolicyTokenHandler append out of the data-plane else-if and into the control-plane default requestHandler build, gated on enableChangeSafety; the data-plane branch stays a clean override. Output is byte-identical.
Summary
Generator half of Change Safety for AutoRest management-plane modules, opt-in per module via an
enable-change-safetyconfig flag. Adds-AcquirePolicyTokenand-ChangeReferenceto write-verb cmdlets and wires the pipeline step that acquires a policy token and stamps thex-ms-policy-external-evaluationsheader on write requests. Az.Accounts (Azure/azure-powershell#29840) fills the pipeline slot.What it does
implementChangeSafetyParameters()incmdlets/class.tsadds an inlineIDynamicParameters.GetDynamicParameters()to generated write cmdlets, emitting-AcquirePolicyToken(SwitchParameter) and-ChangeReference(string) — the same dynamic-parameter mechanism SDK cmdlets use. Names + help text are reused verbatim from azure-powershell-common'sChangeSafetyParameters(a contract pin test inAccounts.Testkeeps them in sync).param()block, soDynamicParamOutput(resources/psruntime/BuildTime/Models/PsProxyOutputs.cs) emits adynamicparamblock that forwards the wrapped cmdlet's dynamic parameters — self-gated on the wrapped cmdlet implementingIDynamicParameters.ExportProxyCmdlet.csinserts it between the proxyparam()block andbegin{}.module/module-class.tsdeclares theChangeSafetyPolicyTokenDelegatealias +AddChangeSafetyPolicyTokenHandlerVTable property and invokes it inCreatePipelineright afterOnNewRequest;generators/psm1.tsmaps it in the.psm1.internal/project.tsreadsenable-change-safetyintoProject.enableChangeSafety(default false);internal/powershell-declarations.tsadds theIDynamicParametersdeclaration.Gating
All change-safety output — parameters, proxy
dynamicparam, and the VTable plumbing — is gated onenable-change-safety(management-plane only). Flag off (default): zero generated-code diff. The proxydynamicparamis additionally self-gated onIDynamicParameters, so cmdlets without dynamic parameters are unaffected. The only unconditional change is to the two build-time proxy runtime sources (PsProxyOutputs.cs,ExportProxyCmdlet.cs), which emit nothing extra for cmdlets without dynamic parameters.Scope
Seven files:
powershell/cmdlets/class.ts,powershell/module/module-class.ts,powershell/generators/psm1.ts,powershell/internal/project.ts,powershell/internal/powershell-declarations.ts,powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs,powershell/resources/psruntime/BuildTime/Cmdlets/ExportProxyCmdlet.cs, plus refreshedtests-emitterbaselines.Verification
npm run build,npm run eslint,npm test,tests-sdk1-support(-AllowList -SkipCsharp): clean / allEqual.tests-emitterbaselines refreshed for the 43 whitelisted cases: only the two build-time runtime sources change per case (noModule.cs/.psm1diff). The refresh also picks up a pre-existing staleruntime/Context.cscomment-typo baseline (fixed in the generator resource by Fix typo in comment: PSBoundParamters -> PSBoundParameters #1514; 25 cases).Az.ManagedServiceIdentitywith--enable-change-safety):autorest→ 425 files, exit 0;build-module.ps1 -NoDocs→ exit 0. The emittedexports/are correctly verb-gated — thedynamicparamblock appears on all write cmdlets (New/Remove/Update-Az*, 6/6) and on none of the read cmdlets (Get-Az*, 0/4). The private write cmdlet'sGetDynamicParameters()emits exactly-AcquirePolicyToken(SwitchParameter) and-ChangeReference(string) with help text matching azure-powershell-common'sChangeSafetyParameters; the public proxy re-declares them via the forwardingdynamicparamblock.Live end-to-end test (real Azure)
Re-validated on the latest
upstream/main(merged into this branch) after rebuilding the generator (rush update && rush rebuild). Full flow on a real subscription with an opted-in module (Az.ManagedServiceIdentity, regenerated by this branch withenable-change-safety) plus the paired Az.Accounts build (Azure/azure-powershell#29840).Command
The public proxy function accepted
-AcquirePolicyToken— surfaced via the generateddynamicparamforwarding block this PR adds — and the identity was created (HTTP 200/201). A read cmdlet does not surface the parameter.Pipeline trace (temporary token-safe debug hook; only metadata + a one-way SHA-256 hash of the stamped header are logged — never the raw token)
Dependencies