fix: …
Some checks failed
CI / build-and-anchors (push) Failing after 2m6s
SMOKE / smoke (push) Successful in 13s

This commit is contained in:
2026-02-23 12:07:01 +01:00
parent ae809e0152
commit 68c3416594
19 changed files with 930 additions and 240 deletions

View File

@@ -30,6 +30,13 @@ const GITEA_REPO = import.meta.env.PUBLIC_GITEA_REPO ?? "";
// ✅ OPTIONNEL : bridge serveur (proxy same-origin)
const ISSUE_BRIDGE_PATH = import.meta.env.PUBLIC_ISSUE_BRIDGE_PATH ?? "";
// ✅ Auth whoami (same-origin) — configurable, antifragile en dev
const WHOAMI_PATH = import.meta.env.PUBLIC_WHOAMI_PATH ?? "/_auth/whoami";
// Par défaut: en DEV local on SKIP pour éviter le spam 404.
// Pour tester lauth en dev: export PUBLIC_WHOAMI_IN_DEV=1
const WHOAMI_IN_DEV = (import.meta.env.PUBLIC_WHOAMI_IN_DEV ?? "") === "1";
const WHOAMI_FORCE_LOCALHOST = (import.meta.env.PUBLIC_WHOAMI_FORCE_LOCALHOST ?? "") === "1";
---
<!doctype html>
@@ -52,54 +59,104 @@ const ISSUE_BRIDGE_PATH = import.meta.env.PUBLIC_ISSUE_BRIDGE_PATH ?? "";
<meta data-pagefind-meta={`version:${String(version ?? "")}`} />
{/* ✅ BOOT EARLY : SidePanel dépend de ces globals. */}
<script is:inline define:vars={{ IS_DEV, GITEA_BASE, GITEA_OWNER, GITEA_REPO, ISSUE_BRIDGE_PATH }}>
<script
is:inline
define:vars={{
IS_DEV,
GITEA_BASE,
GITEA_OWNER,
GITEA_REPO,
ISSUE_BRIDGE_PATH,
WHOAMI_PATH,
WHOAMI_IN_DEV,
WHOAMI_FORCE_LOCALHOST,
}}
>
(() => {
const __DEV__ = Boolean(IS_DEV);
window.__archiFlags = Object.assign({}, window.__archiFlags, { dev: __DEV__ });
// ✅ anti double-init (HMR / inclusion accidentelle)
if (window.__archiBootOnce === 1) return;
window.__archiBootOnce = 1;
const base = String(GITEA_BASE || "").replace(/\/+$/, "");
const owner = String(GITEA_OWNER || "");
const repo = String(GITEA_REPO || "");
const giteaReady = Boolean(base && owner && repo);
window.__archiGitea = { ready: giteaReady, base, owner, repo };
var __DEV__ = Boolean(IS_DEV);
const rawBridge = String(ISSUE_BRIDGE_PATH || "").trim();
const normBridge = rawBridge
// ===== Gitea globals =====
var base = String(GITEA_BASE || "").replace(/\/+$/, "");
var owner = String(GITEA_OWNER || "");
var repo = String(GITEA_REPO || "");
window.__archiGitea = {
ready: Boolean(base && owner && repo),
base, owner, repo
};
// ===== optional issue bridge (same-origin proxy) =====
var rawBridge = String(ISSUE_BRIDGE_PATH || "").trim();
var normBridge = rawBridge
? (rawBridge.startsWith("/") ? rawBridge : ("/" + rawBridge.replace(/^\/+/, ""))).replace(/\/+$/, "")
: "";
window.__archiIssueBridge = { ready: Boolean(normBridge), path: normBridge };
const WHOAMI_PATH = "/_auth/whoami";
const REQUIRED_GROUP = "editors";
const READ_GROUP = "readers";
// ===== whoami config =====
var __WHOAMI_PATH__ = String(WHOAMI_PATH || "/_auth/whoami");
var __WHOAMI_IN_DEV__ = Boolean(WHOAMI_IN_DEV);
// En dev: par défaut on SKIP (=> pas de spam 404). Override via PUBLIC_WHOAMI_IN_DEV=1.
var SHOULD_FETCH_WHOAMI = (!__DEV__) || __WHOAMI_IN_DEV__;
window.__archiFlags = Object.assign({}, window.__archiFlags, {
dev: __DEV__,
whoamiPath: __WHOAMI_PATH__,
whoamiInDev: __WHOAMI_IN_DEV__,
whoamiFetch: SHOULD_FETCH_WHOAMI,
});
var REQUIRED_GROUP = "editors";
var READ_GROUP = "readers";
function parseWhoamiLine(text, key) {
const re = new RegExp(`^${key}:\\s*(.*)$`, "mi");
const m = String(text || "").match(re);
return (m?.[1] ?? "").trim();
var re = new RegExp("^" + key + ":\\s*(.*)$", "mi");
var m = String(text || "").match(re);
return (m && m[1] ? m[1] : "").trim();
}
function inGroup(groups, g) {
const gg = String(g || "").toLowerCase();
var gg = String(g || "").toLowerCase();
return Array.isArray(groups) && groups.some((x) => String(x).toLowerCase() === gg);
}
// ===== Auth info promise (single source of truth) =====
if (!window.__archiAuthInfoP) {
window.__archiAuthInfoP = (async () => {
const res = await fetch(`${WHOAMI_PATH}?_=${Date.now()}`, {
credentials: "include",
cache: "no-store",
redirect: "manual",
headers: { Accept: "text/plain" },
}).catch(() => null);
// ✅ dev default: skip
if (!SHOULD_FETCH_WHOAMI) {
return { ok: false, user: "", name: "", email: "", groups: [], raw: "" };
}
var res = null;
try {
res = await fetch(__WHOAMI_PATH__ + "?_=" + Date.now(), {
credentials: "include",
cache: "no-store",
redirect: "manual",
headers: { Accept: "text/plain" },
});
} catch {
res = null;
}
if (!res) return { ok: false, user: "", name: "", email: "", groups: [], raw: "" };
if (res.type === "opaqueredirect") return { ok: false, user: "", name: "", email: "", groups: [], raw: "" };
if (res.status >= 300 && res.status < 400) return { ok: false, user: "", name: "", email: "", groups: [], raw: "" };
if (res.status === 404) return { ok: false, user: "", name: "", email: "", groups: [], raw: "" };
const text = await res.text().catch(() => "");
const looksLikeWhoami = /Remote-(User|Groups|Email|Name)\s*:/i.test(text);
if (!res.ok || !looksLikeWhoami) return { ok: false, user: "", name: "", email: "", groups: [], raw: text };
var text = "";
try { text = await res.text(); } catch { text = ""; }
const groups = parseWhoamiLine(text, "Remote-Groups")
var looksLikeWhoami = /Remote-(User|Groups|Email|Name)\s*:/i.test(text);
if (!res.ok || !looksLikeWhoami) {
return { ok: false, user: "", name: "", email: "", groups: [], raw: text };
}
var groups = parseWhoamiLine(text, "Remote-Groups")
.split(/[;,]/)
.map((s) => s.trim())
.filter(Boolean)
@@ -116,18 +173,22 @@ const ISSUE_BRIDGE_PATH = import.meta.env.PUBLIC_ISSUE_BRIDGE_PATH ?? "";
})().catch(() => ({ ok: false, user: "", name: "", email: "", groups: [], raw: "" }));
}
// readers + editors (strict)
if (!window.__archiCanReadP) {
window.__archiCanReadP = window.__archiAuthInfoP.then((info) =>
Boolean(info.ok && (inGroup(info.groups, READ_GROUP) || inGroup(info.groups, REQUIRED_GROUP)))
Boolean(info && info.ok && (inGroup(info.groups, READ_GROUP) || inGroup(info.groups, REQUIRED_GROUP)))
);
}
// editors gate for "Proposer"
if (!window.__archiIsEditorP) {
window.__archiIsEditorP = window.__archiAuthInfoP
.then((info) => Boolean(inGroup(info.groups, REQUIRED_GROUP) || (__DEV__ && !info.ok)))
.catch(() => false);
// ✅ DEV fallback: si whoami absent/KO => Proposer autorisé (comme ton intention initiale)
.then((info) => Boolean(inGroup(info.groups, REQUIRED_GROUP) || (__DEV__ && !(info && info.ok))))
.catch(() => Boolean(__DEV__));
}
})();
</script>
</head>
@@ -950,11 +1011,13 @@ const ISSUE_BRIDGE_PATH = import.meta.env.PUBLIC_ISSUE_BRIDGE_PATH ?? "";
safe("propose-gate", () => {
if (!giteaReady) return;
const p = window.__archiIsEditorP || Promise.resolve(false);
p.then((ok) => {
document.querySelectorAll(".para-propose").forEach((el) => {
if (ok) showEl(el);
else el.remove();
else hideEl(el); // ✅ jamais remove => antifragile
});
}).catch((err) => {
console.warn("[proposer] gate failed; keeping Proposer hidden", err);