refactor(core): simplify integration credentials (#31968)

This commit is contained in:
Dax 2026-06-12 02:15:25 -04:00 committed by GitHub
commit 30aec297d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
112 changed files with 2467 additions and 47728 deletions

View file

@ -650,49 +650,67 @@ const scenarios: Scenario[] = [
http.protected.get("/api/agent", "v2.agent.list").json(200, locationData(array)),
http.protected.get("/api/model", "v2.model.list").json(200, locationData(array)),
http.protected.get("/api/provider", "v2.provider.list").json(200, locationData(array)),
http.protected.get("/api/connector", "v2.connector.list").json(200, locationData(array)),
http.protected.get("/api/integration", "v2.integration.list").json(200, locationData(array)),
http.protected
.get("/api/connector/{connectorID}", "v2.connector.get")
.at((ctx) => ({ path: route("/api/connector/{connectorID}", { connectorID: "missing" }), headers: ctx.headers() }))
.get("/api/integration/{integrationID}", "v2.integration.get")
.at((ctx) => ({
path: route("/api/integration/{integrationID}", { integrationID: "missing" }),
headers: ctx.headers(),
}))
.json(200, object),
http.protected
.post("/api/connector/{connectorID}/connect/key", "v2.connector.connect.key")
.post("/api/integration/{integrationID}/connect/key", "v2.integration.connect.key")
.at((ctx) => ({
path: route("/api/connector/{connectorID}/connect/key", { connectorID: "missing" }),
path: route("/api/integration/{integrationID}/connect/key", { integrationID: "missing" }),
headers: ctx.headers(),
body: { methodID: "missing", key: "test", inputs: {} },
body: { key: "test" },
}))
.status(500, undefined, "status"),
http.protected
.post("/api/connector/{connectorID}/connect/oauth", "v2.connector.connect.oauth.begin")
.post("/api/integration/{integrationID}/connect/oauth", "v2.integration.connect.oauth")
.at((ctx) => ({
path: route("/api/connector/{connectorID}/connect/oauth", { connectorID: "missing" }),
path: route("/api/integration/{integrationID}/connect/oauth", { integrationID: "missing" }),
headers: ctx.headers(),
body: { methodID: "missing", inputs: {} },
}))
.status(500, undefined, "status"),
http.protected
.get("/api/connector/oauth/{attemptID}", "v2.connector.connect.oauth.status")
.get("/api/integration/attempt/{attemptID}", "v2.integration.attempt.status")
.at((ctx) => ({
path: route("/api/connector/oauth/{attemptID}", { attemptID: "con_missing" }),
path: route("/api/integration/attempt/{attemptID}", { attemptID: "con_missing" }),
headers: ctx.headers(),
}))
.status(500, undefined, "status"),
http.protected
.post("/api/connector/oauth/{attemptID}/complete", "v2.connector.connect.oauth.complete")
.post("/api/integration/attempt/{attemptID}/complete", "v2.integration.attempt.complete")
.at((ctx) => ({
path: route("/api/connector/oauth/{attemptID}/complete", { attemptID: "con_missing" }),
path: route("/api/integration/attempt/{attemptID}/complete", { attemptID: "con_missing" }),
headers: ctx.headers(),
body: {},
}))
.status(500, undefined, "status"),
http.protected
.delete("/api/connector/oauth/{attemptID}", "v2.connector.connect.oauth.cancel")
.delete("/api/integration/attempt/{attemptID}", "v2.integration.attempt.cancel")
.at((ctx) => ({
path: route("/api/connector/oauth/{attemptID}", { attemptID: "con_missing" }),
path: route("/api/integration/attempt/{attemptID}", { attemptID: "con_missing" }),
headers: ctx.headers(),
}))
.status(204, undefined, "status"),
http.protected
.delete("/api/credential/{credentialID}", "v2.credential.remove")
.at((ctx) => ({
path: route("/api/credential/{credentialID}", { credentialID: "cred_missing" }),
headers: ctx.headers(),
}))
.status(204, undefined, "status"),
http.protected
.patch("/api/credential/{credentialID}", "v2.credential.update")
.at((ctx) => ({
path: route("/api/credential/{credentialID}", { credentialID: "cred_missing" }),
headers: ctx.headers(),
body: { label: "Work" },
}))
.status(204, undefined, "status"),
http.protected.get("/api/command", "v2.command.list").json(200, locationData(array)),
http.protected.get("/api/skill", "v2.skill.list").json(200, locationData(array)),
http.protected

View file

@ -115,25 +115,27 @@ describe("PublicApi OpenAPI v2 errors", () => {
}
})
test("documents connector discovery and connection routes", () => {
test("documents integration discovery and connection routes", () => {
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
for (const [method, path] of [
["get", "/api/connector"],
["get", "/api/connector/{connectorID}"],
["post", "/api/connector/{connectorID}/connect/key"],
["post", "/api/connector/{connectorID}/connect/oauth"],
["get", "/api/connector/oauth/{attemptID}"],
["post", "/api/connector/oauth/{attemptID}/complete"],
["delete", "/api/connector/oauth/{attemptID}"],
["get", "/api/integration"],
["get", "/api/integration/{integrationID}"],
["post", "/api/integration/{integrationID}/connect/key"],
["post", "/api/integration/{integrationID}/connect/oauth"],
["get", "/api/integration/attempt/{attemptID}"],
["post", "/api/integration/attempt/{attemptID}/complete"],
["delete", "/api/integration/attempt/{attemptID}"],
["delete", "/api/credential/{credentialID}"],
["patch", "/api/credential/{credentialID}"],
] as const) {
expect(spec.paths[path]?.[method], `${method.toUpperCase()} ${path}`).toBeDefined()
}
for (const path of [
"/api/connector/{connectorID}/connect/key",
"/api/connector/{connectorID}/connect/oauth",
"/api/connector/oauth/{attemptID}/complete",
"/api/integration/{integrationID}/connect/key",
"/api/integration/{integrationID}/connect/oauth",
"/api/integration/attempt/{attemptID}/complete",
]) {
expect(spec.paths[path]?.post?.requestBody?.required, path).toBe(true)
}

View file

@ -1,50 +0,0 @@
import { describe, expect, test } from "bun:test"
import { Database } from "bun:sqlite"
import { drizzle } from "drizzle-orm/bun-sqlite"
import { migrate } from "drizzle-orm/bun-sqlite/migrator"
import { existsSync, readFileSync, readdirSync } from "fs"
import path from "path"
const target = "20260507164347_add_workspace_time"
function migrations() {
return readdirSync(path.join(import.meta.dirname, "../../../core/migration"), { withFileTypes: true })
.filter(
(entry) =>
entry.isDirectory() &&
existsSync(path.join(import.meta.dirname, "../../../core/migration", entry.name, "migration.sql")),
)
.map((entry) => ({
name: entry.name,
timestamp: Number(entry.name.split("_")[0]),
sql: readFileSync(
path.join(import.meta.dirname, "../../../core/migration", entry.name, "migration.sql"),
"utf-8",
),
}))
.sort((a, b) => a.timestamp - b.timestamp)
}
describe("workspace time migration", () => {
test("discards existing workspace rows during the beta reset", () => {
const sqlite = new Database(":memory:")
const db = drizzle({ client: sqlite })
const entries = migrations()
const index = entries.findIndex((entry) => entry.name === target)
expect(index).toBeGreaterThan(0)
migrate(db, entries.slice(0, index))
sqlite.run(
"INSERT INTO project (id, worktree, vcs, name, time_created, time_updated, sandboxes) VALUES (?, ?, ?, ?, ?, ?, ?)",
["project_1", "/tmp/project", "git", "project", 1, 1, "[]"],
)
sqlite.run(
"INSERT INTO workspace (id, type, name, branch, directory, extra, project_id) VALUES (?, ?, ?, ?, ?, ?, ?)",
["workspace_1", "local", "main", "main", "/tmp/project", null, "project_1"],
)
expect(() => migrate(db, entries.slice(index))).not.toThrow()
expect(sqlite.query("SELECT time_used FROM workspace WHERE id = ?").get("workspace_1")).toBeNull()
})
})