GitRoot
Craft your forge, Build your project, Grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5import { JSON } from "json-as";
6import {
7 Commit,
8 File,
9 InitKind,
10 Plugin,
11 PluginRun,
12 PluginRunWhen,
13 PluginWrite,
14 PluginWriteRight,
15 PluginWriteRightCan,
16 Register,
17 ReportLevel,
18 Server,
19} from "plugin/server";
20import { getInitShContent } from "./embedded-data";
21
22export * from "plugin/exports";
23
24@json
25class Conf {
26 static default(): JSON.Raw {
27 return JSON.Raw.from(JSON.stringify<Conf>(new Conf()));
28 }
29}
30
31const defaultRun: PluginRun = new PluginRun(
32 "**/*",
33 ["*"],
34 [PluginRunWhen.Add, PluginRunWhen.Mod, PluginRunWhen.Del],
35 "",
36 [],
37 new PluginWrite(
38 [
39 new PluginWriteRight(".gitroot/init.sh", [
40 PluginWriteRightCan.Add,
41 PluginWriteRightCan.Mod,
42 PluginWriteRightCan.Del,
43 ]),
44 new PluginWriteRight(".gitroot/allowed_signers", [
45 PluginWriteRightCan.Add,
46 PluginWriteRightCan.Mod,
47 PluginWriteRightCan.Del,
48 ]),
49 ],
50 [],
51 [],
52 [],
53 ),
54 Conf.default(),
55);
56
57class Stigma implements Plugin {
58 private server: Server;
59 private conf: Conf | null = null;
60 private goodCommits: Array<Commit> = new Array<Commit>();
61 private notSignedCommits: Array<Commit> = new Array<Commit>();
62 private badCommits: Array<Commit> = new Array<Commit>();
63
64 constructor(server: Server) {
65 this.server = server;
66 }
67
68 init(repoName: string, initKind: InitKind, serializedConf: string): void {
69 this.conf = JSON.parse<Conf>(serializedConf);
70 if (!this.server.worktree().exists(".gitroot/init.sh")) {
71 this.server
72 .worktree()
73 .writeContent(".gitroot/init.sh", getInitShContent());
74 }
75 if (!this.server.worktree().exists(".gitroot/allowed_signers")) {
76 this.server.worktree().writeContent(".gitroot/allowed_signers", "");
77 }
78 this.server.commitAllIfNeeded("init stigma plugin");
79 return;
80 }
81
82 startCommit(commit: Commit): void {
83 if (commit.isSigned && commit.isValidSignature) {
84 this.goodCommits.push(commit);
85 } else if (commit.isSigned === false) {
86 this.notSignedCommits.push(commit);
87 } else if (commit.isValidSignature === false) {
88 this.badCommits.push(commit);
89 }
90 return;
91 }
92
93 addFile(file: File): void {
94 return;
95 }
96
97 modFile(file: File): void {
98 return;
99 }
100
101 delFile(file: File): void {
102 return;
103 }
104
105 endCommit(commit: Commit): void {
106 return;
107 }
108
109 finish(): void {
110 if (this.badCommits.length > 0) {
111 this.server.report(ReportLevel.Error, ["Commits are bad signed!"]);
112 }
113 if (this.notSignedCommits.length > 0) {
114 this.server.report(ReportLevel.Warning, ["Commits are not signed!"]);
115 }
116 if (this.goodCommits.length > 0) {
117 let content =
118 this.server.worktree().readAll(".gitroot/allowed_signers") || "";
119 for (let i = 0; i < this.goodCommits.length; i++) {
120 const c = this.goodCommits[i];
121 if (!content.includes(c.signingKey)) {
122 content = content + `${c.committerEmail} ${c.signingKey}\n`;
123 }
124 }
125 this.server.worktree().writeContent(".gitroot/allowed_signers", content);
126 this.server.commitAllIfNeeded("added signers");
127 }
128 this.conf = null;
129 this.goodCommits = [];
130 this.notSignedCommits = [];
131 this.badCommits = [];
132 return;
133 }
134}
135
136function build(server: Server): Plugin {
137 return new Stigma(server);
138}
139
140export function install(): void {
141 Register([defaultRun], build);
142}