From dede91c1339535b9245e5912575dbc7579d05c23 Mon Sep 17 00:00:00 2001 From: danny Date: Sun, 28 Dec 2025 05:13:53 +0000 Subject: [PATCH] Trace: add verification badge + context --- .../server/server.mjs | 897 +++++++++++++++++- 1 file changed, 892 insertions(+), 5 deletions(-) diff --git a/site/red-team-shadow-dossiers/server/server.mjs b/site/red-team-shadow-dossiers/server/server.mjs index 1d4ccbe..1d56972 100644 --- a/site/red-team-shadow-dossiers/server/server.mjs +++ b/site/red-team-shadow-dossiers/server/server.mjs @@ -4,6 +4,7 @@ import path from "node:path"; import url from "node:url"; import { spawn } from "node:child_process"; +import MarkdownIt from "markdown-it"; import express from "express"; import multer from "multer"; @@ -17,8 +18,37 @@ const indexHtmlPath = path.join(distDir, "index.html"); const privateUploadToken = process.env.PRIVATE_UPLOAD_TOKEN || ""; const privateUploadMaxBytes = Number(process.env.PRIVATE_UPLOAD_MAX_BYTES || 25 * 1024 * 1024); const privateUploadStyle = process.env.PRIVATE_UPLOAD_STYLE || "if.dave.v1.2"; +const privateUploadActionPack = String(process.env.PRIVATE_UPLOAD_ACTION_PACK || "") + .trim() + .toLowerCase(); const revoiceRepoRoot = path.resolve(projectRoot, "..", ".."); +function normalizeBaseUrl(value) { + return String(value || "") + .trim() + .replace(/\/+$/g, ""); +} + +function uniqBaseUrls(values) { + const out = []; + const seen = new Set(); + for (const v of values || []) { + const base = normalizeBaseUrl(v); + if (!base) continue; + if (seen.has(base)) continue; + seen.add(base); + out.push(base); + } + return out; +} + +function staticMirrorBaseUrls(primaryBaseUrl, publicBaseUrl) { + const env = String(process.env.STATIC_MIRROR_PUBLIC_BASE_URLS || "").trim(); + const defaults = ["https://git.infrafabric.io"]; + const configured = env ? env.split(",") : defaults; + return uniqBaseUrls([primaryBaseUrl, ...configured, publicBaseUrl]); +} + function escapeHtml(value) { return String(value || "") .replaceAll("&", "&") @@ -32,6 +62,613 @@ function ensureDir(dirPath) { fs.mkdirSync(dirPath, { recursive: true }); } +const markdown = new MarkdownIt({ + html: false, + linkify: true, + breaks: false, +}); +const defaultFence = markdown.renderer.rules.fence; +markdown.renderer.rules.fence = (tokens, idx, options, env, self) => { + const token = tokens[idx]; + const info = String(token.info || "") + .trim() + .split(/\s+/g)[0] + .toLowerCase(); + if (info === "mermaid") { + return `
${escapeHtml(token.content)}
\n`; + } + if (typeof defaultFence === "function") return defaultFence(tokens, idx, options, env, self); + return self.renderToken(tokens, idx, options); +}; + +function renderMarkdownPage({ title, html, topLinksHtml }) { + return [ + "", + "", + "", + "", + "", + `${escapeHtml(title || "Shadow Dossier")}`, + "", + "", + topLinksHtml ? `
${topLinksHtml}
` : "", + `
${html}
`, + "", + "", + ].join(""); +} + +function renderVerificationBadgeHtml(verification) { + const status = String(verification?.status || "").toLowerCase(); + const label = String(verification?.label || "").trim(); + const detail = String(verification?.detail || "").trim(); + + if (!status) return ""; + + const cls = status === "verified" ? "ok" : status === "warning" ? "warn" : "fail"; + const safeLabel = escapeHtml(label || status.toUpperCase()); + const safeDetail = escapeHtml(detail); + return `${safeLabel}${safeDetail ? ` ${safeDetail}` : ""}`; +} + +async function computeVerificationStatus({ job, projectRoot, outputsDir, uploadsDir }) { + const expectedOutput = String(job?.outputSha256 || "").trim(); + const expectedSource = String(job?.sourceSha256 || "").trim(); + const warningsPresent = Boolean(job?.warnings && String(job.warnings).trim()); + const status = String(job?.status || "").trim(); + + const outputPathRel = String(job?.outputPath || "").trim(); + const outputAbs = outputPathRel ? path.resolve(projectRoot, outputPathRel) : ""; + + let outputOk = false; + if (expectedOutput && outputAbs && outputAbs.startsWith(outputsDir + path.sep) && fs.existsSync(outputAbs)) { + try { + const actual = await sha256File(outputAbs); + outputOk = actual === expectedOutput; + } catch { + outputOk = false; + } + } + + const sourcePathRel = String(job?.sourcePath || "").trim(); + const sourceAbs = sourcePathRel ? path.resolve(projectRoot, sourcePathRel) : ""; + let sourceOk = false; + let sourceCheckKnown = false; + if (expectedSource && sourceAbs && sourceAbs.startsWith(uploadsDir + path.sep) && fs.existsSync(sourceAbs)) { + sourceCheckKnown = true; + try { + const actual = await sha256File(sourceAbs); + sourceOk = actual === expectedSource; + } catch { + sourceOk = false; + } + } else if (expectedSource) { + sourceCheckKnown = false; + } + + if (!outputOk) { + return { + status: "fail", + label: "FAIL", + detail: "hash mismatch", + checks: { outputOk, sourceOk: sourceCheckKnown ? sourceOk : null, warningsPresent, jobStatus: status }, + }; + } + + if (sourceCheckKnown && !sourceOk) { + return { + status: "fail", + label: "FAIL", + detail: "source mismatch", + checks: { outputOk, sourceOk, warningsPresent, jobStatus: status }, + }; + } + + if (warningsPresent || status === "done_with_warnings" || !sourceCheckKnown) { + const detail = warningsPresent ? "warnings" : !sourceCheckKnown ? "source not locally verifiable" : "check details"; + return { + status: "warning", + label: "WARNING", + detail, + checks: { outputOk, sourceOk: sourceCheckKnown ? sourceOk : null, warningsPresent, jobStatus: status }, + }; + } + + return { + status: "verified", + label: "VERIFIED", + detail: "all checks passed", + checks: { outputOk, sourceOk, warningsPresent, jobStatus: status }, + }; +} + +function renderTraceMarkdown({ shareId, job, publicBaseUrl, staticPublicBaseUrl }) { + const primaryBase = normalizeBaseUrl(staticPublicBaseUrl || publicBaseUrl); + const bases = staticMirrorBaseUrls(primaryBase, publicBaseUrl); + const mirrorBase = bases.find((b) => b !== primaryBase) || ""; + + const verificationStatus = String(job?._verification?.status || "").toUpperCase() || "UNKNOWN"; + const verificationDetail = String(job?._verification?.detail || "").trim(); + const verificationChecks = job?._verification?.checks || {}; + + const createdAt = job?.createdAt ? String(job.createdAt) : ""; + const status = job?.status ? String(job.status) : ""; + const warningsPresent = Boolean(job?.warnings && String(job.warnings).trim()); + + const dossierUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}`; + const traceUrl = `${primaryBase}/static/trace/${encodeURIComponent(shareId)}`; + const downloadUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}/download`; + const packUrl = `${primaryBase}/static/pack/${encodeURIComponent(shareId)}.md`; + const sourceUrl = job?.sourceSha256 + ? `${primaryBase}/static/source/${job.sourceSha256}${path.extname(job.sourcePath || "").toLowerCase()}` + : ""; + + const directBase = primaryBase; // Caddy exposes /r/* on infrafabric.io and git.infrafabric.io too. + const directDossierUrl = `${directBase}/r/${encodeURIComponent(shareId)}`; + const directTraceUrl = `${directBase}/r/${encodeURIComponent(shareId)}/trace`; + const directDownloadUrl = `${directBase}/r/${encodeURIComponent(shareId)}/download`; + const directPackUrl = `${directBase}/r/${encodeURIComponent(shareId)}/pack.md`; + + const lastResortBase = normalizeBaseUrl(publicBaseUrl); + const lastResortDossierUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}` : ""; + const lastResortTraceUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}/trace` : ""; + const lastResortDownloadUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}/download` : ""; + + const lines = [ + "# IF.TTT trace (public evidence view)", + "", + "## Trace verification status", + "", + `**${verificationStatus}**${verificationDetail ? ` — ${verificationDetail}` : ""}`, + "", + "- Output hash check: " + (verificationChecks.outputOk ? "**PASS**" : "**FAIL**"), + "- Source hash check: " + (verificationChecks.sourceOk === true ? "**PASS**" : verificationChecks.sourceOk === false ? "**FAIL**" : "**UNKNOWN**"), + "- Quality warnings: " + (warningsPresent ? "**present**" : "none recorded"), + "", + "IF.TTT (Traceable, Transparent, Trustworthy) is InfraFabric’s chain-of-custody protocol: it binds the **source fingerprint** to the **generated output fingerprint**, so a skeptical reader can verify what was produced and from which input, without needing access to internal systems.", + "This page is intentionally scoped to **one dossier only** (no index, no directory listing).", + "", + "## What this trace proves", + "", + "- You can independently verify the downloaded dossier Markdown by hashing it and comparing to `Output sha256` below.", + "- You can independently verify the hosted source file (if present) by hashing it and comparing to `Source sha256` below.", + "- This page binds those two fingerprints together as a single public evidence record.", + "", + "## What this trace does not prove", + "", + "- It does not validate the truth of the source’s claims.", + "- It does not attest to correctness of any commentary or recommendations in the dossier.", + "- It does not expose internal prompts, intermediate steps, or private systems.", + "", + "## Links", + "", + `- Dossier (rendered): ${dossierUrl}`, + `- Dossier (download Markdown): ${downloadUrl}`, + `- Single-file pack (review + dossier + trace): ${packUrl}`, + sourceUrl ? `- Source (PDF): ${sourceUrl}` : null, + `- This trace page: ${traceUrl}`, + mirrorBase ? "" : null, + mirrorBase ? "## Mirror host (same paths)" : null, + mirrorBase ? "" : null, + mirrorBase ? `- Dossier: ${mirrorBase}/static/dossier/${encodeURIComponent(shareId)}` : null, + mirrorBase ? `- Pack: ${mirrorBase}/static/pack/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- Trace: ${mirrorBase}/static/trace/${encodeURIComponent(shareId)}` : null, + mirrorBase && sourceUrl ? `- Source: ${mirrorBase}/static/source/${job.sourceSha256}${path.extname(job.sourcePath || "").toLowerCase()}` : null, + "", + "## Fallback links (direct)", + "", + `- Dossier: ${directDossierUrl}`, + `- Download: ${directDownloadUrl}`, + `- Pack: ${directPackUrl}`, + `- Trace: ${directTraceUrl}`, + lastResortBase && lastResortBase !== directBase ? "" : null, + lastResortBase && lastResortBase !== directBase ? "## Last resort (alternate host)" : null, + lastResortBase && lastResortBase !== directBase ? "" : null, + lastResortBase && lastResortBase !== directBase ? `- Dossier: ${lastResortDossierUrl}` : null, + lastResortBase && lastResortBase !== directBase ? `- Download: ${lastResortDownloadUrl}` : null, + lastResortBase && lastResortBase !== directBase ? `- Trace: ${lastResortTraceUrl}` : null, + "", + "## Generation context", + "", + createdAt ? `- Generated at (UTC): \`${createdAt}\`` : null, + status ? `- Status: \`${status}\`` : null, + `- Quality warnings: ${warningsPresent ? "present (see pack trace JSON)" : "none recorded"}`, + "", + "## Verifiability", + "", + `- Trace ID: \`${job.id || ""}\``, + `- Dossier: \`${job.originalFilename || ""}\``, + `- Output sha256: \`${job.outputSha256 || ""}\``, + `- Source sha256: \`${job.sourceSha256 || ""}\``, + `- Style: \`${job.style || ""}\``, + `- Source bytes: \`${String(job.sourceBytes ?? "")}\``, + "", + "## How to verify (locally)", + "", + "1) Download the dossier Markdown.", + "2) Compute its hash and compare to `Output sha256` above:", + "", + "```bash", + "sha256sum .md", + "```", + "", + sourceUrl ? "3) Optionally, download the source and verify its hash matches `Source sha256` above:" : null, + sourceUrl ? "" : null, + sourceUrl + ? "```bash\nsha256sum \n```" + : null, + ]; + + return lines.filter(Boolean).join("\n"); +} + +function renderReviewPackMarkdown({ shareId, job, publicBaseUrl, externalReviewUrl, staticSourceUrl, staticPublicBaseUrl }) { + const primaryBase = normalizeBaseUrl(staticPublicBaseUrl || publicBaseUrl); + const bases = staticMirrorBaseUrls(primaryBase, publicBaseUrl); + const mirrorBase = bases.find((b) => b !== primaryBase) || ""; + + const dossierUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}`; + const traceUrl = `${primaryBase}/static/trace/${encodeURIComponent(shareId)}`; + const downloadUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}/download`; + const packUrl = `${primaryBase}/static/pack/${encodeURIComponent(shareId)}.md`; + + const directBase = primaryBase; // Caddy exposes /r/* on infrafabric.io and git.infrafabric.io too. + const directDossierUrl = `${directBase}/r/${encodeURIComponent(shareId)}`; + const directTraceUrl = `${directBase}/r/${encodeURIComponent(shareId)}/trace`; + const directDownloadUrl = `${directBase}/r/${encodeURIComponent(shareId)}/download`; + const directPackUrl = `${directBase}/r/${encodeURIComponent(shareId)}/pack.md`; + + const lastResortBase = normalizeBaseUrl(publicBaseUrl); + const lastResortDossierUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}` : ""; + const lastResortTraceUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}/trace` : ""; + const lastResortDownloadUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}/download` : ""; + const lastResortPackUrl = lastResortBase ? `${lastResortBase}/r/${encodeURIComponent(shareId)}/pack.md` : ""; + + const lines = [ + "# InfraFabric External Review Pack — Shadow Dossier + IF.TTT trace", + "", + "Please review the dossier and the IF.TTT trace page. Provide constructive criticism and patch-style suggestions.", + "", + "## Assets", + "", + `- Dossier (rendered): ${dossierUrl}`, + `- Dossier (download Markdown): ${downloadUrl}`, + `- Single-file pack (review + dossier + trace): ${packUrl}`, + staticSourceUrl ? `- Source (download): ${staticSourceUrl}` : null, + `- IF.TTT trace page: ${traceUrl}`, + externalReviewUrl ? `- Feedback intake (login): ${externalReviewUrl}` : null, + mirrorBase ? "" : null, + mirrorBase ? "## Alternate host mirror (same paths)" : null, + mirrorBase ? "" : null, + mirrorBase ? `- Dossier (rendered): ${mirrorBase}/static/dossier/${encodeURIComponent(shareId)}` : null, + mirrorBase ? `- Dossier (download Markdown): ${mirrorBase}/static/dossier/${encodeURIComponent(shareId)}/download` : null, + mirrorBase ? `- Single-file pack: ${mirrorBase}/static/pack/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- IF.TTT trace page: ${mirrorBase}/static/trace/${encodeURIComponent(shareId)}` : null, + "", + "## Fallback links (direct)", + "", + "- These may be blocked by some scanners/LLM sandboxes; use only if the `infrafabric.io/static/*` links fail.", + "", + `- Dossier (rendered): ${directDossierUrl}`, + `- Dossier (download Markdown): ${directDownloadUrl}`, + `- Single-file pack (review + dossier + trace): ${directPackUrl}`, + `- IF.TTT trace page: ${directTraceUrl}`, + lastResortBase && lastResortBase !== directBase ? "" : null, + lastResortBase && lastResortBase !== directBase ? "## Last resort (alternate host)" : null, + lastResortBase && lastResortBase !== directBase ? "" : null, + lastResortBase && lastResortBase !== directBase ? `- Dossier (rendered): ${lastResortDossierUrl}` : null, + lastResortBase && lastResortBase !== directBase ? `- Dossier (download): ${lastResortDownloadUrl}` : null, + lastResortBase && lastResortBase !== directBase ? `- Pack: ${lastResortPackUrl}` : null, + lastResortBase && lastResortBase !== directBase ? `- Trace: ${lastResortTraceUrl}` : null, + "", + "## Response metadata (required)", + "", + "- `llm_name`: provider + model name/version (exact string)", + "- `probable_model`: if `llm_name` is ambiguous, your best guess", + "- `cutoff_date`: training data cutoff (YYYY-MM, or “unknown”)", + "- `response_date_utc`: current date/time in UTC", + "- `web_access_used`: `yes`/`no` (if yes, list URLs relied on)", + "", + "## Executive read (fast)", + "", + "- 5–10 bullets: what works / what doesn’t", + "- 3 bullets: who this will land with vs who will reject it", + "", + "## Scorecard (0–5 each)", + "", + "- Mirror integrity (section order, headings, high-signal numbers/dates, lists/tables)", + "- Layout fidelity (does it “feel” like the source?)", + "- Humor discipline (sharp without being template-y)", + "- Mermaid value (valid syntax; clarifies, not decorates)", + "- IF.TTT demo value (understandable + credible + worth clicking)", + "- Call-to-action stealth (curious about governance stack without feeling spammed)", + "", + "## Patch suggestions (actionable)", + "", + "Provide 5–15 patch suggestions. Use this format per item:", + "", + "- `target`: dossier / trace page / “generator rules” / site UX", + "- `problem`: 1 sentence", + "- `change`: proposed text or behavior (copy/pasteable if possible)", + "- `why`: 1 sentence", + "- `priority`: P0 / P1 / P2", + "- `confidence`: high / medium / low", + "", + "## Plan iteration (debug our plan)", + "", + "Propose a revised 5–8 step plan for improving the system. Prioritize steps that:", + "", + "- reduce repeatable/template patterns", + "- strengthen mirror fidelity (numbers/tables/caveats)", + "- make Mermaid + output correct-by-construction", + "- make IF.TTT feel like real chain-of-custody (not just “we printed a hash”)", + "", + "## Fact checking guidance (important)", + "", + "Default posture: don’t assume stats are true.", + "", + "- If you did not verify a number externally, refer to it as “the source claims …”", + "- If you did verify, cite URLs and state confirmed/disputed/unclear", + "- If a stat cannot be confirmed, recommend either: keep it attributed (“source claims”) or remove it from commentary", + "", + "## Notes", + "", + `- Dossier ID: \`${job.id || ""}\``, + `- Style: \`${job.style || ""}\``, + ] + .filter((line) => line !== null) + .join("\n"); + + return lines; +} + +function renderSingleFilePackMarkdown({ shareId, job, publicBaseUrl, externalReviewUrl, staticSourceUrl, staticPublicBaseUrl, dossierMarkdown }) { + const primaryBase = normalizeBaseUrl(staticPublicBaseUrl || publicBaseUrl); + const bases = staticMirrorBaseUrls(primaryBase, publicBaseUrl); + const mirrorBase = bases.find((b) => b !== primaryBase) || ""; + + const dossierUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}`; + const traceUrl = `${primaryBase}/static/trace/${encodeURIComponent(shareId)}`; + const downloadUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}/download`; + const reviewUrl = `${primaryBase}/static/review/${encodeURIComponent(shareId)}.md`; + const packUrl = `${primaryBase}/static/pack/${encodeURIComponent(shareId)}.md`; + + const jobSlim = { + id: job?.id || "", + status: job?.status || "", + createdAt: job?.createdAt || "", + originalFilename: job?.originalFilename || "", + style: job?.style || "", + sourceSha256: job?.sourceSha256 || "", + outputSha256: job?.outputSha256 || "", + warnings: job?.warnings || "", + }; + + const lines = [ + "# InfraFabric External Review Pack — Single File", + "", + "This is a single-file bundle intended for review environments that cannot reliably fetch multiple URLs.", + "", + "## Links", + "", + `- Pack (this file): ${packUrl}`, + `- Review pack (links only): ${reviewUrl}`, + `- Dossier (rendered): ${dossierUrl}`, + `- Dossier (download Markdown): ${downloadUrl}`, + `- IF.TTT trace page: ${traceUrl}`, + staticSourceUrl ? `- Source (download): ${staticSourceUrl}` : null, + externalReviewUrl ? `- Feedback intake (login): ${externalReviewUrl}` : null, + mirrorBase ? "" : null, + mirrorBase ? "## Alternate host mirror (same paths)" : null, + mirrorBase ? "" : null, + mirrorBase ? `- Pack (this file): ${mirrorBase}/static/pack/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- Review pack: ${mirrorBase}/static/review/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- Dossier: ${mirrorBase}/static/dossier/${encodeURIComponent(shareId)}` : null, + mirrorBase ? `- Trace: ${mirrorBase}/static/trace/${encodeURIComponent(shareId)}` : null, + "", + "## Review instructions (portable)", + "", + "Hard rules:", + "1) 100% factual: every non-trivial claim must be tagged [SOURCE]/[DOSSIER]/[TRACE]/[INFERENCE]. If unverified, say “unverified” and stop.", + "2) Vendor-neutral: critique deployment conditions + org behaviors, not vendor intent/competence.", + "3) Mirror discipline: follow the dossier’s section order; do not invent a new structure.", + "", + "Deliverables:", + "A) 5–10 bullets: what works / what doesn’t (tag each)", + "B) Scorecard (0–5): mirror integrity, layout fidelity, humor discipline, mermaid value, IF.TTT demo value, CTA stealth", + "C) Section-by-section critique (mirror headings): what’s mirrored, what’s missing, what feels templated/repeated", + "D) Vendor-safe conclusion rewrite: success conditions / traps / questions-to-ask-vendor", + "E) Unified diff patches against `IF_DAVE_BIBLE_v1.3.md` (and patchset if needed)", + "", + "## IF.TTT trace (portable extract)", + "", + "```json", + JSON.stringify(jobSlim, null, 2), + "```", + "", + "## Shadow dossier (Markdown)", + "", + "```markdown", + String(dossierMarkdown || "").trim(), + "```", + "", + ]; + + return lines.filter((line) => line !== null && line !== undefined).join("\n"); +} + +function extractSection(markdownText, sectionMatcher) { + const text = String(markdownText || ""); + if (!text.trim()) return ""; + const lines = text.split("\n"); + const headingRe = /^##\s+/; + let start = -1; + for (let i = 0; i < lines.length; i++) { + if (!headingRe.test(lines[i])) continue; + const title = lines[i].replace(/^##\s+/, "").trim(); + if (sectionMatcher && sectionMatcher.test(title)) { + start = i; + break; + } + } + if (start === -1) return ""; + let end = lines.length; + for (let i = start + 1; i < lines.length; i++) { + if (headingRe.test(lines[i])) { + end = i; + break; + } + } + return lines.slice(start, end).join("\n").trim(); +} + +function extractFirstMermaid(markdownText) { + const text = String(markdownText || ""); + const m = text.match(/```mermaid\s+([\s\S]*?)```/m); + return m ? String(m[1] || "").trim() : ""; +} + +function extractHeroMermaid(dossierMarkdown) { + // Prefer the section that usually produces the most "hero" marketing loop for this dossier: audits. + const sec02 = extractSection(dossierMarkdown, /^02\b/); + const sec02Diagram = extractFirstMermaid(sec02); + if (sec02Diagram) return { label: "Audit theater loop", diagram: sec02Diagram }; + const any = extractFirstMermaid(dossierMarkdown); + if (any) return { label: "Incentive loop (inferred)", diagram: any }; + return { label: "", diagram: "" }; +} + +function renderMarketingPackMarkdown({ shareId, job, publicBaseUrl, staticPublicBaseUrl, staticSourceUrl, dossierMarkdown }) { + const primaryBase = normalizeBaseUrl(staticPublicBaseUrl || publicBaseUrl); + const bases = staticMirrorBaseUrls(primaryBase, publicBaseUrl); + const mirrorBase = bases.find((b) => b !== primaryBase) || ""; + + const marketingUrl = `${primaryBase}/static/marketing/${encodeURIComponent(shareId)}.md`; + const dossierUrl = `${primaryBase}/static/dossier/${encodeURIComponent(shareId)}`; + const traceUrl = `${primaryBase}/static/trace/${encodeURIComponent(shareId)}`; + const packUrl = `${primaryBase}/static/pack/${encodeURIComponent(shareId)}.md`; + + const hero = extractHeroMermaid(dossierMarkdown); + + const lines = [ + "# InfraFabric Red Team — Marketing-safe excerpt", + "", + "This is a **marketing-safe surface** for sharing a Shadow Dossier without rewriting it into “features”.", + "", + "## One sentence (blessed)", + "", + "> InfraFabric shows why AI controls fail in practice and what must be true for them to hold.", + "", + "## Hero asset (blessed)", + "", + hero.diagram ? `### ${hero.label}` : "### (No diagram available)", + "", + hero.diagram ? "```mermaid" : null, + hero.diagram ? hero.diagram : null, + hero.diagram ? "```" : null, + "", + "## Allowed pulls (blessed)", + "", + "- Section titles", + "- “Dave Factor” blocks (verbatim)", + "- Mermaid diagrams (unchanged)", + "- Red Team Conclusion questions (verbatim)", + "", + "## Forbidden moves (do not do this)", + "", + "- Rewriting countermeasures as product capabilities", + "- Adding adjectives that imply guarantees (\"proven\", \"complete\", \"bulletproof\")", + "- Removing the “problem isn’t X” framing (it’s the vendor-safe contract)", + "- Inventing stats, timelines, or customer claims", + "", + "## CTAs (safe buttons)", + "", + "- Run this against your own rollout", + "- See the trace behind this critique", + "- Ask these questions internally", + "", + "## Links", + "", + `- Marketing excerpt (this file): ${marketingUrl}`, + `- Full dossier (rendered): ${dossierUrl}`, + `- Single-file pack (review + dossier + trace): ${packUrl}`, + `- IF.TTT trace: ${traceUrl}`, + staticSourceUrl ? `- Source (PDF): ${staticSourceUrl}` : null, + mirrorBase ? "" : null, + mirrorBase ? "## Mirror host (same paths)" : null, + mirrorBase ? "" : null, + mirrorBase ? `- Marketing excerpt: ${mirrorBase}/static/marketing/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- Full dossier: ${mirrorBase}/static/dossier/${encodeURIComponent(shareId)}` : null, + mirrorBase ? `- Pack: ${mirrorBase}/static/pack/${encodeURIComponent(shareId)}.md` : null, + mirrorBase ? `- Trace: ${mirrorBase}/static/trace/${encodeURIComponent(shareId)}` : null, + ].filter((l) => l !== null); + + return lines.join("\n"); +} + +function ensureStaticSourceFile({ job, uploadsDir, staticSourceDir, projectRoot }) { + if (!job?.sourcePath) return null; + if (!job?.sourceSha256) return null; + + const ext = path.extname(String(job.sourcePath || "")).slice(0, 12).toLowerCase() || ".bin"; + const fileName = `${job.sourceSha256}${ext}`; + const destAbs = path.join(staticSourceDir, fileName); + if (fs.existsSync(destAbs)) return { fileName, destAbs, urlPath: `/static/source/${fileName}` }; + + const srcAbs = path.resolve(projectRoot, job.sourcePath); + if (!srcAbs.startsWith(uploadsDir + path.sep)) return null; + if (!fs.existsSync(srcAbs)) return null; + + ensureDir(staticSourceDir); + fs.copyFileSync(srcAbs, destAbs); + return { fileName, destAbs, urlPath: `/static/source/${fileName}` }; +} + +function buildExternalReviewUrl(baseUrl, sheetId) { + const base = String(baseUrl || "").trim(); + const id = String(sheetId || "").trim(); + if (!base || !id) return ""; + try { + const u = new URL(base); + u.searchParams.set("sheet", id); + return u.toString(); + } catch { + return base.includes("?") ? `${base}&sheet=${encodeURIComponent(id)}` : `${base}?sheet=${encodeURIComponent(id)}`; + } +} + +function publicBaseFromRequest(req, fallbackHost) { + const host = req.get("host") || fallbackHost || "red-team.infrafabric.io"; + const protocol = req.protocol || "https"; + return `${protocol}://${host}`.replace(/\/+$/g, ""); +} + +function staticPublicBaseUrlForRequest(req, fallbackPublicBaseUrl) { + const explicit = String(process.env.STATIC_SOURCE_PUBLIC_BASE_URL || "").trim(); + if (explicit) return explicit.replace(/\/+$/g, ""); + return publicBaseFromRequest(req, fallbackPublicBaseUrl); +} + function looksLikeUuid(value) { return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(value || "")); } @@ -55,6 +692,25 @@ function writeJob(jobsDir, job) { fs.writeFileSync(p, JSON.stringify(job, null, 2) + "\n", "utf8"); } +function shareJsonPath(sharesDir, shareId) { + return path.join(sharesDir, `${shareId}.json`); +} + +function writeShare(sharesDir, shareId, data) { + const p = shareJsonPath(sharesDir, shareId); + fs.writeFileSync(p, JSON.stringify(data, null, 2) + "\n", "utf8"); +} + +function readShare(sharesDir, shareId) { + const p = shareJsonPath(sharesDir, shareId); + if (!fs.existsSync(p)) return null; + try { + return JSON.parse(fs.readFileSync(p, "utf8")); + } catch { + return null; + } +} + async function sha256File(filePath) { return await new Promise((resolve, reject) => { const h = crypto.createHash("sha256"); @@ -104,9 +760,13 @@ async function generateShadowDossier({ inputPath, outputPath }) { PYTHONPATH: path.join(revoiceRepoRoot, "src"), }; + const genArgs = ["-m", "revoice", "generate", "--style", privateUploadStyle]; + if (["1", "true", "yes", "on"].includes(privateUploadActionPack)) genArgs.push("--action-pack"); + genArgs.push("--input", inputPath, "--output", outputPath); + const gen = await runProcess( "python3", - ["-m", "revoice", "generate", "--style", privateUploadStyle, "--input", inputPath, "--output", outputPath], + genArgs, { cwd: revoiceRepoRoot, env: baseEnv } ); if (gen.code !== 0) { @@ -166,17 +826,26 @@ function generateRoastText(content) { function main() { const port = Number(process.env.PORT || 8080); const app = express(); - const dataDir = path.join(projectRoot, "data"); + app.set("trust proxy", true); + const configuredDataDir = String(process.env.RED_TEAM_DATA_DIR || "").trim(); + const dataDir = configuredDataDir ? path.resolve(configuredDataDir) : path.join(projectRoot, "data"); const uploadsDir = path.join(dataDir, "uploads"); const outputsDir = path.join(dataDir, "outputs"); const jobsDir = path.join(dataDir, "jobs"); + const sharesDir = path.join(dataDir, "shares"); + const staticDir = path.join(dataDir, "static"); + const staticSourceDir = path.join(staticDir, "source"); ensureDir(uploadsDir); ensureDir(outputsDir); ensureDir(jobsDir); + ensureDir(sharesDir); + ensureDir(staticDir); + ensureDir(staticSourceDir); app.disable("x-powered-by"); app.use(express.json({ limit: "256kb" })); + app.use("/static", express.static(staticDir, { fallthrough: false, etag: true, maxAge: "30d" })); app.get("/healthz", (_req, res) => { res.status(200).json({ ok: true }); @@ -256,7 +925,16 @@ function main() { const refresh = isDone || isError ? "" : ""; const downloadLink = isDone - ? `

Download shadow dossier

` + ? `

Download Markdown

` + : ""; + const viewLink = isDone + ? `

View rendered dossier

` + : ""; + const shareLinks = isDone && job.shareId + ? [ + "

Share links (no repo):

", + `

Public view · Public download

`, + ].join("") : ""; const sourceLink = job.sourcePath @@ -285,8 +963,11 @@ function main() { job.originalFilename ? `

Source: ${escapeHtml(job.originalFilename)}

` : "", job.sourceSha256 ? `

Source sha256: ${escapeHtml(job.sourceSha256)}

` : "", job.outputSha256 ? `

Output sha256: ${escapeHtml(job.outputSha256)}

` : "", + job.shareId ? `

Share ID: ${escapeHtml(job.shareId)}

` : "", downloadLink, + viewLink, sourceLink, + shareLinks, warnings ? "

Warnings

" + warnings : "", isError ? "

Error

" + error : "", `

Back to upload

`, @@ -295,6 +976,209 @@ function main() { ); }); + app.get("/private/:token/view/:jobId", privateGuard, (req, res) => { + const jobId = String(req.params.jobId || ""); + if (!looksLikeUuid(jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, jobId); + if (!job) return res.status(404).type("text/plain").send("Not found"); + if (!job.outputPath) return res.status(409).type("text/plain").send("Not ready"); + + const abs = path.resolve(projectRoot, job.outputPath); + if (!abs.startsWith(outputsDir + path.sep)) return res.status(400).type("text/plain").send("Bad path"); + if (!fs.existsSync(abs)) return res.status(404).type("text/plain").send("Not found"); + + const mdText = fs.readFileSync(abs, "utf8"); + const html = markdown.render(mdText); + + const token = req.params.token; + const topLinks = [ + `Download Markdown`, + job.sourcePath ? `Download source` : "", + job.shareId ? `Share view` : "", + ] + .filter(Boolean) + .join(" · "); + + res.status(200).type("text/html; charset=utf-8").send(renderMarkdownPage({ title: job.originalFilename || "Shadow dossier", html, topLinksHtml: topLinks })); + }); + + app.get("/r/:shareId/trace", async (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const verification = await computeVerificationStatus({ job, projectRoot, outputsDir, uploadsDir }); + const jobForRender = { ...job, _verification: verification }; + + const publicBaseUrl = publicBaseFromRequest(req, "red-team.infrafabric.io"); + const staticPublicBaseUrl = staticPublicBaseUrlForRequest(req, publicBaseUrl); + const md = renderTraceMarkdown({ shareId, job: jobForRender, publicBaseUrl, staticPublicBaseUrl }); + const html = markdown.render(md); + + const badge = renderVerificationBadgeHtml(verification); + const topLinks = [ + badge, + `Back to dossier`, + `Download Markdown`, + job.sourcePath ? `Download source` : "", + `Review pack (MD)`, + ] + .filter(Boolean) + .join(" · "); + + res + .status(200) + .type("text/html; charset=utf-8") + .send(renderMarkdownPage({ title: "IF.TTT trace", html, topLinksHtml: topLinks })); + }); + + app.get("/r/:shareId/source", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.sourcePath) return res.status(404).type("text/plain").send("Not found"); + + const staticFile = ensureStaticSourceFile({ job, uploadsDir, staticSourceDir, projectRoot }); + if (!staticFile) return res.status(404).type("text/plain").send("Not found"); + res.redirect(302, staticFile.urlPath); + }); + + app.get("/r/:shareId/review-pack.md", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const staticSource = ensureStaticSourceFile({ job, uploadsDir, staticSourceDir, projectRoot }); + const externalReviewBaseUrl = String(process.env.EXTERNAL_REVIEW_BASE_URL || "https://emo-social.infrafabric.io/external-review.html"); + const externalReviewUrl = buildExternalReviewUrl(externalReviewBaseUrl, share.reviewSheetId); + const publicBaseUrl = publicBaseFromRequest(req, "red-team.infrafabric.io"); + const staticPublicBaseUrl = staticPublicBaseUrlForRequest(req, publicBaseUrl); + const staticSourceUrl = staticSource ? `${staticPublicBaseUrl}${staticSource.urlPath}` : ""; + + const md = renderReviewPackMarkdown({ shareId, job, publicBaseUrl, externalReviewUrl, staticSourceUrl, staticPublicBaseUrl }); + const baseName = (job.originalFilename || "dossier").replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 60); + res + .status(200) + .type("text/markdown; charset=utf-8") + .send(md); + }); + + app.get("/r/:shareId/pack.md", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const abs = path.resolve(projectRoot, job.outputPath); + if (!abs.startsWith(outputsDir + path.sep)) return res.status(400).type("text/plain").send("Bad path"); + if (!fs.existsSync(abs)) return res.status(404).type("text/plain").send("Not found"); + const dossierMarkdown = fs.readFileSync(abs, "utf8"); + + const staticSource = ensureStaticSourceFile({ job, uploadsDir, staticSourceDir, projectRoot }); + const externalReviewBaseUrl = String(process.env.EXTERNAL_REVIEW_BASE_URL || "https://emo-social.infrafabric.io/external-review.html"); + const externalReviewUrl = buildExternalReviewUrl(externalReviewBaseUrl, share.reviewSheetId); + const publicBaseUrl = publicBaseFromRequest(req, "red-team.infrafabric.io"); + const staticPublicBaseUrl = staticPublicBaseUrlForRequest(req, publicBaseUrl); + const staticSourceUrl = staticSource ? `${staticPublicBaseUrl}${staticSource.urlPath}` : ""; + + const md = renderSingleFilePackMarkdown({ + shareId, + job, + publicBaseUrl, + externalReviewUrl, + staticSourceUrl, + staticPublicBaseUrl, + dossierMarkdown, + }); + + res.status(200).type("text/markdown; charset=utf-8").send(md); + }); + + app.get("/r/:shareId/marketing.md", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const abs = path.resolve(projectRoot, job.outputPath); + if (!abs.startsWith(outputsDir + path.sep)) return res.status(400).type("text/plain").send("Bad path"); + if (!fs.existsSync(abs)) return res.status(404).type("text/plain").send("Not found"); + const dossierMarkdown = fs.readFileSync(abs, "utf8"); + + const staticSource = ensureStaticSourceFile({ job, uploadsDir, staticSourceDir, projectRoot }); + const publicBaseUrl = publicBaseFromRequest(req, "red-team.infrafabric.io"); + const staticPublicBaseUrl = staticPublicBaseUrlForRequest(req, publicBaseUrl); + const staticSourceUrl = staticSource ? `${staticPublicBaseUrl}${staticSource.urlPath}` : ""; + + const md = renderMarketingPackMarkdown({ + shareId, + job, + publicBaseUrl, + staticPublicBaseUrl, + staticSourceUrl, + dossierMarkdown, + }); + + res.status(200).type("text/markdown; charset=utf-8").send(md); + }); + + app.get("/r/:shareId", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const abs = path.resolve(projectRoot, job.outputPath); + if (!abs.startsWith(outputsDir + path.sep)) return res.status(400).type("text/plain").send("Bad path"); + if (!fs.existsSync(abs)) return res.status(404).type("text/plain").send("Not found"); + + const mdText = fs.readFileSync(abs, "utf8"); + const html = markdown.render(mdText); + const externalReviewBaseUrl = String(process.env.EXTERNAL_REVIEW_BASE_URL || "https://emo-social.infrafabric.io/external-review.html"); + const externalReviewUrl = buildExternalReviewUrl(externalReviewBaseUrl, share.reviewSheetId); + const topLinks = [ + `Download Markdown`, + job.sourcePath ? `Download source` : "", + `IF.TTT trace`, + `Review pack (MD)`, + `Marketing excerpt (MD)`, + externalReviewUrl ? `Feedback intake (login)` : "", + ] + .filter(Boolean) + .join(" · "); + res.status(200).type("text/html; charset=utf-8").send(renderMarkdownPage({ title: job.originalFilename || "Shadow dossier", html, topLinksHtml: topLinks })); + }); + + app.get("/r/:shareId/download", (req, res) => { + const shareId = String(req.params.shareId || "").trim(); + if (!shareId) return res.status(404).type("text/plain").send("Not found"); + const share = readShare(sharesDir, shareId); + if (!share?.jobId || !looksLikeUuid(share.jobId)) return res.status(404).type("text/plain").send("Not found"); + const job = readJob(jobsDir, share.jobId); + if (!job?.outputPath) return res.status(404).type("text/plain").send("Not found"); + + const abs = path.resolve(projectRoot, job.outputPath); + if (!abs.startsWith(outputsDir + path.sep)) return res.status(400).type("text/plain").send("Bad path"); + if (!fs.existsSync(abs)) return res.status(404).type("text/plain").send("Not found"); + + const baseName = (job.originalFilename || "dossier").replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 60); + res.download(abs, `${baseName}.shadow.dave.md`); + }); + app.get("/private/:token/download/:jobId", privateGuard, (req, res) => { const jobId = String(req.params.jobId || ""); if (!looksLikeUuid(jobId)) return res.status(404).type("text/plain").send("Not found"); @@ -328,8 +1212,9 @@ function main() { if (!file?.path) return res.status(400).type("text/plain").send("Missing file"); const relSourcePath = path.relative(projectRoot, file.path); - const relOutputPath = path.join("data", "outputs", `${jobId}.shadow.dave.md`); - const absOutputPath = path.resolve(projectRoot, relOutputPath); + const absOutputPath = path.join(outputsDir, `${jobId}.shadow.dave.md`); + const relOutputPath = path.relative(projectRoot, absOutputPath); + const shareId = crypto.randomBytes(18).toString("base64url"); const now = new Date().toISOString(); const job = { @@ -339,6 +1224,7 @@ function main() { originalFilename: file.originalname || "", sourcePath: relSourcePath, outputPath: relOutputPath, + shareId, style: privateUploadStyle, sourceBytes: Number(file.size || 0), sourceSha256: "", @@ -357,6 +1243,7 @@ function main() { } writeJob(jobsDir, job); + writeShare(sharesDir, shareId, { shareId, jobId, createdAt: now }); void (async () => { try {