ukaea / ukaea/fds

add_child_collection: enforce DAG by rejecting indirect cycles

Open
#46 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
1
Avg merge
26m
Merged PRs (30d)
24

Description

Problem

A Collection nests other Collections (CollectionMember parent→child) and is described as a DAG (acyclic). add_child_collection only guards the direct self-loop:

  • parent_id == child_id → rejected
  • already-a-child → ConflictError

There is no check for indirect cycles. Nesting B under A, C under B, then A under C closes a 3-hop loop, and the code accepts it. So acyclicity is enforced only at depth 1.

Impact

Any recursive walk of the nesting then loops (infinite recursion / stack blow-up). Live consumers:

  • children expansion in the collection response (collection_service ~L493)
  • get_effective_access_level, which walks a collection's relations

Footgun in normal use; a DoS vector if collection nesting is ever exposed to less-trusted writers.

Fix

In add_child_collection, reject the edge if parent is already a descendant of child (ancestor/descendant check), not just the direct parent_id == child_id case.

Scope note

Missing validation, not a data-model flaw — surfaced while pressure-testing the context/run/curation model. Independent of that ADR.


Migrated from the internal tracker, where it was #17, opened 2026-06-25.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating add_child_collection and the children expansion in collection_service around L493. Trace how parent and child relations are traversed, then verify that adding an edge from a collection to one of its descendants is rejected while direct self-loops and duplicate children retain their existing behavior. Done means indirect cycles cannot be created and recursive collection access remains bounded.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.