Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/snippets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ jobs:
- name: Check nav coverage
run: pnpm run check:nav-coverage

- name: Check network docs
run: pnpm run check:network-docs

- name: Unit-test the network docs checker
run: pnpm run test:network-docs

- name: Check contract registry
run: pnpm run check:contract-registry

Expand Down Expand Up @@ -133,7 +139,6 @@ jobs:

- name: Check extended snippets (Rust / Python / shell / JSON / TOML / YAML)
run: pnpm run check:snippets-extended

stellar-testnet-snippets:
name: Stellar snippet testnet validation
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"test:playground": "playwright test --config scripts/playground/tests/playwright.config.ts",
"mint:validate": "mint validate",
"mint:broken-links": "mint broken-links",
"test": "npm run check:snippets && npm run check:nav-coverage && npm run check:contract-registry && npm run check:compatibility-matrix && npm run test:redirects-and-anchors"
"test": "npm run check:snippets && npm run check:nav-coverage && npm run check:network-docs",
"check:network-docs": "tsx scripts/check-network-docs.ts",
"test:network-docs": "tsx --test scripts/tests/network-docs.test.ts"
},
"dependencies": {
"@solana/web3.js": "^1.95.0",
Expand Down
115 changes: 115 additions & 0 deletions scripts/check-network-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* Validate the Stellar network guides.
*
* Checks documented environment variables, network URLs and passphrases against
* the canonical registry, runs placeholder-normalised shell syntax checks, and
* reports stale or conflicting values.
*
* Commands are only ever parsed (`bash -n`), never executed, so no real
* transaction can be sent from CI.
*
* Run: pnpm run check:network-docs
*/
import { readFile, readdir } from "node:fs/promises";
import { spawnSync } from "node:child_process";
import path from "node:path";
import {
checkCommandSyntax,
extractSection,
findConflicts,
findStaleStamps,
formatFinding,
looksLikeNetworkDoc,
summarise,
validateAgainstRegistry,
validateEnvNames,
type DocSection,
type Finding,
} from "./lib/network-docs.js";

const ROOT = process.cwd();
const SKIP_DIRS = new Set([
".git",
"node_modules",
".next",
"dist",
"build",
".agents",
".claude",
".github",
"assets",
]);
const DOC_EXTENSIONS = new Set([".mdx", ".md"]);

async function collectDocs(dir: string, found: string[] = []): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith(".") && entry.isDirectory()) continue;
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
if (SKIP_DIRS.has(entry.name)) continue;
await collectDocs(full, found);
continue;
}
if (DOC_EXTENSIONS.has(path.extname(entry.name))) found.push(full);
}
return found;
}

/** Parse-only shell syntax check — never executes the command. */
function bashSyntaxCheck(command: string): string | null {
const result = spawnSync("bash", ["-n", "-c", command], { encoding: "utf8" });
if (result.error) {
throw new Error(`Unable to run bash for syntax checks: ${result.error.message}`);
}
if (result.status === 0) return null;
const message = (result.stderr || "").trim().split("\n")[0] ?? "unknown syntax error";
return message;
}

async function main() {
const all = await collectDocs(ROOT);
const docs = await Promise.all(
all.map(async (file) => ({ file: path.relative(ROOT, file), markdown: await readFile(file, "utf8") })),
);

const networkDocs = docs.filter((doc) => looksLikeNetworkDoc(doc.markdown));
if (networkDocs.length === 0) {
throw new Error("No network guides found — expected at least one document with STELLAR_NETWORK.");
}

const sections: DocSection[] = networkDocs.map((doc) => extractSection(doc.file, doc.markdown));

const findings: Finding[] = [
...validateEnvNames(sections),
...validateAgainstRegistry(sections),
...checkCommandSyntax(sections, bashSyntaxCheck),
...findConflicts(sections),
...findStaleStamps(networkDocs, new Date()),
];

const envCount = sections.reduce((total, section) => total + section.env.length, 0);
const commandCount = sections.reduce((total, section) => total + section.commands.length, 0);

for (const finding of findings) console.log(formatFinding(finding));

const counts = summarise(findings);
console.log(
[
"",
`Network docs scanned: ${networkDocs.length}`,
`Environment variables validated: ${envCount}`,
`Commands syntax-checked (not executed): ${commandCount}`,
`Findings: ${counts.error} error(s), ${counts.warning} warning(s), ${counts.info} info`,
].join("\n"),
);

if (counts.error > 0) {
throw new Error(`${counts.error} network documentation error(s) found.`);
}
}

main().catch((error) => {
console.error(error instanceof Error ? error.message : error);
process.exit(1);
});
Loading
Loading