From 8ae8c7d272af5327ca14d005814adf0401a01210 Mon Sep 17 00:00:00 2001 From: Sanjay Vasandani Date: Tue, 26 Nov 2024 10:49:40 -0800 Subject: [PATCH] feat: Add database schema for internal Access API --- .../deploy/gcloud/spanner/testing/BUILD.bazel | 17 +++ .../deploy/gcloud/spanner/testing/Schemata.kt | 34 ++++++ src/main/resources/access/spanner/BUILD.bazel | 14 +++ .../resources/access/spanner/changelog.yaml | 20 ++++ .../access/spanner/create-access-schema.sql | 101 ++++++++++++++++++ .../deploy/gcloud/spanner/AccessSchemaTest.kt | 31 ++++++ .../access/deploy/gcloud/spanner/BUILD.bazel | 15 +++ 7 files changed, 232 insertions(+) create mode 100644 src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/BUILD.bazel create mode 100644 src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/Schemata.kt create mode 100644 src/main/resources/access/spanner/BUILD.bazel create mode 100644 src/main/resources/access/spanner/changelog.yaml create mode 100644 src/main/resources/access/spanner/create-access-schema.sql create mode 100644 src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/AccessSchemaTest.kt create mode 100644 src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/BUILD.bazel diff --git a/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/BUILD.bazel b/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/BUILD.bazel new file mode 100644 index 00000000000..bb900ca73f5 --- /dev/null +++ b/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/BUILD.bazel @@ -0,0 +1,17 @@ +load("@wfa_rules_kotlin_jvm//kotlin:defs.bzl", "kt_jvm_library") + +package( + default_testonly = True, + default_visibility = [ + "//src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner:__subpackages__", + ], +) + +kt_jvm_library( + name = "schemata", + srcs = ["Schemata.kt"], + resources = ["//src/main/resources/access/spanner"], + deps = [ + "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/common", + ], +) diff --git a/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/Schemata.kt b/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/Schemata.kt new file mode 100644 index 00000000000..8c0772866b5 --- /dev/null +++ b/src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing/Schemata.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 The Cross-Media Measurement Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wfanet.measurement.access.deploy.gcloud.spanner.testing + +import java.nio.file.Path +import org.wfanet.measurement.common.getJarResourcePath + +object Schemata { + private const val RESOURCE_PREFIX = "access/spanner" + + private fun getResourcePath(fileName: String): Path { + val resourceName = "$RESOURCE_PREFIX/$fileName" + val classLoader = Schemata.javaClass.classLoader + return requireNotNull(classLoader.getJarResourcePath(resourceName)) { + "Resource $resourceName not found" + } + } + + val ACCESS_CHANGELOG_PATH: Path = getResourcePath("changelog.yaml") +} diff --git a/src/main/resources/access/spanner/BUILD.bazel b/src/main/resources/access/spanner/BUILD.bazel new file mode 100644 index 00000000000..f9e1e0ffa68 --- /dev/null +++ b/src/main/resources/access/spanner/BUILD.bazel @@ -0,0 +1,14 @@ +package( + default_visibility = [ + "//src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner:__subpackages__", + "//src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner:__subpackages__", + ], +) + +filegroup( + name = "spanner", + srcs = glob([ + "*.yaml", + "*.sql", + ]), +) diff --git a/src/main/resources/access/spanner/changelog.yaml b/src/main/resources/access/spanner/changelog.yaml new file mode 100644 index 00000000000..78db26859ae --- /dev/null +++ b/src/main/resources/access/spanner/changelog.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 The Cross-Media Measurement Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Liquibase changelog. + +databaseChangeLog: +- include: + file: create-access-schema.sql + relativeToChangeLogFile: true diff --git a/src/main/resources/access/spanner/create-access-schema.sql b/src/main/resources/access/spanner/create-access-schema.sql new file mode 100644 index 00000000000..93d5831c705 --- /dev/null +++ b/src/main/resources/access/spanner/create-access-schema.sql @@ -0,0 +1,101 @@ +-- liquibase formatted sql + +-- Copyright 2024 The Cross-Media Measurement Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- changeset sanjayvas:1 dbms:cloudspanner +-- comment: Create initial schema for the Access system + +START BATCH DDL; + +CREATE TABLE Principals ( + PrincipalId INT64 NOT NULL, + + PrincipalResourceId STRING(63) NOT NULL, + CreateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), + UpdateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), +) +PRIMARY KEY (PrincipalId); + +CREATE UNIQUE INDEX PrincipalsByResourceId ON Principals(PrincipalResourceId); + +-- Principals with identity type USER. +-- There is at most one UserPrincipal per Principal. +CREATE TABLE UserPrincipals ( + PrincipalId INT64 NOT NULL, + + Issuer STRING(MAX) NOT NULL, + Subject STRING(MAX) NOT NULL, +) +PRIMARY KEY (PrincipalId), +INTERLEAVE IN PARENT Principals ON DELETE CASCADE; + +CREATE UNIQUE INDEX UserPrincipalsByClaims ON UserPrincipals(Issuer, Subject); + +CREATE TABLE Roles ( + RoleId INT64 NOT NULL, + + RoleResourceId STRING(63) NOT NULL, + CreateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), + UpdateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), +) +PRIMARY KEY (RoleId); + +CREATE UNIQUE INDEX RolesByResourceId ON Roles(RoleResourceId); + +CREATE TABLE RoleResourceTypes ( + RoleId INT64 NOT NULL, + + ResourceType STRING(MAX) NOT NULL, +) +PRIMARY KEY (RoleId, ResourceType), +INTERLEAVE IN PARENT Roles ON DELETE CASCADE; + +CREATE TABLE RolePermissions ( + RoleId INT64 NOT NULL, + PermissionId INT64 NOT NULL, + + FOREIGN KEY (RoleId) REFERENCES Roles(RoleId), +) +PRIMARY KEY (RoleId, PermissionId), +INTERLEAVE IN PARENT Roles ON DELETE CASCADE; + +CREATE TABLE Policies ( + PolicyId INT64 NOT NULL, + PolicyResourceId STRING(63) NOT NULL, + + -- Name of the protected resource. This may be empty string to mean API root. + ProtectedResourceName STRING(MAX) NOT NULL, + + CreateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), + UpdateTime TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp = true), +) +PRIMARY KEY (PolicyId); + +CREATE UNIQUE INDEX PoliciesByResourceId ON Policies(PolicyResourceId); +CREATE UNIQUE INDEX PoliciesByProtectedResourceName ON Policies(ProtectedResourceName); + +CREATE TABLE PolicyBindings ( + PolicyId INT64 NOT NULL, + RoleId INT64 NOT NULL, + PrincipalId INT64 NOT NULL, + + FOREIGN KEY (RoleId) REFERENCES Roles(RoleId), + FOREIGN KEY (PrincipalId) REFERENCES Principals(PrincipalId), +) +PRIMARY KEY (PolicyId, RoleId, PrincipalId), +INTERLEAVE IN PARENT Policies ON DELETE CASCADE; + +RUN BATCH; + diff --git a/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/AccessSchemaTest.kt b/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/AccessSchemaTest.kt new file mode 100644 index 00000000000..1c2e76793c7 --- /dev/null +++ b/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/AccessSchemaTest.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 The Cross-Media Measurement Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wfanet.measurement.access.deploy.gcloud.spanner + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.wfanet.measurement.access.deploy.gcloud.spanner.testing.Schemata +import org.wfanet.measurement.gcloud.spanner.testing.UsingSpannerEmulator + +@RunWith(JUnit4::class) +class AccessSchemaTest : UsingSpannerEmulator(Schemata.ACCESS_CHANGELOG_PATH) { + + @Test fun `database is created`() { + // No-op. Just ensure that DB is created by test infra. + } +} diff --git a/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/BUILD.bazel b/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/BUILD.bazel new file mode 100644 index 00000000000..bbe08b24e41 --- /dev/null +++ b/src/test/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/BUILD.bazel @@ -0,0 +1,15 @@ +load( + "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/gcloud/spanner/testing:macros.bzl", + "spanner_emulator_test", +) + +spanner_emulator_test( + name = "AccessSchemaTest", + srcs = ["AccessSchemaTest.kt"], + test_class = "org.wfanet.measurement.access.deploy.gcloud.spanner.AccessSchemaTest", + deps = [ + "//src/main/kotlin/org/wfanet/measurement/access/deploy/gcloud/spanner/testing:schemata", + "@wfa_common_jvm//imports/java/com/google/cloud/spanner", + "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/gcloud/spanner/testing", + ], +)