Skip to content

feat!: add package policy management contract - #99

Open
Benoît Cortier (CBenoit) wants to merge 2 commits into
masterfrom
cbenoit-phase-2-policy-contract
Open

feat!: add package policy management contract#99
Benoît Cortier (CBenoit) wants to merge 2 commits into
masterfrom
cbenoit-phase-2-policy-contract

Conversation

@CBenoit

@CBenoit Benoît Cortier (CBenoit) commented Aug 28, 2026

Copy link
Copy Markdown
Member

Summary

  • make package policy documents JSON-only and add editable PolicyDraftDocument models with explicit committed/draft conversions
  • add versioned management snapshots, raw-JSON validation findings/receipts, optimistic replacement intents, and structured management errors
  • add Rust server trait methods/routes/status mappings/OpenAPI plus NativeAOT-safe .NET client APIs and strict cross-language fixtures
  • reject ineffective boolean match arrays containing more than one value
  • enforce validation-result and management-snapshot invariants during Rust/.NET serialization and deserialization and in OpenAPI

Breaking changes

  • removes Rust parse_policy_yaml and .NET PolicyDocument.ParseYaml (public in Devolutions.Now.Policy.Model 2026.8.13)
  • adds required PackageBrokerServer management methods

OpenAPI YAML generation and unrelated YAML request fixtures remain supported.

Contract notes

  • GET /v1/policy is unchanged
  • adds GET /v1/policy/management, POST /v1/policy/validate, and PUT /v1/policy
  • validation preserves raw JSON/unknown fields until authoritative validation
  • valid validation results require canonical draft plus receipt and forbid Error findings; invalid results require at least one Error and forbid success artifacts
  • management state and write-capability combinations are structurally constrained
  • StalePolicyStoreToken errors carry the atomic current Management snapshot for an exact-token confirmed overwrite retry
  • UnsafePolicyPath maps to HTTP 409; authentication/admin/elevation failures retain 401/403
  • absent newer routes remain ordinary HTTP 404s; UnsupportedEndpoint is optional explicit implementation behavior
  • confirmed overwrite remains bound to an exact newly observed store token; no unconditional force mode exists
  • capabilities are advisory and implementations must reparse/revalidate/recheck storage semantics in the write transaction

Coordination

This is the first dependency in the coordinated Phase 2 rollout. It follows merged Phase 1 inspection contract #93. Gateway and UniGetUI PR links will be added by their coordinated follow-up work.

Validation

  • cargo test --workspace --all-targets --locked
  • cargo clippy --workspace --all-targets --locked -- -D warnings
  • .NET 9/10 model and client suites
  • dotnet format ... --verify-no-changes
  • deterministic policy schema and OpenAPI regeneration
  • unpublished NuGet package metadata verified against exact commit provenance

Exact-head unpublished NuGet packages were rebuilt from commit c282ff278c3f5581516c978aa7c4f174ce6e893d; they were not published.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 28, 2026 17:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds cross-language package-policy management contracts, including draft validation, optimistic replacement, management snapshots, and JSON-only policy models.

Changes:

  • Adds Rust and .NET management APIs, routes, DTOs, validation, and clients.
  • Introduces editable policy drafts and removes YAML policy parsing.
  • Adds fixtures and stricter boolean-match validation.

Reviewed changes

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

Show a summary per file
File Description
policies/test-data/package-broker/scenarios/baseline.scenarios.json Removes YAML-policy scenarios.
policies/test-data/package-broker/responses/policy-validation.valid.response.json Adds valid-validation fixture.
policies/test-data/package-broker/responses/policy-validation.invalid.response.json Adds invalid-validation fixture.
policies/test-data/package-broker/responses/policy-stale-token.error.json Adds stale-token error fixture.
policies/test-data/package-broker/responses/policy-replacement.response.json Adds replacement response fixture.
policies/test-data/package-broker/responses/policy-management.missing.response.json Adds missing-policy snapshot.
policies/test-data/package-broker/responses/policy-management.invalid.response.json Adds invalid-policy snapshot.
policies/test-data/package-broker/responses/policy-management.active.response.json Adds active-policy snapshot.
policies/test-data/package-broker/requests/policy-validation.request.json Adds raw validation request.
policies/test-data/package-broker/requests/policy-replacement.update.request.json Adds update intent fixture.
policies/test-data/package-broker/requests/policy-replacement.replace-identity.request.json Adds identity-replacement fixture.
policies/test-data/package-broker/requests/policy-replacement.repair.request.json Adds repair intent fixture.
policies/test-data/package-broker/requests/policy-replacement.overwrite.request.json Adds confirmed-overwrite fixture.
policies/test-data/package-broker/requests/policy-replacement.create.request.json Adds create intent fixture.
policies/rust/now-policy/tests/policy_samples.rs Tests drafts and boolean matches.
policies/rust/now-policy/src/schema.rs Adds draft-schema generation.
policies/rust/now-policy/src/policy.rs Adds draft models and validation.
policies/rust/now-policy/schema/devolutions.now-policy.schema.json Regenerates policy schema.
policies/rust/now-policy/README.md Documents JSON-only drafts.
policies/rust/now-policy/CHANGELOG.md Records model changes.
policies/rust/now-policy/Cargo.toml Removes YAML dependency.
policies/rust/now-policy/assets/samples/corporate-allowlist.policy.yaml Removes YAML sample.
policies/rust/now-policy-server-template/tests/support/mock.rs Extends server mock.
policies/rust/now-policy-server-template/tests/sample_documents.rs Tests routes and fixtures.
policies/rust/now-policy-server-template/src/server.rs Adds management routes and mappings.
policies/rust/now-policy-server-template/README.md Documents server endpoints.
policies/rust/now-policy-server-template/CHANGELOG.md Records server contract changes.
policies/rust/now-policy-api/src/policy.rs Adds draft schema reference.
policies/rust/now-policy-api/src/management.rs Defines management contracts.
policies/rust/now-policy-api/src/lib.rs Exports management models and markers.
policies/rust/now-policy-api/src/enums.rs Adds management error codes.
policies/rust/now-policy-api/src/api.rs Adds validation to errors.
policies/rust/now-policy-api/README.md Documents management architecture.
policies/rust/now-policy-api/openapi/now-policy-api.yaml Adds generated management OpenAPI.
policies/rust/now-policy-api/CHANGELOG.md Records API additions.
policies/dotnet/Devolutions.Now.Policy.Model/README.md Documents .NET draft model.
policies/dotnet/Devolutions.Now.Policy.Model/PolicyModels.cs Adds draft conversion models.
policies/dotnet/Devolutions.Now.Policy.Model/PolicyJson.cs Adds draft and boolean validation.
policies/dotnet/Devolutions.Now.Policy.Model/Devolutions.Now.Policy.Model.csproj Removes YamlDotNet.
policies/dotnet/Devolutions.Now.Policy.Model.Tests/PolicyTests.cs Tests draft conversions.
policies/dotnet/Devolutions.Now.Policy.Client/README.md Documents client methods.
policies/dotnet/Devolutions.Now.Policy.Client/BrokerClient.cs Implements management client APIs.
policies/dotnet/Devolutions.Now.Policy.Client.Tests/TestData.cs Classifies new fixtures.
policies/dotnet/Devolutions.Now.Policy.Client.Tests/PolicyManagementClientTests.cs Tests management client behavior.
policies/dotnet/Devolutions.Now.Policy.Client.Tests/MetaModelTests.cs Verifies source-generated DTOs.
policies/dotnet/Devolutions.Now.Policy.Client.Tests/DtoRoundTripTests.cs Adds contract round-trip tests.
policies/dotnet/Devolutions.Now.Policy.Api/README.md Documents management DTOs.
policies/dotnet/Devolutions.Now.Policy.Api/PolicyManagementModels.cs Defines .NET management DTOs.
policies/dotnet/Devolutions.Now.Policy.Api/MetaModels.cs Extends structured errors.
policies/dotnet/Devolutions.Now.Policy.Api/Enums.cs Adds strict management errors.
policies/dotnet/Devolutions.Now.Policy.Api/BrokerJson.cs Adds management serialization contexts.
policies/dotnet/Devolutions.Now.Policy.Api/BrokerApi.cs Adds protocol discriminators.
Cargo.lock Removes Rust YAML dependency.
Suppressed comments (1)

policies/dotnet/Devolutions.Now.Policy.Api/BrokerJson.cs:119

  • This validation does not reject null entries in PolicyValidationResult.Findings. RespectNullableAnnotations does not enforce collection-element nullability, so a successful response or error containing "Findings":[null] is accepted by the .NET client while Rust rejects it, and callers can then fail when reading a finding. Explicitly reject null finding elements here.
    private static void ValidateValidation(PolicyValidationResult validation)
    {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +39 to +46
switch (value)
{
ValidateRequiredCollectionElements(policy);
case PolicyDocument policy:
ValidateRequiredCollectionElements(policy);
break;
case PolicyDraftDocument draft:
ValidateRequiredCollectionElements(draft);
break;
Comment on lines +110 to +116
private static void ValidateManagement(PolicyManagementSnapshot management)
{
if (management.Policy is { } policy)
{
PolicyJson.ValidateRequiredCollectionElements(policy);
}
}
Comment on lines +116 to +119
if (values.Count > 1)
{
throw new JsonException($"The JSON array at {path} must contain exactly one value when present.");
}
Comment on lines +426 to +430
if values.len() > 1 {
return Err(serde::de::Error::custom(
"boolean match arrays must contain exactly one value when present",
));
}
Require atomic stale-token snapshots, enforce validation and management invariants, preserve legacy route 404s, and map unsafe paths to HTTP 409.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants