97 lines
3.5 KiB
TypeScript
97 lines
3.5 KiB
TypeScript
import * as fs from "node:fs";
|
|
import * as path from "node:path";
|
|
|
|
export type ExternalProjectDecision = "learn-only" | "blocked";
|
|
export type PermissionMode = "read-only" | "plan" | "edit" | "deploy-gated";
|
|
|
|
export interface ExternalProjectReviewReceipt {
|
|
schema: "fable.external_project.review.v1";
|
|
createdAt: string;
|
|
repo: string;
|
|
url: string;
|
|
license: string;
|
|
safeToVendor: boolean;
|
|
patternsLearned: string[];
|
|
adaptations: string[];
|
|
risks: string[];
|
|
decision: ExternalProjectDecision;
|
|
policy: "learn-patterns-no-vendored-code";
|
|
deployAttempted: false;
|
|
}
|
|
|
|
export interface PermissionPostureReceipt {
|
|
schema: "fable.permission_posture.receipt.v1";
|
|
createdAt: string;
|
|
mode: PermissionMode;
|
|
allowed: string[];
|
|
blocked: string[];
|
|
approvalRequired: boolean;
|
|
decision: "ready" | "blocked";
|
|
deployAttempted: false;
|
|
}
|
|
|
|
export function createOpenCovenReviewReceipt(now = new Date()): ExternalProjectReviewReceipt {
|
|
return {
|
|
schema: "fable.external_project.review.v1",
|
|
createdAt: now.toISOString(),
|
|
repo: "OpenCoven/coven-code",
|
|
url: "https://github.com/OpenCoven/coven-code",
|
|
license: "GPL-3.0",
|
|
safeToVendor: false,
|
|
patternsLearned: [
|
|
"local-first agent runtime",
|
|
"explicit permission modes",
|
|
"session resume and branching",
|
|
"agent identity contract",
|
|
"plugin and bridge seams separated from authority",
|
|
"no-telemetry-by-default posture",
|
|
],
|
|
adaptations: [
|
|
"record external reviews as receipts",
|
|
"make permission posture explicit",
|
|
"keep adapters below CLI and receipts as authority",
|
|
"treat GPL projects as learn-only unless legal review says otherwise",
|
|
],
|
|
risks: ["GPL code cannot be copied into Fable", "remote bridge or MCP must not become deploy authority", "plugin systems add attack surface"],
|
|
decision: "learn-only",
|
|
policy: "learn-patterns-no-vendored-code",
|
|
deployAttempted: false,
|
|
};
|
|
}
|
|
|
|
export function createPermissionPostureReceipt(mode: PermissionMode, now = new Date()): PermissionPostureReceipt {
|
|
const rows: Record<PermissionMode, Omit<PermissionPostureReceipt, "schema" | "createdAt" | "mode" | "deployAttempted">> = {
|
|
"read-only": {
|
|
allowed: ["read receipts", "inspect files", "summarize repositories", "emit non-mutating receipts"],
|
|
blocked: ["write code", "mutate factory", "deploy", "use secrets"],
|
|
approvalRequired: false,
|
|
decision: "ready",
|
|
},
|
|
plan: {
|
|
allowed: ["read receipts", "write plan receipts", "propose diffs"],
|
|
blocked: ["apply diffs", "deploy", "mutate factory"],
|
|
approvalRequired: false,
|
|
decision: "ready",
|
|
},
|
|
edit: {
|
|
allowed: ["write code", "run tests", "write receipts"],
|
|
blocked: ["deploy", "mutate factory without gate", "use secrets unless explicitly approved"],
|
|
approvalRequired: true,
|
|
decision: "ready",
|
|
},
|
|
"deploy-gated": {
|
|
allowed: ["deploy only through guarded 8099/deploy with fresh valid gate receipt and explicit approval"],
|
|
blocked: ["8098/deploy-webhook", "memory-only deploy claims", "deploy without fresh ZTE/factory gate"],
|
|
approvalRequired: true,
|
|
decision: "ready",
|
|
},
|
|
};
|
|
return { schema: "fable.permission_posture.receipt.v1", createdAt: now.toISOString(), mode, ...rows[mode], deployAttempted: false };
|
|
}
|
|
|
|
export function writeExternalProjectReviewReceipt(file: string, receipt: ExternalProjectReviewReceipt | PermissionPostureReceipt): string {
|
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`);
|
|
return file;
|
|
}
|