logicsrc/apps/logicsrc-web/src/lib/docs.ts
Anthony Ettinger 0fe1d423df
docs: OpenThreat, one file a security tool serves about what it found in the open (#167)
* docs: OpenThreat, one file a security tool serves about what it found in the open

Twelve rules that degrade and two that do not: a subject is public or it
is not in the file (no private repos, no customer servers, no paid users'
scans), and a secret is never located while it is open (rule, severity,
subject, status only; no location, message or excerpt). Four kinds:
finding, attack, indicator, advisory. Status open, fixed, mitigated,
blocked, withdrawn; a withdrawn threat stays a while so directories
retract it. Announcing is on by default with a one-switch opt-out in the
tool's own settings. Discovery at /.well-known/openthreat.json,
rel="openthreat", or a handed URL; origin is the verification. Mapped
against SARIF, STIX 2.1 and CSAF rather than replacing them.

First reporter: threatcrush.com/discovery (its own PR). First directory:
nichedb.dev/c/threats (its own PR). Registered in DOC_SLUGS, NAV,
STATIC_ROUTES and llms.txt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014cmNRtR2vL1p89dbVQ7FZJ

* ci: trigger workflows

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 20:30:22 -07:00

86 lines
2.1 KiB
TypeScript

import { readFileSync } from "node:fs";
import { resolve } from "node:path";
// Repo-root docs/ (read at build time during static generation, so there is
// no runtime filesystem dependency in the deployed image).
const DOCS_DIR = resolve(process.cwd(), "../../docs");
// Curated, public-facing reference docs. Internal notes (roadmap, positioning,
// arcade) are intentionally excluded.
export const DOC_SLUGS = [
"asdlc",
"openswarm",
"opencreds",
"openprd",
"openontology",
"openontology-governance",
"openontology-interoperability",
"openjob",
"openresume",
"openprofile",
"openmcp",
"openaccess",
"openserver",
"openthreat",
"openfile",
"opendisk",
"opencoupon",
"openrecipe",
"openaffiliate",
"openstream",
"opencpu",
"openmemory",
"opengpu",
"openbandwidth",
"openspec-comparison",
"data-model",
"cli",
"tui",
"config",
"permissions",
"plugins",
"credential-sharing",
"agent-screening",
] as const;
export type DocSlug = (typeof DOC_SLUGS)[number];
export function isDocSlug(slug: string): slug is DocSlug {
return (DOC_SLUGS as readonly string[]).includes(slug);
}
export function readDoc(slug: string): string | null {
if (!isDocSlug(slug)) return null;
try {
return readFileSync(resolve(DOCS_DIR, `${slug}.md`), "utf8");
} catch {
return null;
}
}
export function docTitle(markdown: string, slug: string): string {
const h1 = markdown.split("\n").find((line) => line.startsWith("# "));
return h1 ? h1.replace(/^#\s+/, "").trim() : slug;
}
export function docExcerpt(markdown: string): string {
for (const raw of markdown.split("\n")) {
const line = raw.trim();
if (line && !line.startsWith("#") && !line.startsWith("```") && !line.startsWith(">")) {
return line.replace(/[*_`#>[\]()]/g, "").trim().slice(0, 160);
}
}
return "";
}
export type DocSummary = { slug: DocSlug; title: string; excerpt: string };
export function listDocs(): DocSummary[] {
const out: DocSummary[] = [];
for (const slug of DOC_SLUGS) {
const md = readDoc(slug);
if (!md) continue;
out.push({ slug, title: docTitle(md, slug), excerpt: docExcerpt(md) });
}
return out;
}