feat: add forgejo actions coverage receipt
This commit is contained in:
parent
f4714f146a
commit
1135ef4d7c
|
|
@ -272,6 +272,9 @@ fable-agent plinius godmode "improve explanation quality"
|
|||
- `--body <text>`
|
||||
- `--out <path>`
|
||||
- `--dry-run`
|
||||
- `forgejo actions-coverage`
|
||||
- `--repo <repo>`
|
||||
- `--output <path>`
|
||||
- `forgejo intake <ref>`
|
||||
- `--repo <repo>`
|
||||
- `--out <path>`
|
||||
|
|
|
|||
|
|
@ -2,13 +2,26 @@ import * as fs from "node:fs";
|
|||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createForgejoPullRequest, getForgejoFileContent, listForgejoIssues } from "./forgejo-cli.js";
|
||||
import { createForgejoActionsCoverageReceipt, createForgejoPullRequest, getForgejoFileContent, listForgejoIssues } from "./forgejo-cli.js";
|
||||
|
||||
function tmpDir(): string {
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), "forgejo-cli-"));
|
||||
}
|
||||
|
||||
describe("forgejo cli helpers", () => {
|
||||
it("documents Forgejo Actions coverage without scraping or mutation", () => {
|
||||
const receipt = createForgejoActionsCoverageReceipt("org/repo", new Date("2026-07-01T00:00:00.000Z"));
|
||||
|
||||
expect(receipt).toMatchObject({
|
||||
schema: "fable.forgejo.actions_coverage.v1",
|
||||
repo: "org/repo",
|
||||
decision: "api-only",
|
||||
policy: "no-web-ui-scraping-no-action-mutation",
|
||||
deployAttempted: false,
|
||||
});
|
||||
expect(receipt.rows.find((row) => row.capability === "actions cancel/rerun/trigger")?.status).toBe("blocked");
|
||||
});
|
||||
|
||||
it("lists issues via Forgejo API", async () => {
|
||||
const calls: string[] = [];
|
||||
const issues = await listForgejoIssues({
|
||||
|
|
|
|||
|
|
@ -25,6 +25,41 @@ export interface ForgejoPullRequestReceipt {
|
|||
};
|
||||
}
|
||||
|
||||
export interface ForgejoActionsCoverageReceipt {
|
||||
schema: "fable.forgejo.actions_coverage.v1";
|
||||
createdAt: string;
|
||||
repo?: string;
|
||||
rows: Array<{ capability: string; status: "covered" | "unsupported" | "blocked"; reason: string }>;
|
||||
decision: "api-only";
|
||||
policy: "no-web-ui-scraping-no-action-mutation";
|
||||
deployAttempted: false;
|
||||
}
|
||||
|
||||
export function createForgejoActionsCoverageReceipt(repo?: string, now = new Date()): ForgejoActionsCoverageReceipt {
|
||||
return {
|
||||
schema: "fable.forgejo.actions_coverage.v1",
|
||||
createdAt: now.toISOString(),
|
||||
repo,
|
||||
rows: [
|
||||
{ capability: "actions runs", status: "unsupported", reason: "Forgejo full run details commonly require UI endpoints; Fable will not scrape by default" },
|
||||
{ capability: "actions jobs", status: "unsupported", reason: "use official API only when available" },
|
||||
{ capability: "actions logs", status: "unsupported", reason: "logs may contain secrets; no web UI scraping" },
|
||||
{ capability: "actions artifacts", status: "unsupported", reason: "artifacts may contain secrets; no web UI scraping" },
|
||||
{ capability: "actions cancel/rerun/trigger", status: "blocked", reason: "mutating CI actions requires explicit implementation and approval" },
|
||||
{ capability: "pull request create", status: "covered", reason: "forgejo pr-create emits fable.forgejo.pull_request.v1" },
|
||||
],
|
||||
decision: "api-only",
|
||||
policy: "no-web-ui-scraping-no-action-mutation",
|
||||
deployAttempted: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function writeForgejoActionsCoverageReceipt(file: string, receipt: ForgejoActionsCoverageReceipt): string {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||||
fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`);
|
||||
return file;
|
||||
}
|
||||
|
||||
export async function forgejoApi<T>(opts: ForgejoCliOptions, endpoint: string, init: { method?: string; body?: unknown } = {}): Promise<T> {
|
||||
const base = requireBaseUrl(opts.baseUrl);
|
||||
const res = await (opts.fetcher ?? fetch)(`${base}/api/v1${endpoint}`, {
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ export type { PromptFingerprintFinding, PromptFingerprintReceipt } from "./promp
|
|||
export { createJailbreakAssessmentReceipt, writeJailbreakAssessmentReceipt } from "./jailbreak-assessment.js";
|
||||
export type { JailbreakAssessmentOptions, JailbreakAssessmentReceipt, JailbreakAssessmentScores, JailbreakDecision } from "./jailbreak-assessment.js";
|
||||
|
||||
export { createForgejoPullRequest, forgejoApi, getForgejoFileContent, getForgejoRepository, listForgejoIssues, listForgejoPullRequests, listForgejoRepositories } from "./forgejo-cli.js";
|
||||
export type { ForgejoCliFetch, ForgejoCliOptions, ForgejoPullRequestReceipt } from "./forgejo-cli.js";
|
||||
export { createForgejoActionsCoverageReceipt, createForgejoPullRequest, forgejoApi, getForgejoFileContent, getForgejoRepository, listForgejoIssues, listForgejoPullRequests, listForgejoRepositories, writeForgejoActionsCoverageReceipt } from "./forgejo-cli.js";
|
||||
export type { ForgejoActionsCoverageReceipt, ForgejoCliFetch, ForgejoCliOptions, ForgejoPullRequestReceipt } from "./forgejo-cli.js";
|
||||
|
||||
export { createPlanReceipt, writePlanReceipt } from "./plan-receipt.js";
|
||||
export type { PlanAllowedOutcome, PlanPhase, PlanReceipt, PlanReceiptOptions, PlanTaskType } from "./plan-receipt.js";
|
||||
|
|
|
|||
14
src/index.ts
14
src/index.ts
|
|
@ -1824,6 +1824,20 @@ forgejo
|
|||
if (result.receipt.receipts.quarantine) process.exit(1);
|
||||
});
|
||||
|
||||
forgejo
|
||||
.command("actions-coverage")
|
||||
.description("Write a Forgejo Actions CLI coverage receipt without web scraping or action mutation")
|
||||
.option("--repo <repo>", "Repo slug, e.g. org/repo")
|
||||
.option("--output <path>", "Receipt output path", path.join(".fable", "forgejo", "actions-coverage-live.json"))
|
||||
.action(async (opts: { repo?: string; output?: string }) => {
|
||||
const { createForgejoActionsCoverageReceipt, writeForgejoActionsCoverageReceipt } = await import("./fable5/forgejo-cli.js");
|
||||
const receipt = createForgejoActionsCoverageReceipt(opts.repo);
|
||||
const out = opts.output ?? path.join(".fable", "forgejo", "actions-coverage-live.json");
|
||||
writeForgejoActionsCoverageReceipt(out, receipt);
|
||||
console.log(JSON.stringify(receipt, null, 2));
|
||||
console.log(`\n Receipt: ${out}\n`);
|
||||
});
|
||||
|
||||
forgejo
|
||||
.command("comment <ref>")
|
||||
.description("Post a scanned receipt-backed comment to a Forgejo issue or PR")
|
||||
|
|
|
|||
Loading…
Reference in New Issue