From 33b5b31820cd24170e119792edc4e746762db1dc Mon Sep 17 00:00:00 2001 From: castrojo Date: Tue, 8 Sep 2026 14:53:13 +0000 Subject: [PATCH] fix(factory): use a working public queue-data fallback for anonymous visitors queue.projectbluefin.io/data.json returns 404, so anonymous visitors to the Hive Factory Dashboard never receive queue data when the hosted Knuckle instance requires login. Point the fallback at the queue-feed skill's canonical public mirror (https://projectbluefin.github.io/review/queue.json, documented in projectbluefin/common docs/skills/queue-feed.md). Its schema is a flat PR list rather than the hosted instance's QueueData shape, so normalize it into QueueData (no P0/P1 issue triage or victory-log data is available from this source, so those sections stay empty). Update the CSP connect-src allowlist to match. Fixes #1090 Signed-off-by: castrojo --- docusaurus.config.ts | 2 +- src/components/HiveFactoryDashboard.tsx | 48 +++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/docusaurus.config.ts b/docusaurus.config.ts index b79fe9ad7..2b9b7e2d9 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -164,7 +164,7 @@ const config: Config = { "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "font-src 'self' data:", - "connect-src 'self' https://api.github.com https://raw.githubusercontent.com https://giscus.app https://formulae.brew.sh https://queue.projectbluefin.io https://hosted-projectbluefin-knuckle-gjvq.hive.kubestellar.io https://hive.kubestellar.io", + "connect-src 'self' https://api.github.com https://raw.githubusercontent.com https://giscus.app https://formulae.brew.sh https://projectbluefin.github.io https://hosted-projectbluefin-knuckle-gjvq.hive.kubestellar.io https://hive.kubestellar.io", "frame-src https://giscus.app https://www.youtube.com https://youtube.com https://insights.linuxfoundation.org", ].join("; "), }, diff --git a/src/components/HiveFactoryDashboard.tsx b/src/components/HiveFactoryDashboard.tsx index ca43b3999..1c5b67f67 100644 --- a/src/components/HiveFactoryDashboard.tsx +++ b/src/components/HiveFactoryDashboard.tsx @@ -541,9 +541,12 @@ const HOSTED_INSTANCE_URL = // The old raw.githubusercontent.com HTML snapshot is no longer published. const SNAPSHOT_API_URL = `${HOSTED_INSTANCE_URL}/api/status`; -// Queue data: try the hosted instance first (credentials:include), fall back to public mirror +// Queue data: try the hosted instance first (credentials:include), fall back to public mirror. +// The public mirror is the queue-feed skill's canonical endpoint (see +// projectbluefin/common docs/skills/queue-feed.md) — queue.projectbluefin.io/data.json +// 404s, so anonymous visitors need this URL instead. const QUEUE_URL_HOSTED = `${HOSTED_INSTANCE_URL}/data.json`; -const QUEUE_URL_FALLBACK = "https://queue.projectbluefin.io/data.json"; +const QUEUE_URL_FALLBACK = "https://projectbluefin.github.io/review/queue.json"; const GH_API = "https://api.github.com"; const DAKOTA = "projectbluefin/dakota"; const BUILD_WORKFLOW = "246164114"; @@ -917,6 +920,44 @@ async function fetchTimeout( } } +// Shape of the public queue-feed mirror (projectbluefin/common docs/skills/queue-feed.md): +// a flat list of PR review-queue items. It carries no P0/P1 issue triage or victory-log +// data, so those QueueData sections stay empty when only this fallback is available. +interface PublicQueueItem { + repository: string; + url: string; + title: string; + updated_at: string; + labels?: string[]; +} + +interface PublicQueueFeed { + generated_at: string; + items: PublicQueueItem[]; +} + +function normalizePublicQueueFeed(feed: PublicQueueFeed): QueueData { + const prs: QueuePR[] = (feed.items ?? []).map((item) => ({ + title: item.title, + html_url: item.url, + repository_url: `https://api.github.com/repos/${item.repository}`, + updated_at: item.updated_at, + labels: (item.labels ?? []).map((name) => ({ name, color: "" })), + })); + return { + generated: feed.generated_at, + repos: Array.from(new Set((feed.items ?? []).map((i) => i.repository))), + issues: { p0: [], p1: [] }, + prs: { approved: [], required: prs, none: [] }, + victories: { + startDate: feed.generated_at, + dreams: { count: 0, recent: [] }, + relief: { count: 0, recent: [] }, + toil: { count: 0, recent: [] }, + }, + }; +} + // Fetch queue data from the hosted instance first (works when the user has an active // hive.kubestellar.io session), falling back to the public mirror. async function fetchQueueData(): Promise { @@ -930,7 +971,8 @@ async function fetchQueueData(): Promise { } try { const r = await fetchTimeout(QUEUE_URL_FALLBACK, 10000); - if (r.ok) return (await r.json()) as QueueData; + if (r.ok) + return normalizePublicQueueFeed((await r.json()) as PublicQueueFeed); } catch { // both sources unavailable }