moon-policy-diff

    MoonPolicy extension for finite attribute sampling, tenant invariants and release regression gates

    authorization
    policy
    rbac
    abac
    change-audit
    Download zip
    Author
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    12 hours ago
    Downloads
    4

    Dependencies

    #MoonPolicyDiff

    MoonPolicyDiff 0.2.0 是基于 MoonPolicy 的权限回归与发布风险审查扩展。主要流程直接依赖 Mooncakes 的 eisem/moon_policy 0.1.0,复用其 JSON 解析、授权求值、策略差异和用例回放;本项目增加有限属性域生成、租户隔离及禁止动作不变量、按动作变更预算和回归用例导出。

    公开代码:GitHub;包:Mooncakes。

    #推荐流程:MoonPolicy 扩展

    moon run cmd/main -- release-audit examples/moonpolicy/saas/before.json examples/moonpolicy/saas/after.json examples/moonpolicy/saas/seeds.json examples/moonpolicy/saas/plan.json

    此例生成 6 个属性样本,发现 1 个新增跨租户授权,返回退出码 1。完整的 SaaS、数据平台和 AI 工具运行、用例导出及回放说明见 MoonPolicy 示例。

    责任范围实现来源
    策略 JSON、角色继承、属性条件、拒绝语义、原始决策轨迹、基础差异及原生用例回放eisem/moon_policy 0.1.0
    声明有限属性取值,枚举缺失、布尔、整数边界等组合,超限不输出部分样本release_samples.mbt、release_plan.mbt
    检查所有新版允许请求的租户隔离与禁止动作不变量,缺失租户元数据返回不确定release_audit.mbt
    分动作设置新增授权和撤权预算;重复请求只计一次release_audit.mbt
    导出上游原生回归用例,输出采样范围与机器可读审查报告release_run.mbt、release_audit.mbt

    这些扩展不改写 MoonPolicy 授权语义,不提供其他引擎的语义转换。采样完整性只针对用户声明的有限域;域外属性、其他身份资源及真实租户元数据需调用方保证。租户策略以请求顶层字符串属性 tenant 为默认来源,可以配置其他非保留顶层键。禁止动作使用精确名称。

    #库接入

    在使用方同时导入 geniuszby/moon-policy-diff 和 eisem/moon_policy。调用 parse_release_plan 读取审查配置,随后将上游 Policy 和 Request 交给 run_release_plan;run_moonpolicy_json 可直接处理三份上游 JSON 文本。release_regression_cases 返回上游 PolicyCase 数组,可交给 Policy.run_cases。接口见 pkg.generated.mbti。

    #0.1 兼容流程

    以下旧文本 DSL、求值和分析接口保留给现有使用者。它们使用本项目的旧模型,不会自动转换为 MoonPolicy 策略;两套流程不能混用。旧版求值、diff、verify、coverage、lint 等与生态项目存在功能重叠,不作为本次扩展独创性的依据。反事实归因、结构差异和见证分组目前仍仅适用于旧模型。

    #快速运行

    安装 MoonBit 工具链后,在仓库根目录执行:

    moon run cmd/main -- audit examples/saas/before.policy examples/saas/after.policy examples/saas/universe.txt moon run cmd/main -- audit examples/ai-tools/before.policy examples/ai-tools/after.policy examples/ai-tools/universe.txt moon run cmd/main -- audit examples/finance/before.policy examples/finance/after.policy examples/finance/universe.txt json moon run cmd/main -- audit examples/finance/before.policy examples/finance/after.policy examples/finance/universe.txt attribution moon run cmd/main -- verify examples/finance/before.policy examples/finance/universe.txt examples/finance/expected-before.txt moon run cmd/main -- impact examples/saas/after.policy examples/saas/universe.txt moon run cmd/main -- audit examples/saas/before.policy examples/saas/after.policy examples/saas/universe.txt groups moon run cmd/main -- audit examples/saas/before.policy examples/saas/after.policy examples/saas/universe.txt witnesses moon run cmd/main -- scope examples/saas/universe.txt read,export moon run cmd/main -- audit examples/finance/before.policy examples/finance/after.policy examples/finance/universe.txt structural

    两个示例都会报告新增授权,因此严格门禁退出码为 1。退出码 0 表示通过,2 表示输入无效或结论不确定。

    #输入格式

    策略文件每行一个指令:

    policy NAME inherit CHILD_ROLE PARENT_ROLE rule ID permit|deny ROLES ACTIONS RESOURCE_KINDS RESOURCE_IDS any|same|other CONDITIONS

    列表使用逗号分隔,单个 - 表示不限。条件格式为 principal:KEY:eq:VALUE、resource:KEY:neq:VALUE 或 request:KEY:exists:-。同一条规则的所有条件必须满足;拒绝规则优先于允许规则,未命中时默认拒绝。

    请求样本文件:

    principal ID TENANT ROLE1,ROLE2 KEY=VALUE,... resource ID KIND TENANT KEY=VALUE,... request PRINCIPAL_ID ACTION RESOURCE_ID KEY=VALUE,... matrix ACTION1,ACTION2

    属性为空时使用 -。matrix 将主体、动作和资源做笛卡尔积,最多生成 100000 条显式请求;超过上限会报错,不输出部分结果。示例见 examples/saas、examples/ai-tools 和 examples/finance。

    #能力与边界

    • 角色继承、通配符匹配、资源类型、租户关系和主体/资源/请求属性条件。
    • 对显式请求集做确定性新旧对比,保留每个变更的主体、动作、资源和决定性规则。
    • 严格门禁默认拒绝任何新增授权、撤权或跨租户新增授权。
    • JSON 报告包含请求、决策、规则命中轨迹和门禁发现。
    • MoonBit 库 API 可按动作分别设置新增授权和撤权预算;未配置的动作默认预算为零。
    • 两因素反事实归因可区分规则修订和角色继承修订对样本请求的影响;结论仅针对这两种变更维度。
    • verify 读取 expect PRINCIPAL ACTION RESOURCE allow|deny 断言,检查单版策略是否满足既定权限基线。
    • impact 逐条移除规则重算样本,给出每条规则被删除后新增或失去访问的数量及见证请求。
    • groups 按主体租户、资源租户和动作汇总样本变更,便于查看跨租户授权集中在哪些场景。
    • witnesses 按变更类型、动作、资源类型、跨租户关系和决定性规则合并同类请求,保留每组一个可复现见证;完整结果仍可用 text 或 json 查看。
    • scope 对给定动作检查“主体 × 动作 × 资源”三元组覆盖情况,明确列出缺失示例;属性取值组合仍需单独设计样本。
    • structural 列出规则和角色继承边的增删改,与基于请求的行为对比互补。
    • 分析只覆盖输入的请求集合;未采样请求不构成安全保证。
    • 当前不提供认证、令牌签发、在线授权服务或其他策略语言的兼容解释器。

    #验证

    moon check --target js moon test --target js moon build --target js moon info moon fmt

    GitHub Actions 在 push 和 PR 上运行检查、测试、构建和格式检查。

    #原创性与许可

    本项目新增部分为原创 MoonBit 扩展代码,授权基础复用 MoonPolicy,而不是宣称基础权限引擎和策略差异为本项目独有。上游源码通过包依赖使用,没有复制到本仓库;来源和重叠能力见 RELATED_WORK.md。本项目和 MoonPolicy 均采用 Apache-2.0;依赖、更新和验证记录见 THIRD_PARTY.md、CHANGELOG.md 和 TEST_RECORD.md。

    ReleaseInputError

    pub(all) suberror ReleaseInputError {
    InvalidReleaseInput(String)
    } derive(Eq,
    Debug
    )

    AccessPolicy

    pub(all) struct AccessPolicy {
    name : String
    role_inheritance : Array[RoleInheritance]
    rules : Array[AccessRule]
    } derive(Eq,
    Debug
    )

    AccessRequest

    pub(all) struct AccessRequest {
    principal_id : String
    action : String
    resource_id : String
    attributes : Array[(String, String)]
    } derive(Eq,
    Debug
    )

    AccessResource

    pub(all) struct AccessResource {
    id : String
    kind : String
    tenant : String
    attributes : Array[(String, String)]
    } derive(Eq,
    Debug
    )

    AccessRule

    pub(all) struct AccessRule {
    id : String
    effect : RuleEffect
    roles : Array[String]
    actions : Array[String]
    resource_kinds : Array[String]
    resource_ids : Array[String]
    tenant_relation : TenantRelation
    conditions : Array[AttributeCondition]
    } derive(Eq,
    Debug
    )

    Empty selector arrays mean "any". An explicit * has the same meaning and is accepted by the text parser for readable policy files.

    ActionBudget

    pub(all) struct ActionBudget {
    action : String
    max_new_grants : Int
    max_revocations : Int
    } derive(
    Debug
    )

    AttributeCondition

    pub(all) struct AttributeCondition {
    source : AttributeSource
    key : String
    operator : AttributeOperator
    value : String
    } derive(Eq,
    Debug
    )

    AttributeOperator

    pub(all) enum AttributeOperator {
    Equals
    NotEquals
    Exists
    Missing
    } derive(Eq,
    Debug
    )

    AttributeSource

    pub(all) enum AttributeSource {
    PrincipalAttribute
    ResourceAttribute
    RequestAttribute
    } derive(Eq,
    Debug
    )

    AttributedChange

    pub(all) struct AttributedChange {
    request : AccessRequest
    kind : ChangeKind
    cause : ChangeCause
    changed_rule_ids : Array[String]
    role_edges_changed : Bool
    } derive(
    Debug
    )

    AuditReport

    pub(all) struct AuditReport {
    before_name : String
    after_name : String
    requests_considered : Int
    changes : Array[DecisionChange]
    diagnostics : Array[Diagnostic]
    complete : Bool
    } derive(Eq,
    Debug
    )

    ChangeCause

    pub(all) enum ChangeCause {
    RuleRevision
    RoleInheritanceRevision
    EitherRevision
    CombinedRevision
    Unattributed
    } derive(Eq,
    Debug
    )

    ChangeGroup

    pub(all) struct ChangeGroup {
    principal_tenant : String
    resource_tenant : String
    action : String
    new_grants : Int
    revocations : Int
    unchanged : Int
    inconclusive : Int
    } derive(
    Debug
    )

    ChangeKind

    pub(all) enum ChangeKind {
    NewGrant
    RevokedGrant
    UnchangedAllow
    UnchangedDeny
    Inconclusive
    } derive(Eq,
    Debug
    )

    Decision

    pub(all) struct Decision {
    kind : DecisionKind
    decisive_rules : Array[String]
    traces : Array[RuleTrace]
    explanation : String
    } derive(Eq,
    Debug
    )

    DecisionChange

    pub(all) struct DecisionChange {
    request : AccessRequest
    before : Decision
    after : Decision
    kind : ChangeKind
    } derive(Eq,
    Debug
    )

    DecisionExpectation

    pub(all) struct DecisionExpectation {
    principal_id : String
    action : String
    resource_id : String
    expected : DecisionKind
    } derive(
    Debug
    )

    DecisionKind

    pub(all) enum DecisionKind {
    Allowed
    Denied
    Unknown
    } derive(Eq,
    Debug
    )

    Diagnostic

    pub(all) struct Diagnostic {
    code : String
    severity : DiagnosticSeverity
    message : String
    } derive(Eq,
    Debug
    )

    DiagnosticSeverity

    pub(all) enum DiagnosticSeverity {
    Info
    Warning
    Error
    } derive(Eq,
    Debug
    )

    ExpectationResult

    pub(all) struct ExpectationResult {
    expectation : DecisionExpectation
    actual : DecisionKind
    matched_requests : Int
    passed : Bool
    } derive(
    Debug
    )

    GateConfig

    pub(all) struct GateConfig {
    max_new_grants : Int
    max_revocations : Int
    forbid_cross_tenant_grants : Bool
    permitted_principals : Array[String]
    permitted_actions : Array[String]
    } derive(
    Debug
    )

    GateFinding

    pub(all) struct GateFinding {
    code : String
    request : AccessRequest
    message : String
    } derive(
    Debug
    )

    GateResult

    pub(all) struct GateResult {
    verdict : GateVerdict
    findings : Array[GateFinding]
    } derive(
    Debug
    )

    GateVerdict

    pub(all) enum GateVerdict {
    Pass
    Fail
    Indeterminate
    } derive(Eq,
    Debug
    )

    MatrixExpansion

    pub(all) struct MatrixExpansion {
    universe : RequestUniverse
    generated_requests : Int
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    ParsedExpectations

    pub(all) struct ParsedExpectations {
    expectations : Array[DecisionExpectation]
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    ParsedPolicy

    pub(all) struct ParsedPolicy {
    policy : AccessPolicy
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    ParsedUniverse

    pub(all) struct ParsedUniverse {
    universe : RequestUniverse
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    PolicyCoverage

    pub(all) struct PolicyCoverage {
    policy_name : String
    evaluated_requests : Int
    allowed_requests : Int
    denied_requests : Int
    rule_coverage : Array[RuleCoverage]
    actions_seen : Array[String]
    principal_tenants_seen : Array[String]
    resource_tenants_seen : Array[String]
    } derive(
    Debug
    )

    Principal

    pub(all) struct Principal {
    id : String
    tenant : String
    roles : Array[String]
    attributes : Array[(String, String)]
    } derive(Eq,
    Debug
    )

    ReleaseAttributeDomain

    pub(all) struct ReleaseAttributeDomain {
    source : AttributeSource
    key : String
    values : Array[
    AttributeValue
    ?]
    } derive(
    Debug
    )

    A finite top-level attribute domain. None removes the attribute; Some uses MoonPolicy's typed value. Domains do not enumerate unknown values.

    ReleaseConfig

    pub(all) struct ReleaseConfig {
    action_budgets : Array[ActionBudget]
    forbid_cross_tenant : Bool
    tenant_attribute : String
    forbidden_actions : Array[String]
    } derive(
    Debug
    )

    Release rules layered on MoonPolicy. They do not change authorization semantics. Unlisted actions have a zero change budget.

    ReleaseFinding

    pub(all) struct ReleaseFinding {
    code : String
    message : String
    request :
    Request
    ?
    } derive(
    Debug
    )

    ReleasePlan

    pub(all) struct ReleasePlan {
    config : ReleaseConfig
    domains : Array[ReleaseAttributeDomain]
    max_requests : Int
    } derive(
    Debug
    )

    ReleaseReport

    pub(all) struct ReleaseReport {
    complete : Bool
    requests_evaluated : Int
    changes : Array[
    AccessChange
    ]
    findings : Array[ReleaseFinding]
    verdict : GateVerdict
    } derive(
    Debug
    )

    ReleaseRun

    pub(all) struct ReleaseRun {
    samples : ReleaseSamples
    report : ReleaseReport
    } derive(
    Debug
    )

    ReleaseSamples

    pub(all) struct ReleaseSamples {
    requests : Array[
    Request
    ]
    complete : Bool
    candidate_count : Int
    diagnostics : Array[String]
    } derive(
    Debug
    )

    RequestUniverse

    pub(all) struct RequestUniverse {
    principals : Array[Principal]
    resources : Array[AccessResource]
    requests : Array[AccessRequest]
    } derive(Eq,
    Debug
    )

    The universe is explicit so a finite analysis never silently claims coverage of identities or resources that were not provided.

    RoleInheritance

    pub(all) struct RoleInheritance {
    child : String
    parent : String
    } derive(Eq,
    Debug
    )

    A role name may inherit another role. Inheritance is directed: a holder of child receives all permissions granted to parent.

    RuleCoverage

    pub(all) struct RuleCoverage {
    rule_id : String
    matched_requests : Int
    decisive_requests : Int
    } derive(
    Debug
    )

    RuleDelta

    pub(all) struct RuleDelta {
    rule_id : String
    kind : RuleDeltaKind
    } derive(
    Debug
    )

    RuleDeltaKind

    pub(all) enum RuleDeltaKind {
    AddedRule
    RemovedRule
    ModifiedRule
    UnchangedRule
    } derive(Eq,
    Debug
    )

    RuleEffect

    pub(all) enum RuleEffect {
    Permit
    Deny
    } derive(Eq,
    Debug
    )

    The two possible effects of a policy rule. A deny rule overrides permits.

    RuleImpact

    pub(all) struct RuleImpact {
    rule_id : String
    grants_when_removed : Int
    revocations_when_removed : Int
    example_grant : AccessRequest?
    example_revocation : AccessRequest?
    } derive(
    Debug
    )

    RuleImpactReport

    pub(all) struct RuleImpactReport {
    policy_name : String
    impacts : Array[RuleImpact]
    diagnostics : Array[Diagnostic]
    complete : Bool
    } derive(
    Debug
    )

    RuleTrace

    pub(all) struct RuleTrace {
    rule_id : String
    effect : RuleEffect
    matched : Bool
    reason : String
    } derive(Eq,
    Debug
    )

    ScopeCoverage

    pub(all) struct ScopeCoverage {
    possible_requests : Int
    represented_requests : Int
    missing_requests : Int
    missing_examples : Array[AccessRequest]
    complete : Bool
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    StructuralDiff

    pub(all) struct StructuralDiff {
    rules : Array[RuleDelta]
    added_role_edges : Array[RoleInheritance]
    removed_role_edges : Array[RoleInheritance]
    } derive(
    Debug
    )

    TenantRelation

    pub(all) enum TenantRelation {
    AnyTenant
    SameTenant
    OtherTenant
    } derive(Eq,
    Debug
    )

    VerificationReport

    pub(all) struct VerificationReport {
    policy_name : String
    passed : Int
    failed : Int
    inconclusive : Int
    results : Array[ExpectationResult]
    diagnostics : Array[Diagnostic]
    } derive(
    Debug
    )

    WitnessGroup

    pub(all) struct WitnessGroup {
    kind : ChangeKind
    action : String
    resource_kind : String
    cross_tenant : Bool
    before_rules : Array[String]
    after_rules : Array[String]
    occurrences : Int
    example : AccessRequest
    } derive(
    Debug
    )

    WitnessSelection

    pub(all) struct WitnessSelection {
    groups : Array[WitnessGroup]
    total_changed_requests : Int
    omitted_groups : Int
    complete : Bool
    } derive(
    Debug
    )

    analyze_scope

    fn analyze_scope(universe : RequestUniverse, actions : Array[String], max_combinations : Int) -> ScopeCoverage

    Measures coverage of principal × action × resource triples. Attribute valuations are intentionally excluded; a represented triple may still omit other important attribute combinations.

    attribute_changes

    fn attribute_changes(before : AccessPolicy, after : AccessPolicy, universe : RequestUniverse) -> Array[AttributedChange]

    A two-factor counterfactual: swap only the rules, then only the role graph. The result explains the observed decision for the supplied request and these two policy dimensions; it is not a general causal proof.

    audit_release

    Delegates every access decision to the published MoonPolicy engine. Tenant invariants cover all allowed replacement decisions, including unchanged access. Invalid metadata makes the conclusion indeterminate.

    cause_name

    fn cause_name(cause : ChangeCause) -> String

    change_name

    fn change_name(kind : ChangeKind) -> String

    check_action_budgets

    fn check_action_budgets(report : AuditReport, budgets : Array[ActionBudget]) -> GateResult

    Independent per-action budgets. Unlisted actions have a zero budget. This gate complements the tenant-aware strict gate.

    check_gate

    fn check_gate(report : AuditReport, universe : RequestUniverse, config : GateConfig) -> GateResult

    Exceptions require both the principal and action to be explicitly listed. They affect only the general grant count, never cross-tenant violations.

    classify_change

    fn classify_change(before : Decision, after : Decision) -> ChangeKind

    compare_policies

    fn compare_policies(before : AccessPolicy, after : AccessPolicy, universe : RequestUniverse) -> AuditReport

    Every claim is scoped to the supplied request universe. Invalid input returns an incomplete report and never silently asserts equivalence.

    condition_matches

    fn condition_matches(condition : AttributeCondition, principal : Principal, resource : AccessResource, request : AccessRequest) -> Bool

    count_changes

    fn count_changes(report : AuditReport, kind : ChangeKind) -> Int

    count_lint

    fn count_lint(issues : Array[Diagnostic], severity : DiagnosticSeverity) -> Int

    cross_tenant_change_count

    fn cross_tenant_change_count(groups : Array[ChangeGroup]) -> Int

    default_deny

    fn default_deny() -> Decision

    default_release_plan

    fn default_release_plan() -> ReleasePlan

    effective_roles

    fn effective_roles(policy : AccessPolicy, principal : Principal) -> Array[String]

    Compute roles reachable from the principal's direct grants.

    empty_policy

    fn empty_policy(name : String) -> AccessPolicy

    empty_universe

    fn empty_universe() -> RequestUniverse

    evaluate_request

    fn evaluate_request(policy : AccessPolicy, universe : RequestUniverse, request : AccessRequest) -> Decision

    A deny rule takes precedence over permits. Without a matching rule, evaluation uses default deny.

    evaluate_validated

    fn evaluate_validated(policy : AccessPolicy, universe : RequestUniverse, request : AccessRequest) -> Decision

    expand_request_matrix

    fn expand_request_matrix(universe : RequestUniverse, actions : Array[String], max_requests : Int) -> MatrixExpansion

    Adds all principal × action × resource requests. The caller must supply a bound; overflow fails without returning a partial expanded universe.

    find_witnesses

    fn find_witnesses(report : AuditReport, kind : ChangeKind) -> Array[DecisionChange]

    generate_release_samples

    fn generate_release_samples(seeds : Array[
    Request
    ], domains : Array[ReleaseAttributeDomain], limit : Int) -> ReleaseSamples

    Generates the product of declared domains for each seed, preserving seed and domain order. Overflow or invalid configuration returns no samples. Exact duplicate requests are removed after generation.

    glob_matches

    fn glob_matches(pattern : String, value : String) -> Bool

    Small glob matcher: '*' accepts any sequence and '?' one character. Iterative backtracking avoids a regular-expression dependency.

    group_changes

    fn group_changes(report : AuditReport, universe : RequestUniverse) -> Array[ChangeGroup]

    Groups decisions by subject tenant, resource tenant, and action. This is an aggregate over the explicit sample, not a population estimate.

    has_errors

    fn has_errors(issues : Array[Diagnostic]) -> Bool

    inert_rules

    fn inert_rules(report : RuleImpactReport) -> Array[String]

    is_valid_identifier

    fn is_valid_identifier(value : String) -> Bool

    lint_policy

    fn lint_policy(policy : AccessPolicy, universe : RequestUniverse) -> Array[Diagnostic]

    Static and sample-scoped lint. Lint warnings do not change evaluation.

    lookup_attribute

    fn lookup_attribute(attrs : Array[(String, String)], key : String) -> String?

    matching_rule_ids

    fn matching_rule_ids(policy : AccessPolicy, principal : Principal, resource : AccessResource, request : AccessRequest) -> Array[String]

    measure_policy_coverage

    fn measure_policy_coverage(policy : AccessPolicy, universe : RequestUniverse) -> PolicyCoverage

    Counts are observational: a rule with zero matches in this universe may still match a request outside the supplied finite sample.

    measure_rule_impact

    fn measure_rule_impact(policy : AccessPolicy, universe : RequestUniverse) -> RuleImpactReport

    Measures the effect of deleting each rule, one at a time, over the explicit universe. Interacting rule deletions are outside this analysis.

    parse_expectations

    fn parse_expectations(source : String) -> ParsedExpectations

    Each line: expect PRINCIPAL ACTION RESOURCE allow|deny.

    parse_policy

    fn parse_policy(source : String) -> ParsedPolicy

    Policy DSL: policy NAME; inherit CHILD PARENT; rule ID EFFECT ROLES ACTIONS KINDS IDS TENANT CONDITIONS. Lists are comma separated; '-' means unrestricted or empty.

    parse_release_plan

    fn parse_release_plan(source : String) -> ReleasePlan raise ReleaseInputError

    Unknown configuration fields are rejected, including misspelled restrictions. JSON null in a domain means an absent attribute.

    parse_universe

    fn parse_universe(source : String) -> ParsedUniverse

    Universe DSL: principal ID TENANT ROLES ATTRS resource ID KIND TENANT ATTRS request PRINCIPAL ACTION RESOURCE ATTRS matrix ACTION1,ACTION2

    release_cases_json

    fn release_cases_json(report : ReleaseReport) -> Json

    release_regression_cases

    fn release_regression_cases(report : ReleaseReport) -> Array[
    PolicyCase
    ]

    Replay cases preserve the old outcome for changed requests. Explicit invariant violations override that baseline with an expected denial. These are review artifacts, not automatically applied policy fixes.

    release_report_json

    fn release_report_json(report : ReleaseReport) -> Json

    release_run_json

    fn release_run_json(run : ReleaseRun) -> Json

    render_attribution

    fn render_attribution(changes : Array[AttributedChange]) -> String

    render_coverage

    fn render_coverage(coverage : PolicyCoverage) -> String

    render_groups

    fn render_groups(groups : Array[ChangeGroup]) -> String

    render_lint

    fn render_lint(issues : Array[Diagnostic]) -> String

    render_report

    fn render_report(report : AuditReport, gate : GateResult) -> String

    render_report_json

    fn render_report_json(report : AuditReport, gate : GateResult) -> String

    render_rule_impact

    fn render_rule_impact(report : RuleImpactReport) -> String

    render_scope

    fn render_scope(scope : ScopeCoverage) -> String

    render_structural_diff

    fn render_structural_diff(diff : StructuralDiff) -> String

    render_verification

    fn render_verification(report : VerificationReport) -> String

    render_witnesses

    fn render_witnesses(selection : WitnessSelection) -> String

    replay_moonpolicy_json

    fn replay_moonpolicy_json(policy : String, cases : String) -> Json raise ReleaseInputError

    Uses MoonPolicy's native case loader and runner for replay.

    rule_match_trace

    fn rule_match_trace(rule : AccessRule, roles : Array[String], principal : Principal, resource : AccessResource, request : AccessRequest) -> RuleTrace

    run_moonpolicy_json

    fn run_moonpolicy_json(before : String, after : String, seeds : String, plan : ReleasePlan) -> ReleaseRun raise ReleaseInputError

    select_witnesses

    fn select_witnesses(report : AuditReport, universe : RequestUniverse, max_groups : Int) -> WitnessSelection

    Picks one representative request per decision signature. The first request in input order is retained. This is a compact review view, while the full audit report remains the source of all individual changes.

    selector_matches

    fn selector_matches(selectors : Array[String], value : String) -> Bool

    shadowed_rules

    fn shadowed_rules(coverage : PolicyCoverage) -> Array[String]

    strict_gate

    fn strict_gate() -> GateConfig

    strict_release_config

    fn strict_release_config() -> ReleaseConfig

    structural_diff

    fn structural_diff(before : AccessPolicy, after : AccessPolicy) -> StructuralDiff

    Lists syntactic policy changes by stable rule ID and directed role edge. It complements, but cannot replace, behavioral comparison on requests.

    tenant_pairs

    fn tenant_pairs(universe : RequestUniverse) -> Array[(String, String)]

    Returns a summary of how many distinct subject/target tenant pairs occur in the explicit universe. This helps reviewers judge sample breadth.

    unknown_decision

    fn unknown_decision(message : String) -> Decision

    unmatched_rules

    fn unmatched_rules(coverage : PolicyCoverage) -> Array[String]

    validate_policy

    fn validate_policy(policy : AccessPolicy) -> Array[Diagnostic]

    validate_universe

    fn validate_universe(universe : RequestUniverse) -> Array[Diagnostic]

    verdict_name

    fn verdict_name(verdict : GateVerdict) -> String

    verify_expectations

    fn verify_expectations(policy : AccessPolicy, universe : RequestUniverse, expectations : Array[DecisionExpectation]) -> VerificationReport

    A request match must be unique. Two sampled requests with different attributes but the same three identifiers are ambiguous for this format.