Skip to content

docs(cmf): settle the extensions bag contract - #59

Open
mkoushni wants to merge 2 commits into
praxis-proxy:mainfrom
mkoushni:fix/cmf-extensions-model
Open

docs(cmf): settle the extensions bag contract#59
mkoushni wants to merge 2 commits into
praxis-proxy:mainfrom
mkoushni:fix/cmf-extensions-model

Conversation

@mkoushni

@mkoushni mkoushni commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Document the CMF bag contract: per-type absent values, original vs flattened keys, and why subject.claims is not a bag key (docs/cmf-extensions.md).
  • Bridge tests assert present-empty StringSets, omitted optionals, and paired original/flattened members.
  • ppe-pdp-diff moves present-empty sets into the agreement subset (APL, CEL, cedar-direct, OPA Deny together); unguarded omitted scalars stay on the allowlist.

Closes #18

Changes

Added

  • docs/cmf-extensions.md — normative bag contract:
    • per-type absent-value table (StringSet present-empty; optional String/Int/Float omitted; flattened member bools presence-only; non-option scalars always written)
    • original collections vs flattened role.* / perm.* / team.* / client.role.* (authors should use the original set; last bag.set wins if they disagree)
    • why there is no subject.claims map in the bag (would need a sixth AttributeValue variant and would duplicate flattened claim.*)
    • what APL, CEL, cedar-direct, and OPA do with a missing key
    • catalog of all twelve extract_extensions slots, keys, and types
    • payloads that are not slots (args.* / result.* / data.*; raw_credentials and candidate_constraint stay out of the bag)

ppe-apl-cmf

  • src/lib.rs — rustdoc points at docs/cmf-extensions.md.
  • src/extensions_bridge.rs — rustdoc on extract_extensions restates the per-type contract.
    • present_slots_follow_the_absent_value_contract — present empty slots emit empty sets, omit optionals, skip flattened bools, write non-option zeros/false, and never emit a subject.claims parent key.
    • original_set_and_flattened_bools_stay_paired — a member in the set also appears as the flattened bool, and both stay in lockstep.

ppe-pdp-diff

  • Cargo.toml / Cargo.lock — dev-deps on praxis-policy-apl-cmf and praxis-policy-core so cases can build bags through extract_extensions.
  • README.md — present-empty StringSet is in the semantic subset; new allowlist rows for omitted claim scalars; pointer to docs/cmf-extensions.md.
  • src/cases.rs
    • Case.apl_rule + with_apl so agreement cases also run the native APL evaluator.
    • alice_via_bridge() — bag from extract_extensions, not a hand-built set.
    • empty-set — recategorized from Diverge to AgreeDeny; APL require(subject.teams contains "eng").
    • bridge-empty-teams — same intent, bag from the bridge.
    • bridge-empty-roles — empty subject.roles / no role.* keys; Cedar principal.roles.contains("hr") vs CEL/OPA original set vs APL require(subject.roles contains "hr").
    • missing-claim-string / missing-claim-int — unguarded omitted scalars (allowlisted).
  • src/allowlist.rs
    • removed empty-set (now subset).
    • added missing-claim-string and missing-claim-int.
    • rewrote missing-collection to point at the contract and the original-set cases.
  • src/lib.rs
    • assert_apl on AgreeAllow / AgreeDeny.
    • absent_value_agreement_cases_check_aplempty-set, bridge-empty-teams, and bridge-empty-roles must carry an APL rule.

Changelog

Test plan

  • make lint
  • cargo test -p praxis-policy-apl-cmf
  • cargo test -p praxis-policy-pdp-diff
  • make coverage (95.74% lines, floor 95%)
  • CI on this PR

The twelve CMF slots had an implicit per-type empty/absent rule and a
claims gap that only lived next to extractors. Document the contract,
assert it in the bridge, and move present-empty sets into the PDP
agreement subset so APL, CEL, cedar-direct, and OPA deny the same way.

Signed-off-by: mkoushni <mkoushni@redhat.com>
@araujof araujof added documentation Improvements or additions to documentation area/security labels Sep 1, 2026
@araujof araujof moved this from Backlog to In progress in Praxis Policy Engine (PPE) Sep 1, 2026
@araujof araujof added this to the 0.1.2 milestone Sep 1, 2026
Keep the praxis-proxy#18 changelog bullet and take the assertions entry from praxis-proxy#56.

Signed-off-by: mkoushni <mkoushni@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/security documentation Improvements or additions to documentation

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

fix(cmf): settle the extensions model and document the extension types

3 participants