feat: add integration access settings (#725)

* feat: add integration access settings

* fix: typecheck and test issues

* fix: test timeout

* chore: address pull request feedback

* chore: add throw if action forbidden for integration permissions

* fix: unable to create new migrations because of duplicate prevId in sqlite snapshots

* chore: add sqlite migration for integration permissions

* test: add unit tests for integration access

* test: add permission checks to integration router tests

* test: add unit test for integration permissions

* chore: add mysql migration

* fix: format issues
This commit is contained in:
Meier Lukas
2024-07-08 00:00:37 +02:00
committed by GitHub
parent be711149f7
commit 408cdeb5c3
50 changed files with 4392 additions and 615 deletions

View File

@@ -0,0 +1,18 @@
CREATE TABLE `integrationGroupPermissions` (
`integration_id` varchar(64) NOT NULL,
`group_id` varchar(64) NOT NULL,
`permission` text NOT NULL,
CONSTRAINT `integrationGroupPermissions_integration_id_group_id_permission_pk` PRIMARY KEY(`integration_id`,`group_id`,`permission`)
);
--> statement-breakpoint
CREATE TABLE `integrationUserPermission` (
`integration_id` varchar(64) NOT NULL,
`user_id` varchar(64) NOT NULL,
`permission` text NOT NULL,
CONSTRAINT `integrationUserPermission_integration_id_user_id_permission_pk` PRIMARY KEY(`integration_id`,`user_id`,`permission`)
);
--> statement-breakpoint
ALTER TABLE `integrationGroupPermissions` ADD CONSTRAINT `integrationGroupPermissions_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationGroupPermissions` ADD CONSTRAINT `integrationGroupPermissions_group_id_group_id_fk` FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationUserPermission` ADD CONSTRAINT `integrationUserPermission_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationUserPermission` ADD CONSTRAINT `integrationUserPermission_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -2,7 +2,7 @@
"version": "5",
"dialect": "mysql",
"id": "4e382d0d-a432-4953-bd5e-04f3f33e26a4",
"prevId": "fdeaf6eb-cd62-4fa5-9b38-d7f80a60db9f",
"prevId": "ba2dd885-4e7f-4a45-99a0-7b45cbd0a5c2",
"tables": {
"account": {
"name": "account",

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,13 @@
"when": 1716148439439,
"tag": "0003_freezing_black_panther",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1720113913876,
"tag": "0004_noisy_giant_girl",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,17 @@
CREATE TABLE `integrationGroupPermissions` (
`integration_id` text NOT NULL,
`group_id` text NOT NULL,
`permission` text NOT NULL,
PRIMARY KEY(`group_id`, `integration_id`, `permission`),
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integrationUserPermission` (
`integration_id` text NOT NULL,
`user_id` text NOT NULL,
`permission` text NOT NULL,
PRIMARY KEY(`integration_id`, `permission`, `user_id`),
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);

View File

@@ -2,7 +2,7 @@
"version": "6",
"dialect": "sqlite",
"id": "5ad60251-8450-437d-9081-a456884120d2",
"prevId": "0575873a-9e10-4480-8d7d-c47198622c22",
"prevId": "2ed0ffc3-8612-42e7-bd8e-f5f8f3338a39",
"tables": {
"account": {
"name": "account",

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,13 @@
"when": 1716148434186,
"tag": "0003_adorable_raider",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1720036615408,
"tag": "0004_peaceful_red_ghost",
"breakpoints": true
}
]
}

View File

@@ -10,6 +10,7 @@ import type {
BoardPermission,
GroupPermissionKey,
IntegrationKind,
IntegrationPermission,
IntegrationSecretKind,
SectionKind,
WidgetKind,
@@ -157,6 +158,42 @@ export const integrationSecrets = mysqlTable(
}),
);
export const integrationUserPermissions = mysqlTable(
"integrationUserPermission",
{
integrationId: varchar("integration_id", { length: 64 })
.notNull()
.references(() => integrations.id, { onDelete: "cascade" }),
userId: varchar("user_id", { length: 64 })
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
permission: text("permission").$type<IntegrationPermission>().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.integrationId, table.userId, table.permission],
}),
}),
);
export const integrationGroupPermissions = mysqlTable(
"integrationGroupPermissions",
{
integrationId: varchar("integration_id", { length: 64 })
.notNull()
.references(() => integrations.id, { onDelete: "cascade" }),
groupId: varchar("group_id", { length: 64 })
.notNull()
.references(() => groups.id, { onDelete: "cascade" }),
permission: text("permission").$type<IntegrationPermission>().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.integrationId, table.groupId, table.permission],
}),
}),
);
export const boards = mysqlTable("board", {
id: varchar("id", { length: 64 }).notNull().primaryKey(),
name: varchar("name", { length: 256 }).unique().notNull(),
@@ -387,6 +424,30 @@ export const boardGroupPermissionRelations = relations(boardGroupPermissions, ({
export const integrationRelations = relations(integrations, ({ many }) => ({
secrets: many(integrationSecrets),
items: many(integrationItems),
userPermissions: many(integrationUserPermissions),
groupPermissions: many(integrationGroupPermissions),
}));
export const integrationUserPermissionRelations = relations(integrationUserPermissions, ({ one }) => ({
user: one(users, {
fields: [integrationUserPermissions.userId],
references: [users.id],
}),
integration: one(integrations, {
fields: [integrationUserPermissions.integrationId],
references: [integrations.id],
}),
}));
export const integrationGroupPermissionRelations = relations(integrationGroupPermissions, ({ one }) => ({
group: one(groups, {
fields: [integrationGroupPermissions.groupId],
references: [groups.id],
}),
integration: one(integrations, {
fields: [integrationGroupPermissions.integrationId],
references: [integrations.id],
}),
}));
export const integrationSecretRelations = relations(integrationSecrets, ({ one }) => ({

View File

@@ -12,6 +12,7 @@ import type {
BoardPermission,
GroupPermissionKey,
IntegrationKind,
IntegrationPermission,
IntegrationSecretKind,
SectionKind,
WidgetKind,
@@ -160,6 +161,42 @@ export const integrationSecrets = sqliteTable(
}),
);
export const integrationUserPermissions = sqliteTable(
"integrationUserPermission",
{
integrationId: text("integration_id")
.notNull()
.references(() => integrations.id, { onDelete: "cascade" }),
userId: text("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
permission: text("permission").$type<IntegrationPermission>().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.integrationId, table.userId, table.permission],
}),
}),
);
export const integrationGroupPermissions = sqliteTable(
"integrationGroupPermissions",
{
integrationId: text("integration_id")
.notNull()
.references(() => integrations.id, { onDelete: "cascade" }),
groupId: text("group_id")
.notNull()
.references(() => groups.id, { onDelete: "cascade" }),
permission: text("permission").$type<IntegrationPermission>().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.integrationId, table.groupId, table.permission],
}),
}),
);
export const boards = sqliteTable("board", {
id: text("id").notNull().primaryKey(),
name: text("name").unique().notNull(),
@@ -390,6 +427,30 @@ export const boardGroupPermissionRelations = relations(boardGroupPermissions, ({
export const integrationRelations = relations(integrations, ({ many }) => ({
secrets: many(integrationSecrets),
items: many(integrationItems),
userPermissions: many(integrationUserPermissions),
groupPermissions: many(integrationGroupPermissions),
}));
export const integrationUserPermissionRelations = relations(integrationUserPermissions, ({ one }) => ({
user: one(users, {
fields: [integrationUserPermissions.userId],
references: [users.id],
}),
integration: one(integrations, {
fields: [integrationUserPermissions.integrationId],
references: [integrations.id],
}),
}));
export const integrationGroupPermissionRelations = relations(integrationGroupPermissions, ({ one }) => ({
group: one(groups, {
fields: [integrationGroupPermissions.groupId],
references: [groups.id],
}),
integration: one(integrations, {
fields: [integrationGroupPermissions.integrationId],
references: [integrations.id],
}),
}));
export const integrationSecretRelations = relations(integrationSecrets, ({ one }) => ({