greenhouse

greenhouse

minimal software forge

git clone git@git.lostduk.com:greenhouse.git

docs(*): add README, LICENSE and versioning

commit34ab70a13833f36781408cc2ad2564536aa77754
parentef305878ade57064e5ca67e287560f020bc09899
authorlostduk <hi@lostduk.com>
date2026-10-18 00:27 +0700
LICENSE21+++++++++++++++++++++
README33+++++++++++++++++++++++++++++++++
hedge/Makefile2+-
hedge/README39+++++++++++++++++++++++++++++++++++++++
hedge/config.mk4+++-
hedge/hedge.19++++++++-
hedge/hedge.c6+++++-
herbarium/Makefile2+-
herbarium/README39+++++++++++++++++++++++++++++++++++++++
herbarium/config.mk4+++-
herbarium/herbarium.17++++++-
herbarium/herbarium.c6+++++-
petal/Makefile2+-
petal/README34++++++++++++++++++++++++++++++++++
petal/config.mk4+++-
petal/petal.17++++++-
petal/petal.c6+++++-
pollen/Makefile2+-
pollen/README39+++++++++++++++++++++++++++++++++++++++
pollen/config.mk4+++-
pollen/pollen.19++++++++-
pollen/pollen.c6+++++-

22 files changed, -16/+269

LICENSE

@@ -0,0 +1,21 @@+MIT/X Consortium License++© 2026 lostduk <hi@lostduk.com>++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and associated documentation files (the "Software"),+to deal in the Software without restriction, including without limitation+the rights to use, copy, modify, merge, publish, distribute, sublicense,+and/or sell copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER+DEALINGS IN THE SOFTWARE.

README

@@ -0,0 +1,33 @@+greenhouse - minimal software forge+===================================+greenhouse is a software forge built from a few independent programs.+It hosts git repositories over ssh and the web, and runs the mailing+lists where patches are sent with git send-email, reviewed and+archived.+++Parts+-----+    hedge      git access control for ssh+    petal      git web interface (CGI)+    pollen     mailing list manager (Postfix pipe transport)+    herbarium  mailing list archive web interface (CGI)+++Overview+--------+    git push, fetch  ->  sshd  ->  hedge  ->  git-shell  ->  /srv/git+    browser          ->  httpd ->  petal                 ->  /srv/git+    mail             ->  Postfix -> pollen -> sendmail   ->  subscribers+                                    pollen               ->  /srv/lists+    browser, b4      ->  httpd ->  herbarium             ->  /srv/lists+++Installation+------------+Each part is built and installed on its own:++    cd petal+    make clean install++See the README and man page in each directory.

hedge/Makefile

@@ -24,7 +24,7 @@ install: all 	cp -f hedge ${DESTDIR}${PREFIX}/bin 	chmod 755 ${DESTDIR}${PREFIX}/bin/hedge 	mkdir -p ${DESTDIR}${MANPREFIX}/man1-	cp -f hedge.1 ${DESTDIR}${MANPREFIX}/man1+	sed "s/VERSION/${VERSION}/g" < hedge.1 > ${DESTDIR}${MANPREFIX}/man1/hedge.1 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/hedge.1  uninstall:

hedge/README

@@ -0,0 +1,39 @@+hedge - git access control for ssh+==================================+hedge is run as the forced command of an ssh key. It allows git fetch+and push to the repositories an access list grants to that key, and+nothing else.+++Requirements+------------+In order to run hedge you need git-shell, which comes with git.+++Installation+------------+Edit config.mk to match your local setup (hedge is installed into+the /usr/local namespace by default).++Afterwards enter the following command to build and install hedge (if+necessary as root):++    make clean install+++Running hedge+-------------+List the grants in the acl file:++    greenhouse write alice+    greenhouse read bob++and give each ssh key of the git user its identity:++    command="/usr/local/bin/hedge alice",restrict ssh-ed25519 AAAA...+++Configuration+-------------+The configuration of hedge is done by creating a custom config.h+and (re)compiling the source code.

hedge/config.mk

@@ -1,7 +1,9 @@+VERSION = 0.1+ PREFIX    = /usr/local MANPREFIX = ${PREFIX}/share/man -CPPFLAGS = -D_XOPEN_SOURCE=700+CPPFLAGS = -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" CFLAGS   = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS} LDFLAGS  = 

hedge/hedge.1

@@ -1,9 +1,12 @@-.TH HEDGE 1 hedge+.TH HEDGE 1 hedge\-VERSION .SH NAME hedge \- git access control for ssh .SH SYNOPSIS .B hedge .I id+.br+.B hedge+.B \-v .SH DESCRIPTION .B hedge is run as the forced command of an ssh key and lets the identity@@ -37,6 +40,10 @@ segments matching so nested repositories such as .B group/repo are allowed.+.SH OPTIONS+.TP+.B \-v+prints version information to stderr, then exits. .SH FILES .TP .B acl

hedge/hedge.c

@@ -108,7 +108,7 @@ trim(char *path) void usage(void) {-	fputs("usage: hedge id\n", stderr);+	fputs("usage: hedge -v | id\n", stderr); 	exit(1); } @@ -146,6 +146,10 @@ main(int argc, char *argv[]) 	char *path; 	size_t i; +	if (argc == 2 && !strcmp(argv[1], "-v")) {+		fputs("hedge-"VERSION"\n", stderr);+		return 1;+	} 	if (argc != 2) 		usage(); 	id = argv[1];

herbarium/Makefile

@@ -28,7 +28,7 @@ install: all 	chmod 644 ${DESTDIR}${PREFIX}/share/herbarium/style.css\ 		${DESTDIR}${PREFIX}/share/herbarium/icon.svg 	mkdir -p ${DESTDIR}${MANPREFIX}/man1-	cp -f herbarium.1 ${DESTDIR}${MANPREFIX}/man1+	sed "s/VERSION/${VERSION}/g" < herbarium.1 > ${DESTDIR}${MANPREFIX}/man1/herbarium.1 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/herbarium.1  uninstall:

herbarium/README

@@ -0,0 +1,39 @@+herbarium - mailing list archive web interface+==============================================+herbarium is a CGI program that shows the archives kept by pollen as+threads, with raw messages and thread mboxes for b4 and git am.+++Requirements+------------+In order to build herbarium you need a C library with iconv.+++Installation+------------+Edit config.mk to match your local setup (herbarium is installed into+the /usr/local namespace by default).++Afterwards enter the following command to build and install herbarium+(if necessary as root):++    make clean install+++Running herbarium+-----------------+Run herbarium as a CGI program, for example with nginx and fcgiwrap,+as a user that can read the list archives, and serve style.css and+icon.svg from share/herbarium. Only lists that contain a public file+are shown. See herbarium(1) for an example configuration.++To fetch a thread with b4:++    git config b4.midmask https://lists.example.org/list/%s+    b4 am <message-id>+++Configuration+-------------+The configuration of herbarium is done by creating a custom config.h+and (re)compiling the source code.

herbarium/config.mk

@@ -1,7 +1,9 @@+VERSION = 0.1+ PREFIX    = /usr/local MANPREFIX = ${PREFIX}/share/man -CPPFLAGS = -D_XOPEN_SOURCE=700+CPPFLAGS = -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" CFLAGS   = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS} LDFLAGS  = 

herbarium/herbarium.1

@@ -1,8 +1,9 @@-.TH HERBARIUM 1 herbarium+.TH HERBARIUM 1 herbarium\-VERSION .SH NAME herbarium \- mailing list archive web interface .SH SYNOPSIS .B herbarium+.RB [ \-v ] .SH DESCRIPTION .B herbarium is a CGI program that shows the archives@@ -72,6 +73,10 @@ The whole thread as a gzipped mboxrd file, as fetched by .P Every response carries a Content-Security-Policy that allows only the stylesheet and icon from the same origin.+.SH OPTIONS+.TP+.B \-v+prints version information to stderr, then exits. .SH ENVIRONMENT .TP .B PATH_INFO

herbarium/herbarium.c

@@ -2015,11 +2015,15 @@ xstrndup(const char *s, size_t n)  /* main */ int-main(void)+main(int argc, char *argv[]) { 	char path[2048]; 	const char *q; +	if (argc == 2 && !strcmp(argv[1], "-v")) {+		fputs("herbarium-"VERSION"\n", stderr);+		return 1;+	} 	base = envor("SCRIPT_NAME", ""); 	q = envor("QUERY_STRING", ""); 	if (!strncmp(q, "ofs=", 4) && (ofs = strtol(q + 4, NULL, 10)) < 0)

petal/Makefile

@@ -28,7 +28,7 @@ install: all 	chmod 644 ${DESTDIR}${PREFIX}/share/petal/style.css\ 		${DESTDIR}${PREFIX}/share/petal/icon.svg 	mkdir -p ${DESTDIR}${MANPREFIX}/man1-	cp -f petal.1 ${DESTDIR}${MANPREFIX}/man1+	sed "s/VERSION/${VERSION}/g" < petal.1 > ${DESTDIR}${MANPREFIX}/man1/petal.1 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/petal.1  uninstall:

petal/README

@@ -0,0 +1,34 @@+petal - git web interface+=========================+petal is a CGI program that shows bare git repositories: an index,+log, tree, raw files, commits with diffs, and refs.+++Requirements+------------+In order to build petal you need the libgit2 header files.+++Installation+------------+Edit config.mk to match your local setup (petal is installed into+the /usr/local namespace by default).++Afterwards enter the following command to build and install petal (if+necessary as root):++    make clean install+++Running petal+-------------+Run petal as a CGI program, for example with nginx and fcgiwrap, and+serve style.css and icon.svg from share/petal. Only repositories that+contain git-daemon-export-ok are shown. See petal(1) for an example+configuration.+++Configuration+-------------+The configuration of petal is done by creating a custom config.h+and (re)compiling the source code.

petal/config.mk

@@ -1,3 +1,5 @@+VERSION = 0.1+ PREFIX    = /usr/local MANPREFIX = ${PREFIX}/share/man @@ -7,7 +9,7 @@ GIT2LIB = /usr/local/lib INCS = -I${GIT2INC} LIBS = -L${GIT2LIB} -lgit2 -CPPFLAGS = -D_XOPEN_SOURCE=700+CPPFLAGS = -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" CFLAGS   = -std=c99 -pedantic -Wall -Wextra -Os ${INCS} ${CPPFLAGS} LDFLAGS  = ${LIBS} 

petal/petal.1

@@ -1,8 +1,9 @@-.TH PETAL 1 petal+.TH PETAL 1 petal\-VERSION .SH NAME petal \- git web interface .SH SYNOPSIS .B petal+.RB [ \-v ] .SH DESCRIPTION .B petal is a CGI program that shows the bare git repositories in@@ -67,6 +68,10 @@ Branches and tags. .P Every response carries a Content-Security-Policy that allows only the stylesheet and icon from the same origin.+.SH OPTIONS+.TP+.B \-v+prints version information to stderr, then exits. .SH ENVIRONMENT .TP .B PATH_INFO

petal/petal.c

@@ -1145,11 +1145,15 @@ xmlencoden(const char *s, size_t len)  /* main */ int-main(void)+main(int argc, char *argv[]) { 	char path[1024]; 	const char *q; +	if (argc == 2 && !strcmp(argv[1], "-v")) {+		fputs("petal-"VERSION"\n", stderr);+		return 1;+	} 	base = envor("SCRIPT_NAME", ""); 	q = envor("QUERY_STRING", ""); 	if (!strncmp(q, "ofs=", 4) && (ofs = strtol(q + 4, NULL, 10)) < 0)

pollen/Makefile

@@ -24,7 +24,7 @@ install: all 	cp -f pollen ${DESTDIR}${PREFIX}/bin 	chmod 755 ${DESTDIR}${PREFIX}/bin/pollen 	mkdir -p ${DESTDIR}${MANPREFIX}/man1-	cp -f pollen.1 ${DESTDIR}${MANPREFIX}/man1+	sed "s/VERSION/${VERSION}/g" < pollen.1 > ${DESTDIR}${MANPREFIX}/man1/pollen.1 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/pollen.1  uninstall:

pollen/README

@@ -0,0 +1,39 @@+pollen - mailing list manager+=============================+pollen delivers posts to the subscribers of a mailing list, keeps an+archive, and handles subscribe, unsubscribe and help requests sent by+mail.+++Requirements+------------+In order to run pollen you need Postfix, or another mail server that+can pipe a message to a program, and a sendmail command.+++Installation+------------+Edit config.mk to match your local setup (pollen is installed into+the /usr/local namespace by default).++Afterwards enter the following command to build and install pollen (if+necessary as root):++    make clean install+++Running pollen+--------------+Add pollen as a pipe transport for the list domain in master.cf:++    pollen unix - n n - - pipe+      flags=Rq user=pollen argv=/usr/local/bin/pollen ${user} ${extension}++and create a directory per list. See pollen(1) for the list files and+the rest of the Postfix configuration.+++Configuration+-------------+The configuration of pollen is done by creating a custom config.h+and (re)compiling the source code.

pollen/config.mk

@@ -1,7 +1,9 @@+VERSION = 0.1+ PREFIX    = /usr/local MANPREFIX = ${PREFIX}/share/man -CPPFLAGS = -D_XOPEN_SOURCE=700+CPPFLAGS = -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\" CFLAGS   = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS} LDFLAGS  = 

pollen/pollen.1

@@ -1,10 +1,13 @@-.TH POLLEN 1 pollen+.TH POLLEN 1 pollen\-VERSION .SH NAME pollen \- mailing list manager .SH SYNOPSIS .B pollen .I list .RI [ extension ]+.br+.B pollen+.B \-v .SH DESCRIPTION .B pollen delivers one message, read from standard input, to the mailing list@@ -55,6 +58,10 @@ in a single call for all subscribers, with as envelope sender. If that call fails, the archived copy is removed again so Postfix can retry cleanly.+.SH OPTIONS+.TP+.B \-v+prints version information to stderr, then exits. .SH COMMANDS Commands are addressed as .IB list + command @ domain .

pollen/pollen.c

@@ -913,7 +913,7 @@ end: void usage(void) {-	fputs("usage: pollen list [extension]\n", stderr);+	fputs("usage: pollen -v | list [extension]\n", stderr); 	exit(EX_USAGE); } @@ -942,6 +942,10 @@ main(int argc, char *argv[]) 	char ext[256]; 	struct stat st; +	if (argc == 2 && !strcmp(argv[1], "-v")) {+		fputs("pollen-"VERSION"\n", stderr);+		return 1;+	} 	umask(027); 	signal(SIGPIPE, SIG_IGN); 	openlog("pollen", LOG_PID, LOG_MAIL);