Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/opendox/default_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,20 @@ def resolve(self, repository: str | None,
def resolve_source(self, repository: str | None, ref: str | None,
tail: str) -> Path | None:
"""A `/source/` read through ONE entry, confined to that entry's own
root. An unknown pair, or an entry with no root, serves nothing."""
root. An unknown pair, or an entry with no root, serves nothing.

FOR A CALLER THAT HOLDS ONLY A PAIR. The pair is looked up here, once,
and the path is confined to the entry that one lookup returned. A
caller that ALREADY holds an entry must not ask again by its pair
(Copilot at openDox-code#59 0c946f4e, "previously missed"): a refresh
that re-registers the key in between puts another entry's root behind
the path, so the caller would decide by one entry and act on another.
It confines the entry in hand, through the seam's declared
`resolve_within(entry.source_root, tail)`, as `serve.py`'s `/source`
arm and `serve_project._resolved_listed_edit_entry` do. No module in
openDox calls this today, `tests/test_edit_action_one_entry.py` holds
it so, and it is on no seam's declared list, so nothing may rely on a
contributed registry having one."""
entry = self.resolve(repository, ref)
if entry is None or entry.source_root is None:
return None
Expand Down
33 changes: 29 additions & 4 deletions src/opendox/serve_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
from pathlib import Path

from opendox import action_errors
# THE CONTAINMENT RULE, THROUGH THE REGISTRY SEAM (plan 034 T055 follow-up):
# `_resolved_listed_edit_entry` reads `projection_seams.registry.current()` per
# call, so it confines by the registry registered at that moment, openDox's own
# where no host has contributed one, as `serve.py`'s `/source` arm does. No
# proxy is bound at module level here: `tests/test_projection_seams.py` holds
# the set of modules that bind one, and this module reads the seam in a body.
from opendox import projection_seams
from opendox.serve_wire import (
AGENT_INVOCATION_REFUSAL,
JSON_CTYPE,
Expand Down Expand Up @@ -103,14 +110,32 @@ def _edit_request_fields(body) -> tuple[tuple[str, str, str] | None, str | None]

def _resolved_listed_edit_entry(source, path: str, repository: str | None,
ref: str | None):
"""Return the selected entry only when its projected file is editable."""
"""Return the selected entry only when its projected file is editable.

ONE ENTRY, FOR THE LOOKUP, THE LISTED-PATH CHECK AND THE CONFINEMENT
(Copilot at openDox-code#59 0c946f4e, "previously missed"). The registry is
asked ONCE, and the path is confined to THAT entry's own root. It used to
be asked for the path by the entry's `(repository, ref)` pair, a second
lookup, so a refresh on another thread that re-registered the key between
the two put another entry's root behind the path: the route accepted or
refused a file by the replacement's root, while the listing it read and
the root the editor was started over were the first entry's. `serve.py`'s
`/source` arm holds the same rule since #59.

The confinement is the seam's declared `resolve_within`, which every
registry registration carries, and never a method of the registry instance:
`resolve_source` is on no seam's list, so a contributed registry is never
asked for one. An entry with no root serves nothing."""
registry = getattr(source, "registry", None) if source is not None else None
if registry is None:
return None
entry = registry.resolve(repository, ref)
target = registry.resolve_source(repository, ref, path)
if (entry is None or entry.source_root is None or target is None
or not target.is_file() or path not in _listed_source_paths(entry)):
root = None if entry is None else entry.source_root
if root is None:
return None
target = projection_seams.registry.current().resolve_within(Path(root), path)
if (target is None or not target.is_file()
or path not in _listed_source_paths(entry)):
return None
return entry

Expand Down
Loading
Loading