Skip to content

feat(registry): per-action opt-out for registry admin-only CRUD restriction#299

Open
gonzalesedwin1123 wants to merge 2 commits into
19.0from
feat/registry-restriction-context-bypass
Open

feat(registry): per-action opt-out for registry admin-only CRUD restriction#299
gonzalesedwin1123 wants to merge 2 commits into
19.0from
feat/registry-restriction-context-bypass

Conversation

@gonzalesedwin1123

@gonzalesedwin1123 gonzalesedwin1123 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Closes #298

What

Honor a bypass_registry_admin_only_crud: True flag in an action's context so that action's res.partner views are exempt from the registry_admin_only_crud restriction, while other partner views keep it. The change is in spp_starter_sp_mis/static/src/js/registry_restriction.js.

Usage:

<field name="context">{'bypass_registry_admin_only_crud': True}</field>

Semantics (documented in the docstring and DESCRIPTION.md):

  • The flag follows Odoo's standard context propagation: the exempt action's list/form plus relational dialogs (many2one create/edit and search-more, x2many record dialogs) and actions opened via buttons from inside the exempt view inherit it. This is what authoring flows need; implementers should scope bypass actions deliberately.
  • Exempt form views also disable useSendBeaconToSaveUrgently: authoring actions typically carry default_* context keys that make a new record dirty before the user types, and the blur-triggered urgent save would otherwise raise validation errors on every tab refocus.
  • Like the restriction itself, the flag is a client-side UI affordance, not a security boundary — server-side ACLs and record rules remain the real enforcement.

Why

Downstream implementations sometimes need one dedicated res.partner action where a non-admin role can author records while all other partner views stay restricted. Without a supported opt-out they have to counter-patch ListController/FormController against Odoo web internals; this gives them a supported seam (the flag name matches what downstream workarounds already use, so they can delete their patches directly — the beacon-save opt-out included).

How

In both controller patches the bypass is checked alongside the existing REGISTRY_MODELS guard: the synchronous _registryRestricted cache check ANDs in the bypass, and the post-super.setup() early return also returns when the flag is set — so onWillStart, the DOM enforcement, modelParams readonly forcing, and the action-menu filtering are all skipped for the exempt views. The modelParams getter additionally sets useSendBeaconToSaveUrgently = false on the bypass path.

Versioning / docs

  • spp_starter_sp_mis: 19.0.2.0.0 → 19.0.2.1.0 + HISTORY fragment; opt-out documented in DESCRIPTION.md
  • README.rst/index.html regenerated by applying CI's printed diffs verbatim (local generator output is not byte-identical to CI's)

Testing

The change is JS-only and the repo has no executable JS test infrastructure (no Chrome in the Docker image, no tour runner), so coverage is manual, authorized by the maintainer:

  • ./spp t spp_starter_sp_mis: 1 passed, 0 failed, 0 errors
  • pre-commit hooks on changed files: all passed (eslint, prettier, semgrep, OpenSPP checks)
  • Manual UI verification, executed twice (initial implementation and again on the amended code) with headless Chrome against a live --demo mis stack: non-admin Registry Officer sees no New button on a plain partner action; New button + genuinely editable create form on the bypass-context action; admin unaffected — details in the PR comments
  • Expert-review pass (code review, Odoo 19 web-internals deep-dive verified against framework source, security review): no critical findings; the review's amendments are included — summary in the PR comments

@gemini-code-assist

Copy link
Copy Markdown

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.68%. Comparing base (84fe095) to head (de23a45).
⚠️ Report is 43 commits behind head on 19.0.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             19.0     #299      +/-   ##
==========================================
+ Coverage   71.58%   71.68%   +0.10%     
==========================================
  Files         418      423       +5     
  Lines       26747    26895     +148     
==========================================
+ Hits        19146    19281     +135     
- Misses       7601     7614      +13     
Flag Coverage Δ
spp_base_common 90.26% <ø> (ø)
spp_dci_demo 93.39% <ø> (?)
spp_mis_demo_v2 73.93% <ø> (+0.21%) ⬆️
spp_programs 65.27% <ø> (ø)
spp_registry 86.83% <ø> (ø)
spp_security 66.66% <ø> (ø)
spp_starter_sp_mis 81.25% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
spp_starter_sp_mis/__manifest__.py 0.00% <ø> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gonzalesedwin1123

gonzalesedwin1123 commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

Test and verification results:

Python suite (Docker, isolated):

  • ./spp t spp_starter_sp_mis: 1 passed, 0 failed, 0 errors

Manual UI verification — executed against a local --demo mis stack (fresh DB, spp_starter.registry_admin_only_crud=True) with a headless-Chrome script driving a real session. Fixtures: a non-admin user (internal + Registry Officer only, confirmed not in spp_security.group_spp_admin) and two res.partner act_windows — one plain, one with {'bypass_registry_admin_only_crud': True} in its context. Results:

Check Result
Non-admin, plain action: New button hidden (restriction intact) ✅ present but display:none
Non-admin, bypass action: New button visible ✅ visible
Non-admin, bypass action → New: form opens editable (o_form_editable, Save visible, inputs enabled)
Admin, plain action: New button visible (admin unaffected)

Screenshots confirm the same non-admin session sees no New button on the plain partner list and the New button on the bypass action.

READMEs were regenerated by applying CI's printed diff verbatim (local generator output is not byte-identical to CI's).

@gonzalesedwin1123

gonzalesedwin1123 commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

Expert Review Summary

Three parallel reviews were run on this PR: repo code-reviewer (principles/compliance), an Odoo 19 web-internals deep-dive (verified against the framework source in the openspp-dev image), and a security review. Verdict: sound to ship, no critical findings. The reviews' amendments are included in the PR.

Findings → resolution

  • [security] Docstring framed a UI toggle as access delegation → the docstring now states the flag is a UI affordance, NOT a security boundary; server-side ACLs/record rules remain the real enforcement, and any user who can write ir.actions.act_window can set the flag.
  • [internals] Context propagation is wider than "that action's own list+form" — verified against getFieldContext/CTX_KEY_REGEX in the framework source: relational dialogs (m2o create/search-more, x2many record dialogs), expanded dialogs, and button-opened actions inherit the flag (desirable for authoring flows, but must be stated); breadcrumb restore and m2o internal-links do NOT leak it → documented in the docstring + DESCRIPTION.md so implementers scope bypass actions deliberately.
  • [internals] Downstream decommissioning gap: the known downstream counter-patch also disables useSendBeaconToSaveUrgently because authoring actions carry default_* keys that make new records dirty before the user types — without it, the blur-triggered beacon save raises validation errors on every tab refocus once the downstream file is removed → replicated upstream in the bypass branch of modelParams.
  • [code-review] Flag undocumented in module docs → added to spp_starter_sp_mis/readme/DESCRIPTION.md Implementation Details.
  • [code-review] Double evaluation of the bypass check in FormController.setup → hoisted to const bypassed.

Noted for follow-up (not this PR)

Verified facts from the deep-dive

props.context is guaranteed present at both points of use (required standard view prop, populated before controller instantiation); _registryRestricted === undefined on the early-return path behaves identically to false everywhere it's read (pre-existing pattern); the 30s restriction cache is unaffected; coexistence with the downstream counter-patch is conflict-free and actually calmer (the observer tug-of-war disappears while both are installed).

Re-verification after amendments

Headless-Chrome checks re-run against a live stack on the amended code — all four pass: non-admin plain action New hidden; non-admin bypass action New visible; bypass create form editable with Save; admin unaffected.

…iction

Honor bypass_registry_admin_only_crud in an action's context so that
action's res.partner views are exempt from the registry restriction
while other partner views keep it. The flag follows Odoo's standard
context propagation (relational dialogs and button-opened actions from
the exempt view inherit it), and exempt form views also disable
useSendBeaconToSaveUrgently: authoring actions typically carry default_*
keys that make a new record dirty before the user types, so the
blur-triggered beacon save would raise validation errors on every tab
refocus.

Downstreams that need a dedicated non-admin role to author one registry
list can set the flag on that action instead of counter-patching the
controllers. The flag is a UI affordance, not a security boundary:
server-side ACLs and record rules remain the real enforcement, as
documented in the docstring and DESCRIPTION.md.
@gonzalesedwin1123 gonzalesedwin1123 force-pushed the feat/registry-restriction-context-bypass branch from a397da0 to de23a45 Compare July 10, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spp_starter_sp_mis: make registry_admin_only_crud opt-out per action, not a global New-button hide

1 participant