Skip to content

Commit 82c26ae

Browse files
jopemachineclaude
andcommitted
feat(BA-6628): add allow-list rank update across the v2 surface
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent d8b9699 commit 82c26ae

24 files changed

Lines changed: 443 additions & 4 deletions

File tree

.claude/skills/bai-cli/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ Check options with `--help`.
104104
- **prometheus-query-definition**: user(get, search, execute) · admin(create, update, delete, preview)
105105
- **prometheus-query-definition-category**: user(get, search) · admin(create, delete)
106106
- **app-config**: user(get-domain, get-user, get-merged, delete-domain, delete-user)
107+
- **app-config-definition**: admin(create, get, search, purge)
108+
- **app-config-allow-list**: admin(create, get, search, update, purge)
107109
- **export**: admin(list-reports, get-report, audit-logs, keypairs, projects, sessions, sessions-by-project, users, users-by-domain) · my(keypairs, sessions)
108110

109111
### Utilities (not entities)

changes/12517.feature.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Expose the app config allow-list merge `rank` on the v2 REST/GraphQL APIs and CLI — optional create input (scope-type default when omitted), node field, and order field
1+
Expose the app config allow-list merge `rank` on the v2 REST/GraphQL APIs and CLI — optional create input (scope-type default when omitted), node field, order field, and a new admin update operation (`PATCH /v2/app-config-allow-list/{id}`, `adminUpdateAppConfigAllowList`, `./bai admin app-config-allow-list update --rank`) for re-ordering the merge

docs/manager/graphql-reference/supergraph.graphql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11374,6 +11374,11 @@ type Mutation
1137411374
"""
1137511375
adminPurgeAppConfigAllowList(input: PurgeAppConfigAllowListInput!): PurgeAppConfigAllowListPayload @join__field(graph: STRAWBERRY)
1137611376

11377+
"""
11378+
Added in 26.8.0. Update an app config allow-list entry's rank by id (super admin only).
11379+
"""
11380+
adminUpdateAppConfigAllowList(input: UpdateAppConfigAllowListInput!): UpdateAppConfigAllowListPayload @join__field(graph: STRAWBERRY)
11381+
1137711382
"""
1137811383
Added in 25.14.0. Scan external registries to discover available artifacts. Searches HuggingFace or Reservoir registries for artifacts matching the specified criteria and registers them in the system with SCANNED status. The artifacts become available for import but are not downloaded until explicitly imported. This is the first step in the artifact workflow: Scan → Import → Use
1137911384
"""
@@ -19181,6 +19186,29 @@ input UpdateAllowedResourceGroupsForProjectInput
1918119186
remove: [String!] = null
1918219187
}
1918319188

19189+
"""
19190+
Added in 26.8.0. Input for updating an app config allow-list entry (rank only).
19191+
"""
19192+
input UpdateAppConfigAllowListInput
19193+
@join__type(graph: STRAWBERRY)
19194+
{
19195+
"""App config allow-list entry id to update."""
19196+
id: UUID!
19197+
19198+
"""
19199+
New merge rank applied to fragments under this entry (low to high; higher wins). Omit to leave unchanged.
19200+
"""
19201+
rank: Int = null
19202+
}
19203+
19204+
"""Added in 26.8.0. Payload for app config allow-list entry update."""
19205+
type UpdateAppConfigAllowListPayload
19206+
@join__type(graph: STRAWBERRY)
19207+
{
19208+
"""Updated app config allow-list entry."""
19209+
appConfigAllowList: AppConfigAllowList!
19210+
}
19211+
1918419212
"""
1918519213
Added in 24.09.0. Input for updating artifact metadata properties.
1918619214

docs/manager/graphql-reference/v2-schema.graphql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7233,6 +7233,11 @@ type Mutation {
72337233
"""
72347234
adminPurgeAppConfigAllowList(input: PurgeAppConfigAllowListInput!): PurgeAppConfigAllowListPayload
72357235

7236+
"""
7237+
Added in 26.8.0. Update an app config allow-list entry's rank by id (super admin only).
7238+
"""
7239+
adminUpdateAppConfigAllowList(input: UpdateAppConfigAllowListInput!): UpdateAppConfigAllowListPayload
7240+
72367241
"""
72377242
Added in 25.14.0. Scan external registries to discover available artifacts. Searches HuggingFace or Reservoir registries for artifacts matching the specified criteria and registers them in the system with SCANNED status. The artifacts become available for import but are not downloaded until explicitly imported. This is the first step in the artifact workflow: Scan → Import → Use
72387243
"""
@@ -13372,6 +13377,25 @@ input UpdateAllowedResourceGroupsForProjectInput {
1337213377
remove: [String!] = null
1337313378
}
1337413379

13380+
"""
13381+
Added in 26.8.0. Input for updating an app config allow-list entry (rank only).
13382+
"""
13383+
input UpdateAppConfigAllowListInput {
13384+
"""App config allow-list entry id to update."""
13385+
id: UUID!
13386+
13387+
"""
13388+
New merge rank applied to fragments under this entry (low to high; higher wins). Omit to leave unchanged.
13389+
"""
13390+
rank: Int = null
13391+
}
13392+
13393+
"""Added in 26.8.0. Payload for app config allow-list entry update."""
13394+
type UpdateAppConfigAllowListPayload {
13395+
"""Updated app config allow-list entry."""
13396+
appConfigAllowList: AppConfigAllowList!
13397+
}
13398+
1337513399
"""
1337613400
Added in 24.09.0. Input for updating artifact metadata properties.
1337713401

src/ai/backend/client/cli/v2/admin/app_config_allow_list.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,34 @@ async def _run() -> None:
156156
asyncio.run(_run())
157157

158158

159+
@app_config_allow_list.command()
160+
@click.argument("app_config_allow_list_id", type=click.UUID)
161+
@click.option(
162+
"--rank",
163+
required=True,
164+
type=int,
165+
help=("New merge rank applied to fragments under this entry (low to high; higher wins)."),
166+
)
167+
def update(app_config_allow_list_id: uuid.UUID, rank: int) -> None:
168+
"""Update an app config allow-list entry's rank by ID."""
169+
from ai.backend.common.dto.manager.v2.app_config_allow_list.request import (
170+
UpdateAppConfigAllowListInput,
171+
)
172+
173+
async def _run() -> None:
174+
registry = await create_v2_registry(load_v2_config())
175+
try:
176+
result = await registry.app_config_allow_list.admin_update(
177+
app_config_allow_list_id,
178+
UpdateAppConfigAllowListInput(id=app_config_allow_list_id, rank=rank),
179+
)
180+
print_result(result)
181+
finally:
182+
await registry.close()
183+
184+
asyncio.run(_run())
185+
186+
159187
@app_config_allow_list.command()
160188
@click.argument("app_config_allow_list_id", type=click.UUID)
161189
def purge(app_config_allow_list_id: uuid.UUID) -> None:

src/ai/backend/client/v2/domains_v2/app_config_allow_list.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
from ai.backend.common.dto.manager.v2.app_config_allow_list.request import (
1010
CreateAppConfigAllowListInput,
1111
SearchAppConfigAllowListInput,
12+
UpdateAppConfigAllowListInput,
1213
)
1314
from ai.backend.common.dto.manager.v2.app_config_allow_list.response import (
1415
AppConfigAllowListNode,
1516
CreateAppConfigAllowListPayload,
1617
PurgeAppConfigAllowListPayload,
1718
SearchAppConfigAllowListPayload,
19+
UpdateAppConfigAllowListPayload,
1820
)
1921

2022
_PATH: Final = "/v2/app-config-allow-list"
@@ -24,8 +26,8 @@ class V2AppConfigAllowListClient(BaseDomainClient):
2426
"""SDK client for app config allow-list operations.
2527
2628
Mirrors the REST v2 surface introduced in BA-6546. All calls require
27-
super-admin privileges; the entity supports create, get, search, and
28-
purge (no update or delete).
29+
super-admin privileges; the entity supports create, get, search, update
30+
(rank only), and purge.
2931
"""
3032

3133
async def admin_create(
@@ -60,6 +62,19 @@ async def admin_get(self, app_config_allow_list_id: UUID) -> AppConfigAllowListN
6062
response_model=AppConfigAllowListNode,
6163
)
6264

65+
async def admin_update(
66+
self,
67+
app_config_allow_list_id: UUID,
68+
request: UpdateAppConfigAllowListInput,
69+
) -> UpdateAppConfigAllowListPayload:
70+
"""Update an app config allow-list entry's rank by ID (superadmin only)."""
71+
return await self._client.typed_request(
72+
"PATCH",
73+
f"{_PATH}/{app_config_allow_list_id}",
74+
request=request,
75+
response_model=UpdateAppConfigAllowListPayload,
76+
)
77+
6378
async def admin_purge(
6479
self,
6580
app_config_allow_list_id: UUID,

src/ai/backend/common/dto/manager/v2/app_config_allow_list/request.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"CreateAppConfigAllowListInput",
2323
"PurgeAppConfigAllowListInput",
2424
"SearchAppConfigAllowListInput",
25+
"UpdateAppConfigAllowListInput",
2526
)
2627

2728

@@ -45,6 +46,23 @@ class CreateAppConfigAllowListInput(BaseRequestModel):
4546
)
4647

4748

49+
class UpdateAppConfigAllowListInput(BaseRequestModel):
50+
"""Input for updating an app config allow-list entry.
51+
52+
Only ``rank`` is updatable — the identity pair (``config_name``, ``scope_type``)
53+
is immutable (purge and recreate to change it).
54+
"""
55+
56+
id: UUID = Field(description="App config allow-list entry id to update.")
57+
rank: int | None = Field(
58+
default=None,
59+
description=(
60+
"New merge rank applied to fragments under this entry (low to high; "
61+
"higher wins). Omit to leave unchanged."
62+
),
63+
)
64+
65+
4866
class PurgeAppConfigAllowListInput(BaseRequestModel):
4967
"""Input for purging an app config allow-list entry."""
5068

src/ai/backend/common/dto/manager/v2/app_config_allow_list/response.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"CreateAppConfigAllowListPayload",
1616
"PurgeAppConfigAllowListPayload",
1717
"SearchAppConfigAllowListPayload",
18+
"UpdateAppConfigAllowListPayload",
1819
)
1920

2021

@@ -39,6 +40,14 @@ class CreateAppConfigAllowListPayload(BaseResponseModel):
3940
)
4041

4142

43+
class UpdateAppConfigAllowListPayload(BaseResponseModel):
44+
"""Payload for app config allow-list entry update."""
45+
46+
app_config_allow_list: AppConfigAllowListNode = Field(
47+
description="Updated app config allow-list entry."
48+
)
49+
50+
4251
class PurgeAppConfigAllowListPayload(BaseResponseModel):
4352
"""Payload for app config allow-list entry purge."""
4453

src/ai/backend/manager/api/adapters/app_config_allow_list/adapter.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
CreateAppConfigAllowListInput,
1414
PurgeAppConfigAllowListInput,
1515
SearchAppConfigAllowListInput,
16+
UpdateAppConfigAllowListInput,
1617
)
1718
from ai.backend.common.dto.manager.v2.app_config_allow_list.response import (
1819
AppConfigAllowListNode,
1920
CreateAppConfigAllowListPayload,
2021
PurgeAppConfigAllowListPayload,
2122
SearchAppConfigAllowListPayload,
23+
UpdateAppConfigAllowListPayload,
2224
)
2325
from ai.backend.common.dto.manager.v2.app_config_allow_list.types import (
2426
AppConfigAllowListOrderField,
@@ -40,8 +42,12 @@
4042
from ai.backend.manager.repositories.app_config_allow_list.creators import (
4143
AppConfigAllowListCreatorSpec,
4244
)
45+
from ai.backend.manager.repositories.app_config_allow_list.updaters import (
46+
AppConfigAllowListUpdaterSpec,
47+
)
4348
from ai.backend.manager.repositories.base import (
4449
Purger,
50+
Updater,
4551
combine_conditions_or,
4652
negate_conditions,
4753
)
@@ -58,6 +64,10 @@
5864
from ai.backend.manager.services.app_config_allow_list.actions.search import (
5965
SearchAppConfigAllowListAction,
6066
)
67+
from ai.backend.manager.services.app_config_allow_list.actions.update import (
68+
UpdateAppConfigAllowListAction,
69+
)
70+
from ai.backend.manager.types import OptionalState
6171

6272

6373
@lru_cache(maxsize=1)
@@ -144,6 +154,26 @@ async def admin_search(
144154
has_previous_page=action_result.has_previous_page,
145155
)
146156

157+
async def admin_update(
158+
self, input: UpdateAppConfigAllowListInput
159+
) -> UpdateAppConfigAllowListPayload:
160+
updater = Updater(
161+
spec=AppConfigAllowListUpdaterSpec(
162+
rank=(
163+
OptionalState.update(input.rank)
164+
if input.rank is not None
165+
else OptionalState.nop()
166+
),
167+
),
168+
pk_value=AppConfigAllowListID(input.id),
169+
)
170+
action_result = await self._processors.app_config_allow_list.update.wait_for_complete(
171+
UpdateAppConfigAllowListAction(updater=updater)
172+
)
173+
return UpdateAppConfigAllowListPayload(
174+
app_config_allow_list=self._data_to_node(action_result.allow_list),
175+
)
176+
147177
async def admin_purge(
148178
self, input: PurgeAppConfigAllowListInput
149179
) -> PurgeAppConfigAllowListPayload:

src/ai/backend/manager/api/gql/app_config_allow_list/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
admin_app_config_allow_lists,
66
admin_create_app_config_allow_list,
77
admin_purge_app_config_allow_list,
8+
admin_update_app_config_allow_list,
89
)
910
from .types import (
1011
AppConfigAllowListConnection,
@@ -37,4 +38,5 @@
3738
# Mutation resolvers
3839
"admin_create_app_config_allow_list",
3940
"admin_purge_app_config_allow_list",
41+
"admin_update_app_config_allow_list",
4042
)

0 commit comments

Comments
 (0)