Skip to content

Commit a6ed25c

Browse files
authored
IFC-670 Add global permission to protect schema against changes (#4560)
1 parent d1e41cb commit a6ed25c

File tree

3 files changed

+45
-2
lines changed

3 files changed

+45
-2
lines changed

backend/infrahub/api/schema.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from infrahub.api.exceptions import SchemaNotValidError
1818
from infrahub.core import registry
1919
from infrahub.core.branch import Branch # noqa: TCH001
20+
from infrahub.core.constants import GlobalPermissions, PermissionDecision
2021
from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
2122
from infrahub.core.models import ( # noqa: TCH001
2223
SchemaBranchHash,
@@ -27,7 +28,7 @@
2728
from infrahub.core.schema.constants import SchemaNamespace # noqa: TCH001
2829
from infrahub.core.validators.models.validate_migration import SchemaValidateMigrationData
2930
from infrahub.database import InfrahubDatabase # noqa: TCH001
30-
from infrahub.exceptions import MigrationError
31+
from infrahub.exceptions import MigrationError, PermissionDeniedError
3132
from infrahub.log import get_logger
3233
from infrahub.message_bus import Meta, messages
3334
from infrahub.services import services
@@ -38,6 +39,7 @@
3839
if TYPE_CHECKING:
3940
from typing_extensions import Self
4041

42+
from infrahub.auth import AccountSession
4143
from infrahub.core.schema.schema_branch import SchemaBranch
4244
from infrahub.services import InfrahubServices
4345

@@ -240,8 +242,17 @@ async def load_schema(
240242
background_tasks: BackgroundTasks,
241243
db: InfrahubDatabase = Depends(get_db),
242244
branch: Branch = Depends(get_branch_dep),
243-
_: Any = Depends(get_current_user),
245+
account_session: AccountSession = Depends(get_current_user),
244246
) -> SchemaUpdate:
247+
for permission_backend in registry.permission_backends:
248+
if not await permission_backend.has_permission(
249+
db=db,
250+
account_id=account_session.account_id,
251+
permission=f"global:{GlobalPermissions.MANAGE_SCHEMA.value}:{PermissionDecision.ALLOW.value}",
252+
branch=branch,
253+
):
254+
raise PermissionDeniedError("You are not allowed to manage the schema")
255+
245256
service: InfrahubServices = request.app.state.service
246257
log.info("schema_load_request", branch=branch.name)
247258

backend/infrahub/core/constants/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class GlobalPermissions(InfrahubStringEnum):
5555
SUPER_ADMIN = "super_admin"
5656
MERGE_BRANCH = "merge_branch"
5757
MERGE_PROPOSED_CHANGE = "merge_proposed_change"
58+
MANAGE_SCHEMA = "manage_schema"
5859
MANAGE_ACCOUNTS = "manage_accounts"
5960
MANAGE_PERMISSIONS = "manage_permissions"
6061
MANAGE_REPOSITORIES = "manage_repositories"

backend/tests/unit/api/test_40_schema_api.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from infrahub.core.branch import Branch
55
from infrahub.core.constants import InfrahubKind, SchemaPathType
66
from infrahub.core.initialization import create_branch
7+
from infrahub.core.node import Node
78
from infrahub.core.path import SchemaPath
89
from infrahub.core.schema import SchemaRoot, core_models
910
from infrahub.core.utils import count_relationships
@@ -221,6 +222,36 @@ async def test_schema_load_endpoint_valid_simple(
221222
assert relationships["tags"] == 7000
222223

223224

225+
async def test_schema_load_permission_failure(
226+
db: InfrahubDatabase,
227+
client: TestClient,
228+
first_account,
229+
default_branch: Branch,
230+
prefect_test_fixture,
231+
workflow_local,
232+
authentication_base,
233+
helper,
234+
):
235+
token = await Node.init(db=db, schema=InfrahubKind.ACCOUNTTOKEN)
236+
await token.new(db=db, token="unprivileged", account=first_account)
237+
await token.save(db=db)
238+
239+
# Load the schema in the database
240+
schema = registry.schema.get_schema_branch(name=default_branch.name)
241+
await registry.schema.load_schema_to_db(schema=schema, branch=default_branch, db=db)
242+
243+
# Must execute in a with block to execute the startup/shutdown event
244+
with client:
245+
response = client.post(
246+
"/api/schema/load",
247+
headers={"X-INFRAHUB-KEY": "unprivileged"},
248+
json={"schemas": [helper.schema_file("infra_simple_01.json")]},
249+
)
250+
251+
assert response.status_code == 403
252+
assert response.json()["errors"][0]["message"] == "You are not allowed to manage the schema"
253+
254+
224255
async def test_schema_load_restricted_namespace(
225256
db: InfrahubDatabase,
226257
client: TestClient,

0 commit comments

Comments
 (0)