Add unit tests for PackRunAttestation and SealedInstallEnforcer
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
release-manifest-verify / verify (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
release-manifest-verify / verify (push) Has been cancelled
- Implement comprehensive tests for PackRunAttestationService, covering attestation generation, verification, and event emission. - Add tests for SealedInstallEnforcer to validate sealed install requirements and enforcement logic. - Introduce a MonacoLoaderService stub for testing purposes to prevent Monaco workers/styles from loading during Karma runs.
This commit is contained in:
634
src/Policy/StellaOps.Policy.Registry/PolicyRegistryClient.cs
Normal file
634
src/Policy/StellaOps.Policy.Registry/PolicyRegistryClient.cs
Normal file
@@ -0,0 +1,634 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy.Registry.Contracts;
|
||||
|
||||
namespace StellaOps.Policy.Registry;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP client implementation for Policy Registry API.
|
||||
/// </summary>
|
||||
public sealed class PolicyRegistryClient : IPolicyRegistryClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly JsonSerializerOptions _jsonOptions;
|
||||
|
||||
public PolicyRegistryClient(HttpClient httpClient, IOptions<PolicyRegistryClientOptions>? options = null)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
_jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
if (options?.Value?.BaseUrl is not null && _httpClient.BaseAddress is null)
|
||||
{
|
||||
_httpClient.BaseAddress = new Uri(options.Value.BaseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTenantHeader(HttpRequestMessage request, Guid tenantId)
|
||||
{
|
||||
request.Headers.Add("X-Tenant-Id", tenantId.ToString());
|
||||
}
|
||||
|
||||
private static string BuildQueryString(PaginationParams? pagination, params (string name, string? value)[] additional)
|
||||
{
|
||||
var parts = new List<string>();
|
||||
|
||||
if (pagination is not null)
|
||||
{
|
||||
if (pagination.PageSize != 20)
|
||||
{
|
||||
parts.Add($"page_size={pagination.PageSize}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(pagination.PageToken))
|
||||
{
|
||||
parts.Add($"page_token={Uri.EscapeDataString(pagination.PageToken)}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (name, value) in additional)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
parts.Add($"{name}={Uri.EscapeDataString(value)}");
|
||||
}
|
||||
}
|
||||
|
||||
return parts.Count > 0 ? "?" + string.Join("&", parts) : string.Empty;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// VERIFICATION POLICY OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<VerificationPolicyList> ListVerificationPoliciesAsync(
|
||||
Guid tenantId,
|
||||
PaginationParams? pagination = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = BuildQueryString(pagination);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/verification-policies{query}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<VerificationPolicyList>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<VerificationPolicy> CreateVerificationPolicyAsync(
|
||||
Guid tenantId,
|
||||
CreateVerificationPolicyRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/verification-policies");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<VerificationPolicy>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<VerificationPolicy> GetVerificationPolicyAsync(
|
||||
Guid tenantId,
|
||||
string policyId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/verification-policies/{Uri.EscapeDataString(policyId)}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<VerificationPolicy>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<VerificationPolicy> UpdateVerificationPolicyAsync(
|
||||
Guid tenantId,
|
||||
string policyId,
|
||||
UpdateVerificationPolicyRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Put, $"/api/v1/policy/verification-policies/{Uri.EscapeDataString(policyId)}");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<VerificationPolicy>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task DeleteVerificationPolicyAsync(
|
||||
Guid tenantId,
|
||||
string policyId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Delete, $"/api/v1/policy/verification-policies/{Uri.EscapeDataString(policyId)}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// POLICY PACK OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<PolicyPackList> ListPolicyPacksAsync(
|
||||
Guid tenantId,
|
||||
PolicyPackStatus? status = null,
|
||||
PaginationParams? pagination = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = BuildQueryString(pagination, ("status", status?.ToString().ToLowerInvariant()));
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/packs{query}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPackList>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<PolicyPack> CreatePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
CreatePolicyPackRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/packs");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPack>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<PolicyPack> GetPolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/packs/{packId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPack>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<PolicyPack> UpdatePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
UpdatePolicyPackRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Put, $"/api/v1/policy/packs/{packId}");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPack>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task DeletePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Delete, $"/api/v1/policy/packs/{packId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<CompilationResult> CompilePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/packs/{packId}/compile");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
// Note: 422 also returns CompilationResult, so we read regardless of status
|
||||
return await response.Content.ReadFromJsonAsync<CompilationResult>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<SimulationResult> SimulatePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
SimulationRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/packs/{packId}/simulate");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<SimulationResult>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<PolicyPack> PublishPolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
PublishRequest? request = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/packs/{packId}/publish");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
if (request is not null)
|
||||
{
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPack>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<PolicyPack> PromotePolicyPackAsync(
|
||||
Guid tenantId,
|
||||
Guid packId,
|
||||
PromoteRequest? request = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/packs/{packId}/promote");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
if (request is not null)
|
||||
{
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<PolicyPack>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SNAPSHOT OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<SnapshotList> ListSnapshotsAsync(
|
||||
Guid tenantId,
|
||||
PaginationParams? pagination = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = BuildQueryString(pagination);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/snapshots{query}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<SnapshotList>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Snapshot> CreateSnapshotAsync(
|
||||
Guid tenantId,
|
||||
CreateSnapshotRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/snapshots");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Snapshot>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Snapshot> GetSnapshotAsync(
|
||||
Guid tenantId,
|
||||
Guid snapshotId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/snapshots/{snapshotId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Snapshot>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task DeleteSnapshotAsync(
|
||||
Guid tenantId,
|
||||
Guid snapshotId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Delete, $"/api/v1/policy/snapshots/{snapshotId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<Snapshot> GetSnapshotByDigestAsync(
|
||||
Guid tenantId,
|
||||
string digest,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/snapshots/by-digest/{Uri.EscapeDataString(digest)}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Snapshot>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// VIOLATION OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<ViolationList> ListViolationsAsync(
|
||||
Guid tenantId,
|
||||
Severity? severity = null,
|
||||
PaginationParams? pagination = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = BuildQueryString(pagination, ("severity", severity?.ToString().ToLowerInvariant()));
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/violations{query}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<ViolationList>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Violation> AppendViolationAsync(
|
||||
Guid tenantId,
|
||||
CreateViolationRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/violations");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Violation>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<ViolationBatchResult> AppendViolationBatchAsync(
|
||||
Guid tenantId,
|
||||
ViolationBatchRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/violations/batch");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<ViolationBatchResult>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Violation> GetViolationAsync(
|
||||
Guid tenantId,
|
||||
Guid violationId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/violations/{violationId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Violation>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// OVERRIDE OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<Override> CreateOverrideAsync(
|
||||
Guid tenantId,
|
||||
CreateOverrideRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/overrides");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Override>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Override> GetOverrideAsync(
|
||||
Guid tenantId,
|
||||
Guid overrideId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/policy/overrides/{overrideId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Override>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task DeleteOverrideAsync(
|
||||
Guid tenantId,
|
||||
Guid overrideId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Delete, $"/api/v1/policy/overrides/{overrideId}");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<Override> ApproveOverrideAsync(
|
||||
Guid tenantId,
|
||||
Guid overrideId,
|
||||
ApproveOverrideRequest? request = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/overrides/{overrideId}:approve");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
if (request is not null)
|
||||
{
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Override>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<Override> DisableOverrideAsync(
|
||||
Guid tenantId,
|
||||
Guid overrideId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/policy/overrides/{overrideId}:disable");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<Override>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SEALED MODE OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<SealedModeStatus> GetSealedModeStatusAsync(
|
||||
Guid tenantId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, "/api/v1/policy/sealed-mode/status");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<SealedModeStatus>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<SealedModeStatus> SealAsync(
|
||||
Guid tenantId,
|
||||
SealRequest? request = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/sealed-mode/seal");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
if (request is not null)
|
||||
{
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<SealedModeStatus>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<SealedModeStatus> UnsealAsync(
|
||||
Guid tenantId,
|
||||
UnsealRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/sealed-mode/unseal");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<SealedModeStatus>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<BundleVerificationResult> VerifyBundleAsync(
|
||||
Guid tenantId,
|
||||
VerifyBundleRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/sealed-mode/verify");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<BundleVerificationResult>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// STALENESS OPERATIONS
|
||||
// ============================================================
|
||||
|
||||
public async Task<StalenessStatus> GetStalenessStatusAsync(
|
||||
Guid tenantId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, "/api/v1/policy/staleness/status");
|
||||
AddTenantHeader(request, tenantId);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<StalenessStatus>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
|
||||
public async Task<StalenessEvaluation> EvaluateStalenessAsync(
|
||||
Guid tenantId,
|
||||
EvaluateStalenessRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/policy/staleness/evaluate");
|
||||
AddTenantHeader(httpRequest, tenantId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<StalenessEvaluation>(_jsonOptions, cancellationToken).ConfigureAwait(false)
|
||||
?? throw new InvalidOperationException("Failed to deserialize response");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for Policy Registry client.
|
||||
/// </summary>
|
||||
public sealed class PolicyRegistryClientOptions
|
||||
{
|
||||
public string? BaseUrl { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user