Skip to content

Commit a3cd20d

Browse files
JOYclaude
andcommitted
security: use Edge Function proxy instead of exposing service role key
- sync-changelog.ts now calls Supabase Edge Function with x-write-key header instead of using SUPABASE_SERVICE_KEY directly - Edge Function (sync-changelog) handles upsert internally with service role key that never leaves Supabase - Fallback to direct PostgREST for local dev with service key - GitHub Actions now only needs CHANGELOG_WRITE_KEY (limited scope) and DOS_API_KEY (for LLM rewrite), no service role key exposure Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 323330e commit a3cd20d

2 files changed

Lines changed: 44 additions & 8 deletions

File tree

.github/workflows/sync-changelog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919

2020
- name: Sync changelog
2121
env:
22-
SUPABASE_SERVICE_KEY: ${{ secrets.SUPABASE_SERVICE_KEY }}
22+
CHANGELOG_WRITE_KEY: ${{ secrets.CHANGELOG_WRITE_KEY }}
2323
VLLM_API_KEY: ${{ secrets.DOS_API_KEY }}
2424
VLLM_URL: https://inference.dos.ai
2525
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

scripts/sync-changelog.ts

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010
* deno run --allow-net --allow-read --allow-env scripts/sync-changelog.ts
1111
*
1212
* Env:
13-
* SUPABASE_URL — Supabase project URL
14-
* SUPABASE_SERVICE_KEY — Service role key (for write access)
15-
* GITHUB_TOKEN — (optional) GitHub PAT for higher rate limits
16-
* VLLM_URL — vLLM endpoint for LLM rewrite (optional)
17-
* VLLM_API_KEY — API key for vLLM
13+
* SUPABASE_URL — Supabase project URL
14+
* CHANGELOG_WRITE_KEY — Write key for sync-changelog Edge Function
15+
* SUPABASE_SERVICE_KEY — (fallback) Service role key for direct PostgREST
16+
* GITHUB_TOKEN — (optional) GitHub PAT for higher rate limits
17+
* VLLM_URL — vLLM endpoint for LLM rewrite (optional)
18+
* VLLM_API_KEY — API key for vLLM
1819
*/
1920

2021
const SUPABASE_URL = Deno.env.get("SUPABASE_URL") || "https://gulptwduchsjcsbndmua.supabase.co";
22+
const CHANGELOG_WRITE_KEY = Deno.env.get("CHANGELOG_WRITE_KEY") || "";
2123
const SUPABASE_KEY = Deno.env.get("SUPABASE_SERVICE_KEY") || Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") || "";
2224
const GITHUB_TOKEN = Deno.env.get("GITHUB_TOKEN") || "";
2325
const VLLM_URL = Deno.env.get("VLLM_URL") || "https://inference.dos.ai";
@@ -228,11 +230,45 @@ async function rewriteEntries(entries: ChangelogEntry[]): Promise<ChangelogEntry
228230
// --- 4. Upsert to Supabase ---
229231

230232
async function upsertEntries(entries: ChangelogEntry[]): Promise<number> {
231-
if (!SUPABASE_KEY) {
232-
console.error("SUPABASE_SERVICE_KEY not set, skipping DB sync");
233+
// Prefer Edge Function (only needs write key, no service role exposure)
234+
if (CHANGELOG_WRITE_KEY) {
235+
return upsertViaEdgeFunction(entries);
236+
}
237+
// Fallback: direct PostgREST (local dev with service key)
238+
if (SUPABASE_KEY) {
239+
return upsertViaPostgREST(entries);
240+
}
241+
console.error("Neither CHANGELOG_WRITE_KEY nor SUPABASE_SERVICE_KEY set, skipping DB sync");
242+
return 0;
243+
}
244+
245+
async function upsertViaEdgeFunction(entries: ChangelogEntry[]): Promise<number> {
246+
const res = await fetch(
247+
`${SUPABASE_URL}/functions/v1/sync-changelog`,
248+
{
249+
method: "POST",
250+
headers: {
251+
"Content-Type": "application/json",
252+
"x-write-key": CHANGELOG_WRITE_KEY,
253+
},
254+
body: JSON.stringify({ entries }),
255+
}
256+
);
257+
258+
if (!res.ok) {
259+
const err = await res.text();
260+
console.error(`Edge Function error: ${res.status} ${err}`);
233261
return 0;
234262
}
235263

264+
const result = await res.json();
265+
if (result.errors?.length) {
266+
console.warn(` Edge Function partial errors:`, result.errors);
267+
}
268+
return result.upserted || 0;
269+
}
270+
271+
async function upsertViaPostgREST(entries: ChangelogEntry[]): Promise<number> {
236272
let total = 0;
237273
for (let i = 0; i < entries.length; i += 50) {
238274
const batch = entries.slice(i, i + 50);

0 commit comments

Comments
 (0)