Skip to content

fix(BA-7861): refuse a fragment write at an owner nothing answers to as not found - #14568

Draft
jopemachine wants to merge 3 commits into
mainfrom
fix/BA-7861-fragment-write-missing-owner
Draft

fix(BA-7861): refuse a fragment write at an owner nothing answers to as not found#14568
jopemachine wants to merge 3 commits into
mainfrom
fix/BA-7861-fragment-write-missing-owner

Conversation

@jopemachine

@jopemachine jopemachine commented Sep 11, 2026

Copy link
Copy Markdown
Member

Summary

  • Writing an app config fragment for a domain or user id that names no row (scoped_upsert_app_config_fragments) answered VirtualEntityNotFound — an HTTP 500. app_config_fragments.scope_id has no foreign key (the owner is polymorphic), so the row went in first and the RBAC graph write behind it found no owner node.
  • The fragment write's processor now appends a scope validator, FragmentOwnerExistsValidator, through the validators= extension point ProcessorGroup already offers. It reads the owner row through the existing OpsRepository.get path and refuses a missing one as DomainNotFound / UserNotFound (404) — the same errors the scoped reads give — before the write starts. It runs after the RBAC validator, so a plain user is still refused for permission first.
  • Nothing outside services/app_config/ changes: no generic action, service, repository or write-ops signature is touched, and the write stays on the generic ops path (services/AGENTS.md: an action validator is what keeps a pass-through operation pass-through).

Not changed: VirtualEntityNotFound stays a 500 for what it is — a scope row that exists without its graph node is still an invariant violation, and only a check on the real owner row can tell the two apart.

Follow-up: the scenario row the-superadmin-naming-an-owner-nothing-answers-to-is-refused in #14513 pins the old 500 and switches to UserNotFound once this lands (one line and its document row); whichever of the two merges second carries it.

Found by the BA-7804 scenario research.

Test plan

  • tests/unit/manager/services/app_config/test_validators.py — a missing domain / user owner is refused as DomainNotFound / UserNotFound; an existing one passes
  • tests/unit/manager/actions/test_registry_catalog.py unchanged — the wiring adds a validator, not an action
  • The test(BA-7834): add scenario tests for the app config fragment adapter #14513 fragment write scenarios run against this branch: the missing-owner row now raises UserNotFound, the other 14 unchanged
  • mypy and ruff on the changed targets

Resolves BA-7861

🤖 Generated with Claude Code

https://claude.ai/code/session_011BnvoxSA2RSKgBkJ1yvC9P

jopemachine and others added 2 commits September 11, 2026 14:52
…as not found

Writing an app config fragment for a domain or user id that names no
row answered VirtualEntityNotFound, a 500: the row has no foreign key to
its owner, so it was inserted first and the graph write behind it found
no owner node.

An atomic entity upsert action may now name the operation scopes it
writes in, and the ops write validates their existence checks before any
row, in the same transaction. The fragment write names its owner's scope,
so a missing owner is refused as DomainNotFound or UserNotFound, the way
the scoped reads already refuse it. Every other upsert names no scope and
is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011BnvoxSA2RSKgBkJ1yvC9P
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011BnvoxSA2RSKgBkJ1yvC9P
@github-actions github-actions Bot added size:M 30~100 LoC comp:manager Related to Manager component labels Sep 11, 2026
…face alone

Undo the operation_scopes hook on the generic upsert action, service,
repository and write ops. The fragment write's processor appends a scope
validator instead — the extension point the group already offers — which
reads the owner row through the existing get path and refuses a missing
one as DomainNotFound or UserNotFound before the write starts. Nothing
outside the app config domain changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011BnvoxSA2RSKgBkJ1yvC9P
@github-actions github-actions Bot added size:L 100~500 LoC and removed size:M 30~100 LoC labels Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:manager Related to Manager component size:L 100~500 LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant