feat: add per-widget secret storage for release provider authentication
Adds encrypted token storage per release widget so users can authenticate with GitHub, GitLab, Docker Hub, etc. without needing full integration setup. - New `widget_secret` table (all 3 DB drivers) keyed by (itemId, kind) - tRPC router with setSecret/deleteSecret/getConfiguredKinds (board modify access required) - Releases router injects decrypted tokens into provider requests (board view access required) - Tokens only used for repos matching widget's stored configuration (prevents proxy abuse) - Provider auth: GitHub (Octokit auth), GitLab (PRIVATE-TOKEN), Docker Hub (Bearer), GHCR (registry token), npm (Bearer), Codeberg (token header) - UI: "Provider Tokens" section in widget editor with PasswordInput per provider
This commit is contained in:
14 files changed
+358
-20
No files matched your search
@@ -530,6 +530,25 @@ export const customWidgetSecrets = sqliteTable(
|
||||
}),
|
||||
);
|
||||
|
||||
export const widgetSecrets = sqliteTable(
|
||||
"widget_secret",
|
||||
{
|
||||
itemId: text()
|
||||
.notNull()
|
||||
.references(() => items.id, { onDelete: "cascade" }),
|
||||
kind: text().notNull(),
|
||||
value: text().$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: int({ mode: "timestamp" })
|
||||
.$onUpdateFn(() => new Date())
|
||||
.notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({
|
||||
columns: [table.itemId, table.kind],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
export const cronJobConfigurations = sqliteTable("cron_job_configuration", {
|
||||
name: text().notNull().primaryKey(),
|
||||
cronExpression: text().notNull(),
|
||||
@@ -735,12 +754,20 @@ export const sectionCollapseStateRelations = relations(sectionCollapseStates, ({
|
||||
export const itemRelations = relations(items, ({ one, many }) => ({
|
||||
integrations: many(integrationItems),
|
||||
layouts: many(itemLayouts),
|
||||
secrets: many(widgetSecrets),
|
||||
board: one(boards, {
|
||||
fields: [items.boardId],
|
||||
references: [boards.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const widgetSecretRelations = relations(widgetSecrets, ({ one }) => ({
|
||||
item: one(items, {
|
||||
fields: [widgetSecrets.itemId],
|
||||
references: [items.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const integrationItemRelations = relations(integrationItems, ({ one }) => ({
|
||||
integration: one(integrations, {
|
||||
fields: [integrationItems.integrationId],
|
||||
|
||||
Reference in new issue
Block a user