From 6ad2bda6375dc334cb9fc3d2a7162fdf9fd3f882 Mon Sep 17 00:00:00 2001 From: devolutionsbot <31221910+devolutionsbot@users.noreply.github.com> Date: Thu, 3 Sep 2026 13:58:39 -0400 Subject: [PATCH 1/2] chore(release): prepare for publishing --- Cargo.lock | 111 +++++++++--------- policies/rust/now-policy-api/CHANGELOG.md | 94 +++++++++++++++ policies/rust/now-policy-api/Cargo.toml | 4 +- .../now-policy-server-template/CHANGELOG.md | 110 +++++++++++++++++ .../now-policy-server-template/Cargo.toml | 6 +- policies/rust/now-policy/CHANGELOG.md | 37 ++++++ policies/rust/now-policy/Cargo.toml | 2 +- 7 files changed, 303 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0a37b0..70b014a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -129,9 +129,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.4.2" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" dependencies = [ "find-msvc-tools", "shlex", @@ -203,7 +203,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "form_urlencoded" @@ -305,7 +305,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -434,9 +434,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -447,9 +447,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -461,16 +461,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -481,15 +482,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", @@ -523,9 +524,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" dependencies = [ "equivalent", "hashbrown", @@ -573,15 +574,15 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "matchit" @@ -612,7 +613,7 @@ dependencies = [ [[package]] name = "now-policy" -version = "0.2.0" +version = "0.3.0" dependencies = [ "chrono", "schemars", @@ -625,7 +626,7 @@ dependencies = [ [[package]] name = "now-policy-api" -version = "0.3.1" +version = "0.4.0" dependencies = [ "chrono", "derive_more", @@ -640,7 +641,7 @@ dependencies = [ [[package]] name = "now-policy-server-template" -version = "0.3.0" +version = "0.4.0" dependencies = [ "aide", "async-trait", @@ -713,9 +714,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -749,22 +750,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -912,7 +913,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -990,9 +991,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.2" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" [[package]] name = "stable_deref_trait" @@ -1034,9 +1035,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" dependencies = [ "proc-macro2", "quote", @@ -1077,14 +1078,14 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -1109,7 +1110,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -1362,9 +1363,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "xshell" @@ -1436,9 +1437,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -1447,9 +1448,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -1458,13 +1459,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] diff --git a/policies/rust/now-policy-api/CHANGELOG.md b/policies/rust/now-policy-api/CHANGELOG.md index 8672e17..e9cd03a 100644 --- a/policies/rust/now-policy-api/CHANGELOG.md +++ b/policies/rust/now-policy-api/CHANGELOG.md @@ -7,6 +7,100 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [[0.4.0](https://github.com/Devolutions/now-libraries/compare/now-policy-api-v0.3.1...now-policy-api-v0.4.0)] - 2026-09-03 + +### Features + +- Add active package policy inspection contract ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) + + - add canonical `GET /v1/policy` support across the Rust server + contract, generated OpenAPI, C# DTOs, and + `BrokerClient.GetPolicy(CancellationToken)` + - return the existing canonical `PolicyDocument` inside a versioned + `PolicyResponse`, with structured `404 NotFound` behavior when no active + policy is configured + - make policy inspection unconditional: remove `policy-compat` and its + cross-model conversion impls, and keep runtime mapping ownership in + broker implementations + - name the required Rust server accessor `active_policy`, leaving clear + room for a future explicit `replace_policy` operation backed by a + separate policy-store abstraction + - harden C# successful-response validation for required/null fields, + collection elements, unknown members, and canonical enum casing + - preserve existing OpenAPI component names by namespacing colliding + embedded policy components as `PolicyModel…` + - run workspace Rust tests and Clippy with all features through the + standard xtask commands + + ## API changes + + ### Rust + + - `now-policy-api` adds public `PolicyResponse` and + `PolicyResponseKind`; `now-policy` is now a normal dependency because + `PolicyDocument` is part of the permanent wire contract + - `PackageBrokerServer` adds the required method: + + ```rust + async fn active_policy(&self) -> Result; + ``` + + - `now-policy-server-template` registers the route unconditionally and + extends its mock with policy response/error builders + - `policy-compat` and its `From`/`TryFrom` conversions are removed + + ### C# + + - `Devolutions.Now.Policy.Api` adds `PolicyResponse`, embedding + `Devolutions.Now.Policy.Model.PolicyDocument` + - `Devolutions.Now.Policy.Client` adds `GetPolicy(CancellationToken)` + with strict validation of successful response bodies + - policy-model deserialization now enforces required members, non-null + collection elements, and canonical enum casing + + ### HTTP + + - adds read-only `GET /v1/policy` + - `200`: `PolicyResponse` + - `404`: structured `ErrorResponse` when no active policy is configured + - other failures use the existing `ErrorResponse` contract + - no policy mutation endpoint is introduced + + --------- + +- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) + + Add a versioned package-policy management contract alongside the + unchanged active-policy inspection API. New management, validation, and + replacement endpoints expose atomic Active/Missing/Invalid snapshots, + raw-draft authoritative validation with structured findings and + warning-bound receipts, and exact-token optimistic replacement with + explicit Update, ReplaceIdentity, Create, and Repair intents. Rust + server implementations gain the corresponding required trait methods and + routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware + client APIs. + + Make policy documents JSON-only, removing Rust `parse_policy_yaml` and + .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for + authored policy content without server-managed revision and publication + metadata, with its own versioned JSON Schema identity and explicit named + conversions to and from committed policies. Rename the public .NET + serialization helpers to `PolicySerializer` and `BrokerSerializer`, and + replace Rust’s lossy `From<&PolicyDocument>` draft projection with + `PolicyDocument::to_draft()`. + + Tighten cross-language contract validation for boolean matches, revision + bounds, Unicode text lengths, opaque ASCII tokens and receipts, + validation results, management snapshots, stale-token errors, and + nullable schema fields. Unsafe paths and stale state use conflict + semantics, unsupported policy formats and filesystems use + unprocessable-entity semantics, and absent newer routes remain ordinary + 404 responses. Validation and replacement accept complete HTTP request + bodies up to 16 MiB through public Rust and .NET constants, while + package-operation limits remain unchanged. + + + ### Added - Add versioned policy management, raw-draft validation, structured findings/receipts, optimistic replacement, and management error contracts, including the atomic current snapshot required on stale-token errors, explicit unsupported non-JSON path semantics, and generated 16 MiB full-request-body metadata for management write endpoints. diff --git a/policies/rust/now-policy-api/Cargo.toml b/policies/rust/now-policy-api/Cargo.toml index b01c9ff..19d8622 100644 --- a/policies/rust/now-policy-api/Cargo.toml +++ b/policies/rust/now-policy-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "now-policy-api" -version = "0.3.1" +version = "0.4.0" edition = "2024" license.workspace = true homepage.workspace = true @@ -16,7 +16,7 @@ workspace = true [dependencies] chrono = { version = "0.4", features = ["serde"] } derive_more = { version = "2", features = ["as_ref", "deref", "display", "from"] } -now-policy = { version = "0.2", path = "../now-policy" } +now-policy = { version = "0.3", path = "../now-policy" } schemars = { version = "0.9", features = ["chrono04"] } semver = "1" serde = { version = "1", features = ["derive"] } diff --git a/policies/rust/now-policy-server-template/CHANGELOG.md b/policies/rust/now-policy-server-template/CHANGELOG.md index fe42158..a249035 100644 --- a/policies/rust/now-policy-server-template/CHANGELOG.md +++ b/policies/rust/now-policy-server-template/CHANGELOG.md @@ -7,6 +7,116 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [[0.4.0](https://github.com/Devolutions/now-libraries/compare/now-policy-server-template-v0.3.0...now-policy-server-template-v0.4.0)] - 2026-09-03 + +### Features + +- Add active package policy inspection contract ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) + + - add canonical `GET /v1/policy` support across the Rust server + contract, generated OpenAPI, C# DTOs, and + `BrokerClient.GetPolicy(CancellationToken)` + - return the existing canonical `PolicyDocument` inside a versioned + `PolicyResponse`, with structured `404 NotFound` behavior when no active + policy is configured + - make policy inspection unconditional: remove `policy-compat` and its + cross-model conversion impls, and keep runtime mapping ownership in + broker implementations + - name the required Rust server accessor `active_policy`, leaving clear + room for a future explicit `replace_policy` operation backed by a + separate policy-store abstraction + - harden C# successful-response validation for required/null fields, + collection elements, unknown members, and canonical enum casing + - preserve existing OpenAPI component names by namespacing colliding + embedded policy components as `PolicyModel…` + - run workspace Rust tests and Clippy with all features through the + standard xtask commands + + ## API changes + + ### Rust + + - `now-policy-api` adds public `PolicyResponse` and + `PolicyResponseKind`; `now-policy` is now a normal dependency because + `PolicyDocument` is part of the permanent wire contract + - `PackageBrokerServer` adds the required method: + + ```rust + async fn active_policy(&self) -> Result; + ``` + + - `now-policy-server-template` registers the route unconditionally and + extends its mock with policy response/error builders + - `policy-compat` and its `From`/`TryFrom` conversions are removed + + ### C# + + - `Devolutions.Now.Policy.Api` adds `PolicyResponse`, embedding + `Devolutions.Now.Policy.Model.PolicyDocument` + - `Devolutions.Now.Policy.Client` adds `GetPolicy(CancellationToken)` + with strict validation of successful response bodies + - policy-model deserialization now enforces required members, non-null + collection elements, and canonical enum casing + + ### HTTP + + - adds read-only `GET /v1/policy` + - `200`: `PolicyResponse` + - `404`: structured `ErrorResponse` when no active policy is configured + - other failures use the existing `ErrorResponse` contract + - no policy mutation endpoint is introduced + + --------- + +- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) + + Add a versioned package-policy management contract alongside the + unchanged active-policy inspection API. New management, validation, and + replacement endpoints expose atomic Active/Missing/Invalid snapshots, + raw-draft authoritative validation with structured findings and + warning-bound receipts, and exact-token optimistic replacement with + explicit Update, ReplaceIdentity, Create, and Repair intents. Rust + server implementations gain the corresponding required trait methods and + routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware + client APIs. + + Make policy documents JSON-only, removing Rust `parse_policy_yaml` and + .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for + authored policy content without server-managed revision and publication + metadata, with its own versioned JSON Schema identity and explicit named + conversions to and from committed policies. Rename the public .NET + serialization helpers to `PolicySerializer` and `BrokerSerializer`, and + replace Rust’s lossy `From<&PolicyDocument>` draft projection with + `PolicyDocument::to_draft()`. + + Tighten cross-language contract validation for boolean matches, revision + bounds, Unicode text lengths, opaque ASCII tokens and receipts, + validation results, management snapshots, stale-token errors, and + nullable schema fields. Unsafe paths and stale state use conflict + semantics, unsupported policy formats and filesystems use + unprocessable-entity semantics, and absent newer routes remain ordinary + 404 responses. Validation and replacement accept complete HTTP request + bodies up to 16 MiB through public Rust and .NET constants, while + package-operation limits remain unchanged. + +### Bug Fixes + +- [**breaking**] Keep policy mock server out of the public API ([#97](https://github.com/Devolutions/now-libraries/issues/97)) ([2f8f425def](https://github.com/Devolutions/now-libraries/commit/2f8f425def03720189a96a657571551918e1034d)) + + The package broker mock is an internal test double, so exposing it from + the published server-template crate creates an unnecessary API + commitment. Shared protocol fixtures also belong at repository scope + rather than under one language's crate. + + - move `MockPackageBrokerServer` into private integration-test support + - keep all mock-backed router tests enabled in the default test run + - remove the mock from the crate API, metadata, and public documentation + - relocate shared package-broker fixtures to + `policies/test-data/package-broker` and update Rust, .NET, and protocol + documentation references + + + ### Added - [**breaking**] Add required policy management, validation, and optimistic replacement trait methods, routes, status mappings, and OpenAPI operations. Unsafe policy paths map to HTTP 409, unsupported non-JSON policy paths map to HTTP 422, and absent routes retain ordinary HTTP 404 behavior. Validation and replacement use a separate public 16 MiB full-request-body limit while package operations retain their 256 KiB limit. diff --git a/policies/rust/now-policy-server-template/Cargo.toml b/policies/rust/now-policy-server-template/Cargo.toml index 444b411..eea4c86 100644 --- a/policies/rust/now-policy-server-template/Cargo.toml +++ b/policies/rust/now-policy-server-template/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "now-policy-server-template" -version = "0.3.0" +version = "0.4.0" edition = "2024" license.workspace = true homepage.workspace = true @@ -17,8 +17,8 @@ workspace = true aide = { version = "0.15", features = ["axum", "axum-json"] } async-trait = "0.1" axum = { version = "0.8", default-features = false, features = ["json"] } -now-policy-api = { version = "0.3", path = "../now-policy-api" } -now-policy = { version = "0.2", path = "../now-policy" } +now-policy-api = { version = "0.4", path = "../now-policy-api" } +now-policy = { version = "0.3", path = "../now-policy" } schemars = "0.9" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/policies/rust/now-policy/CHANGELOG.md b/policies/rust/now-policy/CHANGELOG.md index 4a038a2..10cad22 100644 --- a/policies/rust/now-policy/CHANGELOG.md +++ b/policies/rust/now-policy/CHANGELOG.md @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [[0.3.0](https://github.com/Devolutions/now-libraries/compare/now-policy-v0.2.0...now-policy-v0.3.0)] - 2026-09-03 + +### Features + +- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) + + Add a versioned package-policy management contract alongside the + unchanged active-policy inspection API. New management, validation, and + replacement endpoints expose atomic Active/Missing/Invalid snapshots, + raw-draft authoritative validation with structured findings and + warning-bound receipts, and exact-token optimistic replacement with + explicit Update, ReplaceIdentity, Create, and Repair intents. Rust + server implementations gain the corresponding required trait methods and + routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware + client APIs. + + Make policy documents JSON-only, removing Rust `parse_policy_yaml` and + .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for + authored policy content without server-managed revision and publication + metadata, with its own versioned JSON Schema identity and explicit named + conversions to and from committed policies. Rename the public .NET + serialization helpers to `PolicySerializer` and `BrokerSerializer`, and + replace Rust’s lossy `From<&PolicyDocument>` draft projection with + `PolicyDocument::to_draft()`. + + Tighten cross-language contract validation for boolean matches, revision + bounds, Unicode text lengths, opaque ASCII tokens and receipts, + validation results, management snapshots, stale-token errors, and + nullable schema fields. Unsafe paths and stale state use conflict + semantics, unsupported policy formats and filesystems use + unprocessable-entity semantics, and absent newer routes remain ordinary + 404 responses. Validation and replacement accept complete HTTP request + bodies up to 16 MiB through public Rust and .NET constants, while + package-operation limits remain unchanged. + + + ### Fixed - Count Unicode scalar values for `StringPattern`, `VersionString`, and `CustomParameterString` length bounds, matching JSON Schema and .NET policy validation semantics. diff --git a/policies/rust/now-policy/Cargo.toml b/policies/rust/now-policy/Cargo.toml index 7bd3b55..54205fa 100644 --- a/policies/rust/now-policy/Cargo.toml +++ b/policies/rust/now-policy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "now-policy" -version = "0.2.0" +version = "0.3.0" edition = "2024" license.workspace = true homepage.workspace = true From 8ee133752b8313595a28596ea62fd0b47f276a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Thu, 3 Sep 2026 16:30:31 -0400 Subject: [PATCH 2/2] docs: clean up release changelogs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- policies/rust/now-policy-api/CHANGELOG.md | 101 ++------------- .../now-policy-server-template/CHANGELOG.md | 116 ++---------------- policies/rust/now-policy/CHANGELOG.md | 49 ++------ 3 files changed, 25 insertions(+), 241 deletions(-) diff --git a/policies/rust/now-policy-api/CHANGELOG.md b/policies/rust/now-policy-api/CHANGELOG.md index e9cd03a..470a84c 100644 --- a/policies/rust/now-policy-api/CHANGELOG.md +++ b/policies/rust/now-policy-api/CHANGELOG.md @@ -11,100 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- Add active package policy inspection contract ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) - - - add canonical `GET /v1/policy` support across the Rust server - contract, generated OpenAPI, C# DTOs, and - `BrokerClient.GetPolicy(CancellationToken)` - - return the existing canonical `PolicyDocument` inside a versioned - `PolicyResponse`, with structured `404 NotFound` behavior when no active - policy is configured - - make policy inspection unconditional: remove `policy-compat` and its - cross-model conversion impls, and keep runtime mapping ownership in - broker implementations - - name the required Rust server accessor `active_policy`, leaving clear - room for a future explicit `replace_policy` operation backed by a - separate policy-store abstraction - - harden C# successful-response validation for required/null fields, - collection elements, unknown members, and canonical enum casing - - preserve existing OpenAPI component names by namespacing colliding - embedded policy components as `PolicyModel…` - - run workspace Rust tests and Clippy with all features through the - standard xtask commands - - ## API changes - - ### Rust - - - `now-policy-api` adds public `PolicyResponse` and - `PolicyResponseKind`; `now-policy` is now a normal dependency because - `PolicyDocument` is part of the permanent wire contract - - `PackageBrokerServer` adds the required method: - - ```rust - async fn active_policy(&self) -> Result; - ``` - - - `now-policy-server-template` registers the route unconditionally and - extends its mock with policy response/error builders - - `policy-compat` and its `From`/`TryFrom` conversions are removed - - ### C# - - - `Devolutions.Now.Policy.Api` adds `PolicyResponse`, embedding - `Devolutions.Now.Policy.Model.PolicyDocument` - - `Devolutions.Now.Policy.Client` adds `GetPolicy(CancellationToken)` - with strict validation of successful response bodies - - policy-model deserialization now enforces required members, non-null - collection elements, and canonical enum casing - - ### HTTP - - - adds read-only `GET /v1/policy` - - `200`: `PolicyResponse` - - `404`: structured `ErrorResponse` when no active policy is configured - - other failures use the existing `ErrorResponse` contract - - no policy mutation endpoint is introduced - - --------- - -- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) - - Add a versioned package-policy management contract alongside the - unchanged active-policy inspection API. New management, validation, and - replacement endpoints expose atomic Active/Missing/Invalid snapshots, - raw-draft authoritative validation with structured findings and - warning-bound receipts, and exact-token optimistic replacement with - explicit Update, ReplaceIdentity, Create, and Repair intents. Rust - server implementations gain the corresponding required trait methods and - routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware - client APIs. - - Make policy documents JSON-only, removing Rust `parse_policy_yaml` and - .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for - authored policy content without server-managed revision and publication - metadata, with its own versioned JSON Schema identity and explicit named - conversions to and from committed policies. Rename the public .NET - serialization helpers to `PolicySerializer` and `BrokerSerializer`, and - replace Rust’s lossy `From<&PolicyDocument>` draft projection with - `PolicyDocument::to_draft()`. - - Tighten cross-language contract validation for boolean matches, revision - bounds, Unicode text lengths, opaque ASCII tokens and receipts, - validation results, management snapshots, stale-token errors, and - nullable schema fields. Unsafe paths and stale state use conflict - semantics, unsupported policy formats and filesystems use - unprocessable-entity semantics, and absent newer routes remain ordinary - 404 responses. Validation and replacement accept complete HTTP request - bodies up to 16 MiB through public Rust and .NET constants, while - package-operation limits remain unchanged. - - - -### Added - -- Add versioned policy management, raw-draft validation, structured findings/receipts, optimistic replacement, and management error contracts, including the atomic current snapshot required on stale-token errors, explicit unsupported non-JSON path semantics, and generated 16 MiB full-request-body metadata for management write endpoints. - +- Add `PolicyResponse` for active policy inspection ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- [**breaking**] Make `now-policy` a required dependency because `PolicyDocument` is part of `PolicyResponse` ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- [**breaking**] Remove the `policy-compat` feature and its cross-model conversions ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- Add policy management snapshots for active, missing, and invalid policies ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add raw-draft validation contracts with structured findings and receipts ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add optimistic policy replacement contracts with explicit update, identity replacement, creation, and repair operations ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add policy management error contracts, including the current snapshot on stale-token errors ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) ## [[0.3.1](https://github.com/Devolutions/now-libraries/compare/now-policy-api-v0.3.0...now-policy-api-v0.3.1)] - 2026-08-13 diff --git a/policies/rust/now-policy-server-template/CHANGELOG.md b/policies/rust/now-policy-server-template/CHANGELOG.md index a249035..c9c0bec 100644 --- a/policies/rust/now-policy-server-template/CHANGELOG.md +++ b/policies/rust/now-policy-server-template/CHANGELOG.md @@ -11,116 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- Add active package policy inspection contract ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) - - - add canonical `GET /v1/policy` support across the Rust server - contract, generated OpenAPI, C# DTOs, and - `BrokerClient.GetPolicy(CancellationToken)` - - return the existing canonical `PolicyDocument` inside a versioned - `PolicyResponse`, with structured `404 NotFound` behavior when no active - policy is configured - - make policy inspection unconditional: remove `policy-compat` and its - cross-model conversion impls, and keep runtime mapping ownership in - broker implementations - - name the required Rust server accessor `active_policy`, leaving clear - room for a future explicit `replace_policy` operation backed by a - separate policy-store abstraction - - harden C# successful-response validation for required/null fields, - collection elements, unknown members, and canonical enum casing - - preserve existing OpenAPI component names by namespacing colliding - embedded policy components as `PolicyModel…` - - run workspace Rust tests and Clippy with all features through the - standard xtask commands - - ## API changes - - ### Rust - - - `now-policy-api` adds public `PolicyResponse` and - `PolicyResponseKind`; `now-policy` is now a normal dependency because - `PolicyDocument` is part of the permanent wire contract - - `PackageBrokerServer` adds the required method: - - ```rust - async fn active_policy(&self) -> Result; - ``` - - - `now-policy-server-template` registers the route unconditionally and - extends its mock with policy response/error builders - - `policy-compat` and its `From`/`TryFrom` conversions are removed - - ### C# - - - `Devolutions.Now.Policy.Api` adds `PolicyResponse`, embedding - `Devolutions.Now.Policy.Model.PolicyDocument` - - `Devolutions.Now.Policy.Client` adds `GetPolicy(CancellationToken)` - with strict validation of successful response bodies - - policy-model deserialization now enforces required members, non-null - collection elements, and canonical enum casing - - ### HTTP - - - adds read-only `GET /v1/policy` - - `200`: `PolicyResponse` - - `404`: structured `ErrorResponse` when no active policy is configured - - other failures use the existing `ErrorResponse` contract - - no policy mutation endpoint is introduced - - --------- - -- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) - - Add a versioned package-policy management contract alongside the - unchanged active-policy inspection API. New management, validation, and - replacement endpoints expose atomic Active/Missing/Invalid snapshots, - raw-draft authoritative validation with structured findings and - warning-bound receipts, and exact-token optimistic replacement with - explicit Update, ReplaceIdentity, Create, and Repair intents. Rust - server implementations gain the corresponding required trait methods and - routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware - client APIs. - - Make policy documents JSON-only, removing Rust `parse_policy_yaml` and - .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for - authored policy content without server-managed revision and publication - metadata, with its own versioned JSON Schema identity and explicit named - conversions to and from committed policies. Rename the public .NET - serialization helpers to `PolicySerializer` and `BrokerSerializer`, and - replace Rust’s lossy `From<&PolicyDocument>` draft projection with - `PolicyDocument::to_draft()`. - - Tighten cross-language contract validation for boolean matches, revision - bounds, Unicode text lengths, opaque ASCII tokens and receipts, - validation results, management snapshots, stale-token errors, and - nullable schema fields. Unsafe paths and stale state use conflict - semantics, unsupported policy formats and filesystems use - unprocessable-entity semantics, and absent newer routes remain ordinary - 404 responses. Validation and replacement accept complete HTTP request - bodies up to 16 MiB through public Rust and .NET constants, while - package-operation limits remain unchanged. +- [**breaking**] Add the required `PackageBrokerServer::active_policy` method ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- Expose active policy inspection through `GET /v1/policy` ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- Return `404 Not Found` when no active policy is configured ([#93](https://github.com/Devolutions/now-libraries/issues/93)) ([cd5a6e9f8e](https://github.com/Devolutions/now-libraries/commit/cd5a6e9f8eeb3c70cc9ef9003ffeb46716ceced6)) +- [**breaking**] Add the required `PackageBrokerServer::policy_management` method and expose it through `GET /v1/policy/management` ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- [**breaking**] Add the required `PackageBrokerServer::validate_policy` method and expose it through `POST /v1/policy/validate` ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- [**breaking**] Add the required `PackageBrokerServer::replace_policy` method and expose it through `PUT /v1/policy` ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Map policy management failures to structured HTTP status responses ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add the public 16 MiB `MAX_POLICY_MANAGEMENT_BODY_BYTES` limit for policy validation and replacement requests ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) ### Bug Fixes -- [**breaking**] Keep policy mock server out of the public API ([#97](https://github.com/Devolutions/now-libraries/issues/97)) ([2f8f425def](https://github.com/Devolutions/now-libraries/commit/2f8f425def03720189a96a657571551918e1034d)) - - The package broker mock is an internal test double, so exposing it from - the published server-template crate creates an unnecessary API - commitment. Shared protocol fixtures also belong at repository scope - rather than under one language's crate. - - - move `MockPackageBrokerServer` into private integration-test support - - keep all mock-backed router tests enabled in the default test run - - remove the mock from the crate API, metadata, and public documentation - - relocate shared package-broker fixtures to - `policies/test-data/package-broker` and update Rust, .NET, and protocol - documentation references - - - -### Added - -- [**breaking**] Add required policy management, validation, and optimistic replacement trait methods, routes, status mappings, and OpenAPI operations. Unsafe policy paths map to HTTP 409, unsupported non-JSON policy paths map to HTTP 422, and absent routes retain ordinary HTTP 404 behavior. Validation and replacement use a separate public 16 MiB full-request-body limit while package operations retain their 256 KiB limit. - +- [**breaking**] Remove the public `MockPackageBrokerServer` test double from the crate API ([#97](https://github.com/Devolutions/now-libraries/issues/97)) ([2f8f425def](https://github.com/Devolutions/now-libraries/commit/2f8f425def03720189a96a657571551918e1034d)) ## [[0.3.0](https://github.com/Devolutions/now-libraries/compare/now-policy-server-template-v0.2.0...now-policy-server-template-v0.3.0)] - 2026-08-05 diff --git a/policies/rust/now-policy/CHANGELOG.md b/policies/rust/now-policy/CHANGELOG.md index 10cad22..cb4c4e5 100644 --- a/policies/rust/now-policy/CHANGELOG.md +++ b/policies/rust/now-policy/CHANGELOG.md @@ -11,49 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [**breaking**] Add package policy management contract ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) - - Add a versioned package-policy management contract alongside the - unchanged active-policy inspection API. New management, validation, and - replacement endpoints expose atomic Active/Missing/Invalid snapshots, - raw-draft authoritative validation with structured findings and - warning-bound receipts, and exact-token optimistic replacement with - explicit Update, ReplaceIdentity, Create, and Repair intents. Rust - server implementations gain the corresponding required trait methods and - routes, while .NET gains NativeAOT-safe DTOs and cancellation-aware - client APIs. - - Make policy documents JSON-only, removing Rust `parse_policy_yaml` and - .NET `PolicyDocument.ParseYaml`. Introduce `PolicyDraftDocument` for - authored policy content without server-managed revision and publication - metadata, with its own versioned JSON Schema identity and explicit named - conversions to and from committed policies. Rename the public .NET - serialization helpers to `PolicySerializer` and `BrokerSerializer`, and - replace Rust’s lossy `From<&PolicyDocument>` draft projection with - `PolicyDocument::to_draft()`. - - Tighten cross-language contract validation for boolean matches, revision - bounds, Unicode text lengths, opaque ASCII tokens and receipts, - validation results, management snapshots, stale-token errors, and - nullable schema fields. Unsafe paths and stale state use conflict - semantics, unsupported policy formats and filesystems use - unprocessable-entity semantics, and absent newer routes remain ordinary - 404 responses. Validation and replacement accept complete HTTP request - bodies up to 16 MiB through public Rust and .NET constants, while - package-operation limits remain unchanged. - - +- [**breaking**] Make policy documents JSON-only by removing `parse_policy_yaml` ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add `PolicyDraftDocument` for authored policy content without server-managed metadata ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add the versioned `now-policy-draft` JSON Schema ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add `PolicyDocument::to_draft()` for creating editable policy drafts ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Add `PolicyDraftDocument::into_policy_document()` for committing drafts with server-managed metadata ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- [**breaking**] Reject boolean match arrays containing multiple values ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) ### Fixed -- Count Unicode scalar values for `StringPattern`, `VersionString`, and `CustomParameterString` length bounds, matching JSON Schema and .NET policy validation semantics. - -### Changed - -- [**breaking**] Make policy documents JSON-only and remove `parse_policy_yaml`. -- Add editable `PolicyDraftDocument` and explicit named committed/draft conversion methods. -- Reject boolean match arrays containing more than one value. - +- Count Unicode scalar values for `StringPattern` length bounds ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Count Unicode scalar values for `VersionString` length bounds ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) +- Count Unicode scalar values for `CustomParameterString` length bounds ([#99](https://github.com/Devolutions/now-libraries/issues/99)) ([cd7f3ba741](https://github.com/Devolutions/now-libraries/commit/cd7f3ba7416358f9cc137dcd1774511e9aab0e9b)) ## [[0.2.0](https://github.com/Devolutions/now-libraries/compare/now-policy-v0.1.0...now-policy-v0.2.0)] - 2026-07-27