diff --git a/tools/auth/destructive-verb-gate.ts b/tools/auth/destructive-verb-gate.ts new file mode 100644 index 000000000..4120ae887 --- /dev/null +++ b/tools/auth/destructive-verb-gate.ts @@ -0,0 +1,19 @@ +export interface RefusalVerb { + name: string; + pattern: string; + description: string; +} + +export interface RefusalList { + verbs: RefusalVerb[]; +} + +export function assertVerbAllowed(command: string, args: string[]): void { + // Mechanical refusal gate + // Throws an error if the verb/args match the refusal list. + const fullCmd = [command, ...args].join(' '); + + // Skeleton implementation. + // In future slices, this will load from refusal-list.json and evaluate patterns. + console.log(`[Gate] Checking verb: ${command} with args:`, args); +} diff --git a/tools/auth/refusal-list.json b/tools/auth/refusal-list.json new file mode 100644 index 000000000..eba2aa237 --- /dev/null +++ b/tools/auth/refusal-list.json @@ -0,0 +1,34 @@ +{ + "verbs": [ + { + "name": "repository_deletion", + "pattern": "gh (repo delete|api.*DELETE.*repos/)", + "description": "Repository deletion" + }, + { + "name": "history_rewrite", + "pattern": "git push.*--force", + "description": "History rewrite on protected refs" + }, + { + "name": "org_membership_mutation", + "pattern": "gh api.*(PUT|DELETE).*orgs/.*/memberships/", + "description": "Org membership mutation" + }, + { + "name": "webhook_creation", + "pattern": "gh api.*POST.*hooks", + "description": "Webhook creation to unallowlisted endpoint" + }, + { + "name": "audit_log_mutation", + "pattern": "gh api.*(DELETE|PATCH).*audit-log", + "description": "Audit-log mutation" + }, + { + "name": "repository_visibility", + "pattern": "gh api.*PATCH.*repos/.*private.*false", + "description": "Repository visibility change to public" + } + ] +} \ No newline at end of file