From ad427c7b4cf3af25f1854883ce344d6890eedb38 Mon Sep 17 00:00:00 2001 From: gorkii Date: Wed, 4 Mar 2026 04:33:35 -0500 Subject: [PATCH 1/5] update listContainerGroups to accept optional apiKey parameter and log entitlement errors --- src/middleware.ts | 6 +++--- src/utils/salad.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index fedb663..f0ed465 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -49,7 +49,7 @@ export async function validateAuth(req: AuthedRequest, env: Env) { req.saladOrg = payload.organization_name; payload.organization_id; try { - await listContainerGroups(env, req.saladOrg, saladProject, true); + await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey); req.saladProject = saladProject; /** * If everything is valid, we check to see if we have a user provisioned for this org already. @@ -102,7 +102,7 @@ export async function validateAuth(req: AuthedRequest, env: Env) { * If we check to make sure the project exists and is valid. */ try { - await listContainerGroups(env, req.saladOrg, saladProject, true); + await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey); req.saladProject = saladProject; /** @@ -182,7 +182,7 @@ export async function validateSaladApiKey(env: Env, apiKey: string, orgName: str } if (!body.is_entitled) { - throw new Error('This organization is not entitled to use the Kelpie API'); + console.log(`Organization ${orgName} is not entitled to use the Kelpie API`); } await env.token_cache.put(cacheKey, JSON.stringify(body), { diff --git a/src/utils/salad.ts b/src/utils/salad.ts index 06f3965..506abc8 100644 --- a/src/utils/salad.ts +++ b/src/utils/salad.ts @@ -22,7 +22,7 @@ export async function fetchWithRetries(url: string, options: RequestInit, retrie throw new Error(`Did not receive response from API after ${retries} attempts`); } -export async function listContainerGroups(env: Env, orgName: string, projectName: string, noCache = false): Promise { +export async function listContainerGroups(env: Env, orgName: string, projectName: string, noCache = false, apiKey?: string): Promise { // Check to see if we cached the value already if (!noCache) { const cachedValue = await env.salad_cache.get(`${orgName}/${projectName}`); @@ -35,7 +35,7 @@ export async function listContainerGroups(env: Env, orgName: string, projectName // Fetch the container groups from Salad const url = `${saladBaseUrl}/organizations/${orgName}/projects/${projectName}/containers`; - const response = await fetchWithRetries(url, { headers: { 'Salad-Api-Key': env.SALAD_API_KEY } }, maxRetries); + const response = await fetchWithRetries(url, { headers: { 'Salad-Api-Key': apiKey || env.SALAD_API_KEY } }, maxRetries); if (!response.ok) { console.log(`Failed to fetch container groups in project ${orgName}/${projectName}: ${response.status}`); console.log(await response.text()); From c13750031b9614d20a464ef84d74f1eae38c6346 Mon Sep 17 00:00:00 2001 From: gorkii Date: Wed, 4 Mar 2026 05:34:41 -0500 Subject: [PATCH 2/5] version update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f53a14b..3849cd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kelpie-api", - "version": "0.7.0", + "version": "0.7.1", "private": true, "scripts": { "deploy": "wrangler deploy", From be5f45ea39c2ffa0b3ecd096b78fc2e2fcdb3e46 Mon Sep 17 00:00:00 2001 From: gorkii Date: Wed, 4 Mar 2026 05:49:24 -0500 Subject: [PATCH 3/5] make validateAuth optional and fallback to saladApiKey --- src/middleware.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index f0ed465..04cd386 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -45,11 +45,14 @@ export async function validateAuth(req: AuthedRequest, env: Env) { * If we don't have a cached user ID, we need to validate the API Key. */ try { - const payload = await validateSaladApiKey(env, saladApiKey, saladOrg || ''); - req.saladOrg = payload.organization_name; - payload.organization_id; try { - await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey); + const payload = await validateSaladApiKey(env, saladApiKey, saladOrg || ''); + req.saladOrg = payload.organization_name; + } catch { + req.saladOrg = saladOrg; + } + try { + await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey ?? undefined); req.saladProject = saladProject; /** * If everything is valid, we check to see if we have a user provisioned for this org already. @@ -102,7 +105,7 @@ export async function validateAuth(req: AuthedRequest, env: Env) { * If we check to make sure the project exists and is valid. */ try { - await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey); + await listContainerGroups(env, req.saladOrg, saladProject, true, saladApiKey ?? undefined); req.saladProject = saladProject; /** From 944e674ff1825e96a4a1852f27c02695943877ef Mon Sep 17 00:00:00 2001 From: gorkii Date: Wed, 4 Mar 2026 08:31:37 -0500 Subject: [PATCH 4/5] version update --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 733e007..2dc167c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kelpie-api", - "version": "0.7.0", + "version": "0.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kelpie-api", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@cloudflare/itty-router-openapi": "^1.0.10", "jose": "5.10.0", From b19bdae61fe99e0faaa7d93b233a15ca2c670b60 Mon Sep 17 00:00:00 2001 From: gorkii Date: Thu, 5 Mar 2026 06:43:48 -0500 Subject: [PATCH 5/5] Updated toml example --- example-wrangler.toml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/example-wrangler.toml b/example-wrangler.toml index 2d51729..78cecb5 100644 --- a/example-wrangler.toml +++ b/example-wrangler.toml @@ -16,7 +16,14 @@ crons = ["*/5 * * * *"] # * * * * * = run every 5 minutes API_HEADER = "x-kelpie-key" MAX_FAILURES_PER_WORKER = "5" ADMIN_ID = "00000000-0000-0000-0000-000000000000" - +TOKEN_CACHE_TTL = "60" +JWKS_CACHE_TTL = "600" +MAX_SALAD_API_RETRIES = "3" +AUTH_URL="" +JWKS_URL="" +MAX_CONCURRENT_SCALING_RULES="4" +MAX_FAILURES_PER_WORKER="3" +SALAD_USERNAME="" # Bind a KV Namespace. Use KV as persistent storage for small key-value pairs. # Docs: https://developers.cloudflare.com/workers/runtime-apis/kv @@ -32,6 +39,10 @@ id = "330b9fef-d0b3-4061-962c-9f1a038f488c" binding = "salad_cache" id = "fea342ad-1262-4264-8fe9-57a9984204d7" +[[kv_namespaces]] +binding = "token_cache" +id = "fea342ad-1262-4264-8fe9-57a9984204d7" + [[d1_databases]] binding = "DB" database_name = "kelpie"