Skip to content

fix(BA-7773): open the last two image read paths that still require super-admin - #14413

Draft
jopemachine wants to merge 3 commits into
mainfrom
fix/BA-7773-installed-agents-public
Draft

fix(BA-7773): open the last two image read paths that still require super-admin#14413
jopemachine wants to merge 3 commits into
mainfrom
fix/BA-7773-installed-agents-public

Conversation

@jopemachine

@jopemachine jopemachine commented Sep 8, 2026

Copy link
Copy Markdown
Member

📚 Stacked PRs

This PR is part of a 2-PR stack. Merge in order:

  1. fix(BA-7772): open the image reads that a wiring swap can fix #14399fix(BA-7772): open the image reads that a wiring swap can fix (merged)
  2. 👉 fix(BA-7773): open the last two image read paths that still require super-admin #14413fix(BA-7773): open the last two image read paths that still require super-admin ← you are here

Rebased onto main now that #14399 has merged, so this PR's diff stands on its own.

Summary

Two commits, one per issue. Together with #14399 they finish opening the image reads that the v2 processor migration put behind the SUPERADMIN gate.

get_image_installed_agents (BA-7773). #14399 left this one out, on the stated grounds that opening it would expose the agent list. That was wrong. Its only production caller is ImageNode._batch_load_installed_agents, and the resolver reduces the answer to len(agent_ids) > 0. ImageNode declares no installed_agents field — that one belongs to the legacy Image type, which reads it off agent_install_status.agent_names at construction, on a path already applying hide_agents. No agent name leaves the manager through this action, so the gate only cost every non-superadmin the installed boolean. Wired through ProcessorGroup.public; no hide_agents branch needed.

search_images / search_aliases (BA-7774). One action served two audiences needing opposite gates: admin_search* (superadmin by design, per api/AGENTS.md) and the DataLoader batch_load_by_ids / batch_load_aliases_by_ids, reached from more than ten places in gql/data_loader/data_loaders.py by every authenticated caller. One action cannot carry two gates, so add the read the DataLoader actually performs — it names rows by id, which actions/AGENTS.md classifies as a bulk get, not a search. PublicGetImagesByIdsAction and PublicGetImageAliasesByIdsAction build the same by-ids querier inside the service and run behind the public gate. The search actions keep their gate; the admin handlers are untouched.

This also lands the get_images_by_ids that the deprecation notes on get_images_by_canonicals already point at, in both the repository and the service.

Backport: none

Same reasoning as #14399: on 26.8 and 26.4 these actions are wired as ActionProcessor(service.…, action_monitors) with no validators. The gate arrived on main with the v2 processor migration.

Resolves BA-7773.
Resolves BA-7774.

jopemachine added a commit that referenced this pull request Sep 8, 2026
@github-actions github-actions Bot added size:L 100~500 LoC comp:manager Related to Manager component labels Sep 8, 2026
Base automatically changed from fix/BA-7772-images-public-gate to main September 8, 2026 07:06
jopemachine and others added 3 commits September 8, 2026 16:10
…caller

`ImageNode.installed` is the one field this action feeds, and its resolver
reduces the answer to `len(agent_ids) > 0`. `ImageNode` declares no
`installed_agents` field -- that one belongs to the legacy `Image` type,
which reads it off `agent_install_status.agent_names` at construction, on a
path that already applies `hide_agents`. So no agent name leaves the manager
through this action, and the SUPERADMIN gate in front of it only cost every
non-superadmin the `installed` boolean.

Wire it through `ProcessorGroup.public` like the four reads BA-7772 moved.
The service method needs no `hide_agents` branch to make that safe: the
names never reach a caller.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HACXXC51LMccMUQLDVfxhg
`SearchImagesAction` and `SearchAliasesAction` served two audiences that
need opposite gates. `admin_search`, `admin_search_images_gql` and
`admin_search_image_aliases` back the REST v2 `admin_search_*` handlers,
which `api/AGENTS.md` defines as superadmin-only, so the SUPERADMIN gate is
right for them. `batch_load_by_ids` and `batch_load_aliases_by_ids` are
DataLoader entry points reached from more than ten places in
`gql/data_loader/data_loaders.py` by every authenticated caller, and they
answered `user_auth_forbidden`.

One action cannot carry two gates, so add the read the DataLoader actually
performs: it names the rows by id, which `actions/AGENTS.md` classifies as a
bulk get rather than a search. `PublicGetImagesByIdsAction` and
`PublicGetImageAliasesByIdsAction` build the same by-ids querier inside the
service and run behind the public gate; the two adapter methods call them.
The search actions keep their gate and the admin handlers are untouched.

This is the `get_images_by_ids` that the deprecation notes on
`get_images_by_canonicals` in the repository and the service point at.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HACXXC51LMccMUQLDVfxhg
@jopemachine
jopemachine force-pushed the fix/BA-7773-installed-agents-public branch from 267e5f7 to 9fe2ed9 Compare September 8, 2026 07:14
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