Skip to content

chore(spp_change_request_v2): drop dead hasattr() guards on hard-dependency fields (one of them is always False) #496

Description

@kneckinator

Filed at origin/19.0 (23f43963). From the expert review of #477.

Summary

spp_change_request_v2 guards accesses to res.partner registry fields with hasattr(), but spp_registry is a hard dependency (__manifest__.pydepends), so those fields always exist. The guards are dead code, and they read as defensive in places where the actual failure mode was a hard crash one line inside them — #476 was exactly that: hasattr(registrant, "group_membership_ids") passed, then the very next line raised KeyError: 'individual_id'.

Sites (all on origin/19.0):

Location Guard Field defined at
models/conflict_mixin.py:280 hasattr(registrant, "group_membership_ids") spp_registry/models/group.py:49
models/conflict_mixin.py:287 hasattr(registrant, "individual_membership_ids") spp_registry/models/individual.py:48
models/change_request.py:604 hasattr(reg, "group_membership_ids") as above
models/res_partner.py:46 hasattr(partner, "reg_ids") spp_registry/models/registrant.py:35
models/res_partner.py:52 hasattr(partner, "group_membership_ids") spp_registry/models/group.py:49
wizards/create_wizard.py:193 hasattr(reg, "group_membership_ids") spp_registry/models/group.py:49
models/change_request.py:662, :1129 hasattr(record/self, "_run_conflict_checks") spp.change.request unconditionally inherits spp.cr.conflict.mixin (models/change_request.py:18-23)

One guard is worse than dead — it is always False

models/change_request.py:585:

if hasattr(reg, "spp_id") and reg.spp_id:
    escaped_id = html_escape(reg.spp_id)
    html_parts.append(f'<div class="mb-2"><span class="badge bg-secondary">ID: {escaped_id}</span></div>')

No module in this repo defines spp_id on res.partner (grep -rn "spp_id = fields" → no hits repo-wide). The ID badge in registrant_summary_html therefore never renders, and the XSS regression test written for it passes trivially — test_registrant_summary_escapes_spp_id (tests/test_html_escaping.py:56-71) wraps its entire body, assertions included, in if hasattr(registrant, "spp_id"), which is never true.

Two related loose ends turned up while checking this, worth a look but not part of this cleanup:

  • spp_api_v2/routers/consent.py:236,238 read signatory_id.spp_id / group_id.spp_id unguarded — a latent AttributeError on that path if the field really does not exist there.
  • spp_change_request_v2/static/src/components/review_panel/review_panel.xml:89-92 renders state.registrantData.spp_id, which the same absence would make permanently empty.

Whoever picks this up should decide whether spp_id is meant to exist (add the field / bridge it) or whether these are leftovers from an earlier data model, and then either fix the branches or delete them.

Keep

  • models/change_request.py:862hasattr(detail, "prefill_from_registrant"): detail models are contributed by other modules and genuinely vary. Real duck-typing.
  • models/conflict_mixin.py:616hasattr(value, "ids"): a recordset-vs-scalar check on a field value. Real duck-typing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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