From dcf87c797db9d64fda17868de76544933173bca0 Mon Sep 17 00:00:00 2001 From: efiten Date: Wed, 2 Sep 2026 10:28:04 +0200 Subject: [PATCH 1/2] fix(#1890): drop the hardcoded og:url so shared links stay on the instance (#1893) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1890. ## The problem `public/index.html:16` shipped this to every deployment: ```html ``` Open Graph consumers — Facebook and Messenger among them — treat `og:url` as the canonical destination. Clicking the preview of a link shared from *any* CoreScope instance navigated to that one host. The direct link text still resolved correctly, which is why this went unnoticed; the preview card and the surrounding message body did not. It is the only occurrence in the frontend. ## The change Remove the tag. `og:url` is optional — with no tag present, consumers fall back to the URL they crawled, which is correct for every deployment and needs no configuration. ## Why not the config-driven variant The issue also proposes deriving the URL from `config.json`. I did not take that shape, on purpose: `index.html` is pre-processed **once at startup** — `spaHandler` reads it and substitutes `__BUST__` (`cmd/server/main.go:565`), then serves the same byte slice for every request. A correct per-host `og:url` therefore needs either a new public-URL config key or per-request templating of the index. Both are decisions about config surface and request-path cost that belong to you, and neither is needed to stop the redirect. Happy to follow up with whichever shape you prefer — this PR is the part that is unambiguous. ## What is left alone `og:image` still points at `raw.githubusercontent.com/Kpa-clawbot/corescope/master/public/og-image.png`. That is the project's own asset, a shared project resource rather than a redirect target, so it is correct for every instance to reference it. ## Test `test-issue-1890-og-url.js`, a static scan, registered in `test-all.sh`: - no `og:url` meta tag - no `rel="canonical"` link - no `00id.net` reference anywhere in `index.html` - `og:title` / `og:description` / `og:image` still present That last assertion is deliberate: without it the guard could be satisfied by deleting the whole embed block. Watched fail first — 2 passed, 2 failed before the change, 4 passed after. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) (cherry picked from commit c5a71b34ec948f69c17956c4deebffe7e8a5051e) Co-Authored-By: Claude Opus 5 --- public/index.html | 5 +++- test-all.sh | 1 + test-issue-1890-og-url.js | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test-issue-1890-og-url.js diff --git a/public/index.html b/public/index.html index 73a0a9b6a..3e6e91dcb 100644 --- a/public/index.html +++ b/public/index.html @@ -13,7 +13,10 @@ - + diff --git a/test-all.sh b/test-all.sh index b831175e7..ca4c3847d 100755 --- a/test-all.sh +++ b/test-all.sh @@ -50,6 +50,7 @@ node test-issue-1648-m2-emoji-scan.js node test-issue-1648-m3-emoji-scan.js node test-issue-1648-m6-final-sweep.js node test-issue-1648-m6-lint-self.js +node test-issue-1890-og-url.js node test-traces.js node test-live-multibyte-filter.js diff --git a/test-issue-1890-og-url.js b/test-issue-1890-og-url.js new file mode 100644 index 000000000..8db009a2e --- /dev/null +++ b/test-issue-1890-og-url.js @@ -0,0 +1,61 @@ +#!/usr/bin/env node +/* Issue #1890 — index.html must not hardcode one instance's URL in its + * Open Graph tags. + * + * `` shipped to + * every self-hosted CoreScope. Facebook, Messenger and other OG consumers treat + * og:url as the canonical destination, so clicking a shared preview from ANY + * instance navigated to that one host instead of the instance the link came + * from. With no og:url present, consumers fall back to the URL they crawled, + * which is correct for every deployment without any configuration. + * + * og:image is deliberately NOT covered: it points at the project's own asset on + * raw.githubusercontent.com, which is a shared project resource, not a + * redirect target. + */ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); + +const INDEX = path.resolve(__dirname, 'public', 'index.html'); +const html = fs.readFileSync(INDEX, 'utf8'); + +let passed = 0, failed = 0; +function test(name, fn) { + try { + fn(); + passed++; + console.log(` ✅ ${name}`); + } catch (e) { + failed++; + console.log(` ❌ ${name}: ${e.message}`); + } +} + +console.log('\n=== #1890: index.html carries no instance-specific canonical URL ==='); + +test('no og:url meta tag pinning a single instance', () => { + const m = html.match(/]*property=["']og:url["'][^>]*>/i); + assert.ok(!m, `og:url must not be hardcoded; found: ${m && m[0]}`); +}); + +test('no rel="canonical" pinning a single instance', () => { + const m = html.match(/]*rel=["']canonical["'][^>]*>/i); + assert.ok(!m, `canonical link must not be hardcoded; found: ${m && m[0]}`); +}); + +test('the analyzer.00id.net host appears nowhere in index.html', () => { + assert.ok(!/00id\.net/i.test(html), 'index.html still references 00id.net'); +}); + +test('og:title and og:description are still present', () => { + // The fix removes one tag, not the embed. Guard against over-deletion. + assert.ok(/property=["']og:title["']/i.test(html), 'og:title missing'); + assert.ok(/property=["']og:description["']/i.test(html), 'og:description missing'); + assert.ok(/property=["']og:image["']/i.test(html), 'og:image missing'); +}); + +console.log(`\n #1890 og:url: ${passed} passed, ${failed} failed\n`); +process.exit(failed ? 1 : 0); From efa6a033337e2e1f88cb77318211b5a462cd3b6b Mon Sep 17 00:00:00 2001 From: Openclaw Date: Mon, 14 Sep 2026 09:08:27 +0200 Subject: [PATCH 2/2] reviewfix(#1890): register regression test in CI, fix og:url comments Two review fixes on this PR. 1. CI registration. `test-issue-1890-og-url.js` was only wired into `test-all.sh` (used by `npm test`), not into the JS test step in `.github/workflows/deploy.yml`. CI could not catch a regression of the hardcoded og:url. Added `node test-issue-1890-og-url.js` to that step's existing list, directly before `test-issue-1375-scope-stats- fetch.js` (the test that currently stops the step). test-all.sh is unchanged; the registration there was already correct. 2. Comment accuracy, in `public/index.html` and `test-issue-1890-og-url.js`. The removed tag declared the upstream analyzer instance's own URL as the canonical URL for every self-hosted deployment (#1890) -- correct metadata for upstream, wrong for everyone else. Reworded both comments to say that precisely, and to stop implying things not established: - og:url is metadata, not an HTTP redirect, and does not by itself decide what a viewer's click navigates to. - Per the Open Graph protocol it is a required property, not "optional" -- omitting it leaves the crawled URL as the fallback canonical reference, which is what actually fixes this for every instance. - This change does not refresh previews a consumer has already cached under the old, hardcoded value. No functional assertions changed in test-issue-1890-og-url.js -- only the file-level comment. The `public/index.html` comment change had to avoid writing the literal removed domain: the test's own 4th assertion scans the whole file for that string, and an earlier draft of this comment briefly reintroduced it and failed its own guard before landing on the current wording. Verified on this branch's own base (pre-#51/#33 master) and against a merge into current master: test-issue-1890-og-url.js passes 4/4 on the resulting index.html and still fails 2/4 (og:url present, 00id.net present) against the original hardcoded tag. The merge result's deploy.yml differs from current master by exactly the one added test line; release-fast-path.yml and cmd/server/fork_guard_workflow_test.go are byte-identical to master, and all four #51 repository guards (the five build-and-publish publish steps, release-artifacts, deploy, publish, retag-or-fallback) are present in the merged file. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/deploy.yml | 1 + public/index.html | 12 ++++++++---- test-issue-1890-og-url.js | 16 +++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1e8be8f62..22279ade4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -119,6 +119,7 @@ jobs: node test-issue-1356-map-a11y.js node test-issue-1360-pill-letter-count.js node test-issue-1364-pill-no-clamp.js + node test-issue-1890-og-url.js node test-issue-1375-scope-stats-fetch.js node test-issue-1361-cb-presets.js node test-issue-1380-cb-sim-overlay.js diff --git a/public/index.html b/public/index.html index 3e6e91dcb..34e833881 100644 --- a/public/index.html +++ b/public/index.html @@ -13,10 +13,14 @@ - + diff --git a/test-issue-1890-og-url.js b/test-issue-1890-og-url.js index 8db009a2e..603d04ea6 100644 --- a/test-issue-1890-og-url.js +++ b/test-issue-1890-og-url.js @@ -3,11 +3,17 @@ * Open Graph tags. * * `` shipped to - * every self-hosted CoreScope. Facebook, Messenger and other OG consumers treat - * og:url as the canonical destination, so clicking a shared preview from ANY - * instance navigated to that one host instead of the instance the link came - * from. With no og:url present, consumers fall back to the URL they crawled, - * which is correct for every deployment without any configuration. + * every self-hosted CoreScope, declaring that one upstream URL as the + * canonical destination for the page's Open Graph metadata on every + * instance. og:url is metadata, not an HTTP redirect, and it does not by + * itself determine what a viewer's click navigates to — but Facebook, + * Messenger and other OG consumers treat it as canonical (per Meta's own + * sharing docs, likes/shares aggregate at that URL, and a differing og:url + * is followed), so every self-hosted instance was shipping the wrong + * canonical reference for its own pages. With no og:url present, consumers + * fall back to treating the URL they crawled as canonical, which is correct + * for every deployment without any configuration. This does not refresh + * previews a consumer already cached under the old, hardcoded value. * * og:image is deliberately NOT covered: it points at the project's own asset on * raw.githubusercontent.com, which is a shared project resource, not a