History

Repair OpenAPI OAuth credential-binding cutover residue

Rhys Sullivan committed 6 months ago

Commit 70725e61 parent 7c00f9d5 files · +702 −0Browse files

Unified · Split

5 files
  1. apps/cloud/drizzle/0014_repair_openapi_oauth_cutover_residue.sql +241 −0
  2. apps/cloud/drizzle/meta/_journal.json +7 −0
  3. apps/local/drizzle/0009_repair_openapi_oauth_cutover_residue.sql +253 −0
  4. apps/local/drizzle/meta/_journal.json +7 −0
  5. apps/local/src/server/migrate-oauth-connections.test.ts +194 −0
apps/cloud/drizzle/0014_repair_openapi_oauth_cutover_residue.sql+241−0
@@ -0,0 +1,241 @@
1-- Repair OpenAPI OAuth residue from the scoped-credential cutover.
2--
3-- 0009 only normalized provider='openapi:oauth2' rows whose provider_state
4-- still had the old `flow` shape. Some live rows already had canonical
5-- `kind` provider_state, so the provider key was skipped. 0012 also collapsed
6-- user-scoped OpenAPI OAuth client credential bindings when the backing Secret
7-- row lived at the source/org scope. Runtime refresh reads provider_state
8-- directly, but edit/refresh UI reads credential_binding rows, so recreate
9-- those explicit bindings from the already-canonical Connection rows.
10
11UPDATE "connection"
12SET "provider" = 'oauth2',
13 "updated_at" = now()
14WHERE "provider" = 'openapi:oauth2'
15 AND "provider_state" ? 'kind';--> statement-breakpoint
16
17WITH oauth_connections AS (
18 SELECT
19 b."scope_id",
20 b."id" AS "binding_id",
21 b."plugin_id",
22 b."source_id",
23 b."source_scope_id",
24 s."oauth2"->>'clientIdSlot' AS "slot_key",
25 c."provider_state"->>'clientIdSecretId' AS "secret_id",
26 b."created_at"
27 FROM "credential_binding" b
28 JOIN "openapi_source" s
29 ON s."id" = b."source_id"
30 AND s."scope_id" = b."source_scope_id"
31 JOIN "connection" c
32 ON c."id" = b."connection_id"
33 AND c."scope_id" = b."scope_id"
34 WHERE b."plugin_id" = 'openapi'
35 AND b."kind" = 'connection'
36 AND s."oauth2" IS NOT NULL
37 AND c."provider" = 'oauth2'
38 AND c."provider_state" ? 'clientIdSecretId'
39 AND coalesce(c."provider_state"->>'clientIdSecretId', '') <> ''
40)
41UPDATE "credential_binding" b
42SET "secret_id" = r."secret_id",
43 "text_value" = NULL,
44 "connection_id" = NULL,
45 "updated_at" = now()
46FROM oauth_connections r
47WHERE b."scope_id" = r."scope_id"
48 AND b."plugin_id" = r."plugin_id"
49 AND b."source_id" = r."source_id"
50 AND b."source_scope_id" = r."source_scope_id"
51 AND b."slot_key" = r."slot_key"
52 AND b."kind" = 'secret';--> statement-breakpoint
53
54WITH oauth_connections AS (
55 SELECT
56 b."scope_id",
57 b."id" AS "binding_id",
58 b."plugin_id",
59 b."source_id",
60 b."source_scope_id",
61 s."oauth2"->>'clientIdSlot' AS "slot_key",
62 c."provider_state"->>'clientIdSecretId' AS "secret_id",
63 b."created_at"
64 FROM "credential_binding" b
65 JOIN "openapi_source" s
66 ON s."id" = b."source_id"
67 AND s."scope_id" = b."source_scope_id"
68 JOIN "connection" c
69 ON c."id" = b."connection_id"
70 AND c."scope_id" = b."scope_id"
71 WHERE b."plugin_id" = 'openapi'
72 AND b."kind" = 'connection'
73 AND s."oauth2" IS NOT NULL
74 AND c."provider" = 'oauth2'
75 AND c."provider_state" ? 'clientIdSecretId'
76 AND coalesce(c."provider_state"->>'clientIdSecretId', '') <> ''
77)
78INSERT INTO "credential_binding" (
79 "id",
80 "scope_id",
81 "plugin_id",
82 "source_id",
83 "source_scope_id",
84 "slot_key",
85 "kind",
86 "text_value",
87 "secret_id",
88 "connection_id",
89 "created_at",
90 "updated_at"
91)
92SELECT
93 '[' || to_jsonb('oconn-openapi-oauth-client'::text)::text || ',' || to_jsonb(r."binding_id")::text || ',' || to_jsonb(r."scope_id")::text || ',' || to_jsonb(r."slot_key")::text || ']',
94 r."scope_id",
95 r."plugin_id",
96 r."source_id",
97 r."source_scope_id",
98 r."slot_key",
99 'secret',
100 NULL,
101 r."secret_id",
102 NULL,
103 r."created_at",
104 now()
105FROM oauth_connections r
106WHERE r."slot_key" IS NOT NULL
107 AND NOT EXISTS (
108 SELECT 1
109 FROM "credential_binding" existing
110 WHERE existing."scope_id" = r."scope_id"
111 AND existing."plugin_id" = r."plugin_id"
112 AND existing."source_id" = r."source_id"
113 AND existing."source_scope_id" = r."source_scope_id"
114 AND existing."slot_key" = r."slot_key"
115 )
116ON CONFLICT ("scope_id", "id") DO UPDATE SET
117 "plugin_id" = excluded."plugin_id",
118 "source_id" = excluded."source_id",
119 "source_scope_id" = excluded."source_scope_id",
120 "slot_key" = excluded."slot_key",
121 "kind" = excluded."kind",
122 "text_value" = excluded."text_value",
123 "secret_id" = excluded."secret_id",
124 "connection_id" = excluded."connection_id",
125 "updated_at" = excluded."updated_at";--> statement-breakpoint
126
127WITH oauth_connections AS (
128 SELECT
129 b."scope_id",
130 b."id" AS "binding_id",
131 b."plugin_id",
132 b."source_id",
133 b."source_scope_id",
134 coalesce(
135 s."oauth2"->>'clientSecretSlot',
136 'oauth2:' || COALESCE(NULLIF(trim(both '-' from lower(regexp_replace(trim(s."oauth2"->>'securitySchemeName'), '[^a-zA-Z0-9]+', '-', 'g'))), ''), 'default') || ':client-secret'
137 ) AS "slot_key",
138 c."provider_state"->>'clientSecretSecretId' AS "secret_id",
139 b."created_at"
140 FROM "credential_binding" b
141 JOIN "openapi_source" s
142 ON s."id" = b."source_id"
143 AND s."scope_id" = b."source_scope_id"
144 JOIN "connection" c
145 ON c."id" = b."connection_id"
146 AND c."scope_id" = b."scope_id"
147 WHERE b."plugin_id" = 'openapi'
148 AND b."kind" = 'connection'
149 AND s."oauth2" IS NOT NULL
150 AND c."provider" = 'oauth2'
151 AND c."provider_state" ? 'clientSecretSecretId'
152 AND coalesce(c."provider_state"->>'clientSecretSecretId', '') <> ''
153)
154UPDATE "credential_binding" b
155SET "secret_id" = r."secret_id",
156 "text_value" = NULL,
157 "connection_id" = NULL,
158 "updated_at" = now()
159FROM oauth_connections r
160WHERE b."scope_id" = r."scope_id"
161 AND b."plugin_id" = r."plugin_id"
162 AND b."source_id" = r."source_id"
163 AND b."source_scope_id" = r."source_scope_id"
164 AND b."slot_key" = r."slot_key"
165 AND b."kind" = 'secret';--> statement-breakpoint
166
167WITH oauth_connections AS (
168 SELECT
169 b."scope_id",
170 b."id" AS "binding_id",
171 b."plugin_id",
172 b."source_id",
173 b."source_scope_id",
174 coalesce(
175 s."oauth2"->>'clientSecretSlot',
176 'oauth2:' || COALESCE(NULLIF(trim(both '-' from lower(regexp_replace(trim(s."oauth2"->>'securitySchemeName'), '[^a-zA-Z0-9]+', '-', 'g'))), ''), 'default') || ':client-secret'
177 ) AS "slot_key",
178 c."provider_state"->>'clientSecretSecretId' AS "secret_id",
179 b."created_at"
180 FROM "credential_binding" b
181 JOIN "openapi_source" s
182 ON s."id" = b."source_id"
183 AND s."scope_id" = b."source_scope_id"
184 JOIN "connection" c
185 ON c."id" = b."connection_id"
186 AND c."scope_id" = b."scope_id"
187 WHERE b."plugin_id" = 'openapi'
188 AND b."kind" = 'connection'
189 AND s."oauth2" IS NOT NULL
190 AND c."provider" = 'oauth2'
191 AND c."provider_state" ? 'clientSecretSecretId'
192 AND coalesce(c."provider_state"->>'clientSecretSecretId', '') <> ''
193)
194INSERT INTO "credential_binding" (
195 "id",
196 "scope_id",
197 "plugin_id",
198 "source_id",
199 "source_scope_id",
200 "slot_key",
201 "kind",
202 "text_value",
203 "secret_id",
204 "connection_id",
205 "created_at",
206 "updated_at"
207)
208SELECT
209 '[' || to_jsonb('oconn-openapi-oauth-secret'::text)::text || ',' || to_jsonb(r."binding_id")::text || ',' || to_jsonb(r."scope_id")::text || ',' || to_jsonb(r."slot_key")::text || ']',
210 r."scope_id",
211 r."plugin_id",
212 r."source_id",
213 r."source_scope_id",
214 r."slot_key",
215 'secret',
216 NULL,
217 r."secret_id",
218 NULL,
219 r."created_at",
220 now()
221FROM oauth_connections r
222WHERE r."slot_key" IS NOT NULL
223 AND NOT EXISTS (
224 SELECT 1
225 FROM "credential_binding" existing
226 WHERE existing."scope_id" = r."scope_id"
227 AND existing."plugin_id" = r."plugin_id"
228 AND existing."source_id" = r."source_id"
229 AND existing."source_scope_id" = r."source_scope_id"
230 AND existing."slot_key" = r."slot_key"
231 )
232ON CONFLICT ("scope_id", "id") DO UPDATE SET
233 "plugin_id" = excluded."plugin_id",
234 "source_id" = excluded."source_id",
235 "source_scope_id" = excluded."source_scope_id",
236 "slot_key" = excluded."slot_key",
237 "kind" = excluded."kind",
238 "text_value" = excluded."text_value",
239 "secret_id" = excluded."secret_id",
240 "connection_id" = excluded."connection_id",
241 "updated_at" = excluded."updated_at";
apps/cloud/drizzle/meta/_journal.json+7−0
@@ -99,6 +99,13 @@ · 98 unmodified lines
99 "when": 1778179800000,99 "when": 1778179800000,
100 "tag": "0013_cleanup_orphan_oauth_rows",100 "tag": "0013_cleanup_orphan_oauth_rows",
101 "breakpoints": true101 "breakpoints": true
102 },
103 {
104 "idx": 14,
105 "version": "7",
106 "when": 1778192434062,
107 "tag": "0014_repair_openapi_oauth_cutover_residue",
108 "breakpoints": true
102 }109 }
103 ]110 ]
104}111}
apps/local/drizzle/0009_repair_openapi_oauth_cutover_residue.sql+253−0
@@ -0,0 +1,253 @@
1-- Repair OpenAPI OAuth residue from the scoped-credential cutover.
2
3UPDATE `connection`
4SET `provider` = 'oauth2',
5 `updated_at` = CAST(strftime('%s', 'now') AS INTEGER) * 1000
6WHERE `provider` = 'openapi:oauth2'
7 AND json_extract(`provider_state`, '$.kind') IS NOT NULL;--> statement-breakpoint
8
9WITH oauth_connections AS (
10 SELECT
11 b.`scope_id`,
12 b.`id` AS `binding_id`,
13 b.`plugin_id`,
14 b.`source_id`,
15 b.`source_scope_id`,
16 json_extract(s.`oauth2`, '$.clientIdSlot') AS `slot_key`,
17 json_extract(c.`provider_state`, '$.clientIdSecretId') AS `secret_id`,
18 b.`created_at`
19 FROM `credential_binding` b
20 JOIN `openapi_source` s
21 ON s.`id` = b.`source_id`
22 AND s.`scope_id` = b.`source_scope_id`
23 JOIN `connection` c
24 ON c.`id` = b.`connection_id`
25 AND c.`scope_id` = b.`scope_id`
26 WHERE b.`plugin_id` = 'openapi'
27 AND b.`kind` = 'connection'
28 AND s.`oauth2` IS NOT NULL
29 AND c.`provider` = 'oauth2'
30 AND json_extract(c.`provider_state`, '$.clientIdSecretId') IS NOT NULL
31 AND coalesce(json_extract(c.`provider_state`, '$.clientIdSecretId'), '') <> ''
32)
33UPDATE `credential_binding`
34SET
35 `secret_id` = (
36 SELECT r.`secret_id`
37 FROM oauth_connections r
38 WHERE r.`scope_id` = `credential_binding`.`scope_id`
39 AND r.`plugin_id` = `credential_binding`.`plugin_id`
40 AND r.`source_id` = `credential_binding`.`source_id`
41 AND r.`source_scope_id` = `credential_binding`.`source_scope_id`
42 AND r.`slot_key` = `credential_binding`.`slot_key`
43 LIMIT 1
44 ),
45 `text_value` = NULL,
46 `connection_id` = NULL,
47 `updated_at` = CAST(strftime('%s', 'now') AS INTEGER) * 1000
48WHERE `kind` = 'secret'
49 AND EXISTS (
50 SELECT 1
51 FROM oauth_connections r
52 WHERE r.`scope_id` = `credential_binding`.`scope_id`
53 AND r.`plugin_id` = `credential_binding`.`plugin_id`
54 AND r.`source_id` = `credential_binding`.`source_id`
55 AND r.`source_scope_id` = `credential_binding`.`source_scope_id`
56 AND r.`slot_key` = `credential_binding`.`slot_key`
57 );--> statement-breakpoint
58
59WITH oauth_connections AS (
60 SELECT
61 b.`scope_id`,
62 b.`id` AS `binding_id`,
63 b.`plugin_id`,
64 b.`source_id`,
65 b.`source_scope_id`,
66 json_extract(s.`oauth2`, '$.clientIdSlot') AS `slot_key`,
67 json_extract(c.`provider_state`, '$.clientIdSecretId') AS `secret_id`,
68 b.`created_at`
69 FROM `credential_binding` b
70 JOIN `openapi_source` s
71 ON s.`id` = b.`source_id`
72 AND s.`scope_id` = b.`source_scope_id`
73 JOIN `connection` c
74 ON c.`id` = b.`connection_id`
75 AND c.`scope_id` = b.`scope_id`
76 WHERE b.`plugin_id` = 'openapi'
77 AND b.`kind` = 'connection'
78 AND s.`oauth2` IS NOT NULL
79 AND c.`provider` = 'oauth2'
80 AND json_extract(c.`provider_state`, '$.clientIdSecretId') IS NOT NULL
81 AND coalesce(json_extract(c.`provider_state`, '$.clientIdSecretId'), '') <> ''
82)
83INSERT INTO `credential_binding` (
84 `id`,
85 `scope_id`,
86 `plugin_id`,
87 `source_id`,
88 `source_scope_id`,
89 `slot_key`,
90 `kind`,
91 `text_value`,
92 `secret_id`,
93 `connection_id`,
94 `created_at`,
95 `updated_at`
96)
97SELECT
98 json_array('oconn-openapi-oauth-client', r.`binding_id`, r.`scope_id`, r.`slot_key`),
99 r.`scope_id`,
100 r.`plugin_id`,
101 r.`source_id`,
102 r.`source_scope_id`,
103 r.`slot_key`,
104 'secret',
105 NULL,
106 r.`secret_id`,
107 NULL,
108 r.`created_at`,
109 CAST(strftime('%s', 'now') AS INTEGER) * 1000
110FROM oauth_connections r
111WHERE r.`slot_key` IS NOT NULL
112 AND NOT EXISTS (
113 SELECT 1
114 FROM `credential_binding` existing
115 WHERE existing.`scope_id` = r.`scope_id`
116 AND existing.`plugin_id` = r.`plugin_id`
117 AND existing.`source_id` = r.`source_id`
118 AND existing.`source_scope_id` = r.`source_scope_id`
119 AND existing.`slot_key` = r.`slot_key`
120 )
121ON CONFLICT(`scope_id`, `id`) DO UPDATE SET
122 `plugin_id` = excluded.`plugin_id`,
123 `source_id` = excluded.`source_id`,
124 `source_scope_id` = excluded.`source_scope_id`,
125 `slot_key` = excluded.`slot_key`,
126 `kind` = excluded.`kind`,
127 `text_value` = excluded.`text_value`,
128 `secret_id` = excluded.`secret_id`,
129 `connection_id` = excluded.`connection_id`,
130 `updated_at` = excluded.`updated_at`;--> statement-breakpoint
131
132WITH oauth_connections AS (
133 SELECT
134 b.`scope_id`,
135 b.`id` AS `binding_id`,
136 b.`plugin_id`,
137 b.`source_id`,
138 b.`source_scope_id`,
139 json_extract(s.`oauth2`, '$.clientSecretSlot') AS `slot_key`,
140 json_extract(c.`provider_state`, '$.clientSecretSecretId') AS `secret_id`,
141 b.`created_at`
142 FROM `credential_binding` b
143 JOIN `openapi_source` s
144 ON s.`id` = b.`source_id`
145 AND s.`scope_id` = b.`source_scope_id`
146 JOIN `connection` c
147 ON c.`id` = b.`connection_id`
148 AND c.`scope_id` = b.`scope_id`
149 WHERE b.`plugin_id` = 'openapi'
150 AND b.`kind` = 'connection'
151 AND s.`oauth2` IS NOT NULL
152 AND c.`provider` = 'oauth2'
153 AND json_extract(c.`provider_state`, '$.clientSecretSecretId') IS NOT NULL
154 AND coalesce(json_extract(c.`provider_state`, '$.clientSecretSecretId'), '') <> ''
155)
156UPDATE `credential_binding`
157SET
158 `secret_id` = (
159 SELECT r.`secret_id`
160 FROM oauth_connections r
161 WHERE r.`scope_id` = `credential_binding`.`scope_id`
162 AND r.`plugin_id` = `credential_binding`.`plugin_id`
163 AND r.`source_id` = `credential_binding`.`source_id`
164 AND r.`source_scope_id` = `credential_binding`.`source_scope_id`
165 AND r.`slot_key` = `credential_binding`.`slot_key`
166 LIMIT 1
167 ),
168 `text_value` = NULL,
169 `connection_id` = NULL,
170 `updated_at` = CAST(strftime('%s', 'now') AS INTEGER) * 1000
171WHERE `kind` = 'secret'
172 AND EXISTS (
173 SELECT 1
174 FROM oauth_connections r
175 WHERE r.`scope_id` = `credential_binding`.`scope_id`
176 AND r.`plugin_id` = `credential_binding`.`plugin_id`
177 AND r.`source_id` = `credential_binding`.`source_id`
178 AND r.`source_scope_id` = `credential_binding`.`source_scope_id`
179 AND r.`slot_key` = `credential_binding`.`slot_key`
180 );--> statement-breakpoint
181
182WITH oauth_connections AS (
183 SELECT
184 b.`scope_id`,
185 b.`id` AS `binding_id`,
186 b.`plugin_id`,
187 b.`source_id`,
188 b.`source_scope_id`,
189 json_extract(s.`oauth2`, '$.clientSecretSlot') AS `slot_key`,
190 json_extract(c.`provider_state`, '$.clientSecretSecretId') AS `secret_id`,
191 b.`created_at`
192 FROM `credential_binding` b
193 JOIN `openapi_source` s
194 ON s.`id` = b.`source_id`
195 AND s.`scope_id` = b.`source_scope_id`
196 JOIN `connection` c
197 ON c.`id` = b.`connection_id`
198 AND c.`scope_id` = b.`scope_id`
199 WHERE b.`plugin_id` = 'openapi'
200 AND b.`kind` = 'connection'
201 AND s.`oauth2` IS NOT NULL
202 AND c.`provider` = 'oauth2'
203 AND json_extract(c.`provider_state`, '$.clientSecretSecretId') IS NOT NULL
204 AND coalesce(json_extract(c.`provider_state`, '$.clientSecretSecretId'), '') <> ''
205)
206INSERT INTO `credential_binding` (
207 `id`,
208 `scope_id`,
209 `plugin_id`,
210 `source_id`,
211 `source_scope_id`,
212 `slot_key`,
213 `kind`,
214 `text_value`,
215 `secret_id`,
216 `connection_id`,
217 `created_at`,
218 `updated_at`
219)
220SELECT
221 json_array('oconn-openapi-oauth-secret', r.`binding_id`, r.`scope_id`, r.`slot_key`),
222 r.`scope_id`,
223 r.`plugin_id`,
224 r.`source_id`,
225 r.`source_scope_id`,
226 r.`slot_key`,
227 'secret',
228 NULL,
229 r.`secret_id`,
230 NULL,
231 r.`created_at`,
232 CAST(strftime('%s', 'now') AS INTEGER) * 1000
233FROM oauth_connections r
234WHERE r.`slot_key` IS NOT NULL
235 AND NOT EXISTS (
236 SELECT 1
237 FROM `credential_binding` existing
238 WHERE existing.`scope_id` = r.`scope_id`
239 AND existing.`plugin_id` = r.`plugin_id`
240 AND existing.`source_id` = r.`source_id`
241 AND existing.`source_scope_id` = r.`source_scope_id`
242 AND existing.`slot_key` = r.`slot_key`
243 )
244ON CONFLICT(`scope_id`, `id`) DO UPDATE SET
245 `plugin_id` = excluded.`plugin_id`,
246 `source_id` = excluded.`source_id`,
247 `source_scope_id` = excluded.`source_scope_id`,
248 `slot_key` = excluded.`slot_key`,
249 `kind` = excluded.`kind`,
250 `text_value` = excluded.`text_value`,
251 `secret_id` = excluded.`secret_id`,
252 `connection_id` = excluded.`connection_id`,
253 `updated_at` = excluded.`updated_at`;
apps/local/drizzle/meta/_journal.json+7−0
@@ -64,6 +64,13 @@ · 63 unmodified lines
64 "when": 1778128200000,64 "when": 1778128200000,
65 "tag": "0008_scoped_credentials_cutover",65 "tag": "0008_scoped_credentials_cutover",
66 "breakpoints": true66 "breakpoints": true
67 },
68 {
69 "idx": 9,
70 "version": "6",
71 "when": 1778192434062,
72 "tag": "0009_repair_openapi_oauth_cutover_residue",
73 "breakpoints": true
67 }74 }
68 ]75 ]
69}76}
apps/local/src/server/migrate-oauth-connections.test.ts+194−0
@@ -6,6 +6,10 @@ import { join } from "node:path"; · 5 unmodified lines
6import { Schema } from "effect";6import { Schema } from "effect";
7 7
8const MIGRATION = join(import.meta.dirname, "../../drizzle/0008_scoped_credentials_cutover.sql");8const MIGRATION = join(import.meta.dirname, "../../drizzle/0008_scoped_credentials_cutover.sql");
9const REPAIR_MIGRATION = join(
10 import.meta.dirname,
11 "../../drizzle/0009_repair_openapi_oauth_cutover_residue.sql",
12);
9 13
10let workDir: string;14let workDir: string;
11let db: Database;15let db: Database;
@@ -126,3 +130,193 @@ describe("0008_scoped_credentials_cutover OAuth connection section", () => { · 114 unmodified lines
126 });130 });
127 });131 });
128});132});
133
134describe("0009_repair_openapi_oauth_cutover_residue", () => {
135 it("repairs already-canonical OpenAPI rows and restores user-scoped OAuth secret bindings", () => {
136 const now = Date.now();
137 db.exec(`
138 CREATE TABLE \`openapi_source\` (
139 \`id\` text NOT NULL,
140 \`scope_id\` text NOT NULL,
141 \`oauth2\` text,
142 PRIMARY KEY(\`scope_id\`, \`id\`)
143 );
144 CREATE TABLE \`credential_binding\` (
145 \`id\` text NOT NULL,
146 \`scope_id\` text NOT NULL,
147 \`plugin_id\` text NOT NULL,
148 \`source_id\` text NOT NULL,
149 \`source_scope_id\` text NOT NULL,
150 \`slot_key\` text NOT NULL,
151 \`kind\` text NOT NULL,
152 \`text_value\` text,
153 \`secret_id\` text,
154 \`connection_id\` text,
155 \`created_at\` integer NOT NULL,
156 \`updated_at\` integer NOT NULL,
157 PRIMARY KEY(\`scope_id\`, \`id\`)
158 );
159 `);
160
161 db.prepare(
162 "INSERT INTO `openapi_source` (id, scope_id, oauth2) VALUES (?, ?, ?)",
163 ).run(
164 "dealcloud_api",
165 "org-1",
166 JSON.stringify({
167 kind: "oauth2",
168 securitySchemeName: "oauth2",
169 clientIdSlot: "oauth2:oauth2:client-id",
170 clientSecretSlot: "oauth2:oauth2:client-secret",
171 connectionSlot: "oauth2:oauth2:connection",
172 }),
173 );
174
175 const insertConnection = db.prepare(
176 "INSERT INTO `connection` (id, scope_id, provider, provider_state, scope, updated_at) VALUES (?, ?, ?, ?, ?, ?)",
177 );
178 insertConnection.run(
179 "openapi-oauth2-app-dealcloud_api",
180 "org-1",
181 "oauth2",
182 JSON.stringify({
183 kind: "client-credentials",
184 tokenEndpoint: "https://resolve.dealcloud.com/oauth/token",
185 clientIdSecretId: "dealcloud-client-id",
186 clientSecretSecretId: "dealcloud-client-secret",
187 }),
188 null,
189 now,
190 );
191 insertConnection.run(
192 "openapi-oauth2-app-dealcloud_api",
193 "user-org:user-jd:org-1",
194 "openapi:oauth2",
195 JSON.stringify({
196 kind: "client-credentials",
197 tokenEndpoint: "https://resolve.dealcloud.com/oauth/token",
198 clientIdSecretId: "dealcloud-client-id-jd",
199 clientSecretSecretId: "dealcloud-client-secret-jd",
200 }),
201 null,
202 now,
203 );
204
205 const insertBinding = db.prepare(
206 "INSERT INTO `credential_binding` (id, scope_id, plugin_id, source_id, source_scope_id, slot_key, kind, text_value, secret_id, connection_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
207 );
208 insertBinding.run(
209 "org-client-id",
210 "org-1",
211 "openapi",
212 "dealcloud_api",
213 "org-1",
214 "oauth2:oauth2:client-id",
215 "secret",
216 null,
217 "dealcloud-client-id-jd",
218 null,
219 now,
220 now,
221 );
222 insertBinding.run(
223 "org-client-secret",
224 "org-1",
225 "openapi",
226 "dealcloud_api",
227 "org-1",
228 "oauth2:oauth2:client-secret",
229 "secret",
230 null,
231 "dealcloud-client-secret-jd",
232 null,
233 now,
234 now,
235 );
236 insertBinding.run(
237 "org-connection",
238 "org-1",
239 "openapi",
240 "dealcloud_api",
241 "org-1",
242 "oauth2:oauth2:connection",
243 "connection",
244 null,
245 null,
246 "openapi-oauth2-app-dealcloud_api",
247 now,
248 now,
249 );
250 insertBinding.run(
251 "jd-connection",
252 "user-org:user-jd:org-1",
253 "openapi",
254 "dealcloud_api",
255 "org-1",
256 "oauth2:oauth2:connection",
257 "connection",
258 null,
259 null,
260 "openapi-oauth2-app-dealcloud_api",
261 now,
262 now,
263 );
264
265 db.exec(readFileSync(REPAIR_MIGRATION, "utf-8"));
266
267 const providers = decodeConnectionRows(
268 db.prepare("SELECT provider, provider_state FROM `connection` ORDER BY scope_id").all(),
269 );
270 expect(providers.map((row) => row.provider)).toEqual(["oauth2", "oauth2"]);
271
272 const bindings = db
273 .prepare(
274 "SELECT scope_id, slot_key, kind, secret_id, connection_id FROM `credential_binding` WHERE source_id = ? ORDER BY scope_id, slot_key",
275 )
276 .all("dealcloud_api");
277 expect(bindings).toEqual([
278 {
279 scope_id: "org-1",
280 slot_key: "oauth2:oauth2:client-id",
281 kind: "secret",
282 secret_id: "dealcloud-client-id",
283 connection_id: null,
284 },
285 {
286 scope_id: "org-1",
287 slot_key: "oauth2:oauth2:client-secret",
288 kind: "secret",
289 secret_id: "dealcloud-client-secret",
290 connection_id: null,
291 },
292 {
293 scope_id: "org-1",
294 slot_key: "oauth2:oauth2:connection",
295 kind: "connection",
296 secret_id: null,
297 connection_id: "openapi-oauth2-app-dealcloud_api",
298 },
299 {
300 scope_id: "user-org:user-jd:org-1",
301 slot_key: "oauth2:oauth2:client-id",
302 kind: "secret",
303 secret_id: "dealcloud-client-id-jd",
304 connection_id: null,
305 },
306 {
307 scope_id: "user-org:user-jd:org-1",
308 slot_key: "oauth2:oauth2:client-secret",
309 kind: "secret",
310 secret_id: "dealcloud-client-secret-jd",
311 connection_id: null,
312 },
313 {
314 scope_id: "user-org:user-jd:org-1",
315 slot_key: "oauth2:oauth2:connection",
316 kind: "connection",
317 secret_id: null,
318 connection_id: "openapi-oauth2-app-dealcloud_api",
319 },
320 ]);
321 });
322});

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t