feat!: simplify policy document identity - #106
Conversation
Remove document schema URIs and introduce the software-managed PolicyFormatVersion contract across Rust and .NET. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Two canonical error fixtures retain the ambiguous “policy version” wording after adopting PolicyFormatVersion.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Simplifies policy identity across Rust, .NET, schemas, APIs, and fixtures by replacing PolicyVersion with software-managed PolicyFormatVersion and removing document $schema members.
Changes:
- Adds validated, SemVer-compatible
PolicyFormatVersiontypes. - Updates policy models, serializers, schemas, OpenAPI, and finding codes.
- Migrates samples, fixtures, and tests to the canonical shape.
File summaries
| File | Description |
|---|---|
policies/test-data/package-broker/responses/winget-vscode-skiphash.denied.response.json |
Renames projected version field. |
policies/test-data/package-broker/responses/winget-vscode-install.allowed.response.json |
Renames projected version field. |
policies/test-data/package-broker/responses/policy.response.json |
Migrates embedded policy identity. |
policies/test-data/package-broker/responses/policy-validation.valid.response.json |
Migrates canonical draft identity. |
policies/test-data/package-broker/responses/policy-validation.invalid.response.json |
Updates format-version finding. |
policies/test-data/package-broker/responses/policy-stale-token.error.json |
Migrates embedded policy identity. |
policies/test-data/package-broker/responses/policy-replacement.response.json |
Migrates replacement policy documents. |
policies/test-data/package-broker/responses/policy-management.invalid.response.json |
Updates format-version diagnostics. |
policies/test-data/package-broker/responses/policy-management.active.response.json |
Migrates active policy identity. |
policies/test-data/package-broker/responses/execution-winget-vscode-install.response.json |
Renames projected version field. |
policies/test-data/package-broker/requests/policy-validation.request.json |
Migrates validation draft identity. |
policies/test-data/package-broker/requests/policy-replacement.update.request.json |
Migrates update draft identity. |
policies/test-data/package-broker/requests/policy-replacement.replace-identity.request.json |
Migrates replacement draft identity. |
policies/test-data/package-broker/requests/policy-replacement.repair.request.json |
Migrates repair draft identity. |
policies/test-data/package-broker/requests/policy-replacement.overwrite.request.json |
Migrates overwrite draft identity. |
policies/test-data/package-broker/requests/policy-replacement.create.request.json |
Migrates creation draft identity. |
policies/test-data/package-broker/invalid/responses/policy-validation.valid-with-error.response.json |
Migrates invalid response fixture. |
policies/rust/now-policy/tools/generate_schema.rs |
Removes schema-ID injection. |
policies/rust/now-policy/tests/policy_samples.rs |
Tests strict parsing and version preservation. |
policies/rust/now-policy/src/policy.rs |
Replaces schema/version fields in policy models. |
policies/rust/now-policy/src/newtypes.rs |
Adds validated format-version type. |
policies/rust/now-policy/src/markers.rs |
Removes obsolete schema markers. |
policies/rust/now-policy/schema/devolutions.now-policy.schema.json |
Updates committed-policy schema. |
policies/rust/now-policy/schema/devolutions.now-policy-draft.schema.json |
Updates draft-policy schema. |
policies/rust/now-policy/README.md |
Documents identity semantics. |
policies/rust/now-policy/assets/samples/scenario-coverage.policy.json |
Migrates sample identity. |
policies/rust/now-policy/assets/samples/powershell-current-user.policy.json |
Migrates sample identity. |
policies/rust/now-policy/assets/samples/powershell-advanced.policy.json |
Migrates sample identity. |
policies/rust/now-policy/assets/samples/invalid/policies/invalid-failure-decision.policy.json |
Migrates invalid sample identity. |
policies/rust/now-policy/assets/samples/deny-risky-options.policy.json |
Migrates sample identity. |
policies/rust/now-policy/assets/samples/corporate-allowlist.policy.json |
Migrates sample identity. |
policies/rust/now-policy-server-template/src/server.rs |
Tests OpenAPI component namespacing. |
policies/rust/now-policy-api/src/management.rs |
Renames validation finding code. |
policies/rust/now-policy-api/src/api.rs |
Updates response policy projection. |
policies/rust/now-policy-api/openapi/now-policy-api.yaml |
Regenerates the public API contract. |
policies/dotnet/Devolutions.Now.Policy.Model/README.md |
Documents .NET identity semantics. |
policies/dotnet/Devolutions.Now.Policy.Model/PolicySerializer.cs |
Removes schema-URI validation. |
policies/dotnet/Devolutions.Now.Policy.Model/PolicyModels.cs |
Adds format-version model and converter. |
policies/dotnet/Devolutions.Now.Policy.Model.Tests/PolicyTests.cs |
Tests parsing, conversion, and compatibility. |
policies/dotnet/Devolutions.Now.Policy.Client.Tests/PolicyManagementClientTests.cs |
Updates management client expectations. |
policies/dotnet/Devolutions.Now.Policy.Client.Tests/MetaModelTests.cs |
Tests strict response parsing. |
policies/dotnet/Devolutions.Now.Policy.Client.Tests/BrokerClientTests.cs |
Updates broker response fixtures. |
policies/dotnet/Devolutions.Now.Policy.Api/ResponseModels.cs |
Updates .NET response projection. |
policies/dotnet/Devolutions.Now.Policy.Api/README.md |
Documents API projection semantics. |
policies/dotnet/Devolutions.Now.Policy.Api/PolicyManagementModels.cs |
Renames .NET finding code. |
policies/dotnet/Devolutions.Now.Policy.Api/BrokerSerializer.cs |
Removes obsolete schema constants. |
Review details
- Files reviewed: 46/46 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The parsers reject a valid SemVer 1.x value despite the stated compatibility contract.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
policies/dotnet/Devolutions.Now.Policy.Model.Tests/PolicyTests.cs:266
- This case is valid SemVer 2.0.0: the specification does not bound the size of core numeric identifiers, and its major version is still compatible
1. Rejecting it contradicts the PR contract that readers accept compatible SemVer 1.x values. Avoid converting minor/patch toulong(and align the Rust parser, schemas, and tests) so syntactically valid 1.x values are preserved.
- Files reviewed: 46/46 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The standalone JSON schemas unexpectedly lose their canonical $id values, and malformed-version coverage is incomplete in Rust.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
policies/rust/now-policy/tools/generate_schema.rs:28
- Removing the instance-level
$schemamember does not require removing the standalone schema's own$id. This generator now strips the canonical identifiers from both published schema artifacts, so external schemas can no longer reference them by their established URIs even though that additional breaking change is not part of the stated document migration. Keep generator-local schema IDs (they need not be exposed as policy model fields) and continue injecting them into the generated roots.
- Files reviewed: 47/48 changed files
- Comments generated: 1
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The diagnostic fixture misstates 1.x compatibility, and generated schema documentation exposes unresolved Rust-specific markup.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
policies/test-data/package-broker/responses/policy-management.invalid.response.json:26
- This renamed finding still reports
supported: "1.0.0", which implies that only the current stamped value is accepted. The new contract accepts every valid SemVer 1.x value, so advertise the compatible line (or a supported-major field) instead of an exact version.
policies/rust/now-policy/src/newtypes.rs:118 - Schemars copies this Rustdoc text into the public JSON Schemas and OpenAPI descriptions, where the Rust-only intra-doc link is emitted literally as
[`CURRENT_POLICY_FORMAT_VERSION`]and cannot resolve. Use language-neutral wording so generated API documentation is meaningful to non-Rust consumers.
- Files reviewed: 47/48 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
The breaking identity change is consistently implemented and covered across both language models, generated contracts, and fixtures.
Review details
- Files reviewed: 48/49 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The generated schema pattern accepts format versions that both runtime readers reject.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 47/47 changed files
- Comments generated: 1
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
Runtime models, schemas, API contracts, fixtures, and regression coverage consistently implement the breaking identity change.
Review details
- Files reviewed: 47/47 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The generated version schema accepts values that the Rust and .NET readers reject.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 47/47 changed files
- Comments generated: 1
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
The breaking contract migration is consistent across implementations, schemas, fixtures, documentation, and regression tests.
Review details
- Files reviewed: 47/47 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The generated schema accepts numeric components outside the runtime readers’ unsigned 64-bit range.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 47/47 changed files
- Comments generated: 1
- Review effort level: Balanced
## 🤖 New release
* `now-policy`: 0.3.0 -> 0.4.0 (⚠ API breaking changes)
* `now-policy-api`: 0.4.0 -> 0.5.0 (⚠ API breaking changes)
* `now-policy-server-template`: 0.4.0 -> 0.5.0 (⚠ API breaking changes)
### ⚠ `now-policy` breaking changes
```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---
Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/constructible_struct_adds_field.ron
Failed in:
field PolicyDocument.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy/src/policy.rs:25
field PolicyDocument.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy/src/policy.rs:25
field PolicyDraftDocument.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy/src/policy.rs:64
field PolicyDraftDocument.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy/src/policy.rs:64
--- failure pub_module_level_const_missing: pub module-level const is missing ---
Description:
A public const is missing or renamed
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/pub_module_level_const_missing.ron
Failed in:
POLICY_SCHEMA_URI in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:56
POLICY_SCHEMA_URI in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:56
POLICY_DRAFT_SCHEMA_URI in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:59
POLICY_DRAFT_SCHEMA_URI in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:59
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/struct_missing.ron
Failed in:
struct now_policy::markers::PolicyDraftSchemaUri, previously in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:67
struct now_policy::PolicyDraftSchemaUri, previously in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:67
struct now_policy::markers::PolicySchemaUri, previously in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:61
struct now_policy::PolicySchemaUri, previously in file /tmp/.tmpn9o9zp/now-policy/src/markers.rs:61
--- failure struct_pub_field_missing: pub struct's pub field removed or renamed ---
Description:
A publicly-visible struct has at least one public field that is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/struct_pub_field_missing.ron
Failed in:
field _schema of struct PolicyDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:25
field policy_version of struct PolicyDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:28
field _schema of struct PolicyDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:25
field policy_version of struct PolicyDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:28
field _schema of struct PolicyDraftDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:66
field policy_version of struct PolicyDraftDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:69
field _schema of struct PolicyDraftDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:66
field policy_version of struct PolicyDraftDocument, previously in file /tmp/.tmpn9o9zp/now-policy/src/policy.rs:69
```
### ⚠ `now-policy-api` breaking changes
```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---
Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/constructible_struct_adds_field.ron
Failed in:
field ResponsePolicyInfo.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/api.rs:258
field ResponsePolicyInfo.policy_format_version in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/api.rs:258
--- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value ---
Description:
The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`.
ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/enum_no_repr_variant_discriminant_changed.ron
Failed in:
variant PolicyFindingCode::UnsupportedPolicyType 13 -> 12 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:105
variant PolicyFindingCode::AuditModeEnabled 15 -> 14 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:107
variant PolicyFindingCode::DefaultAllow 16 -> 15 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:108
variant PolicyFindingCode::SensitiveOptionAllowed 17 -> 16 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:109
variant PolicyFindingCode::UnsupportedPolicyType 13 -> 12 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:105
variant PolicyFindingCode::AuditModeEnabled 15 -> 14 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:107
variant PolicyFindingCode::DefaultAllow 16 -> 15 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:108
variant PolicyFindingCode::SensitiveOptionAllowed 17 -> 16 in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:109
--- failure enum_variant_added: enum variant added on exhaustive enum ---
Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/enum_variant_added.ron
Failed in:
variant PolicyFindingCode:UnsupportedPolicyFormatVersion in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:106
variant PolicyFindingCode:UnsupportedPolicyFormatVersion in /tmp/.tmpLwzI34/now-libraries/policies/rust/now-policy-api/src/management.rs:106
--- failure enum_variant_missing: pub enum variant removed or renamed ---
Description:
A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/enum_variant_missing.ron
Failed in:
variant PolicyFindingCode::UnsupportedSchema, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/management.rs:105
variant PolicyFindingCode::UnsupportedPolicyVersion, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/management.rs:107
variant PolicyFindingCode::UnsupportedSchema, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/management.rs:105
variant PolicyFindingCode::UnsupportedPolicyVersion, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/management.rs:107
--- failure struct_pub_field_missing: pub struct's pub field removed or renamed ---
Description:
A publicly-visible struct has at least one public field that is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/struct_pub_field_missing.ron
Failed in:
field policy_version of struct ResponsePolicyInfo, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/api.rs:258
field policy_version of struct ResponsePolicyInfo, previously in file /tmp/.tmpn9o9zp/now-policy-api/src/api.rs:258
```
<details><summary><i><b>Changelog</b></i></summary><p>
## `now-policy`
<blockquote>
##
[[0.4.0](now-policy-v0.3.0...now-policy-v0.4.0)]
- 2026-09-15
### <!-- 1 -->Features
- [**breaking**] Simplify policy document identity
([#106](#106))
([cc841bf](cc841bf))
Policy documents no longer contain `$schema`, and `PolicyVersion` is
renamed to `PolicyFormatVersion` to identify software-managed
document-format compatibility rather than a publisher-authored release
version.
Consumers must remove `$schema` and use `"PolicyFormatVersion":
"1.0.0"`. New documents emit `1.0.0`; readers accept and preserve
supported SemVer 1.x values and reject malformed or unsupported-major
values. Applications must not expose this field as editable policy
metadata. `Revision` and `PublishedAt` remain server-managed.
</blockquote>
## `now-policy-api`
<blockquote>
##
[[0.5.0](now-policy-api-v0.4.0...now-policy-api-v0.5.0)]
- 2026-09-15
### <!-- 1 -->Features
- [**breaking**] Simplify policy document identity
([#106](#106))
([cc841bf](cc841bf))
Policy documents no longer contain `$schema`, and `PolicyVersion` is
renamed to `PolicyFormatVersion` to identify software-managed
document-format compatibility rather than a publisher-authored release
version.
Consumers must remove `$schema` and use `"PolicyFormatVersion":
"1.0.0"`. New documents emit `1.0.0`; readers accept and preserve
supported SemVer 1.x values and reject malformed or unsupported-major
values. Applications must not expose this field as editable policy
metadata. `Revision` and `PublishedAt` remain server-managed.
</blockquote>
## `now-policy-server-template`
<blockquote>
##
[[0.5.0](now-policy-server-template-v0.4.0...now-policy-server-template-v0.5.0)]
- 2026-09-15
### <!-- 1 -->Features
- [**breaking**] Simplify policy document identity
([#106](#106))
([cc841bf](cc841bf))
Policy documents no longer contain `$schema`, and `PolicyVersion` is
renamed to `PolicyFormatVersion` to identify software-managed
document-format compatibility rather than a publisher-authored release
version.
Consumers must remove `$schema` and use `"PolicyFormatVersion":
"1.0.0"`. New documents emit `1.0.0`; readers accept and preserve
supported SemVer 1.x values and reject malformed or unsupported-major
values. Applications must not expose this field as editable policy
metadata. `Revision` and `PublishedAt` remain server-managed.
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
---------
Co-authored-by: Benoît Cortier <3809077+CBenoit@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Benoît CORTIER <git.divisible626@passmail.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Policy documents no longer contain
$schema, andPolicyVersionis renamed toPolicyFormatVersionto identify software-managed document-format compatibility rather than a publisher-authored release version.Consumers must remove
$schemaand use"PolicyFormatVersion": "1.0.0". New documents emit1.0.0; readers accept canonical numericmajor.minor.patchversions in the 1.x line, with components represented as unsigned 64-bit integers. Applications must not expose this field as editable policy metadata.RevisionandPublishedAtremain server-managed.