@arbium/enterprise-agent-connect 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +117 -2
- package/dist/connectors/dell-techdirect/connector.json +39 -0
- package/dist/connectors/dell-techdirect/index.js +7 -0
- package/dist/connectors/dell-techdirect/index.js.map +1 -0
- package/dist/connectors/dell-techdirect/tools.js +49 -0
- package/dist/connectors/dell-techdirect/tools.js.map +1 -0
- package/dist/connectors/dell-techdirect/vendor.js +57 -0
- package/dist/connectors/dell-techdirect/vendor.js.map +1 -0
- package/dist/connectors/entra/connector.json +85 -0
- package/dist/connectors/entra/index.js +4 -0
- package/dist/connectors/entra/index.js.map +1 -0
- package/dist/connectors/entra/tools.js +262 -0
- package/dist/connectors/entra/tools.js.map +1 -0
- package/dist/connectors/fedex/connector.json +118 -0
- package/dist/connectors/fedex/index.js +7 -0
- package/dist/connectors/fedex/index.js.map +1 -0
- package/dist/connectors/fedex/tools.js +152 -0
- package/dist/connectors/fedex/tools.js.map +1 -0
- package/dist/connectors/fedex/vendor.js +98 -0
- package/dist/connectors/fedex/vendor.js.map +1 -0
- package/dist/connectors/http/index.js +235 -0
- package/dist/connectors/http/index.js.map +1 -0
- package/dist/connectors/intune/connector.json +106 -0
- package/dist/connectors/intune/index.js +4 -0
- package/dist/connectors/intune/index.js.map +1 -0
- package/dist/connectors/intune/tools.js +416 -0
- package/dist/connectors/intune/tools.js.map +1 -0
- package/dist/connectors/jira/connector.json +129 -0
- package/dist/connectors/jira/index.js +7 -0
- package/dist/connectors/jira/index.js.map +1 -0
- package/dist/connectors/jira/jql.js +67 -0
- package/dist/connectors/jira/jql.js.map +1 -0
- package/dist/connectors/jira/tools.js +464 -0
- package/dist/connectors/jira/tools.js.map +1 -0
- package/dist/connectors/jira/vendor.js +94 -0
- package/dist/connectors/jira/vendor.js.map +1 -0
- package/dist/connectors/microsoft/client.js +434 -0
- package/dist/connectors/microsoft/client.js.map +1 -0
- package/dist/connectors/microsoft/provider.json +118 -0
- package/dist/connectors/outlook-calendar/connector.json +136 -0
- package/dist/connectors/outlook-calendar/index.js +4 -0
- package/dist/connectors/outlook-calendar/index.js.map +1 -0
- package/dist/connectors/outlook-calendar/tools.js +398 -0
- package/dist/connectors/outlook-calendar/tools.js.map +1 -0
- package/dist/connectors/outlook-mail/connector.json +154 -0
- package/dist/connectors/outlook-mail/index.js +4 -0
- package/dist/connectors/outlook-mail/index.js.map +1 -0
- package/dist/connectors/outlook-mail/tools.js +236 -0
- package/dist/connectors/outlook-mail/tools.js.map +1 -0
- package/dist/connectors/salesforce/connector.json +122 -0
- package/dist/connectors/salesforce/index.js +7 -0
- package/dist/connectors/salesforce/index.js.map +1 -0
- package/dist/connectors/salesforce/soql.js +60 -0
- package/dist/connectors/salesforce/soql.js.map +1 -0
- package/dist/connectors/salesforce/tools.js +234 -0
- package/dist/connectors/salesforce/tools.js.map +1 -0
- package/dist/connectors/salesforce/vendor.js +107 -0
- package/dist/connectors/salesforce/vendor.js.map +1 -0
- package/dist/connectors/sharepoint-files/connector.json +194 -0
- package/dist/connectors/sharepoint-files/excel.js +300 -0
- package/dist/connectors/sharepoint-files/excel.js.map +1 -0
- package/dist/connectors/sharepoint-files/index.js +12 -0
- package/dist/connectors/sharepoint-files/index.js.map +1 -0
- package/dist/connectors/sharepoint-files/tools.js +365 -0
- package/dist/connectors/sharepoint-files/tools.js.map +1 -0
- package/dist/connectors/sharepoint-files/vendor.js +167 -0
- package/dist/connectors/sharepoint-files/vendor.js.map +1 -0
- package/dist/connectors/teams/connector.json +298 -0
- package/dist/connectors/teams/index.js +5 -0
- package/dist/connectors/teams/index.js.map +1 -0
- package/dist/connectors/teams/tools.js +391 -0
- package/dist/connectors/teams/tools.js.map +1 -0
- package/dist/packages/connector-kit/src/branding.js +102 -0
- package/dist/packages/connector-kit/src/branding.js.map +1 -0
- package/dist/packages/connector-kit/src/certificate.js +84 -0
- package/dist/packages/connector-kit/src/certificate.js.map +1 -0
- package/dist/packages/connector-kit/src/common.js +107 -0
- package/dist/packages/connector-kit/src/common.js.map +1 -0
- package/dist/packages/connector-kit/src/connector.js +492 -0
- package/dist/packages/connector-kit/src/connector.js.map +1 -0
- package/dist/packages/connector-kit/src/oauth.js +79 -0
- package/dist/packages/connector-kit/src/oauth.js.map +1 -0
- package/dist/packages/connector-kit/src/types.js +20 -0
- package/dist/packages/connector-kit/src/types.js.map +1 -0
- package/dist/packages/server/migrations/0001_tables.sql +268 -0
- package/dist/packages/server/migrations/0002_organizations.sql +72 -0
- package/dist/packages/server/migrations/0003_drop_unused.sql +3 -0
- package/dist/packages/server/migrations/0004_trigger_runners.sql +15 -0
- package/dist/packages/server/migrations/0005_run_runner.sql +3 -0
- package/dist/packages/server/migrations/0006_approvals.sql +36 -0
- package/dist/packages/server/migrations/rollback/to-legacy.sql +87 -0
- package/dist/packages/server/src/api.js +684 -0
- package/dist/packages/server/src/api.js.map +1 -0
- package/dist/packages/server/src/app.js +444 -0
- package/dist/packages/server/src/app.js.map +1 -0
- package/dist/packages/server/src/builtin.js +24 -0
- package/dist/packages/server/src/builtin.js.map +1 -0
- package/dist/packages/server/src/consent.js +36 -0
- package/dist/packages/server/src/consent.js.map +1 -0
- package/dist/packages/server/src/index.js +129 -0
- package/dist/packages/server/src/index.js.map +1 -0
- package/dist/packages/server/src/migrate.js +134 -0
- package/dist/packages/server/src/migrate.js.map +1 -0
- package/dist/packages/server/src/openapi.js +101 -0
- package/dist/packages/server/src/openapi.js.map +1 -0
- package/dist/packages/server/src/secrets.js +76 -0
- package/dist/packages/server/src/secrets.js.map +1 -0
- package/dist/packages/server/src/server.js +69 -0
- package/dist/packages/server/src/server.js.map +1 -0
- package/dist/packages/server/src/service.js +908 -0
- package/dist/packages/server/src/service.js.map +1 -0
- package/dist/packages/server/src/store.js +411 -0
- package/dist/packages/server/src/store.js.map +1 -0
- package/dist/packages/server/src/teams/activity.js +187 -0
- package/dist/packages/server/src/teams/activity.js.map +1 -0
- package/dist/packages/server/src/teams/admin.js +699 -0
- package/dist/packages/server/src/teams/admin.js.map +1 -0
- package/dist/packages/server/src/teams/approval.js +118 -0
- package/dist/packages/server/src/teams/approval.js.map +1 -0
- package/dist/packages/server/src/teams/bot.js +124 -0
- package/dist/packages/server/src/teams/bot.js.map +1 -0
- package/dist/packages/server/src/teams/claude.js +165 -0
- package/dist/packages/server/src/teams/claude.js.map +1 -0
- package/dist/packages/server/src/teams/jwt.js +121 -0
- package/dist/packages/server/src/teams/jwt.js.map +1 -0
- package/dist/packages/server/src/teams/package.js +319 -0
- package/dist/packages/server/src/teams/package.js.map +1 -0
- package/dist/packages/server/src/teams/provision.js +505 -0
- package/dist/packages/server/src/teams/provision.js.map +1 -0
- package/dist/packages/server/src/teams/runner.js +143 -0
- package/dist/packages/server/src/teams/runner.js.map +1 -0
- package/dist/packages/server/src/teams/runtime.js +701 -0
- package/dist/packages/server/src/teams/runtime.js.map +1 -0
- package/dist/packages/server/src/teams/store.js +507 -0
- package/dist/packages/server/src/teams/store.js.map +1 -0
- package/package.json +42 -4
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { createApp } from "./app.js";
|
|
3
|
+
import { parseBranding, setBranding, } from "../../connector-kit/src/branding.js";
|
|
4
|
+
import { builtinConnectors } from "./builtin.js";
|
|
5
|
+
import httpConnector from "../../../connectors/http/index.js";
|
|
6
|
+
import { loadConnectors, loadProviders } from "../../connector-kit/src/connector.js";
|
|
7
|
+
import { migrate as runMigrations } from "./migrate.js";
|
|
8
|
+
import { CredentialKey } from "./secrets.js";
|
|
9
|
+
import { assertToolsImplemented, createService } from "./service.js";
|
|
10
|
+
import { assertSchemaName, connectDatabase, createStore } from "./store.js";
|
|
11
|
+
import { createTeamsAdmin, resealTeamsCredentials } from "./teams/admin.js";
|
|
12
|
+
import { botClient } from "./teams/bot.js";
|
|
13
|
+
import { claudeClient } from "./teams/claude.js";
|
|
14
|
+
import { botFrameworkAuth } from "./teams/jwt.js";
|
|
15
|
+
import { LIVE_CHECKS } from "./teams/provision.js";
|
|
16
|
+
import { claudeManagedAgents, signedWebhook } from "./teams/runner.js";
|
|
17
|
+
import { createTeamsRuntime } from "./teams/runtime.js";
|
|
18
|
+
import { createTeamsStore } from "./teams/store.js";
|
|
19
|
+
import { microsoftClient } from "../../../connectors/microsoft/client.js";
|
|
20
|
+
export { builtinConnectors } from "./builtin.js";
|
|
21
|
+
export { claudeManagedAgents, signature, signedWebhook } from "./teams/runner.js";
|
|
22
|
+
/** The whole service, checked and wired: fetch serves /agent-connect/*, start runs the Teams
|
|
23
|
+
* queue worker and watcher. Throws on anything misconfigured. */
|
|
24
|
+
export async function createAgentConnect(options) {
|
|
25
|
+
const log = options.log ?? console;
|
|
26
|
+
setBranding(parseBranding(options.branding));
|
|
27
|
+
const schema = options.schema ?? "agent_connect";
|
|
28
|
+
assertSchemaName(schema);
|
|
29
|
+
const microsoft = microsoftClient({ sharedApp: options.microsoftSharedApp ?? null });
|
|
30
|
+
const modules = new Map((options.connectors ?? builtinConnectors).map((m) => [m.id, m]));
|
|
31
|
+
const connectors = [
|
|
32
|
+
...loadConnectors(),
|
|
33
|
+
...(options.extraConnectorDirs ?? []).flatMap((dir) => {
|
|
34
|
+
const found = loadConnectors(pathToFileURL(`${dir.replace(/\/+$/, "")}/`));
|
|
35
|
+
if (!found.length)
|
|
36
|
+
throw new Error(`No connector.json in a subfolder of ${dir}`);
|
|
37
|
+
return found;
|
|
38
|
+
}),
|
|
39
|
+
];
|
|
40
|
+
const apps = connectors.map((connector) => {
|
|
41
|
+
if (connectors.filter((c) => c.id === connector.id).length > 1)
|
|
42
|
+
throw new Error(`Two connectors have the id ${connector.id}`);
|
|
43
|
+
// An app described entirely in its connector.json runs on the generic http module.
|
|
44
|
+
const module = modules.get(connector.id) ?? (connector.http ? httpConnector : undefined);
|
|
45
|
+
if (!module)
|
|
46
|
+
throw new Error(`Connector ${connector.id} has no code (ConnectorModule)`);
|
|
47
|
+
return { connector, ...module.create({ microsoft, connector }) };
|
|
48
|
+
});
|
|
49
|
+
assertToolsImplemented(apps);
|
|
50
|
+
// Every `live` step check a connector names is one the Teams admin runs.
|
|
51
|
+
for (const { connector } of apps)
|
|
52
|
+
for (const step of [...connector.setup, ...connector.afterConnect])
|
|
53
|
+
if (step.live && !LIVE_CHECKS.includes(step.live))
|
|
54
|
+
throw new Error(`Connector ${connector.id}: no live check ${step.live}`);
|
|
55
|
+
const providerClients = { microsoft: microsoft.provider };
|
|
56
|
+
const providers = loadProviders().map((provider) => {
|
|
57
|
+
const client = providerClients[provider.id];
|
|
58
|
+
if (!client)
|
|
59
|
+
throw new Error(`connectors/${provider.id}/provider.json has no client`);
|
|
60
|
+
return { provider, client };
|
|
61
|
+
});
|
|
62
|
+
const teamsConnector = apps.find((a) => a.connector.id === "teams")?.connector;
|
|
63
|
+
if (!teamsConnector)
|
|
64
|
+
throw new Error("The teams connector is missing");
|
|
65
|
+
const ownsSql = !("unsafe" in options.database);
|
|
66
|
+
const sql = "unsafe" in options.database ? options.database : connectDatabase(options.database.url);
|
|
67
|
+
if (options.migrate ?? true)
|
|
68
|
+
await runMigrations(sql, schema);
|
|
69
|
+
const store = createStore(sql, schema);
|
|
70
|
+
const key = new CredentialKey(options.encryptionKey, options.previousEncryptionKey);
|
|
71
|
+
const teamsStore = createTeamsStore(sql, schema);
|
|
72
|
+
const bots = botClient();
|
|
73
|
+
const base = options.publicBaseUrl?.trim().replace(/\/+$/, "");
|
|
74
|
+
const publicUrl = base ? `${base}/agent-connect` : null;
|
|
75
|
+
const runners = new Map((options.runners ?? [claudeManagedAgents(), signedWebhook()])
|
|
76
|
+
.map((make) => make({ teams: teamsStore, key, publicUrl }))
|
|
77
|
+
.map((r) => [r.id, r]));
|
|
78
|
+
const runtime = createTeamsRuntime({
|
|
79
|
+
store,
|
|
80
|
+
teams: teamsStore,
|
|
81
|
+
key,
|
|
82
|
+
auth: botFrameworkAuth(),
|
|
83
|
+
bots,
|
|
84
|
+
runners,
|
|
85
|
+
connector: teamsConnector,
|
|
86
|
+
publicUrl,
|
|
87
|
+
});
|
|
88
|
+
const service = createService({
|
|
89
|
+
apps,
|
|
90
|
+
providers,
|
|
91
|
+
store,
|
|
92
|
+
key,
|
|
93
|
+
bots: { botForAgent: teamsStore.botForAgent, access: runtime.access },
|
|
94
|
+
});
|
|
95
|
+
const app = createApp({
|
|
96
|
+
service,
|
|
97
|
+
store,
|
|
98
|
+
adminToken: options.adminToken,
|
|
99
|
+
teams: {
|
|
100
|
+
runtime,
|
|
101
|
+
admin: createTeamsAdmin({
|
|
102
|
+
store,
|
|
103
|
+
teams: teamsStore,
|
|
104
|
+
key,
|
|
105
|
+
bots,
|
|
106
|
+
claude: claudeClient,
|
|
107
|
+
runners,
|
|
108
|
+
publicUrl,
|
|
109
|
+
microsoft,
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
fetch: (req) => app.fetch(req),
|
|
115
|
+
connectors: apps.map((a) => a.connector.id),
|
|
116
|
+
start() {
|
|
117
|
+
runtime.start();
|
|
118
|
+
// While rotating the key, move what Teams sealed onto the new one.
|
|
119
|
+
if (options.previousEncryptionKey)
|
|
120
|
+
resealTeamsCredentials(teamsStore, key).then((n) => log.log(`[agent-connect] re-sealed ${n.bots} bot credentials, ${n.claudeKeys} Claude keys and ${n.triggerSecrets} trigger secrets`), (error) => log.error("[agent-connect] re-sealing Teams credentials failed", error));
|
|
121
|
+
},
|
|
122
|
+
async stop() {
|
|
123
|
+
await runtime.stop();
|
|
124
|
+
if (ownsSql)
|
|
125
|
+
await sql.end();
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/server/src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { assertSchemaName } from "./store.js";
|
|
4
|
+
// The service's own schema migrations: plain numbered SQL in migrations/, written with
|
|
5
|
+
// unqualified names and run with search_path set to the configured schema, recorded in that
|
|
6
|
+
// schema's schema_migrations.
|
|
7
|
+
const DIR = new URL("../migrations/", import.meta.url);
|
|
8
|
+
// What the earlier layout had in public, made by the host's migration before the service had a schema.
|
|
9
|
+
// 0001 makes the same tables, so an install that has them adopts them as 0001.
|
|
10
|
+
const PREFIX = "agent_connect_";
|
|
11
|
+
const LEGACY = [
|
|
12
|
+
"agents",
|
|
13
|
+
"providers",
|
|
14
|
+
"connections",
|
|
15
|
+
"grants",
|
|
16
|
+
"audit",
|
|
17
|
+
"confirmed",
|
|
18
|
+
"teams_bots",
|
|
19
|
+
"teams_conversations",
|
|
20
|
+
"teams_events",
|
|
21
|
+
"teams_triggers",
|
|
22
|
+
"teams_runs",
|
|
23
|
+
"teams_spend",
|
|
24
|
+
].map((name) => `${PREFIX}${name}`);
|
|
25
|
+
export function migrationFiles() {
|
|
26
|
+
return readdirSync(DIR)
|
|
27
|
+
.filter((file) => /^\d{4}_[a-z0-9_]+\.sql$/.test(file))
|
|
28
|
+
.sort()
|
|
29
|
+
.map((file) => {
|
|
30
|
+
const sql = readFileSync(new URL(file, DIR), "utf8");
|
|
31
|
+
return {
|
|
32
|
+
id: file.slice(0, -4),
|
|
33
|
+
version: Number(file.slice(0, 4)),
|
|
34
|
+
name: file.slice(5, -4),
|
|
35
|
+
sql,
|
|
36
|
+
checksum: createHash("sha256").update(sql).digest("hex"),
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** Applies pending migrations in one transaction; returns what it did, in order. */
|
|
41
|
+
export async function migrate(sql, schema, log = console.log) {
|
|
42
|
+
assertSchemaName(schema);
|
|
43
|
+
const files = migrationFiles();
|
|
44
|
+
return sql.begin(async (tx) => {
|
|
45
|
+
// One run at a time, e.g. two pods starting together; released with the transaction.
|
|
46
|
+
await tx `select pg_advisory_xact_lock(hashtext(${`${schema}.migrate`}))`;
|
|
47
|
+
// "Already exists, skipping" on every start is noise.
|
|
48
|
+
await tx `set local client_min_messages = warning`;
|
|
49
|
+
await tx.unsafe(`create schema if not exists ${schema}`);
|
|
50
|
+
await tx.unsafe(`revoke all on schema ${schema} from public`);
|
|
51
|
+
await tx.unsafe(`create table if not exists ${schema}.schema_migrations (
|
|
52
|
+
version int primary key,
|
|
53
|
+
name text not null,
|
|
54
|
+
checksum text not null,
|
|
55
|
+
adopted boolean not null default false,
|
|
56
|
+
applied_at timestamptz not null default now())`);
|
|
57
|
+
const applied = await tx.unsafe(`select version, checksum from ${schema}.schema_migrations order by version`);
|
|
58
|
+
for (const row of applied) {
|
|
59
|
+
const file = files.find((f) => f.version === row.version);
|
|
60
|
+
if (!file)
|
|
61
|
+
throw new Error(`Migration ${row.version} is applied in ${schema} but not known to this version`);
|
|
62
|
+
if (file.checksum !== row.checksum)
|
|
63
|
+
throw new Error(`Migration ${file.id} changed after it was applied`);
|
|
64
|
+
}
|
|
65
|
+
const ran = [];
|
|
66
|
+
const legacy = await legacyTables(tx);
|
|
67
|
+
const adopting = legacy.length > 0 && !applied.length;
|
|
68
|
+
if (adopting) {
|
|
69
|
+
// Moved, not copied: the rows, ids and sequences stay as they are.
|
|
70
|
+
for (const table of LEGACY)
|
|
71
|
+
await tx.unsafe(`alter table public.${table} set schema ${schema}`);
|
|
72
|
+
const first = files[0];
|
|
73
|
+
await tx.unsafe(`insert into ${schema}.schema_migrations (version, name, checksum, adopted)
|
|
74
|
+
values ($1, $2, $3, true)`, [first.version, first.name, first.checksum]);
|
|
75
|
+
applied.push({ version: first.version, checksum: first.checksum });
|
|
76
|
+
ran.push(`adopted public.agent_connect_* as ${first.id}`);
|
|
77
|
+
}
|
|
78
|
+
else if (legacy.length) {
|
|
79
|
+
// The host's migration made them after this schema existed: a fresh install where the
|
|
80
|
+
// service started before the host's migrations ran. Empty, they are dropped; rows are not.
|
|
81
|
+
const filled = [];
|
|
82
|
+
for (const table of legacy) {
|
|
83
|
+
// FORCE RLS with no policies hides every row from an owner without bypassrls, and
|
|
84
|
+
// this check is all that stands before the drop. Rolled back with the transaction.
|
|
85
|
+
await tx.unsafe(`alter table public.${table} no force row level security`);
|
|
86
|
+
const [{ any }] = await tx.unsafe(`select exists (select from public.${table}) as any`);
|
|
87
|
+
if (any)
|
|
88
|
+
filled.push(table);
|
|
89
|
+
}
|
|
90
|
+
if (filled.length)
|
|
91
|
+
throw new Error(`public.${filled.join(", public.")} hold rows, but ${schema} already has the service's tables`);
|
|
92
|
+
await tx.unsafe(`drop table ${legacy.map((t) => `public.${t}`).join(", ")}`);
|
|
93
|
+
ran.push(`dropped empty public.${legacy.join(", public.")}`);
|
|
94
|
+
}
|
|
95
|
+
await tx.unsafe(`set local search_path to ${schema}`);
|
|
96
|
+
const done = new Set(applied.map((row) => row.version));
|
|
97
|
+
for (const file of files.filter((f) => !done.has(f.version))) {
|
|
98
|
+
await tx.unsafe(file.sql).simple();
|
|
99
|
+
await tx.unsafe(`insert into ${schema}.schema_migrations (version, name, checksum) values ($1, $2, $3)`, [file.version, file.name, file.checksum]);
|
|
100
|
+
ran.push(`applied ${file.id}`);
|
|
101
|
+
}
|
|
102
|
+
if (adopting) {
|
|
103
|
+
// So that a rolled-back 0.7.x image, which reads public.agent_connect_*, keeps serving
|
|
104
|
+
// until to-legacy.sql runs. Simple views, so its inserts, upserts and row locks go
|
|
105
|
+
// through. TODO(next release): drop them in a migration before any column changes.
|
|
106
|
+
for (const table of LEGACY)
|
|
107
|
+
await tx.unsafe(`create view public.${table} as select * from ${schema}.${table.slice(PREFIX.length)}`);
|
|
108
|
+
// Default privileges on public can grant them to API roles; they bypass RLS, so only
|
|
109
|
+
// their owner keeps them.
|
|
110
|
+
const grants = await tx.unsafe(`select distinct c.relname as view, a.grantee::regrole::text as role
|
|
111
|
+
from pg_class c join pg_namespace n on n.oid = c.relnamespace,
|
|
112
|
+
aclexplode(c.relacl) a
|
|
113
|
+
where n.nspname = 'public' and c.relname = any($1::text[])
|
|
114
|
+
and a.grantee not in (0, c.relowner)`, [LEGACY]);
|
|
115
|
+
for (const { view, role } of grants)
|
|
116
|
+
await tx.unsafe(`revoke all on public.${view} from ${role}`);
|
|
117
|
+
for (const table of LEGACY)
|
|
118
|
+
await tx.unsafe(`revoke all on public.${table} from public`);
|
|
119
|
+
ran.push(`made views public.${PREFIX}* for the previous release`);
|
|
120
|
+
}
|
|
121
|
+
for (const line of ran)
|
|
122
|
+
log(`[agent-connect] migrations: ${line} (schema ${schema})`);
|
|
123
|
+
return ran;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async function legacyTables(tx) {
|
|
127
|
+
// Tables only: the views made on adoption have the same names. In LEGACY's order, not the
|
|
128
|
+
// catalog's, which moves as other tables are made.
|
|
129
|
+
const rows = await tx.unsafe(`select c.relname as name from pg_class c join pg_namespace n on n.oid = c.relnamespace
|
|
130
|
+
where n.nspname = 'public' and c.relkind in ('r', 'p') and c.relname = any($1::text[])
|
|
131
|
+
order by array_position($1::text[], c.relname::text)`, [LEGACY]);
|
|
132
|
+
return rows.map((row) => row.name);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../../packages/server/src/migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { PARAMS, routes, schemas } from "./api.js";
|
|
4
|
+
export const ADMIN_V1 = "/agent-connect/admin/v1";
|
|
5
|
+
function convert(schema, io, components) {
|
|
6
|
+
const { $schema: _, $defs, ...json } = z.toJSONSchema(schema, {
|
|
7
|
+
io,
|
|
8
|
+
target: "draft-2020-12",
|
|
9
|
+
});
|
|
10
|
+
const ref = (value) => Array.isArray(value)
|
|
11
|
+
? value.map(ref)
|
|
12
|
+
: value && typeof value === "object"
|
|
13
|
+
? Object.fromEntries(Object.entries(value).map(([k, v]) => [
|
|
14
|
+
k,
|
|
15
|
+
k === "$ref" && typeof v === "string"
|
|
16
|
+
? v.replace("#/$defs/", "#/components/schemas/")
|
|
17
|
+
: ref(v),
|
|
18
|
+
]))
|
|
19
|
+
: value;
|
|
20
|
+
for (const [id, def] of Object.entries($defs ?? {})) {
|
|
21
|
+
const next = ref(def);
|
|
22
|
+
// One id, one shape: a body and an answer naming the same schema must agree.
|
|
23
|
+
if (id in components && !isDeepStrictEqual(components[id], next))
|
|
24
|
+
throw new Error(`Schema ${id} differs between its uses`);
|
|
25
|
+
components[id] = next;
|
|
26
|
+
}
|
|
27
|
+
return ref(json);
|
|
28
|
+
}
|
|
29
|
+
function answer(status, a, components) {
|
|
30
|
+
const description = status < 300 ? "OK" : "Refused";
|
|
31
|
+
if (a === null)
|
|
32
|
+
return { description };
|
|
33
|
+
if ("file" in a)
|
|
34
|
+
return { description, content: { [a.file]: { schema: { type: "string", format: "binary" } } } };
|
|
35
|
+
return {
|
|
36
|
+
description,
|
|
37
|
+
content: { "application/json": { schema: convert(a, "output", components) } },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function openapi() {
|
|
41
|
+
const components = {};
|
|
42
|
+
const error = () => answer(400, schemas.Error, components);
|
|
43
|
+
const paths = {};
|
|
44
|
+
for (const [operationId, spec] of Object.entries(routes)) {
|
|
45
|
+
const parameters = [
|
|
46
|
+
...[...spec.path.matchAll(/\{(\w+)\}/g)].map(([, p]) => ({
|
|
47
|
+
name: p,
|
|
48
|
+
in: "path",
|
|
49
|
+
required: true,
|
|
50
|
+
schema: { type: "string", pattern: `^${PARAMS[p]}$` },
|
|
51
|
+
})),
|
|
52
|
+
...Object.entries(spec.query ?? {}).map(([q, description]) => ({
|
|
53
|
+
name: q,
|
|
54
|
+
in: "query",
|
|
55
|
+
required: false,
|
|
56
|
+
description,
|
|
57
|
+
schema: { type: "string" },
|
|
58
|
+
})),
|
|
59
|
+
];
|
|
60
|
+
const responses = {};
|
|
61
|
+
for (const [status, a] of Object.entries(spec.responses))
|
|
62
|
+
responses[status] = answer(Number(status), a, components);
|
|
63
|
+
// Every route: bad input, a wrong token, an unknown organization or route, a refusal by
|
|
64
|
+
// the app being connected.
|
|
65
|
+
for (const status of ["400", "401", "404", "422"])
|
|
66
|
+
responses[status] ??= error();
|
|
67
|
+
(paths[spec.path] ??= {})[spec.method.toLowerCase()] = {
|
|
68
|
+
operationId,
|
|
69
|
+
summary: spec.summary,
|
|
70
|
+
...(spec.teams ? { tags: ["teams"] } : {}),
|
|
71
|
+
...(parameters.length ? { parameters } : {}),
|
|
72
|
+
...(spec.body
|
|
73
|
+
? {
|
|
74
|
+
requestBody: {
|
|
75
|
+
required: !spec.body.safeParse(undefined).success,
|
|
76
|
+
content: { "application/json": { schema: convert(spec.body, "input", components) } },
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
: {}),
|
|
80
|
+
responses,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
openapi: "3.1.0",
|
|
85
|
+
info: {
|
|
86
|
+
title: "Agent Connect admin API",
|
|
87
|
+
version: "1",
|
|
88
|
+
description: "Server to server only: a bearer token (AGENT_CONNECT_ADMIN_TOKEN), and requests " +
|
|
89
|
+
"carrying X-Forwarded-For are refused. Routes tagged teams are served only where " +
|
|
90
|
+
"Teams is set up.",
|
|
91
|
+
},
|
|
92
|
+
servers: [{ url: ADMIN_V1 }],
|
|
93
|
+
security: [{ bearer: [] }],
|
|
94
|
+
paths,
|
|
95
|
+
components: {
|
|
96
|
+
schemas: Object.fromEntries(Object.entries(components).sort(([a], [b]) => a.localeCompare(b))),
|
|
97
|
+
securitySchemes: { bearer: { type: "http", scheme: "bearer" } },
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../../packages/server/src/openapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHash, hkdfSync, randomBytes, timingSafeEqual, } from "node:crypto";
|
|
2
|
+
const keyId = (key) => createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
3
|
+
function parseKey(base64, name) {
|
|
4
|
+
const key = Buffer.from(base64, "base64");
|
|
5
|
+
if (key.length !== 32)
|
|
6
|
+
throw new Error(`${name} must be 32 bytes, base64`);
|
|
7
|
+
return key;
|
|
8
|
+
}
|
|
9
|
+
// Rotation: set the new key as CONNECT_ENCRYPTION_KEY and the old one as `previous`. Rows
|
|
10
|
+
// sealed with the old key still open, and are re-sealed with the new one when next checked.
|
|
11
|
+
export class CredentialKey {
|
|
12
|
+
id;
|
|
13
|
+
#key;
|
|
14
|
+
#previous;
|
|
15
|
+
constructor(base64, previousBase64) {
|
|
16
|
+
this.#key = parseKey(base64, "CONNECT_ENCRYPTION_KEY");
|
|
17
|
+
this.id = keyId(this.#key);
|
|
18
|
+
const previous = previousBase64
|
|
19
|
+
? parseKey(previousBase64, "CONNECT_ENCRYPTION_KEY_PREVIOUS")
|
|
20
|
+
: null;
|
|
21
|
+
this.#previous = new Map(previous ? [[keyId(previous), previous]] : []);
|
|
22
|
+
}
|
|
23
|
+
/** Ids of the previous key(s) still loaded while rotating. */
|
|
24
|
+
get previousIds() {
|
|
25
|
+
return [...this.#previous.keys()];
|
|
26
|
+
}
|
|
27
|
+
// A separate key for another purpose (e.g. signing consent state), never the sealing key.
|
|
28
|
+
derive(purpose) {
|
|
29
|
+
return Buffer.from(hkdfSync("sha256", this.#key, "", `agent-connect:${purpose}`, 32));
|
|
30
|
+
}
|
|
31
|
+
seal(secret, aad) {
|
|
32
|
+
const iv = randomBytes(12);
|
|
33
|
+
const cipher = createCipheriv("aes-256-gcm", this.#key, iv);
|
|
34
|
+
cipher.setAAD(Buffer.from(aad));
|
|
35
|
+
const body = Buffer.concat([cipher.update(JSON.stringify(secret), "utf8"), cipher.final()]);
|
|
36
|
+
return { ciphertext: Buffer.concat([iv, cipher.getAuthTag(), body]), keyId: this.id };
|
|
37
|
+
}
|
|
38
|
+
open(sealed, aad) {
|
|
39
|
+
const key = sealed.keyId === this.id ? this.#key : this.#previous.get(sealed.keyId);
|
|
40
|
+
if (!key)
|
|
41
|
+
throw new Error(`Credential was sealed with key ${sealed.keyId}, which is not loaded`);
|
|
42
|
+
const iv = sealed.ciphertext.subarray(0, 12);
|
|
43
|
+
const tag = sealed.ciphertext.subarray(12, 28);
|
|
44
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
45
|
+
decipher.setAAD(Buffer.from(aad));
|
|
46
|
+
decipher.setAuthTag(tag);
|
|
47
|
+
const plain = Buffer.concat([
|
|
48
|
+
decipher.update(sealed.ciphertext.subarray(28)),
|
|
49
|
+
decipher.final(),
|
|
50
|
+
]);
|
|
51
|
+
return JSON.parse(plain.toString("utf8"));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export const credentialAad = (organizationId, connectorId) => `agent-connect:${organizationId}:${connectorId}`;
|
|
55
|
+
// Both shapes are accepted, forever (the shape check is not the authentication; the hash
|
|
56
|
+
// lookup is). New keys keep arb_agent_ for this release, because a rollback to the previous one,
|
|
57
|
+
// which accepts only that, must still take keys made meanwhile. Switch to eac_agent_ in the
|
|
58
|
+
// next release.
|
|
59
|
+
const AGENT_KEY_PREFIX = "arb_agent_";
|
|
60
|
+
export function newAgentKey() {
|
|
61
|
+
return AGENT_KEY_PREFIX + randomBytes(32).toString("base64url");
|
|
62
|
+
}
|
|
63
|
+
// Agent keys carry 256 bits of randomness, so an unsalted SHA-256 is enough to make a
|
|
64
|
+
// database read useless for calling the service.
|
|
65
|
+
export function hashAgentKey(key) {
|
|
66
|
+
return createHash("sha256").update(key).digest("hex");
|
|
67
|
+
}
|
|
68
|
+
export function looksLikeAgentKey(key) {
|
|
69
|
+
return /^(eac|arb)_agent_[A-Za-z0-9_-]{43}$/.test(key);
|
|
70
|
+
}
|
|
71
|
+
export function tokensEqual(a, b) {
|
|
72
|
+
const ha = createHash("sha256").update(a).digest();
|
|
73
|
+
const hb = createHash("sha256").update(b).digest();
|
|
74
|
+
return timingSafeEqual(ha, hb);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../../packages/server/src/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
2
|
+
import { createAgentConnect } from "./index.js";
|
|
3
|
+
import { migrate } from "./migrate.js";
|
|
4
|
+
import { assertSchemaName, connectDatabase } from "./store.js";
|
|
5
|
+
// The container's entry: reads the environment, builds the service with createAgentConnect
|
|
6
|
+
// and listens. `node dist/server.js migrate` only applies pending migrations and exits, for
|
|
7
|
+
// installs that run schema changes as their own step (MIGRATE_ON_START=false).
|
|
8
|
+
function required(name) {
|
|
9
|
+
const value = process.env[name];
|
|
10
|
+
if (!value)
|
|
11
|
+
throw new Error(`Missing required env var: ${name}`);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
// The name a setting had before the service had its own; read for one release so an install
|
|
15
|
+
// whose environment still sets only the old name keeps working, saying so in its log.
|
|
16
|
+
function renamed(name, old) {
|
|
17
|
+
const value = process.env[name]?.trim();
|
|
18
|
+
if (value)
|
|
19
|
+
return value;
|
|
20
|
+
const legacy = process.env[old]?.trim();
|
|
21
|
+
if (legacy)
|
|
22
|
+
console.log(`[agent-connect] ${old} is deprecated; set ${name} instead`);
|
|
23
|
+
return legacy || undefined;
|
|
24
|
+
}
|
|
25
|
+
const schema = process.env.DATABASE_SCHEMA?.trim() || "agent_connect";
|
|
26
|
+
assertSchemaName(schema);
|
|
27
|
+
const migrateOnStart = process.env.MIGRATE_ON_START?.trim() ?? "true";
|
|
28
|
+
if (migrateOnStart !== "true" && migrateOnStart !== "false")
|
|
29
|
+
throw new Error("MIGRATE_ON_START must be true or false");
|
|
30
|
+
if (process.argv[2] === "migrate") {
|
|
31
|
+
const sql = connectDatabase(required("DATABASE_URL"));
|
|
32
|
+
await migrate(sql, schema);
|
|
33
|
+
await sql.end();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const sharedApp = process.env.MICROSOFT_SHARED_APP?.trim() ?? "";
|
|
37
|
+
if (sharedApp !== "" && sharedApp !== "enabled")
|
|
38
|
+
throw new Error("MICROSOFT_SHARED_APP must be unset or enabled");
|
|
39
|
+
const sharedAppSetting = (name, old) => {
|
|
40
|
+
const value = renamed(name, old);
|
|
41
|
+
if (!value)
|
|
42
|
+
throw new Error(`Missing required env var: ${name}`);
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
const service = await createAgentConnect({
|
|
46
|
+
database: { url: required("DATABASE_URL") },
|
|
47
|
+
schema,
|
|
48
|
+
migrate: migrateOnStart === "true",
|
|
49
|
+
encryptionKey: required("CONNECT_ENCRYPTION_KEY"),
|
|
50
|
+
previousEncryptionKey: process.env.CONNECT_ENCRYPTION_KEY_PREVIOUS || undefined,
|
|
51
|
+
adminToken: required("AGENT_CONNECT_ADMIN_TOKEN"),
|
|
52
|
+
publicBaseUrl: renamed("PUBLIC_BASE_URL", "SELF_HOST_PUBLIC_BASE_URL") ?? null,
|
|
53
|
+
branding: process.env.BRANDING?.trim() ? JSON.parse(process.env.BRANDING) : undefined,
|
|
54
|
+
extraConnectorDirs: (process.env.CONNECTOR_DIRS ?? "").split(":").filter(Boolean),
|
|
55
|
+
microsoftSharedApp: sharedApp === "enabled"
|
|
56
|
+
? {
|
|
57
|
+
clientId: sharedAppSetting("MICROSOFT_SHARED_APP_CLIENT_ID", "ARBIUM_MICROSOFT_CLIENT_ID"),
|
|
58
|
+
clientSecret: sharedAppSetting("MICROSOFT_SHARED_APP_CLIENT_SECRET", "ARBIUM_MICROSOFT_CLIENT_SECRET"),
|
|
59
|
+
}
|
|
60
|
+
: null,
|
|
61
|
+
});
|
|
62
|
+
service.start();
|
|
63
|
+
process.on("SIGTERM", () => {
|
|
64
|
+
service.stop().finally(() => process.exit(0));
|
|
65
|
+
});
|
|
66
|
+
const port = Number(process.env.PORT || 3000);
|
|
67
|
+
serve({ fetch: service.fetch, port });
|
|
68
|
+
console.log(`[agent-connect] listening on :${port} with ${service.connectors.join(", ")}`);
|
|
69
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../packages/server/src/server.ts"],"names":[],"mappings":"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"}
|