Skip to content

bug(permissions): "security-level ids are universal" is an assumption, not a guarantee — they are editable master data #110

Closed

Description

@2000game

Split out of #109, where this surfaced as a side-finding. It is the one item there that affects
grants already declared and applied, so it deserves its own issue.

The assumption

src/permissions/scope.ts treats security-level dataIds as universal and therefore safe to hard-code:

a raw numeric dataId (number, #49) — an escape hatch that passes straight through with no
state lookup at all … e.g. cc_securitylevel … where the dataId names something this tool has no
managed representation for (a security level, not a group)

eqrm/ct-structure relies on it heavily and says so in docs/permissions-status.md:

The numeric escape hatch is only safe for dimensions whose ids are universal (security levels, and
CT's -1 "all" sentinel).

Live today: struktur_roles (33 grants), skidscheckinopsmz_mitglied and
skidscheckinopskoblenz_mitglied (15 each), sflow2_5viewer_mitglied and others all carry
scope: [1, 2, 3]-style literals.

Why it is shakier than it looks

cc_securitylevel appears in ChurchTools' editable master-data registry (getMasterData →
masterDataTables), as table cc_securitylevel with columns id, bezeichnung, sortkey and the label
"Sicherheitslevel". They are admin-editable rows with an auto-increment id, not a protocol constant.
So "1/2/3 mean the same everywhere" holds by convention — because nobody has added or reordered one —
not by construction. An admin adding a level on dev, or a future instance created differently, changes
what a hard-coded scope: [1, 2, 3] grants there, silently and with a green plan.

And there is already a catalog to resolve against

GET /api/securitylevels exists (found in a HAR of the groups page; verified live on eqrm prod,
CT 3.135.2):

[ {"id":1,"name":"Stufe 1 (Niedrig)","sortKey":1},
  {"id":2,"name":"Stufe 2 (Mittel)","sortKey":2},
  {"id":3,"name":"Stufe 3 (Hoch)","sortKey":3},
  {"id":4,"name":"Stufe 4 (Sehr hoch)","sortKey":4} ]

Flat array, id + name — exactly the shape resolveFromCatalog already consumes for campuses,
departments, group types and person statuses. So this is a new CATALOG_PATH entry and a RefKind,
not new machinery:

{ right: "churchdb:+see persons", scope: [{ securityLevel: "stufe_3_hoch" }] }

Caveat worth weighing

Security-level names are localised German strings with parentheses ("Stufe 3 (Hoch)" slugs to
stufe_3_hoch), which is uglier and more brittle than 3 — a rename breaks the ref, where today it
would not. Two defensible positions:

  1. Add the ref kind, keep numerics working, and let a config choose. Portability where it matters,
    brevity where it does not.
  2. Decide the ids really are stable in practice and write that down as a verified assumption with
    the evidence (they are seeded by CT, sortkey-ordered, rarely touched) rather than leaving it as an
    aside in a code comment.

Either is fine. What is not fine is the current state: a load-bearing portability assumption that the
master-data registry quietly contradicts.

Acceptance

  • Decide and document whether cc_securitylevel ids are guaranteed stable across instances.
  • If not: securityLevel becomes a ref kind resolving through GET /securitylevels, numeric stays
    supported.
  • Either way, the "numeric hatch is safe for security levels" claim in scope.ts and in
    eqrm/ct-structure's docs is updated to match the finding.

Related: #109 (master-data registry, where this was found), #98 (typed scope refs), #49 (numeric hatch).

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageUnsorted intake — decide in the weekly sweep

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions