Added Linter rule to disallow reserved property presence in resource's property bag. - #4842
Merged
Merged
Conversation
vayada
requested review from
bterlson,
markcowl and
timotheeguerin
as code owners
July 6, 2026 20:18
commit: |
Contributor
⚡ Benchmark Results
Full details – comparing
|
| Metric | Baseline | Current | Change |
|---|---|---|---|
| total | 🔴 1.00s | 🔴 1.04s | +3.5% |
| loader | 🟡 303.9ms | 🟡 322.3ms | +6.1% 🔴 |
| resolver | 🟢 39.9ms | 🟢 39.9ms | +0.1% |
| checker | 🟡 362.3ms | 🟡 371.2ms | +2.4% |
| validation | 🟢 84.5ms | 🟢 85.5ms | +1.3% |
| ↳ validation/@azure-tools/typespec-azure-core | 🟡 12.5ms | 🟡 13.1ms | +4.2% |
| ↳ validation/@typespec/http | 🟡 15.4ms | 🟡 15.9ms | +3.2% |
| ↳ validation/@typespec/rest | 🟢 1.6ms | 🟢 1.6ms | -0.3% |
| ↳ validation/@typespec/versioning | 🔴 50.9ms | 🔴 51.0ms | +0.2% |
| ↳ validation/compiler | 🟢 3.8ms | 🟢 3.8ms | +0.6% |
| linter | 🟡 213.8ms | 🟡 220.2ms | +3.0% |
| ↳ linter/@azure-tools/typespec-azure-core/auth-required | 🟢 0.1ms | 🟢 0.1ms | +2.3% |
| ↳ linter/@azure-tools/typespec-azure-core/bad-record-type | 🟢 0.6ms | 🟢 0.6ms | -0.3% |
| ↳ linter/@azure-tools/typespec-azure-core/byos | 🟢 8.3ms | 🟢 8.4ms | +1.7% |
| ↳ linter/@azure-tools/typespec-azure-core/casing-style | 🟢 1.4ms | 🟢 1.4ms | +0.8% |
| ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance | 🟢 0.2ms | 🟢 0.2ms | -0.1% |
| ↳ linter/@azure-tools/typespec-azure-core/documentation-required | 🟢 1.9ms | 🟢 1.9ms | -1.2% |
| ↳ linter/@azure-tools/typespec-azure-core/friendly-name | 🟢 1.4ms | 🟢 1.4ms | +1.5% |
| ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required | 🟢 0.4ms | 🟢 0.4ms | +1.0% |
| ↳ linter/@azure-tools/typespec-azure-core/known-encoding | 🟢 0.5ms | 🟢 0.5ms | +1.9% |
| ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required | 🟢 0.8ms | 🟢 0.8ms | +0.0% |
| ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch | 🟢 0.7ms | 🟢 0.7ms | -1.6% |
| ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union | 🟢 1.0ms | 🟢 0.9ms | -2.8% |
| ↳ linter/@azure-tools/typespec-azure-core/no-enum | 🟢 0.2ms | 🟢 0.2ms | -0.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes | 🟢 0.3ms | 🟢 0.3ms | +2.3% |
| ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops | 🟢 0.2ms | 🟢 0.2ms | +1.4% |
| ↳ linter/@azure-tools/typespec-azure-core/no-format | 🟢 0.8ms | 🟢 0.8ms | -0.3% |
| ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric | 🟢 0.8ms | 🟢 0.8ms | +1.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-header-explode | 🔴 26.5ms | 🔴 28.1ms | +6.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage | 🟢 2.0ms | 🟢 2.1ms | +2.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator | 🟢 0.2ms | 🟢 0.2ms | +4.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-nullable | 🟢 0.4ms | 🟢 0.4ms | +0.9% |
| ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime | 🟢 1.9ms | 🟢 2.0ms | +3.1% |
| ↳ linter/@azure-tools/typespec-azure-core/no-openapi | 🟢 2.3ms | 🟢 2.3ms | -0.4% |
| ↳ linter/@azure-tools/typespec-azure-core/no-private-usage | 🟢 3.1ms | 🟢 3.2ms | +1.2% |
| ↳ linter/@azure-tools/typespec-azure-core/no-query-explode | 🔴 27.7ms | 🔴 28.6ms | +3.5% |
| ↳ linter/@azure-tools/typespec-azure-core/no-response-body | 🔴 33.0ms | 🔴 34.1ms | +3.4% |
| ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces | 🟢 0.1ms | 🟢 0.1ms | +3.9% |
| ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch | 🟢 7.6ms | 🟢 8.0ms | +5.0% |
| ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params | 🟢 0.4ms | 🟢 0.4ms | +1.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator | 🟢 0.1ms | 🟢 0.1ms | +1.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-unknown | 🟢 0.3ms | 🟢 0.4ms | +3.0% |
| ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union | 🟢 0.8ms | 🟢 0.8ms | -1.5% |
| ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version | 🟢 0.4ms | 🟢 0.3ms | -4.0% |
| ↳ linter/@azure-tools/typespec-azure-core/request-body-problem | 🟢 0.5ms | 🟢 0.4ms | -0.5% |
| ↳ linter/@azure-tools/typespec-azure-core/require-versioned | 🟢 0.1ms | 🟢 0.1ms | +2.3% |
| ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem | 🔴 32.5ms | 🔴 33.8ms | +4.0% |
| ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body | 🟢 0.7ms | 🟢 0.7ms | +3.0% |
| ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model | 🟢 0.5ms | 🟢 0.5ms | -0.5% |
| ↳ linter/@azure-tools/typespec-azure-core/use-standard-names | 🟢 7.5ms | 🟢 7.9ms | +4.2% |
| ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations | 🟢 0.3ms | 🟢 0.2ms | -1.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources | 🔴 21.4ms | 🔴 21.5ms | +0.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations | 🟢 0.3ms | 🟢 0.3ms | +4.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version | 🟡 12.1ms | 🟡 12.4ms | +2.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key | 🟢 0.2ms | 🟢 0.2ms | +2.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage | 🟢 0.1ms | 🟢 0.1ms | +2.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes | 🟢 4.9ms | 🟢 5.2ms | +5.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts | 🟡 17.0ms | 🟡 16.9ms | -1.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record | 🟢 0.6ms | 🟢 0.6ms | +1.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes | 🟢 1.4ms | 🟢 1.4ms | -2.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes | 🟢 0.2ms | 🟢 0.2ms | -3.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment | 🟢 0.4ms | 🟢 0.4ms | -0.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property | 🟢 0.4ms | 🟢 0.4ms | +3.1% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator | 🟢 0.1ms | 🟢 0.1ms | -8.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb | 🟢 0.2ms | 🟢 0.2ms | -0.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property | 🟢 0.3ms | 🟢 0.3ms | +4.1% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format | 🟢 0.2ms | 🟢 0.2ms | -2.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars | 🟢 0.5ms | 🟢 0.5ms | +5.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern | 🟢 0.1ms | 🟢 0.1ms | -2.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation | 🟢 0.5ms | 🟢 0.5ms | +0.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response | 🟢 8.9ms | 🟢 9.0ms | +1.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch | 🟢 0.8ms | 🟢 0.8ms | -2.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars | 🟢 0.4ms | 🟢 0.4ms | +1.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state | 🟢 0.4ms | 🟢 0.4ms | +0.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels | 🟢 0.2ms | 🟢 0.2ms | -0.1% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties | 🟢 0.4ms | 🟢 0.4ms | -4.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation | 🟢 0.1ms | 🟢 0.1ms | +8.1% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header | 🟡 19.5ms | 🔴 20.7ms | +6.1% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint | 🟢 0.1ms | 🟢 0.2ms | +6.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers | 🟢 1.0ms | 🟢 1.0ms | +0.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model | 🟢 0.3ms | 🟢 0.3ms | +2.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props | 🟢 0.3ms | 🟢 0.3ms | +2.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-reserved-resource-property | 🟢 0.0ms | 🟢 0.2ms | +100.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation | 🟢 0.5ms | 🟢 0.5ms | +1.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body | 🔴 29.7ms | 🔴 31.1ms | +4.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope | 🟢 0.4ms | 🟢 0.4ms | +1.1% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name | 🟢 0.4ms | 🟢 0.4ms | -0.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop | 🟢 5.4ms | 🟢 5.0ms | -6.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type | 🟢 0.7ms | 🟢 0.7ms | -3.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression | 🟢 0.3ms | 🟢 0.3ms | -5.5% |
| ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict | 🟢 2.3ms | 🟢 2.3ms | +1.2% |
| ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix | 🟢 1.7ms | 🟢 1.7ms | +0.1% |
| emit | 🔴 6.01s | 🔴 6.13s | +2.0% |
| ↳ emit/@Azure-Tools | 🟢 0.0ms | 🟢 0.0ms | +0.0% |
| ↳ emit/@azure-tools/typespec-autorest | 🟢 124.4ms | 🟢 125.9ms | +1.2% |
| ↳ emit/@azure-tools/typespec-python | 🔴 2.24s | 🔴 2.29s | +2.1% |
| ↳ emit/@typespec | 🟢 0.0ms | 🟢 0.0ms | +0.0% |
| ↳ emit/@typespec/http-client-js | 🔴 566.7ms | 🔴 576.5ms | +1.7% |
| ↳ emit/@typespec/openapi3 | 🟢 106.9ms | 🟢 109.8ms | +2.7% |
| ↳ emit/@typespec/openapi3/compute | 🟢 92.9ms | 🟢 95.4ms | +2.7% |
| ↳ emit/@typespec/openapi3/write | 🟢 13.8ms | 🟢 14.2ms | +2.9% |
Averaged across 3 specs (azure-arm-resource-manager, azure-core-dataplane, azure-full).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Azure Resource Manager linter rule to prevent resource providers from defining a BillingData property inside an ARM resource’s properties model, since the name is reserved for platform billing integration and is being standardized via common types.
Changes:
- Added
no-billing-data-in-properties-baglinter rule implementation and registered it in the ARM linter. - Added rule coverage tests for direct, inherited, and spread-in property definitions (case-insensitive match).
- Documented the rule in the website docs and added it to the published rule lists; enabled it in the ARM resource-manager ruleset; added a Chronus change entry.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| website/src/content/docs/docs/libraries/azure-resource-manager/rules/no-billing-data-in-properties-bag.md | New rule documentation with correct/incorrect examples. |
| website/src/content/docs/docs/libraries/azure-resource-manager/reference/linter.md | Adds the new rule to the linter reference table. |
| packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts | Enables the new rule in the ARM resource-manager ruleset. |
| packages/typespec-azure-resource-manager/test/rules/no-billing-data-in-properties-bag.test.ts | Adds unit tests validating allowed/flagged cases, including inheritance/spreads and casing. |
| packages/typespec-azure-resource-manager/src/rules/no-billing-data-in-properties-bag.ts | Implements the new linter rule. |
| packages/typespec-azure-resource-manager/src/linter.ts | Registers the rule in the ARM linter rule list. |
| packages/typespec-azure-resource-manager/README.md | Adds the new rule to the README rule list. |
| .chronus/changes/add-no-billing-data-in-properties-bag-rule-2026-7-6-12-40-0.md | Records the feature addition for release notes/versioning. |
markcowl
reviewed
Jul 7, 2026
- Rename rule from no-billing-data-in-properties-bag to no-reserved-resource-property to accommodate additional reserved property names (per review) - Use an extensible reserved-name -> reason map so new reserved properties are easy to add - Parameterize the diagnostic message with the property name and reservation reason - Match property names case-insensitively; use camelCase in docs/description Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
markcowl
reviewed
Jul 7, 2026
…-resource-property.ts Updated case Co-authored-by: Mark Cowlishaw <1054056+markcowl@users.noreply.github.com>
markcowl
requested changes
Jul 7, 2026
The reserved-name map keys are camelCase, but the lookup lowercased the property name, so nothing matched. Build a lowercase-keyed lookup and compare lowercased names on both sides; report the reserved name with its canonical casing in the diagnostic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
markcowl
approved these changes
Jul 9, 2026
github-actions Bot
added a commit
to XiaofeiCao/typespec-azure
that referenced
this pull request
Jul 11, 2026
Sync documentation from Azure/typespec-azure upstream main branch. Key changes included: - Add docs for new ARM linter rule `no-reserved-resource-property` (PR Azure#4842) - Add docs for new TCGC linter rule `csharp-no-url-suffix` (PR Azure#4541) - Add ARM agent base type rules docs: `arm-agent-base-type-child-resources`, `arm-agent-base-type-lifecycle-operations`, `no-override-props` - Update ARM `data-types.md`: align Agent ResponseStatus enum to PascalCase and `createdAt` to utcDateTime per ARM guidelines (PR Azure#4855) - Fix `@azureBaseType` decorator doc example (PR Azure#4755) - Improve ARM library decorators, interfaces, and models docs (PR Azure#4494) - Add TCGC `@override` path-param and `@clientLocation` type-conflict caution admonitions to howto (PR Azure#4844) - Regen Java emitter docs with default values and improved type info (PR Azure#4863) - Update Python emitter docs with new `typeddict` models mode (upstream) - Update TypeScript emitter reference docs - Update autorest and autorest-canonical emitter docs - Update azure-rulesets linter reference - Update azure-core, azure-portal-core, TCGC reference docs - Update howtos for ARM and Generate client libraries - Add release notes for 2026-06-09 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Added Linter rule to disallow reserved property presence in resource's property bag.
One such example is "BillingData" property which is reserved for Billing Feature through RP Platform and is being standardized through Common Types.