Skip to content

[IMP] fs_attachment: use sudo() for accessing storage code in ir_attachment#559

Open
CRogos wants to merge 1 commit intoOCA:18.0from
c4a8-odoo:18.0-ticket-1298
Open

[IMP] fs_attachment: use sudo() for accessing storage code in ir_attachment#559
CRogos wants to merge 1 commit intoOCA:18.0from
c4a8-odoo:18.0-ticket-1298

Conversation

@CRogos
Copy link

@CRogos CRogos commented Mar 6, 2026

Solves: #536

I don't know the exact reason why/when this happens, but from time to time users got access errors on attachments located in an Azure blob storage. We've added a stack trace (see below) for deeper analysis.
Since we've added these changes, these errors did not occur again.

2026-02-19 09:57:40,233 51698 ERROR c4a8-production-1830547 odoo.addons.c4a8_logging.models.ir_model_access: Access DENIED - User: xxxx (UID: 13), Model: fs.storage, Mode: read 
Stack (most recent call last):
  File "/usr/lib/python3.12/threading.py", line 1030, in _bootstrap
    self._bootstrap_inner()
  File "/usr/lib/python3.12/threading.py", line 1073, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.12/threading.py", line 1010, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.12/socketserver.py", line 692, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib/python3.12/socketserver.py", line 362, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/home/odoo/src/odoo/odoo/service/server.py", line 128, in __init__
    super().__init__(*args, **kwargs)
  File "/usr/lib/python3.12/socketserver.py", line 761, in __init__
    self.handle()
  File "/usr/lib/python3/dist-packages/werkzeug/serving.py", line 390, in handle
    super().handle()
  File "/usr/lib/python3.12/http/server.py", line 436, in handle
    self.handle_one_request()
  File "/usr/lib/python3.12/http/server.py", line 424, in handle_one_request
    method()
  File "/usr/lib/python3/dist-packages/werkzeug/serving.py", line 362, in run_wsgi
    execute(self.server.app)
  File "/usr/lib/python3/dist-packages/werkzeug/serving.py", line 323, in execute
    application_iter = app(environ, start_response)
  File "/home/odoo/src/odoo/odoo/http.py", line 2576, in __call__
    response = request._serve_db()
  File "/home/odoo/src/odoo/odoo/http.py", line 2103, in _serve_db
    return self._transactioning(
  File "/home/odoo/src/odoo/odoo/http.py", line 2166, in _transactioning
    return service_model.retrying(func, env=self.env)
  File "/home/odoo/src/odoo/odoo/service/model.py", line 157, in retrying
    result = func()
  File "/home/odoo/src/odoo/odoo/http.py", line 2133, in _serve_ir_http
    response = self.dispatcher.dispatch(rule.endpoint, args)
  File "/home/odoo/src/odoo/odoo/http.py", line 2294, in dispatch
    return self.request.registry['ir.http']._dispatch(endpoint)
  File "/home/odoo/src/odoo/odoo/addons/base/models/ir_http.py", line 333, in _dispatch
    result = endpoint(**request.params)
  File "/home/odoo/src/odoo/odoo/http.py", line 754, in route_wrapper
    result = endpoint(self, *args, **params_ok)
  File "/home/odoo/src/odoo/addons/mail/models/discuss/mail_guest.py", line 38, in wrapper
    return func(self, *args, **kwargs)
  File "/home/odoo/src/odoo/addons/mail/controllers/discuss/binary.py", line 68, in content_image
    return super().content_image(*args, **kwargs)
  File "/home/odoo/src/odoo/odoo/http.py", line 754, in route_wrapper
    result = endpoint(self, *args, **params_ok)
  File "/home/odoo/src/odoo/addons/web/controllers/binary.py", line 185, in content_image
    stream = request.env['ir.binary']._get_image_stream_from(
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_binary.py", line 137, in _get_image_stream_from
    stream.data = stream.read()
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/fs_stream.py", line 37, in read
    with self.fs_attachment.open("rb") as f:
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 1011, in __enter__
    self._file_open()
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 1031, in _file_open
    fs, _storage, fname = self.attachment._get_fs_parts()
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 585, in _get_fs_parts
    return self._fs_parse_store_fname(self.store_fname)
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 516, in _fs_parse_store_fname
    fs = self._get_fs_storage_for_code(storage_code)
  File "/home/odoo/src/user/modules/oca/storage/fs_attachment/models/ir_attachment.py", line 500, in _get_fs_storage_for_code
    fs = self.env["fs.storage"].get_fs_by_code(code)
  File "/home/odoo/src/user/modules/oca/storage/fs_storage/models/fs_storage.py", line 359, in get_fs_by_code
    use_cache = not force_no_cache and self._is_fs_cacheable(code)
  File "/usr/lib/python3/dist-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/home/odoo/src/odoo/odoo/tools/cache.py", line 110, in lookup
    value = d[key] = self.method(*args, **kwargs)
  File "/home/odoo/src/user/modules/oca/storage/fs_storage/models/fs_storage.py", line 339, in _is_fs_cacheable
    return fs_storage and fs_storage.is_cacheable
  File "/home/odoo/src/odoo/odoo/fields.py", line 1274, in __get__
    recs._fetch_field(self)
  File "/home/odoo/src/odoo/odoo/models.py", line 4115, in _fetch_field
    self.fetch(fnames)
  File "/home/odoo/src/odoo/odoo/models.py", line 4137, in fetch
    query = self.with_context(active_test=False)._search([('id', 'in', self.ids)])
  File "/home/odoo/src/odoo/odoo/models.py", line 5807, in _search
    self.browse().check_access('read')
  File "/home/odoo/src/odoo/odoo/models.py", line 4439, in check_access
    raise result[1]()
  File "/home/odoo/src/user/modules/c4a8/custom/c4a8_logging/models/ir_model_access.py", line 16, in _make_access_error
    _logger.error(
2026-02-19 09:57:40,233 51698 INFO c4a8-production-1830547 odoo.addons.base.models.ir_model: Access Denied by ACLs for operation: read, uid: 13, model: fs.storage 

@OCA-git-bot
Copy link
Contributor

Hi @lmignon,
some modules you are maintaining are being modified, check this out!

Copy link
Contributor

@lmignon lmignon left a comment

Choose a reason for hiding this comment

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

Thank you for the fix @CRogos In my opinion (and it makes sense) the only required sudo to fix the problem is the one added into the `is_fs_cacheable' method. The others should be removed.

):
if self.attachment._is_file_from_a_storage(self.attachment.store_fname):
fs, _storage, fname = self.attachment._get_fs_parts()
fs, _storage, fname = self.attachment.sudo()._get_fs_parts()
Copy link
Contributor

Choose a reason for hiding this comment

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

according to the stack trace the only the sudo() required to fix the problem is the one added into the is_fs_cacheable method of the `fs.storage' model. This change should be revert.

Copy link
Author

Choose a reason for hiding this comment

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

Based on the provided stack traces I agree. I'll give it a try and wait for the feedback of the testers.

new_filepath,
) = self.attachment._fs_parse_store_fname(new_store_fname)
_fs, _storage, old_filepath = self.attachment._get_fs_parts()
_fs, _storage, old_filepath = self.attachment.sudo()._get_fs_parts()
Copy link
Contributor

Choose a reason for hiding this comment

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

See previous comment.

@CRogos CRogos force-pushed the 18.0-ticket-1298 branch from 35c86b8 to 5a70923 Compare March 9, 2026 08:09
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.

3 participants