mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 04:43:58 +00:00
Add AgentGit M1: agent-native git layer over a Forgejo backend
AgentGit is a thin, DID-gated source-collaboration layer over a backend forge (default Forgejo at git.profullstack.com, BBS-members-only) — not a new git host. M1 implements the contract and engines: - forge/adapter.ts: ForgeAdapter interface (only forge-specific surface) - forge/forgejo.ts: ForgejoAdapter over Forgejo/Gitea REST v1 (injectable fetch, typed errors), incl. ensureUser for member provisioning - access.ts: gateAccess DID membership gate (owner/role/visibility) - merge-policy.ts: evaluateMergePolicy pure engine (reviews, reputation floor, checks, escrow, merge method, agent-merge toggle) - service.ts: AgentGitService ties gate + policy to the adapter; refuses policy-failing merges; provisionMember hook for AgentBBS - schemas: logicsrc-repo + logicsrc-pull-request, registered in @logicsrc/validators with fixtures - docs/agentgit.md spec; plugin wired into root build (default/disabled) 27 vitest tests pass; full monorepo build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
14fe9d608f
commit
bf046ae280
25 changed files with 1776 additions and 3 deletions
51
plugins/agentgit/src/access.ts
Normal file
51
plugins/agentgit/src/access.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import type { MemberRole, Repo } from "./domain.js";
|
||||
|
||||
export type Action = "read" | "write" | "review" | "merge" | "admin";
|
||||
|
||||
export interface GateResult {
|
||||
allowed: boolean;
|
||||
role?: MemberRole;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
const ROLE_ACTIONS: Record<MemberRole, Action[]> = {
|
||||
reader: ["read"],
|
||||
reviewer: ["read", "review"],
|
||||
contributor: ["read", "review", "write"],
|
||||
maintainer: ["read", "review", "write", "merge", "admin"]
|
||||
};
|
||||
|
||||
function rolePermits(role: MemberRole, action: Action): boolean {
|
||||
return ROLE_ACTIONS[role].includes(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* The membership gate. Every AgentGit operation runs through this before any
|
||||
* backend call. The owner is an implicit maintainer; public repos allow `read`
|
||||
* to anyone; everything else requires a matching member role. There is no
|
||||
* anonymous access to members_only/private repos.
|
||||
*/
|
||||
export function gateAccess(repo: Repo, callerDid: string | undefined, action: Action): GateResult {
|
||||
if (callerDid && callerDid === repo.owner_did) {
|
||||
return { allowed: true, role: "maintainer" };
|
||||
}
|
||||
|
||||
if (action === "read" && repo.visibility === "public") {
|
||||
return { allowed: true, role: "reader" };
|
||||
}
|
||||
|
||||
if (!callerDid) {
|
||||
return { allowed: false, reason: "authentication required (DID)" };
|
||||
}
|
||||
|
||||
const member = repo.members.find((entry) => entry.did === callerDid);
|
||||
if (!member) {
|
||||
return { allowed: false, reason: `${callerDid} is not a member of ${repo.slug}` };
|
||||
}
|
||||
|
||||
if (!rolePermits(member.role, action)) {
|
||||
return { allowed: false, role: member.role, reason: `role "${member.role}" cannot ${action}` };
|
||||
}
|
||||
|
||||
return { allowed: true, role: member.role };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue