From f522fb4f17114d48e2de5b60a9b34dea350e77cb Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sat, 31 Oct 2026 11:01:59 +0200 Subject: feat!: Initial setup --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ bins.list | 12 ++++++++++++ devs.list | 5 +++++ libs.list | 9 +++++++++ scripts/checkout | 18 ++++++++++++++++++ scripts/desc | 25 +++++++++++++++++++++++++ scripts/h | 20 ++++++++++++++++++++ scripts/homepage | 37 +++++++++++++++++++++++++++++++++++++ scripts/logo | 37 +++++++++++++++++++++++++++++++++++++ scripts/new | 20 ++++++++++++++++++++ scripts/private | 28 ++++++++++++++++++++++++++++ scripts/public | 33 +++++++++++++++++++++++++++++++++ 12 files changed, 289 insertions(+) create mode 100644 README.md create mode 100644 bins.list create mode 100644 devs.list create mode 100644 libs.list create mode 100755 scripts/checkout create mode 100755 scripts/desc create mode 100755 scripts/h create mode 100755 scripts/homepage create mode 100755 scripts/logo create mode 100755 scripts/new create mode 100755 scripts/private create mode 100755 scripts/public diff --git a/README.md b/README.md new file mode 100644 index 0000000..53b62ea --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# git.syndamia.com CLI + +Command-line utilities for managing my git repositories (creating a new repo, making it public/private, ...). + +## Usage + +The way I use them is by ssh-ing into my server in a chroot jail, which contains these, and only these, tools. + +I'll be the only one directly using , so I've opted to *not* use a software forge or any other fine-grained access control program (e.g. [gitolite](https://gitolite.com/gitolite/index.html)). +As you'll see from the `new` script, repositories are stored as bare and [git over ssh](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols.html#_the_ssh_protocol) is used for push/pull operations (thank you [tsoding](https://www.youtube.com/watch?v=iuIdBfjL62s)). + +## Setup + +Do note, I've only done this once for my server, manually. +If ever do it again, I'll setup scripts for an automated configuration. + +### chroot jail + +The best tutorial for a n00b like me was . +[Appendix B.7](https://web.archive.org/web/20260424212124/https://www.debian.org/doc/manuals/securing-debian-manual/chroot-ssh-env.en.html) from the severely outdated Securing Debian Manual also helped. + +Some extra sshd configuration options which should always be added are: + +``` +PermitTunnel no +AllowAgentForwarding no +AllowTcpForwarding no +X11Forwarding no +``` + +Documentation can be found on the [sshd_config man page](https://www.man7.org/linux/man-pages/man5/sshd_config.5.html). + +### External dependencies + +The primary utilities in this repository are simple shell scripts, however for them to work, a shell and some UNIX programs need to be available. +Since I'm jailing the ssh-ed user, every program, alongside its dynamically-linked libraries, needs to be copied over. + +All `.list` files contain newline-separated names of **external** files and directories, relative to the root directory, which need to be **copied** into the jail root. + +- `libs.list` - all needed dynamically-allocated libraries +- `bins.list` - all needed precompiled binaries. +- `devs.list` - all needed devices (they are all pseudo-devices, not related to actual hardware) + +You also **must create `/tmp` directory**! +Otherwise, git commands will not work properly. diff --git a/bins.list b/bins.list new file mode 100644 index 0000000..673b33d --- /dev/null +++ b/bins.list @@ -0,0 +1,12 @@ +/bin/bash +/bin/cat +/bin/ed +/bin/git +/bin/git-receive-pack +/bin/git-shell +/bin/git-upload-archive +/bin/git-upload-pack +/bin/ln +/bin/ls +/bin/mkdir +/bin/mv diff --git a/devs.list b/devs.list new file mode 100644 index 0000000..70abbaf --- /dev/null +++ b/devs.list @@ -0,0 +1,5 @@ +/dev/null +/dev/random +/dev/tty +/dev/urandom +/dev/zero diff --git a/libs.list b/libs.list new file mode 100644 index 0000000..01d1a3b --- /dev/null +++ b/libs.list @@ -0,0 +1,9 @@ +/lib64/ld-linux-x86-64.so.2 +/lib/x86_64-linux-gnu/libacl.so.1 +/lib/x86_64-linux-gnu/libattr.so.1 +/lib/x86_64-linux-gnu/libcap.so.2 +/lib/x86_64-linux-gnu/libc.so.6 +/lib/x86_64-linux-gnu/libpcre2-8.so.0 +/lib/x86_64-linux-gnu/libselinux.so.1 +/lib/x86_64-linux-gnu/libtinfo.so.6 +/lib/x86_64-linux-gnu/libz.so.1 diff --git a/scripts/checkout b/scripts/checkout new file mode 100755 index 0000000..26a36b0 --- /dev/null +++ b/scripts/checkout @@ -0,0 +1,18 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository: ' + read + set "$REPLY" +fi + +if [ -z "$2" ] +then + printf 'Branch : ' + read + set "$1" "$REPLY" +fi + +cd "$1" && \ +git symbolic-ref HEAD refs/heads/"$2" diff --git a/scripts/desc b/scripts/desc new file mode 100755 index 0000000..ee7c13b --- /dev/null +++ b/scripts/desc @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository : ' + read + set "$REPLY" +fi + +if [ ! -f "$1/HEAD" ] +then + echo 'Not a repository!' + exit 1 +fi + +if [ -z "$2" ] +then + printf 'Description: ' + read + set "$1" "$REPLY" +fi + +# Beware of https://stackoverflow.com/questions/53465980/how-to-keep-parameter-with-spaces-when-running-remote-script-file-with-ssh +cd "$1" && \ +git config set --file ./config gitweb.description "$2" diff --git a/scripts/h b/scripts/h new file mode 100755 index 0000000..5bdf467 --- /dev/null +++ b/scripts/h @@ -0,0 +1,20 @@ +#!/bin/bash + +cat < Create a repository +public Make repository publicly accessible +private Make repository publicly inaccessible + +checkout Set remote's active (default) branch +desc Set repository description +logo Set repository logo URL + + +Standard tools: cat ed git ln ls mkdir mv new +Delete : To remove a repository, move it to /trash +Reorder : To change order of repositories, edit /public_repos +HELP diff --git a/scripts/homepage b/scripts/homepage new file mode 100755 index 0000000..c72c91a --- /dev/null +++ b/scripts/homepage @@ -0,0 +1,37 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository : ' + read + set "$REPLY" +fi + +if [ ! -f "$1/HEAD" ] +then + echo 'Not a repository!' + exit 1 +fi + +if [ ! -w "$1/HEAD" ] +then + echo 'Read-only repository!' + exit 2 +fi + +if [ -z "$2" ] +then + printf 'Homepage URL: ' + read + set "$1" "$REPLY" +fi + +if cd "$1" +then + if [ "$2" = 'initial' ] + then + git config unset --file ./config gitweb.homepage + else + git config set --file ./config gitweb.homepage "$2" + fi +fi diff --git a/scripts/logo b/scripts/logo new file mode 100755 index 0000000..d380e00 --- /dev/null +++ b/scripts/logo @@ -0,0 +1,37 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository: ' + read + set "$REPLY" +fi + +if [ ! -f "$1/HEAD" ] +then + echo 'Not a repository!' + exit 1 +fi + +if [ ! -w "$1/HEAD" ] +then + echo 'Read-only repository!' + exit 2 +fi + +if [ -z "$2" ] +then + printf 'Logo URL : ' + read + set "$1" "$REPLY" +fi + +if cd "$1" +then + if [ "$2" = 'initial' ] + then + git config unset --file ./config cgit.logo + else + git config set --file ./config cgit.logo "$2" + fi +fi diff --git a/scripts/new b/scripts/new new file mode 100755 index 0000000..65e677a --- /dev/null +++ b/scripts/new @@ -0,0 +1,20 @@ +#!/bin/bash + +while [ -z "$1" ] +do + printf 'Repository: ' + read + set "$REPLY" +done + +set "${1##/}" + +root_dir="${1%%/*}" +repo_dir="${1#*/}" + +cd "$root_dir" +if git init --bare "$repo_dir" +then + echo -e "\nClone repo with:\n\tgit clone git@syndamia.com:$1" + echo -e "\nUpload local repo with:\n\tgit push git@syndamia.com:$1 '*:*'" +fi diff --git a/scripts/private b/scripts/private new file mode 100755 index 0000000..7035c19 --- /dev/null +++ b/scripts/private @@ -0,0 +1,28 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository: ' + read + set "$REPLY" +fi + +if [ ! -f "$1/HEAD" ] +then + echo 'Repository has been deleted or moved!' +fi + +set "${1##/}" + +if echo -e "?^$1\$?" | ed -s /public_repos >/dev/null 2>&1 +then + echo -e "g|^$1$|d\nw" | ed -s /public_repos + echo "'$1' is now private!" +elif [ -f "$1/HEAD" ] +then + echo "Already private!" +else + clue="$(echo -e "?$1?" | ed -s /public_repos 2>/dev/null)" + [ "$clue" != '?' ] && echo "Perhaps you wanted: $clue" + exit 1 +fi diff --git a/scripts/public b/scripts/public new file mode 100755 index 0000000..155a81e --- /dev/null +++ b/scripts/public @@ -0,0 +1,33 @@ +#!/bin/bash + +if [ -z "$1" ] +then + printf 'Repository: ' + read + set "$REPLY" +fi + +if [ ! -f "$1/HEAD" ] +then + echo 'Not a repository!' + exit 1 +fi + +set "${1##/}" + +# If repo is in file +if echo -e "?^$1\$?" | ed -s /public_repos >/dev/null 2>&1 +then + echo "Already public!" +# If repo root dir is in file +elif echo -e "?^${1%%/*}?" | ed -s /public_repos >/dev/null 2>&1 +then + echo -e "?^${1%%/*}?a\n$1\n.\nw" | ed -s /public_repos + echo "'$1' is now public!" +# Repo and repo root dir are not anywhere in file +else + echo -e "\$a\n$1\n.\nw" | ed -s /public_repos + echo "'$1' is now public!" +fi + +echo "https://git.syndamia.com/$1" -- cgit v1.3.1-23-gd82d