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:
18
packages/db/migrations/mysql/0004_noisy_giant_girl.sql
Normal file
18
packages/db/migrations/mysql/0004_noisy_giant_girl.sql
Normal 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;
|
||||
@@ -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",
|
||||
|
||||
1320
packages/db/migrations/mysql/meta/0004_snapshot.json
Normal file
1320
packages/db/migrations/mysql/meta/0004_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
17
packages/db/migrations/sqlite/0004_peaceful_red_ghost.sql
Normal file
17
packages/db/migrations/sqlite/0004_peaceful_red_ghost.sql
Normal 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
|
||||
);
|
||||
@@ -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",
|
||||
|
||||
1263
packages/db/migrations/sqlite/meta/0004_snapshot.json
Normal file
1263
packages/db/migrations/sqlite/meta/0004_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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 }) => ({
|
||||
|
||||
@@ -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 }) => ({
|
||||
|
||||
Reference in New Issue
Block a user