fix(plugin): address scoped config review findings

This commit is contained in:
Alkim Ake Gozen 2026-06-04 11:53:05 +09:00
parent db0ef46900
commit 06a9428a36
6 changed files with 19844 additions and 93 deletions

View file

@ -44,7 +44,7 @@ function isPluginKeyConflict(error: unknown): boolean {
return err.code === "23505" && constraint === "plugins_plugin_key_idx";
}
function pluginConfigScopeCondition(pluginId: string, companyId?: string | null) {
function pluginConfigExactScopeCondition(pluginId: string, companyId?: string | null) {
return and(
eq(pluginConfig.pluginId, pluginId),
companyId ? eq(pluginConfig.companyId, companyId) : isNull(pluginConfig.companyId),
@ -288,12 +288,22 @@ export function pluginRegistryService(db: Db) {
// ----- Config ---------------------------------------------------------
/** Retrieve a plugin's company-scoped config, or the legacy global fallback. */
getConfig: (pluginId: string, companyId?: string | null) =>
db
getConfig: async (pluginId: string, companyId?: string | null) => {
if (companyId) {
const scoped = await db
.select()
.from(pluginConfig)
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.then((rows) => rows[0] ?? null);
if (scoped) return scoped;
}
return db
.select()
.from(pluginConfig)
.where(pluginConfigScopeCondition(pluginId, companyId))
.then((rows) => rows[0] ?? null),
.where(pluginConfigExactScopeCondition(pluginId, null))
.then((rows) => rows[0] ?? null);
},
/**
* Create or fully replace a plugin's instance configuration.
@ -307,7 +317,7 @@ export function pluginRegistryService(db: Db) {
const existing = await db
.select()
.from(pluginConfig)
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.then((rows) => rows[0] ?? null);
if (existing) {
@ -318,7 +328,7 @@ export function pluginRegistryService(db: Db) {
lastError: null,
updatedAt: new Date(),
})
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.returning()
.then((rows) => rows[0]);
}
@ -345,7 +355,7 @@ export function pluginRegistryService(db: Db) {
const existing = await db
.select()
.from(pluginConfig)
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.then((rows) => rows[0] ?? null);
if (existing) {
@ -357,7 +367,7 @@ export function pluginRegistryService(db: Db) {
lastError: null,
updatedAt: new Date(),
})
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.returning()
.then((rows) => rows[0]);
}
@ -381,7 +391,7 @@ export function pluginRegistryService(db: Db) {
const rows = await db
.update(pluginConfig)
.set({ lastError, updatedAt: new Date() })
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.returning();
if (rows.length === 0) throw notFound("Plugin config not found");
@ -392,7 +402,7 @@ export function pluginRegistryService(db: Db) {
deleteConfig: async (pluginId: string, companyId?: string | null) => {
const rows = await db
.delete(pluginConfig)
.where(pluginConfigScopeCondition(pluginId, companyId))
.where(pluginConfigExactScopeCondition(pluginId, companyId))
.returning();
return rows[0] ?? null;

View file

@ -2034,6 +2034,7 @@ export function secretService(db: Db) {
required?: boolean;
label?: string | null;
}>,
options?: { db?: SecretBindingDb },
) => {
const normalizedRefs: Array<{
secretId: string;
@ -2042,8 +2043,9 @@ export function secretService(db: Db) {
required: boolean;
label: string | null;
}> = [];
const bindingDb = options?.db ?? db;
for (const ref of refs) {
await assertSecretInCompany(companyId, ref.secretId);
await assertSecretInCompany(companyId, ref.secretId, bindingDb);
normalizedRefs.push({
secretId: ref.secretId,
configPath: ref.configPath,
@ -2055,10 +2057,10 @@ export function secretService(db: Db) {
const pathPrefixes = [...new Set(normalizedRefs.map((ref) => ref.configPath.split(".")[0]))];
await db.transaction(async (tx) => {
const writeBindings = async (targetDb: SecretBindingDb) => {
if (pathPrefixes.length > 0) {
for (const pathPrefix of pathPrefixes) {
await tx
await targetDb
.delete(companySecretBindings)
.where(
and(
@ -2070,7 +2072,7 @@ export function secretService(db: Db) {
);
}
} else {
await tx
await targetDb
.delete(companySecretBindings)
.where(
and(
@ -2081,7 +2083,7 @@ export function secretService(db: Db) {
);
}
if (normalizedRefs.length === 0) return;
await tx.insert(companySecretBindings).values(
await targetDb.insert(companySecretBindings).values(
normalizedRefs.map((ref) => ({
companyId,
secretId: ref.secretId,
@ -2093,7 +2095,13 @@ export function secretService(db: Db) {
label: ref.label,
})),
);
});
};
if (options?.db) {
await writeBindings(options.db);
} else {
await db.transaction(async (tx) => writeBindings(tx));
}
return normalizedRefs;
},