Skip to content

Commit

Permalink
feat: authz schema changes for data connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
olevski committed Jan 22, 2025
1 parent f6f13da commit 369e0a8
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 0 deletions.
74 changes: 74 additions & 0 deletions components/renku_data_services/authz/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,77 @@ def generate_v4(public_project_ids: Iterable[str]) -> AuthzSchemaMigration:
)

return AuthzSchemaMigration(up=up, down=down)


_v5: str = "to be added by Eike in a separate PR"

v5 = AuthzSchemaMigration(
up=[WriteSchemaRequest(schema=_v5)],
down=[WriteSchemaRequest(schema=_v4)],
)

_v6: str = """\
definition user {}
definition group {
relation group_platform: platform
relation owner: user
relation editor: user
relation viewer: user
relation public_viewer: user:* | anonymous_user:*
permission read = public_viewer + read_children
permission read_children = viewer + write
permission write = editor + delete
permission change_membership = delete
permission delete = owner + group_platform->is_admin
}
definition user_namespace {
relation user_namespace_platform: platform
relation owner: user
relation public_viewer: user:* | anonymous_user:*
permission read = public_viewer + read_children
permission read_children = delete
permission write = delete
permission delete = owner + user_namespace_platform->is_admin
}
definition anonymous_user {}
definition platform {
relation admin: user
permission is_admin = admin
}
definition project {
relation project_platform: platform
relation project_namespace: user_namespace | group
relation owner: user
relation editor: user
relation viewer: user
relation public_viewer: user:* | anonymous_user:*
permission read = public_viewer + read_children
permission read_children = viewer + write + project_namespace->read_children
permission write = editor + delete + project_namespace->write
permission change_membership = delete
permission delete = owner + project_platform->is_admin + project_namespace->delete
}
definition data_connector {
relation data_connector_platform: platform
relation data_connector_namespace: user_namespace | group | project
relation linked_to: project
relation owner: user
relation editor: user
relation viewer: user
relation public_viewer: user:* | anonymous_user:*
permission read = public_viewer + viewer + write + data_connector_namespace->read
permission write = editor + delete + data_connector_namespace->write
permission delete = owner + data_connector_platform->is_admin + data_connector_namespace->delete
}"""

v6 = AuthzSchemaMigration(
up=[WriteSchemaRequest(schema=_v6)],
# TODO: change to v5 when the search changes are merged
down=[WriteSchemaRequest(schema=_v4)],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Migrate authz schema to v6
Revision ID: 483af0d70cf4
Revises: d71f0f795d30
Create Date: 2025-01-22 10:37:40.218992
"""

import logging

from renku_data_services.authz.config import AuthzConfig
from renku_data_services.authz.schemas import v6

# revision identifiers, used by Alembic.
revision = "483af0d70cf4"
down_revision = "d71f0f795d30"
branch_labels = None
depends_on = None


def upgrade() -> None:
config = AuthzConfig.from_env()
client = config.authz_client()
responses = v6.upgrade(client)
logging.info(
f"Finished upgrading the Authz schema to version 6 in Alembic revision {revision}, response: {responses}"
)


def downgrade() -> None:
config = AuthzConfig.from_env()
client = config.authz_client()
responses = v6.downgrade(client)
logging.info(
f"Finished downgrading the Authz schema from version 6 in Alembic revision {revision}, response: {responses}"
)
117 changes: 117 additions & 0 deletions test/components/renku_data_services/authz/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,117 @@ def v2_schema() -> SpiceDBSchema:
)


@pytest.fixture
def v6_schema() -> SpiceDBSchema:
return SpiceDBSchema(
schemas._v6,
relationships=[
# there is an an admin
"platform:renku#admin@user:admin1",
# user namespaces
"user_namespace:user1#owner@user:user1",
"user_namespace:user2#owner@user:user2",
# project1 is public and owned by user1
"project:project1#owner@user:user1",
"project:project1#project_namespace@user_namespace:user1",
"project:project1#public_viewer@user:*",
"project:project1#public_viewer@anonymous_user:*",
"project:project1#project_platform@platform:renku",
# project2 is private, in group1 which is also private
"project:project2#owner@user:user2",
"project:project2#project_namespace@group:group1",
# project2 has other generic members
"project:project2#viewer@user:project2_viewer",
"project:project2#editor@user:project2_editor",
"project:project2#project_platform@platform:renku",
# user2 is owner of group1
"group:group1#owner@user:user2",
# group1 has other generic members
"group:group1#owner@user:group1_owner",
"group:group1#editor@user:group1_editor",
"group:group1#viewer@user:group1_viewer",
# dc1 is owned by project1
"data_connector:dc1#data_connector_namespace@project:project1",
"data_connector:dc1#data_connector_platform@platform:renku",
# dc2 is owned by group1
"data_connector:dc2#data_connector_namespace@group:group1",
"data_connector:dc2#data_connector_platform@platform:renku",
# dc3 is owned by user1 and is private
"data_connector:dc3#data_connector_namespace@user_namespace:user1",
"data_connector:dc3#data_connector_platform@platform:renku",
# dc4 is owned by user1 and is public
"data_connector:dc4#data_connector_namespace@user_namespace:user1",
"data_connector:dc4#data_connector_platform@platform:renku",
"data_connector:dc4#public_viewer@user:*",
"data_connector:dc4#public_viewer@anonymous_user:*",
],
assertions={
"assertTrue": [
# admins can do everything to all data connectors
"data_connector:dc1#delete@user:admin1",
"data_connector:dc2#delete@user:admin1",
"data_connector:dc3#delete@user:admin1",
"data_connector:dc4#delete@user:admin1",
"data_connector:dc1#write@user:admin1",
"data_connector:dc2#write@user:admin1",
"data_connector:dc3#write@user:admin1",
"data_connector:dc4#write@user:admin1",
"data_connector:dc1#read@user:admin1",
"data_connector:dc2#read@user:admin1",
"data_connector:dc3#read@user:admin1",
"data_connector:dc4#read@user:admin1",
# user1 can do everything on dc1 since it is owned by the project that user1 owns
"data_connector:dc1#delete@user:user1",
"data_connector:dc1#write@user:user1",
"data_connector:dc1#read@user:user1",
# user1 can read dc3 because it is owned by user1
"data_connector:dc3#delete@user:user1",
"data_connector:dc3#write@user:user1",
"data_connector:dc3#read@user:user1",
# user1 can read dc4 because it is owned by user1
"data_connector:dc4#delete@user:user1",
"data_connector:dc4#write@user:user1",
"data_connector:dc4#read@user:user1",
# user2 can read dc1 because it is owned by a public project
"data_connector:dc1#read@user:user2",
# user2 has full access on dc2 because they own the group that owns the dc
"data_connector:dc2#delete@user:user2",
"data_connector:dc2#write@user:user2",
"data_connector:dc2#read@user:user2",
# user2 has read access on dc4 because the dc is public
"data_connector:dc4#read@user:user2",
# anonymous user checks
"data_connector:dc1#read@user:ANON",
"data_connector:dc4#read@user:ANON",
"data_connector:dc1#read@anonymous_user:ANON",
"data_connector:dc4#read@anonymous_user:ANON",
],
"assertFalse": [
# user1 has no access to dc2 since the dc is owned by group1 which is private
# and user1 has no affiliation with group1
"data_connector:dc2#delete@user:user1",
"data_connector:dc2#write@user:user1",
"data_connector:dc2#read@user:user1",
# user2 has no edit or write access to dc1
"data_connector:dc1#delete@user:user2",
"data_connector:dc1#write@user:user2",
# user2 has no access to dc3 because it is owned by user1 and is private
"data_connector:dc3#delete@user:user2",
"data_connector:dc3#write@user:user2",
"data_connector:dc3#read@user:user2",
# user2 does not have write or delete permissions on dc4
"data_connector:dc4#delete@user:user2",
"data_connector:dc4#write@user:user2",
# anonymous user checks
"data_connector:dc2#read@user:ANON",
"data_connector:dc3#read@user:ANON",
"data_connector:dc2#read@anonymous_user:ANON",
"data_connector:dc3#read@anonymous_user:ANON",
],
},
)


def test_v1_schema(tmp_path: Path, v1_schema: SpiceDBSchema) -> None:
validation_file = tmp_path / "validate.yaml"
v1_schema.to_yaml(validation_file)
Expand All @@ -310,3 +421,9 @@ def test_v2_schema(tmp_path: Path, v2_schema: SpiceDBSchema) -> None:
validation_file = tmp_path / "validate.yaml"
v2_schema.to_yaml(validation_file)
check_call(["zed", "validate", validation_file.as_uri()])


def test_v6_schema(tmp_path: Path, v6_schema: SpiceDBSchema) -> None:
validation_file = tmp_path / "validate.yaml"
v6_schema.to_yaml(validation_file)
check_call(["zed", "validate", validation_file.as_uri()])

0 comments on commit 369e0a8

Please sign in to comment.