Repository navigation
Description
Note
🤖 Claude Opus 5.5 (reasoning effort: high) writing on behalf of Augie (@AugusDogus)
https://executor.sh/oauth/client-metadata.json says "logo_uri": "https://executor.sh/favicon.png", but that URL is v1's HTML app page, not an image. Authorization servers that show the client's logo on their consent page show a broken image for Executor.
$ curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://executor.sh/favicon.png
200 text/html; charset=utf-8
$ curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://v2.executor.sh/favicon.png
200 image/png
Cause
The logo worked until the document moved to executor.sh on 2026-11-09 (#2528 on v1, and the v2 export 141787b9a, which builds the document's URL from the edge origin). logo_uri is built on the document's origin (apps/hosted/server/src/implementation/oauth-client-metadata.ts:111), so it moved too. v1's edge forwards /oauth/client-metadata.json to v2 but not /favicon.png, and v1 has no file at that path, so its SPA fallback answers. Before the move the document was on v2.executor.sh, which serves the real PNG.
e2e/tests/cloud-client-metadata.spec.ts checks the logo_uri string but never fetches it. The self-host scenario does fetch it, and self-host is fine.
Fix
Forward /favicon.png from executor.sh to v2, the same way as the document. Pointing logo_uri at /favicon-192.png instead would break self-host, which only serves /favicon.png.
Patches, with the same two halves as #2528. Pull requests here are limited to collaborators, so they are linked and inlined instead of opened:
- v2: AugusDogus@55bf3a1 (branch
AugusDogus:fix/cimd-logo-on-edge). It addsclientMetadataLogoPathto the hosted server's contract, used by both the document andsiteFiles, so the edge serves/favicon.pngand cannot drift from the document again. It also regenerates the edge contract (one forwardedGET /favicon.pngexample) and makescloud-client-metadata.spec.tsfetch each document's logo and expect a PNG. Typecheck, lint, format,edge-contract.ts --checkand the e2e boundary check pass; I could not run the cloud scenario, which needs a deployed test stage. - v1 (
main): forward the path and copy v2's new contract.vitest run src/edge/marketing.test.ts src/edge/production-config.test.tspasses (352 tests); without themarketing.tschange, the two contract cases forGET /favicon.pngfail.
v1 patch
diff --git a/apps/cloud/src/edge/marketing.test.ts b/apps/cloud/src/edge/marketing.test.ts
index 1f8e31d70..003b362c7 100644
--- a/apps/cloud/src/edge/marketing.test.ts
+++ b/apps/cloud/src/edge/marketing.test.ts
@@ -648,6 +648,8 @@ describe("isV2MarketingPath", () => {
"/authors/author.png",
"/og-image.png",
"/pattern-graph-paper.svg",
+ // The logo v2's OAuth client metadata document names; v1 has no such file.
+ "/favicon.png",
"/docs",
"/docs/",
"/docs/quickstart",
diff --git a/apps/cloud/src/edge/marketing.ts b/apps/cloud/src/edge/marketing.ts
index 7ef91d2c1..36e044e43 100644
--- a/apps/cloud/src/edge/marketing.ts
+++ b/apps/cloud/src/edge/marketing.ts
@@ -105,7 +105,9 @@ export const isV2Path = (pathname: string): boolean =>
* `/apps/*` and `/experiments/*` are v2's; v2 publishes nothing at a bare
* `/experiments`, which stays with v1. `/demo` is a valid, unreserved v1
* organization slug, so it and everything below it stay with v1. The
- * favicons stay with v1 too: v1's dashboard serves identical files. */
+ * favicons stay with v1 too: v1's dashboard serves identical files. v1 has
+ * no `/favicon.png`, which v2's OAuth client metadata document names as its
+ * logo, so that one is v2's. */
const V2_MARKETING_PATHS: ReadonlyArray<string> = [
"/home",
"/pricing",
@@ -126,6 +128,7 @@ const V2_MARKETING_PATHS: ReadonlyArray<string> = [
"/authors/*",
"/og-image.png",
"/pattern-graph-paper.svg",
+ "/favicon.png",
];
/** Whether a pathname belongs to v2's marketing site on `executor.sh`. `/`
diff --git a/apps/cloud/src/edge/v2-edge-contract.json b/apps/cloud/src/edge/v2-edge-contract.json
index 5af17e08a..6031aed94 100644
--- a/apps/cloud/src/edge/v2-edge-contract.json
+++ b/apps/cloud/src/edge/v2-edge-contract.json
@@ -32,6 +32,7 @@
"/authors/*",
"/og-image.png",
"/pattern-graph-paper.svg",
+ "/favicon.png",
"/.well-known/agent-skills/*",
"/api/00e2e1f082a6ef17/*",
"/api/fd6fab1fbb4883e1/submit"
@@ -62,6 +63,11 @@
"target": "/oauth/client-metadata.json",
"forwards": true
},
+ {
+ "method": "GET",
+ "target": "/favicon.png",
+ "forwards": true
+ },
{
"method": "GET",
"target": "/git/acme/site.git/info/refs?service=git-upload-pack",Merge either first: until both deploy, the logo stays broken as it is today.
Activity
Forward /favicon.png to v2 (#2542)