mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-21 22:52:19 +03:00
Passo 10 of the Radar go-live: publish the OmniRoute catalog export the Radar
server consumes to a stable URL, so the 1 GB-RAM private server pulls it via
RADAR_EXPORT_URL instead of depending on the deploy-time snapshot.
- scripts/release/radar-export.mjs: emits {geradoEm, budgets, totais, registry,
provenance} from the catalog config modules. Provenance (sourceCommit,
sourceRef, runUrl, generatedBy) is never fabricated — unknown fields stay null.
- .github/workflows/radar-export.yml: on main catalog changes / manual dispatch /
weekly, generates the export and clobbers the stable 'radar-export-latest'
release asset (gh release, GH_TOKEN — checkout persist-credentials:false).
- tests/unit/radar-export.test.mjs: consumer contract (budgets[] non-empty) +
provenance null-when-unknown + GitHub-env reflection.
Stable URL for RADAR_EXPORT_URL:
https://github.com/diegosouzapw/OmniRoute/releases/download/radar-export-latest/export-omniroute.json
Re-baselines zizmorFindings 190->192 (+2 unpinned-uses @vN, the repo-wide
deliberate convention; artipacked auto-fixed).
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
94 lines
3.5 KiB
JavaScript
94 lines
3.5 KiB
JavaScript
#!/usr/bin/env node
|
|
// Gera o export estável do catálogo OmniRoute consumido pelo OmniRoute Radar
|
|
// (`RADAR_EXPORT_URL` → `${DATA_DIR}/export-omniroute.json` no servidor privado).
|
|
//
|
|
// Por que existe: o servidor Radar (1 GB RAM na Akamai) NUNCA clona nem instala
|
|
// o OmniRoute; ele só baixa este JSON de uma URL estável. Antes o export vinha
|
|
// do snapshot gravado no deploy, preso à máquina do operador. Este script roda
|
|
// no CI do OmniRoute (que tem os módulos de catálogo + tsx), emite o export com
|
|
// PROVENIÊNCIA e o workflow o publica como asset de release de URL fixa.
|
|
//
|
|
// Contrato do consumidor (`src/feed/exportSource.ts` no radar-server): exige
|
|
// `budgets[]` não-vazio e lê `geradoEm`; chaves extras são ignoradas, então
|
|
// `totais`, `registry` e `provenance` viajam junto sem quebrar retrocompat.
|
|
//
|
|
// Uso (precisa de tsx, pois lê .ts):
|
|
// node --import tsx/esm scripts/release/radar-export.mjs [saída.json]
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
const REPO = path.resolve(DIR, "../.."); // …/OmniRoute
|
|
const SAIDA = process.argv[2] || path.join(REPO, "export-omniroute.json");
|
|
|
|
const { FREE_MODEL_BUDGETS } = await import(
|
|
path.join(REPO, "open-sse/config/freeModelCatalog.data.ts")
|
|
);
|
|
const { computeFreeModelTotals } = await import(
|
|
path.join(REPO, "open-sse/config/freeModelCatalog.ts")
|
|
);
|
|
const { REGISTRY } = await import(path.join(REPO, "open-sse/config/providerRegistry.ts"));
|
|
|
|
/**
|
|
* Proveniência: quem/quando/de-qual-commit gerou o export. Cada campo é `null`
|
|
* quando a origem é desconhecida — NUNCA inventamos um valor (D16: desconhecido
|
|
* permanece `null`). No CI o GitHub popula as variáveis; localmente caímos no
|
|
* `git` e, sem repositório, em `null`.
|
|
*/
|
|
function firstEnv(...names) {
|
|
for (const name of names) {
|
|
const value = process.env[name]?.trim();
|
|
if (value) return value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function gitHead() {
|
|
try {
|
|
return execFileSync("git", ["-C", REPO, "rev-parse", "HEAD"], {
|
|
encoding: "utf8",
|
|
stdio: ["ignore", "pipe", "ignore"],
|
|
}).trim() || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function buildProvenance(geradoEm) {
|
|
const sourceCommit = firstEnv("GITHUB_SHA") ?? gitHead();
|
|
const sourceRef = firstEnv("GITHUB_REF_NAME", "GITHUB_REF");
|
|
const server = firstEnv("GITHUB_SERVER_URL");
|
|
const repository = firstEnv("GITHUB_REPOSITORY");
|
|
const runId = firstEnv("GITHUB_RUN_ID");
|
|
const runUrl = server && repository && runId ? `${server}/${repository}/actions/runs/${runId}` : null;
|
|
return {
|
|
generatedAt: geradoEm,
|
|
generator: "scripts/release/radar-export.mjs",
|
|
generatedBy: firstEnv("GITHUB_ACTIONS") ? "github-actions" : "manual",
|
|
sourceCommit,
|
|
sourceRef,
|
|
runUrl,
|
|
};
|
|
}
|
|
|
|
const geradoEm = new Date().toISOString();
|
|
const dados = {
|
|
geradoEm,
|
|
budgets: FREE_MODEL_BUDGETS,
|
|
totais: computeFreeModelTotals(),
|
|
// Só as chaves: o consumidor apenas pergunta "sabemos rotear este provider?".
|
|
registry: Object.keys(REGISTRY).sort(),
|
|
provenance: buildProvenance(geradoEm),
|
|
};
|
|
|
|
fs.mkdirSync(path.dirname(path.resolve(SAIDA)), { recursive: true });
|
|
fs.writeFileSync(SAIDA, JSON.stringify(dados));
|
|
console.log(
|
|
`catálogo exportado → ${path.basename(SAIDA)}: ` +
|
|
`${dados.budgets.length} modelos, ${dados.registry.length} providers no registry` +
|
|
` (commit ${dados.provenance.sourceCommit ?? "desconhecido"})`
|
|
);
|