Skip to content

Commit 2a47dd4

Browse files
fregataaclaude
andauthored
feat(BA-5078): Apply RBAC Creator pattern to ArtifactRevision (#10021)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 2c538ba commit 2a47dd4

3 files changed

Lines changed: 95 additions & 26 deletions

File tree

changes/10021.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Apply RBAC Creator pattern to ArtifactRevision for consistent entity creation and access control

src/ai/backend/manager/repositories/artifact/creators.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44

55
import uuid
66
from dataclasses import dataclass
7+
from datetime import datetime
78
from typing import Any, override
89

910
from ai.backend.common.data.artifact.types import ArtifactRegistryType
10-
from ai.backend.manager.data.artifact.types import ArtifactType
11+
from ai.backend.manager.data.artifact.types import (
12+
ArtifactRemoteStatus,
13+
ArtifactStatus,
14+
ArtifactType,
15+
)
1116
from ai.backend.manager.models.artifact import ArtifactRow
17+
from ai.backend.manager.models.artifact_revision.row import ArtifactRevisionRow
1218
from ai.backend.manager.repositories.base.creator import CreatorSpec
1319

1420

@@ -39,3 +45,49 @@ def build_row(self) -> ArtifactRow:
3945
description=self.description,
4046
extra=self.extra,
4147
)
48+
49+
50+
@dataclass
51+
class ArtifactRevisionCreatorSpec(CreatorSpec[ArtifactRevisionRow]):
52+
"""CreatorSpec for artifact revision creation."""
53+
54+
artifact_id: uuid.UUID
55+
version: str
56+
readme: str | None = None
57+
size: int | None = None
58+
status: ArtifactStatus = ArtifactStatus.SCANNED
59+
remote_status: ArtifactRemoteStatus | None = None
60+
created_at: datetime | None = None
61+
updated_at: datetime | None = None
62+
digest: str | None = None
63+
verification_result: dict[str, Any] | None = None
64+
id: uuid.UUID | None = None
65+
66+
@override
67+
def build_row(self) -> ArtifactRevisionRow:
68+
if self.id is not None:
69+
return ArtifactRevisionRow(
70+
id=self.id,
71+
artifact_id=self.artifact_id,
72+
version=self.version,
73+
readme=self.readme,
74+
size=self.size,
75+
status=self.status.value,
76+
remote_status=self.remote_status.value if self.remote_status else None,
77+
created_at=self.created_at,
78+
updated_at=self.updated_at,
79+
digest=self.digest,
80+
verification_result=self.verification_result,
81+
)
82+
return ArtifactRevisionRow(
83+
artifact_id=self.artifact_id,
84+
version=self.version,
85+
readme=self.readme,
86+
size=self.size,
87+
status=self.status.value,
88+
remote_status=self.remote_status.value if self.remote_status else None,
89+
created_at=self.created_at,
90+
updated_at=self.updated_at,
91+
digest=self.digest,
92+
verification_result=self.verification_result,
93+
)

src/ai/backend/manager/repositories/artifact/db_source/db_source.py

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040
from ai.backend.manager.models.artifact_revision import ArtifactRevisionRow
4141
from ai.backend.manager.models.association_artifacts_storages import AssociationArtifactsStorageRow
4242
from ai.backend.manager.models.utils import ExtendedAsyncSAEngine
43-
from ai.backend.manager.repositories.artifact.creators import ArtifactCreatorSpec
43+
from ai.backend.manager.repositories.artifact.creators import (
44+
ArtifactCreatorSpec,
45+
ArtifactRevisionCreatorSpec,
46+
)
4447
from ai.backend.manager.repositories.base import BatchQuerier, execute_batch_querier
4548
from ai.backend.manager.repositories.base.rbac.entity_creator import (
4649
RBACEntityCreator,
@@ -231,23 +234,27 @@ async def upsert_artifact_revisions(
231234
if revision_data.verification_result is not None:
232235
verification_result = revision_data.verification_result.model_dump()
233236

234-
new_revision = ArtifactRevisionRow(
235-
id=revision_data.id,
236-
artifact_id=revision_data.artifact_id,
237-
version=revision_data.version,
238-
readme=revision_data.readme,
239-
size=revision_data.size,
240-
status=ArtifactStatus.SCANNED,
241-
remote_status=revision_data.remote_status,
242-
created_at=revision_data.created_at,
243-
updated_at=revision_data.updated_at,
244-
digest=revision_data.digest,
245-
verification_result=verification_result,
237+
creator = RBACEntityCreator(
238+
spec=ArtifactRevisionCreatorSpec(
239+
id=revision_data.id,
240+
artifact_id=revision_data.artifact_id,
241+
version=revision_data.version,
242+
readme=revision_data.readme,
243+
size=revision_data.size,
244+
status=ArtifactStatus.SCANNED,
245+
remote_status=revision_data.remote_status,
246+
created_at=revision_data.created_at,
247+
updated_at=revision_data.updated_at,
248+
digest=revision_data.digest,
249+
verification_result=verification_result,
250+
),
251+
element_type=RBACElementType.ARTIFACT_REVISION,
252+
scope_ref=RBACElementRef(
253+
RBACElementType.ARTIFACT, str(revision_data.artifact_id)
254+
),
246255
)
247-
db_sess.add(new_revision)
248-
await db_sess.flush()
249-
await db_sess.refresh(new_revision)
250-
result_revisions.append(new_revision.to_dataclass())
256+
creator_result = await execute_rbac_entity_creator(db_sess, creator)
257+
result_revisions.append(creator_result.row.to_dataclass())
251258
artifact_ids_to_update.add(revision_data.artifact_id)
252259
else:
253260
# Update existing revision only if there are changes
@@ -368,15 +375,24 @@ async def upsert_huggingface_model_artifacts(
368375
artifacts_map[artifact_row.id][1].append(existing_revision)
369376
else:
370377
# Insert new artifact revision
371-
new_revision = ArtifactRevisionRow.from_huggingface_model_data(
372-
artifact_id=artifact_row.id,
373-
model_data=model,
378+
creator = RBACEntityCreator(
379+
spec=ArtifactRevisionCreatorSpec(
380+
artifact_id=artifact_row.id,
381+
version=model.revision,
382+
readme=model.readme,
383+
size=model.size,
384+
status=ArtifactStatus.SCANNED,
385+
remote_status=None,
386+
created_at=model.created_at,
387+
updated_at=model.modified_at,
388+
digest=model.sha,
389+
verification_result=None,
390+
),
391+
element_type=RBACElementType.ARTIFACT_REVISION,
392+
scope_ref=RBACElementRef(RBACElementType.ARTIFACT, str(artifact_row.id)),
374393
)
375-
376-
db_sess.add(new_revision)
377-
await db_sess.flush()
378-
await db_sess.refresh(new_revision)
379-
artifacts_map[artifact_row.id][1].append(new_revision)
394+
creator_result = await execute_rbac_entity_creator(db_sess, creator)
395+
artifacts_map[artifact_row.id][1].append(creator_result.row)
380396
artifact_ids_to_update.add(artifact_row.id)
381397

382398
# Update artifact updated_at timestamp for affected artifacts

0 commit comments

Comments
 (0)