Skip to content

fix: two install/runtime crashes from the DCBO report (TOTP column leak + auditlog rule collision) - #6

Open
rutgerhofste wants to merge 2 commits into
19.0from
fix/apikeys-fields-leak-to-totp-device
Open

fix: two install/runtime crashes from the DCBO report (TOTP column leak + auditlog rule collision)#6
rutgerhofste wants to merge 2 commits into
19.0from
fix/apikeys-fields-leak-to-totp-device

Conversation

@rutgerhofste

@rutgerhofste rutgerhofste commented Jul 9, 2026

Copy link
Copy Markdown
Member

Fixes two separate issues reported by Mil Cuyvers (DCBO Open Solutions) via support@pantalytics.com, both hit while installing/using MCP Pro Governance on a database that already ran OCA auditlog with 2FA in use.


1. User form crashes: UndefinedColumn: auth_totp_device.x_role_id

Root cause

auth_totp.device uses prototype inheritance of our extended model:

class Auth_TotpDevice(models.Model):
    _name = 'auth_totp.device'
    _inherit = ["res.users.apikeys"]   # different _name → copies fields onto its own table
    _auto = False

So Odoo copies our x_role_id, x_state, x_last_used, x_use_count fields onto auth_totp.device too, but our init() hard-coded res_users_apikeys as the DDL target, so the columns were never created on auth_totp_device. Reading a user's trusted TOTP devices (the user-form onchange snapshots totp_trusted_device_ids) then hits the missing column. The customer's own diagnosis was spot-on.

Fix

init() is inherited by auth_totp.device (which defines none of its own), so it already runs for both models — it just always wrote to the wrong table. Keying every statement on self._table (via odoo.tools.SQL) provisions the columns on whichever table is being initialised. Existing DBs heal on upgrade; no manual migration.

Verified

On a fresh DB (auth_totp + module): before, auth_totp_device had none of the columns and the read crashed; after, both tables carry all four columns + indexes and the previously-crashing search_read returns cleanly.


2. Install aborts: UniqueViolation: auditlog_rule_model_uniq

Root cause

post_init_hook seeds a draft auditlog.rule per AI-target model, but auditlog.rule enforces unique(model_id) (one rule per model). The hook only skipped a model when a rule with our exact name already existed. A DB that already had an audit rule on that model under a different name (e.g. migrated from a pre-existing OCA auditlog install) tripped the constraint and the whole install failed.

Fix

Skip a model when any auditlog.rule already exists for it, leaving the operator's rule untouched.

Verified

On a fresh DB with a pre-existing partner rule under a different name, the old hook raised UniqueViolation: auditlog_rule_model_uniq; after the change the hook skips the model and installs cleanly.


Housekeeping

  • Regression tests: TestApiKeyFieldsOnTotpDevice and TestPostInitHook.test_preexisting_rule_on_model_does_not_break_install.
  • Manifest → 19.0.1.20.3, CHANGELOG updated.
  • Single 19.0 branch serves 17/18/19; the customer is on the 18.0.x build and both fixes are version-agnostic (odoo.tools.SQL exists since 17.0), so all published builds are covered.

🤖 Generated with Claude Code

rutgerhofste and others added 2 commits July 9, 2026 15:48
`auth_totp.device` inherits `res.users.apikeys` by prototype inheritance
(`_inherit` with a distinct `_name`, `_auto = False`), so Odoo copies our
x_role_id / x_state / x_last_used / x_use_count fields onto its own
`auth_totp_device` table. Our `init()` hard-coded `res_users_apikeys` as
the ALTER/CREATE INDEX target, so those columns were never created on
`auth_totp_device`. Any ORM read of a trusted TOTP device — e.g. the user
form snapshotting `totp_trusted_device_ids` while granting another user
MCP Pro admin rights — then raised
`psycopg2.errors.UndefinedColumn: auth_totp_device.x_role_id`.

`init()` is inherited by `auth_totp.device` (which defines none of its
own), so keying every statement on `self._table` provisions the columns
on whichever table is being initialised. Existing databases heal on
upgrade; no manual migration needed.

Reproduced and verified on a fresh DB (auth_totp + module): before, the
columns were absent on auth_totp_device and present on res_users_apikeys;
after upgrade, both tables carry all four columns and the previously
crashing ORM read succeeds.

Reported by Mil Cuyvers (DCBO Open Solutions) via support@pantalytics.com.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the model

`auditlog.rule` enforces `unique(model_id)` (one rule per model), but
`post_init_hook` only skipped a model when a rule with OUR exact name was
already present. A database that already had an audit rule on a target
model under a different name — e.g. migrated from a pre-existing OCA
`auditlog` install — hit the constraint when the hook tried to create a
second rule, aborting the whole module install.

Skip a model when ANY auditlog.rule already exists for it, leaving the
operator's own rule untouched.

Reproduced on a fresh DB: with a pre-existing partner rule under a
different name, the old hook raised
`UniqueViolation: auditlog_rule_model_uniq`; after the change the hook
skips the model and installs cleanly.

Second issue from the same report by Mil Cuyvers (DCBO Open Solutions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rutgerhofste rutgerhofste changed the title fix: apikeys x_* fields leak to auth_totp.device, crashing the user form fix: two install/runtime crashes from the DCBO report (TOTP column leak + auditlog rule collision) Jul 9, 2026
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