Skip to content

fix(og): org profile images and Downloads metric in OG cards#2840

Merged
Patrick-Erichsen merged 6 commits into
openclaw:mainfrom
vyctorbrzezowski:fix/org-og-profile-images
Jun 24, 2026
Merged

fix(og): org profile images and Downloads metric in OG cards#2840
Patrick-Erichsen merged 6 commits into
openclaw:mainfrom
vyctorbrzezowski:fix/org-og-profile-images

Conversation

@vyctorbrzezowski

@vyctorbrzezowski vyctorbrzezowski commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Pass publisher avatar, kind, and downloads into publisher OG image URLs so crawlers do not need a Convex round-trip for org logos.
  • Allow the OG image renderer to fetch public HTTPS org profile images (with SSRF guards) instead of only GitHub/Gravatar hosts.
  • Switch all OG image cards (skills, plugins, publishers) from Installs to Downloads, using compact stat formatting (e.g. 43.5k) with a muted Downloads label (no icon).
  • Bump publisher/skill/plugin OG layout versions (v=7 / v=10 / v=5) to bust stale social previews.

Problem

Organization profile pages like @nvidia had custom profile images on ClawHub, but their og:image cards fell back to the default ClawHub lobster mark because:

  1. Page meta only passed handle to /og/profile, omitting the avatar URL.
  2. The OG renderer only trusted GitHub/Gravatar image hosts, rejecting org logos hosted elsewhere.

Additionally, OG cards labeled the stat as "Installs" while the product surface emphasizes downloads, and raw integer counts from query params (e.g. 43456) were rendered without compact formatting.

Visual proof

See proof/org-og-profile-images/pr-visual-proof.md in the branch.

Publisher Expected Result
@nvidia NVIDIA logo + compact downloads ✅ custom logo, 43.5k Downloads
@openclaw GitHub avatar + compact downloads ✅ org avatar, 282k Downloads
@expediagroup default mark (no image) + compact downloads ✅ default lobster mark, 48 Downloads

NVIDIA OG

OpenClaw OG

Expedia Group OG

Test plan

  • bun run test server/og/ server/routes/og/ src/lib/og.test.ts
  • bun run ci:static
  • Local visual proof at http://localhost:3000/og/profile for openclaw, nvidia, expediagroup
  • CI unit + types-build

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

@vyctorbrzezowski is attempting to deploy a commit to the OpenClaw Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@openclaw-barnacle openclaw-barnacle Bot added the triage: dirty-candidate Candidate: broad unrelated surfaces; may need splitting or cleanup. label Jun 24, 2026
@vyctorbrzezowski vyctorbrzezowski force-pushed the fix/org-og-profile-images branch from 7c70d26 to ce47f20 Compare June 24, 2026 07:56
@openclaw-barnacle openclaw-barnacle Bot added the triage: blank-template Candidate: PR template appears mostly untouched. label Jun 24, 2026
@vyctorbrzezowski vyctorbrzezowski changed the title fix(og): render org profile images in publisher OG cards fix(og): org profile images and Downloads metric in OG cards Jun 24, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context. label Jun 24, 2026
@vyctorbrzezowski vyctorbrzezowski marked this pull request as ready for review June 24, 2026 08:18
@vyctorbrzezowski vyctorbrzezowski marked this pull request as draft June 24, 2026 09:31
Pass publisher avatar, kind, and installs into OG meta URLs and allow
safely fetching public HTTPS org logos when generating profile images.
Org logos use public HTTPS URLs outside the GitHub/gravatar allowlist, so OG
generation fell back to the default mark. Allow SSRF-safe public fetches for
publisher profile avatars and embed avatar/kind metadata in OG URLs.
Switch skill, plugin, and publisher OG image generators to read and
label download counts, with legacy installs query param fallback.
Export SkillStatReadable so fetchSkillOgMeta can pass API skill stats
through readCanonicalStat without a TypeScript error.
Query-param download counts were rendered as raw integers on publisher
OG images. Reuse formatCompactStat, add download icon + lowercase label,
bump layout versions, and refresh org profile visual proof.
Remove the download SVG from OG stat blocks and show only a muted
"Downloads" label above compact values. Bump skill/plugin/publisher
layout versions to bust cached social previews.
@vyctorbrzezowski vyctorbrzezowski force-pushed the fix/org-og-profile-images branch from d5609fd to 890f33e Compare June 24, 2026 09:38
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 24, 2026
@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed June 24, 2026, 7:26 AM ET / 11:26 UTC.

Summary
The PR passes publisher avatar metadata into profile OG URLs, allows public HTTPS publisher avatar fetches, switches OG cards back to Downloads, bumps OG cache versions, and adds route/helper tests plus proof assets.

Reproducibility: yes. by source inspection: current main only passes handle into publisher profile OG URLs and only fetches avatars from trusted GitHub/Gravatar hosts, so non-allowlisted org logos fall back. I did not run a live before/after route in this review.

Review metrics: 2 noteworthy metrics.

  • Diff size: +389/-99 across 34 files. The branch combines route logic, shared helpers, tests, version bumps, and proof artifacts, so maintainers should review it as more than a one-line OG fix.
  • Proof artifacts added: 9 PNGs and 1 proof doc added. The images are useful proof, but maintainers may prefer proof artifacts to stay in the PR body or artifact storage rather than source history.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Validate the actual resolved address for every public avatar fetch and redirect, or keep org avatars behind an approved proxy/allowlist.
  • Remove the Downloads switch or get explicit maintainer approval for replacing the shipped Installs social-card metric.

Risk before merge

  • [P1] The public-HTTPS avatar path can fetch an attacker-controlled hostname that resolves or rebinds to private, link-local, loopback, or metadata infrastructure unless the actual resolved address is validated for every hop.
  • [P1] The Downloads switch silently replaces the shipped Installs metric across public social cards and needs explicit maintainer product approval if it stays in scope.
  • [P1] The screenshots prove the visual OG output but do not prove SSRF safety because the risky behavior is server-side network resolution.

Maintainer options:

  1. Harden and Preserve Current Metric (recommended)
    Keep the org-avatar metadata fix, validate the actual resolved address for every fetch and redirect or use an approved proxy/allowlist, and leave the shipped Installs metric intact.
  2. Use a Strict Image Proxy or Allowlist
    If maintainers do not want direct DNS/IP validation in this route, route publisher images through an approved image proxy or a narrow allowlist before enabling arbitrary org avatars.
  3. Pause for Metric Direction
    If Downloads is the desired social-card metric, pause this PR until a maintainer explicitly accepts replacing the recently shipped Installs behavior.

Next step before merge

  • [P2] Manual review is needed because one blocker is a security-boundary design choice and the other is maintainer product approval for the social-card metric.

Security
Needs attention: The diff introduces a concrete SSRF concern by allowing public server-side image fetches based on hostname-string checks only.

Review findings

  • [P1] Validate the resolved image address before fetching — server/og/fetchImageDataUrl.ts:54
  • [P1] Preserve the shipped Installs metric or get approval — server/og/registryOgSvg.ts:10-11
Review details

Best possible solution:

Land a narrower change that safely renders organization profile avatars while preserving the shipped Installs metric unless maintainers explicitly choose another product direction.

Do we have a high-confidence way to reproduce the issue?

Yes by source inspection: current main only passes handle into publisher profile OG URLs and only fetches avatars from trusted GitHub/Gravatar hosts, so non-allowlisted org logos fall back. I did not run a live before/after route in this review.

Is this the best way to solve the issue?

No. The org-avatar metadata direction is plausible, but this branch also broadens server-side fetches without resolved-address protection and reverses a recently shipped metric decision.

Full review comments:

  • [P1] Validate the resolved image address before fetching — server/og/fetchImageDataUrl.ts:54
    isSafePublicHttpsOgImageUrl permits any non-IP HTTPS hostname and fetchOgImageResponse then fetches it. An attacker-controlled hostname can resolve or rebind to loopback, link-local, metadata, or RFC1918 space, so validate the actual resolved address on every hop or keep public org avatars behind an approved proxy/allowlist.
    Confidence: 0.9
  • [P1] Preserve the shipped Installs metric or get approval — server/og/registryOgSvg.ts:10-11
    Current main intentionally shows Installs on social cards via Fix social cards to show installs instead of downloads #2713. This helper switches all OG cards back to Downloads and makes downloads the preferred query param, so remove that part from this PR or include explicit maintainer approval for replacing shipped behavior.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against abab93554182.

Label changes

Label changes:

  • add P2: This is a normal-priority OG/social-card PR with concrete security and compatibility blockers, not a core outage.
  • add merge-risk: 🚨 compatibility: The diff replaces the recently shipped Installs social-card metric with Downloads across skill, plugin, and publisher OG cards.
  • add merge-risk: 🚨 security-boundary: The diff broadens public server-side image fetching based on hostname string checks without validating the resolved address.

Label justifications:

  • P2: This is a normal-priority OG/social-card PR with concrete security and compatibility blockers, not a core outage.
  • merge-risk: 🚨 security-boundary: The diff broadens public server-side image fetching based on hostname string checks without validating the resolved address.
  • merge-risk: 🚨 compatibility: The diff replaces the recently shipped Installs social-card metric with Downloads across skill, plugin, and publisher OG cards.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (screenshot): The PR body includes local real ClawHub screenshots showing after-fix publisher OG cards, which is sufficient proof for visible OG output but not for SSRF safety.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes local real ClawHub screenshots showing after-fix publisher OG cards, which is sufficient proof for visible OG output but not for SSRF safety.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The PR body includes local real ClawHub screenshots showing after-fix publisher OG cards, which is sufficient proof for visible OG output but not for SSRF safety.
Evidence reviewed

Security concerns:

  • [high] Hostname-only public image fetch guard — server/og/fetchImageDataUrl.ts:54
    The new public-HTTPS path rejects obvious private host strings but does not validate the DNS-resolved address that fetch connects to, while the public profile OG route accepts query or metadata avatar URLs.
    Confidence: 0.9

What I checked:

Likely related people:

  • vyctorbrzezowski: GitHub history shows this contributor authored the dynamic OG image refresh, the CJK OG renderer follow-up, and the prior shipped Installs metric change for the same route/helper surface. (role: recent OG/social-card contributor; confidence: high; commits: b8efe83d1b7d, 526d84f33878, 2d93401234ef; files: server/og/fetchImageDataUrl.ts, server/og/registryOgSvg.ts, server/routes/og/profile.png.ts)
  • Patrick-Erichsen: GitHub path history shows recent owner-qualified route work touching src/lib/og.ts, and local blame shows the current release snapshot for the affected OG files under the v0.23.0 release commit. (role: recent adjacent contributor/releaser; confidence: medium; commits: 55fe4a856333, a128c101adca; files: src/lib/og.ts, server/og/fetchImageDataUrl.ts, server/routes/og/profile.png.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@vyctorbrzezowski vyctorbrzezowski marked this pull request as ready for review June 24, 2026 10:03
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jun 24, 2026
@Patrick-Erichsen Patrick-Erichsen merged commit 6f537bf into openclaw:main Jun 24, 2026
36 of 41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient Contributor real behavior proof is sufficient. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. triage: blank-template Candidate: PR template appears mostly untouched. triage: dirty-candidate Candidate: broad unrelated surfaces; may need splitting or cleanup. triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants