Skip to content

security(spp_cel_domain): blanket base.group_user revoke on spp.data.value breaks DRIMS KPI computes [Severity: High if DRIMS-only roles exist] #348

Description

@gonzalesedwin1123

Deferred finding from the PR #234 access-control audit (internal/plans/pr234-dci-access-audit-findings.md, Finding 1). Re-verified live on 19.0 on 2026-07-24 — the "another PR" expected to cover this never materialized, so filing it for tracking.

Finding

spp_cel_domain/security/ir.model.access.csv:2 revokes base.group_user read on the entire spp.data.value cache (0,0,0,0), not just DCI-sensitive rows. read_values() (spp_cel_domain/models/data_value.py:433) runs a plain self.search(domain) with no .sudo(), so it executes under the caller's ACL.

DRIMS has store=True KPI computes that call read_values() in the operating user's context:

  • spp_drims/models/hazard_incident.py_compute_drims_kpis (~173/193), _compute_drims_stock_kpis (~217/238/243), _compute_drims_return_kpis (~391/405).

DRIMS groups (spp_drims/security/groups.xml) imply no cel_domain group and ship no ACL on model_spp_data_value. Impact: a DRIMS-only officer editing a donation/picking/return triggers a stored KPI recompute → AccessError → core DRIMS write workflow breaks. Users who also hold a programs role get cel_domain_viewer and are unaffected, so severity depends on whether DRIMS-only roles exist in a deployment.

Not caught by tests (DRIMS tests run as superuser). Wider blast radius to sweep: spp_drims/models/donation_line.py:159, returns.py:327,479, donation.py:538, stock_picking.py:317.

Design decision needed

  • Option A (preferred in the audit) — scope the protection: revert the blanket revoke; protect only DCI-sensitive rows via a record rule / dedicated group keyed on DCI-backed variable_name/source_type. Matches the original goal (hide disability/health values) without nuking PMT scores, household size, eligibility features, DRIMS KPIs.
  • Option B — sudo the readers: .sudo() the DRIMS cache reads (precedent: spp_studio_api_v2/services/variable_value_service.py:87,150; spp_cel_domain/models/data_cache_invalidation.py:85,132,198). Smaller diff but leaves the blanket revoke, so every base-user ORM reader must be audited forever.

Also: if the blanket revoke stays, docs/principles/access-rights.md:60-77 (documents spp.data.value as readable by all internal users) must change too. A with_user(group_drims_*) regression test should be added.

Source: internal/plans/pr234-dci-access-audit-findings.md. Related: #234, #235.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions