feat: preview governed policy impact

This commit is contained in:
2026-08-20 20:27:17 +02:00
parent be5e3a7d72
commit 861e9b8b8d
10 changed files with 1232 additions and 36 deletions
+91 -4
View File
@@ -46,6 +46,46 @@ export type ViewPolicyReferenceData = {
surfaces: Array<{ id: string; label: string; module_id: string; kind: string }>;
};
export type PolicyImpactCategory = "newly_allowed" | "newly_denied" | "unchanged" | "indeterminate";
export type PolicyImpactPreviewResponse = {
preview_id: string;
proposal_hash: string;
policy_family: string;
scope_type: string;
scope_id?: string | null;
base_revision?: number | null;
counts: Record<PolicyImpactCategory, number>;
effects: Array<{
category: PolicyImpactCategory;
subject: {
module_id: string;
resource_type: string;
resource_id: string;
action: string;
label?: string | null;
scope_type?: string | null;
scope_id?: string | null;
};
current_allowed?: boolean | null;
proposed_allowed?: boolean | null;
rule: string;
current_sources: Array<{ path: string; label: string }>;
proposed_sources: Array<{ path: string; label: string }>;
explanation?: string | null;
}>;
populations: Array<{
provider_id: string;
state: "complete" | "sampled" | "truncated" | "unavailable";
returned: number;
total_available?: number | null;
explanation?: string | null;
}>;
details_hidden: boolean;
details_explanation?: string | null;
high_impact: boolean;
};
export function fetchViewPolicy(
settings: ApiSettings,
scope: ViewPolicyScope,
@@ -60,26 +100,73 @@ export function updateViewPolicy(
settings: ApiSettings,
scope: ViewPolicyScope,
scopeId: string | null | undefined,
policy: ViewPolicyItem
policy: ViewPolicyItem,
impactPreview?: Pick<PolicyImpactPreviewResponse, "preview_id" | "proposal_hash"> | null
): Promise<ViewPolicyScopeResponse> {
return apiFetch(settings, apiPath(`/api/v1/admin/view-policies/${scope}`, {
scope_id: scopeId || undefined
}), {
method: "PUT",
body: JSON.stringify({ policy })
body: JSON.stringify({
policy,
impact_preview_id: impactPreview?.preview_id,
impact_proposal_hash: impactPreview?.proposal_hash
})
});
}
export function deleteViewPolicy(
settings: ApiSettings,
scope: ViewPolicyScope,
scopeId?: string | null
scopeId?: string | null,
impactPreview?: Pick<PolicyImpactPreviewResponse, "preview_id" | "proposal_hash"> | null
): Promise<ViewPolicyScopeResponse> {
return apiFetch(settings, apiPath(`/api/v1/admin/view-policies/${scope}`, {
scope_id: scopeId || undefined
scope_id: scopeId || undefined,
impact_preview_id: impactPreview?.preview_id,
impact_proposal_hash: impactPreview?.proposal_hash
}), { method: "DELETE" });
}
export function previewViewPolicyImpact(
settings: ApiSettings,
scope: ViewPolicyScope,
scopeId: string | null | undefined,
policy: ViewPolicyItem,
population: { viewIds: string[]; surfaceIds: string[] }
): Promise<PolicyImpactPreviewResponse> {
return apiFetch(settings, "/api/v1/admin/policy-impact/preview", {
method: "POST",
body: JSON.stringify({
policy_family: "view",
scope_type: scope,
scope_id: scopeId || null,
proposed_policy: policy,
populations: [
{
provider_id: "views",
selector: {
include_views: true,
include_surfaces: false,
view_ids: population.viewIds.slice(0, 500)
},
limit: 500
},
{
provider_id: "views",
selector: {
include_views: false,
include_surfaces: true,
surface_ids: population.surfaceIds.slice(0, 500)
},
limit: 500
}
],
include_details: true
})
});
}
export async function fetchViewPolicyReferences(settings: ApiSettings): Promise<ViewPolicyReferenceData> {
const [definitionResult, surfaceResult] = await Promise.allSettled([
apiFetch<{ definitions: Array<{ id: string; name: string; scope_type?: string }> }>(