Company tree: the ten-deep cap only measures upwards, so a chain built bottom-up grows past it and its group loses the top #532
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#532
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, readingCompany.cleanandCompany.groupand building a chain against a test database.Related to #55.
Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atjobs/models.py:367-403(Company.clean),jobs/models.py:405-418(Company.group) andjobs/forms.py:221-230(the parent choices inCompanyForm.scope_querysets).Company.cleanrefuses a parent when the chain above the new parent is more thanMAX_DEPTH(10) companies deep, but it ignores whatever already hangs under the company being edited. Giving the current top of a chain a new parent is always checked as a chain of two, so a chain built from the bottom up, or two chains joined, can grow without limit.Company.groupthen stops after ten steps and reports a company in the middle of the chain as the top.jobs/models.py:364-400(Company.clean:seen, node, depth = set(), self.parent, 1counts only upwards),jobs/models.py:402-415(Company.group, bounded byMAX_DEPTH), reached throughCompanyForm(jobs/forms.py:220-229offers any company outside the edited one's subtree as parent, and the model form runsCompany.clean)full_clean(). With fifteen companies (C0 at the bottom, C14 at the top),C0.groupis C10, not C14. The same happens when an existing six-deep chain is attached under another six-deep chain.group_members(), the companies list's?group=filter, the "across the group" figures and the rule deciding which departments an application may name all work on a partial group, silently. The cap's own comment says it exists so that a mistake cannot make a very deep chain that every page walks; it does not hold.Company.clean, whenself.pkis set, add the height of the company's own subtree (the longest path throughdescendants, with the same visited set) to the depth above the new parent, and refuse when the sum exceedsMAX_DEPTH.Done when
tests/test_company_tree.pybuilds a chain ofMAX_DEPTHcompanies, then gives its top a new parent and asserts thatfull_clean()raises the "more than 10 companies deep" error. It fails today.