java-topology/defects/trytond/SCAN.md

50 lines
2.6 KiB
Markdown

## Tryton (trytond) 5-MOAD Scan — 2026-03-31
Target: https://github.com/tryton/trytond (depth=1)
Focus: trytond/model/, trytond/ir/, trytond/res/, trytond/protocols/
### MOAD-0001 (CWE-407) — 1 PRE-EXISTING DEFECT (tryton-0001)
Tryton uses sets and dicts throughout hot paths. Specific checks:
- `ir/model.py` `fill_models()`: uses a list for visited-set dedup but the list is
bounded by the number of models in a single access check (typically 1-10) and is
only called at access-check time, not in a per-record inner loop. Low severity.
- `model/tree.py` `check_recursion()`: `visited = set()` throughout. O(1) lookup.
- `model/modelsql.py`: field membership checks use dicts/sets. O(1) throughout.
- `ir/translation.py`: `trans_reports` and `strings` are dicts. O(1) lookups.
- `ir/rule.py`: domain building uses `defaultdict(list)`, no membership scans.
- `model/modelstorage.py` `_save_values()`: pre-existing defect — `previous` list
O(T*P) in one2many/many2many save. Fixed in tryton-0001.
### MOAD-0002 (Intertangle) — CLEAN
`Pool` is our class registry (model, wizard, report types per database). It is
intentionally a registry/locator pattern, not a god object coupling subsystems.
Modules load independently via `load_modules`. Transaction, Pool, Cache and Model
layers are cleanly separated. No shared mutable state coupling unrelated subsystems.
### MOAD-0003 (Leaked Context) — CLEAN
`Transaction._local = threading.local()` is an intentional per-thread transaction
stack for the WSGI worker thread model. The `_request` context key is explicitly
stripped from cache keys (`cache.py` `_key()` strips `_request`). The transaction
carries user ID, database name, and context, which are properly scoped to each
thread's request lifetime and cleared on `stop()`. This is a standard WSGI
thread-per-request pattern, not a leaked identity defect.
### MOAD-0004 (CWE-312) — CLEAN
`protocols/dispatcher.py` routes `common.db.login` to its own `login()` function
that does NOT call `_safe_repr` or any logger with the `parameters` dict containing
the password. `security.login()` logs only username and remote address on success
or failure, never the password or session token. No SMTP or LDAP password logged
in any logger call found in trytond core.
### MOAD-0005 (Thundering Herd) — CLEAN
`MemoryCache` uses a per-transaction `_database_cache` (defaultdict of LRUDict).
The transaction isolation model means each transaction sees a consistent snapshot.
Cache invalidation uses PostgreSQL `NOTIFY` channels or a polling timeout, not
concurrent get+compute+set without synchronization. No unsynchronized
cache stampede pattern found.