Skip to content

fix: skip field types before getattr and isolate detail prefetch#129

Open
haklyray wants to merge 1 commit into19.0from
fix/serialize-detail-skip-before-getattr
Open

fix: skip field types before getattr and isolate detail prefetch#129
haklyray wants to merge 1 commit into19.0from
fix/serialize-detail-skip-before-getattr

Conversation

@haklyray
Copy link

_serialize_detail called getattr() on all fields before checking if the field type should be skipped (many2many, one2many, binary). This triggered computed Many2many fields like household_member_ids, causing AccessError when the compute traverses res.partner records.

Also isolate get_detail() prefetch set via with_prefetch() to prevent sudo-contamination from _ensure_detail() causing record-rule checks against the wrong user (public user instead of authenticated user).

Why is this change needed?

When creating a Change Request via the FastAPI endpoint (e.g. add_member_4ps), _serialize_detail() triggers AccessError: Public user (id=3) doesn't have 'read' access to res.partner. This happens because:

  1. _serialize_detail() calls getattr(detail, field_name) on every field before checking if the field type (many2many, one2many, binary) should be skipped. For non-stored computed Many2many fields like household_member_ids, getattr triggers the compute method, which traverses res.partner records and fails with AccessError.

  2. get_detail() returns a record that shares the prefetch set with _ensure_detail()'s sudo() context. This causes Odoo's prefetch mechanism to trigger record-rule checks against the public user (uid=3, the FastAPI endpoint's base user) instead of the authenticated user.

How was the change implemented?

  1. spp_api_v2_change_request/services/change_request_service.py: Moved the field type check (many2many, one2many, binary) to run before getattr(). Previously these types were checked after getattr() had already triggered side effects. The skip set is defined once as _SKIP_FIELD_TYPES and checked in the loop before any field access.

  2. spp_change_request_v2/models/change_request.py: get_detail() now calls .with_prefetch() on the browsed record to isolate it from _ensure_detail()'s sudo prefetch set.

New unit tests

None — this is a bugfix to existing behavior, not a new feature. Existing tests should continue to pass.

Unit tests executed by the author

python -m odoo -c odoo-dev.conf -p 5679 --test-enable -i spp_change_request_v2,spp_api_v2_change_request --stop-after-init

How to test manually

  1. Configure FastAPI endpoint with user_id = base.public_user (the default)
  2. Authenticate via RS256 Keycloak token as a user with Change Requests / User group
  3. POST a Change Request submission that includes an addMembers section (type add_member_4ps)
  4. Before fix: AccessError — Public user (id=3) doesn't have 'read' access to res.partner
  5. After fix: CR created successfully, response returned with detail fields

Also verify CR creation via the Odoo web UI still works normally.

Related links

N/A

_serialize_detail called getattr() on all fields before checking if the
field type should be skipped (many2many, one2many, binary). This triggered
computed Many2many fields like household_member_ids, causing AccessError
when the compute traverses res.partner records.

Also isolate get_detail() prefetch set via with_prefetch() to prevent
sudo-contamination from _ensure_detail() causing record-rule checks
against the wrong user (public user instead of authenticated user).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses critical access and permission issues encountered during Change Request creation, particularly via FastAPI endpoints. It refines the serialization of detail fields by ensuring that certain field types are skipped before their values are accessed, preventing unintended side effects from computed fields. Additionally, it isolates the prefetch context for detail records to avoid incorrect record-rule checks caused by sudo() contamination, thereby enhancing security and stability.

Highlights

  • Prevented AccessError during detail serialization: The _serialize_detail method in change_request_service.py was triggering getattr() on all fields before checking if certain field types (many2many, one2many, binary) should be skipped. This caused computed fields to execute prematurely, leading to AccessError when traversing res.partner records with insufficient permissions. The fix moves the field type check to occur before getattr() is called.
  • Isolated detail prefetch set: The get_detail() method in change_request.py was returning records that shared their prefetch set with _ensure_detail()'s sudo() context. This could lead to Odoo's prefetch mechanism performing record-rule checks against the wrong user (e.g., public user instead of the authenticated user). The fix introduces .with_prefetch() to isolate the prefetch set for the detail record.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces two important fixes related to change request serialization and data fetching. The first fix correctly defers getattr calls on certain field types, preventing an AccessError on computed fields. The second fix properly isolates the prefetch cache to avoid user context contamination. The changes are logical and well-implemented. I have one suggestion to improve maintainability by removing a duplicated constant.

Comment on lines +207 to +209
# Field types that are skipped entirely — check BEFORE reading the
# value so that computed fields of these types are never triggered.
_SKIP_FIELD_TYPES = {"many2many", "one2many", "binary"}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability and avoid code duplication, it's better to reuse the SKIP_FIELD_TYPES constant that is already defined in odoo.addons.spp_api_v2.services.schema_builder and used elsewhere in this file (in _validate_detail_input).

I suggest you remove this local definition and instead:

  1. Add from odoo.addons.spp_api_v2.services.schema_builder import SKIP_FIELD_TYPES to the file's top-level imports.
  2. Use SKIP_FIELD_TYPES on line 215.
  3. Remove the now-redundant local import from _validate_detail_input.

@codecov
Copy link

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 69.97%. Comparing base (a8efe28) to head (0832042).
⚠️ Report is 1 commits behind head on 19.0.

Files with missing lines Patch % Lines
..._change_request/services/change_request_service.py 66.66% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##             19.0     #129    +/-   ##
========================================
  Coverage   69.96%   69.97%            
========================================
  Files         832      835     +3     
  Lines       48813    49138   +325     
========================================
+ Hits        34154    34385   +231     
- Misses      14659    14753    +94     
Flag Coverage Δ
spp_api_v2_change_request 66.85% <66.66%> (+0.18%) ⬆️
spp_base_common 90.26% <ø> (ø)
spp_change_request_v2 73.86% <100.00%> (-0.02%) ⬇️
spp_cr_types_advanced 0.00% <ø> (ø)
spp_cr_types_base 0.00% <ø> (ø)
spp_dci_demo 69.23% <ø> (ø)
spp_farmer_registry_cr 61.15% <ø> (ø)
spp_farmer_registry_demo 54.01% <ø> (ø)
spp_mis_demo_v2 69.73% <ø> (-0.09%) ⬇️
spp_programs 45.51% <ø> (ø)
spp_security 66.66% <ø> (ø)
spp_starter_social_registry 0.00% <ø> (ø)
spp_starter_sp_mis 81.25% <ø> (ø)
spp_studio_change_requests 84.67% <ø> (ø)

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

Files with missing lines Coverage Δ
spp_change_request_v2/models/change_request.py 83.81% <100.00%> (+0.83%) ⬆️
..._change_request/services/change_request_service.py 86.99% <66.66%> (+0.64%) ⬆️

... and 16 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.

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.

1 participant