Add provider auth broker profiles
This commit is contained in:
1 parent
c862cd1319
commit
c6be8a4ee4
10 files changed
+370
-37
No files matched your search
@@ -23,7 +23,7 @@ describe("domain services", () => {
|
||||
const connection = createConnection();
|
||||
|
||||
const rows = connection.db.prepare("select version from schema_migrations order by version asc").all() as Array<{ version: number }>;
|
||||
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
|
||||
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]);
|
||||
connection.close();
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { providerAuthBrokerSchema } from "../../src/main/database/migrations/021-provider-auth-broker";
|
||||
|
||||
function createDatabase(): DatabaseSync {
|
||||
return new DatabaseSync(join(tmpdir(), `agentcompany-auth-broker-migration-${randomUUID()}.db`));
|
||||
}
|
||||
|
||||
describe("provider auth broker migration", () => {
|
||||
test("backfills active auth profiles from configured credentials", () => {
|
||||
const db = createDatabase();
|
||||
db.exec(`
|
||||
create table schema_migrations(version integer primary key, name text not null, applied_at text not null);
|
||||
create table organizations(id text primary key);
|
||||
create table providers(
|
||||
id text primary key,
|
||||
org_id text not null,
|
||||
provider_key text not null,
|
||||
auth_type text not null,
|
||||
credential_id text
|
||||
);
|
||||
create table credentials(
|
||||
id text primary key,
|
||||
org_id text not null,
|
||||
provider_key text not null,
|
||||
kind text not null,
|
||||
ciphertext blob not null,
|
||||
display_hint text not null,
|
||||
created_at text not null
|
||||
);
|
||||
insert into schema_migrations(version, name, applied_at) values (20, 'rollback_snapshots', datetime('now'));
|
||||
insert into organizations(id) values ('org_1');
|
||||
insert into credentials(id, org_id, provider_key, kind, ciphertext, display_hint, created_at)
|
||||
values ('cred_1', 'org_1', 'openai', 'api_key', x'736563726574', 'sk-liv...ider', '2026-05-23T01:02:03.000Z');
|
||||
insert into providers(id, org_id, provider_key, auth_type, credential_id)
|
||||
values ('prov_1', 'org_1', 'openai', 'api_key', 'cred_1');
|
||||
`);
|
||||
|
||||
db.exec(providerAuthBrokerSchema);
|
||||
|
||||
const profile = db.prepare(`
|
||||
select org_id, provider_id, credential_id, provider_key, auth_type,
|
||||
profile_kind, display_hint, source_type, capability_json, active, created_at
|
||||
from provider_auth_profiles
|
||||
`).get() as {
|
||||
org_id: string;
|
||||
provider_id: string;
|
||||
credential_id: string;
|
||||
provider_key: string;
|
||||
auth_type: string;
|
||||
profile_kind: string;
|
||||
display_hint: string;
|
||||
source_type: string;
|
||||
capability_json: string;
|
||||
active: number;
|
||||
created_at: string;
|
||||
};
|
||||
const migration = db.prepare("select version, name from schema_migrations where version = 21").get();
|
||||
|
||||
expect(profile).toMatchObject({
|
||||
org_id: "org_1",
|
||||
provider_id: "prov_1",
|
||||
credential_id: "cred_1",
|
||||
provider_key: "openai",
|
||||
auth_type: "api_key",
|
||||
profile_kind: "api_key",
|
||||
display_hint: "sk-liv...ider",
|
||||
source_type: "migrated_credential",
|
||||
active: 1,
|
||||
created_at: "2026-05-23T01:02:03.000Z",
|
||||
});
|
||||
expect(JSON.parse(profile.capability_json)).toEqual({ providerKey: "openai", authType: "api_key", capabilityTags: [] });
|
||||
expect(migration).toEqual({ version: 21, name: "provider_auth_broker" });
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
@@ -41,6 +41,46 @@ describe("provider service", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("creates active auth broker profiles during credential rotation", () => {
|
||||
const connection = createConnection();
|
||||
const organization = new OrganizationService(connection.db);
|
||||
const snapshot = new SnapshotService(connection.db);
|
||||
const providers = new ProviderService(connection.db, providerAdapters, testVault);
|
||||
let orgId = "";
|
||||
let openAiProviderId = "";
|
||||
|
||||
connection.transaction(() => {
|
||||
orgId = createOrganization(organization);
|
||||
openAiProviderId = providerId(connection, orgId, "openai");
|
||||
providers.saveCredential({ orgId, providerId: openAiProviderId, secret: "sk-live-provider-one", model: "gpt-5.4" });
|
||||
providers.saveCredential({ orgId, providerId: openAiProviderId, secret: "sk-live-provider-two", model: "gpt-5.4" });
|
||||
});
|
||||
|
||||
const rows = connection.db.prepare(`
|
||||
select credential_id, display_hint, source_type, capability_json, active
|
||||
from provider_auth_profiles
|
||||
where org_id = ? and provider_id = ?
|
||||
order by active desc, created_at desc
|
||||
`).all(orgId, openAiProviderId) as Array<{
|
||||
credential_id: string;
|
||||
display_hint: string;
|
||||
source_type: string;
|
||||
capability_json: string;
|
||||
active: number;
|
||||
}>;
|
||||
const state = snapshot.load();
|
||||
const activeProfile = state.providerAuthProfiles.find((profile) => profile.providerId === openAiProviderId && profile.active);
|
||||
const provider = state.providers.find((item) => item.id === openAiProviderId);
|
||||
|
||||
expect(rows.map((row) => row.active)).toEqual([1, 0]);
|
||||
expect(rows[0]).toMatchObject({ display_hint: "sk-liv...-two", source_type: "manual_secret" });
|
||||
expect(JSON.parse(rows[0].capability_json)).toMatchObject({ providerKey: "openai", capabilityTags: ["responses", "tools", "background"] });
|
||||
expect(provider?.credentialId).toBe(rows[0].credential_id);
|
||||
expect(activeProfile?.credentialId).toBe(rows[0].credential_id);
|
||||
expect(state.auditEvents.some((event) => event.entityType === "provider_auth_profile" && event.action === "created")).toBe(true);
|
||||
connection.close();
|
||||
});
|
||||
|
||||
test("checks provider health through its adapter", async () => {
|
||||
const connection = createConnection();
|
||||
const organization = new OrganizationService(connection.db);
|
||||
|
||||
Reference in new issue
Block a user