summaryrefslogtreecommitdiff
path: root/README.md
blob: 6e0bfc1d4a01168a39f452bcaadd07ac0b95d2f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
[![crates.io](https://img.shields.io/crates/v/shackle-shell)](https://crates.io/crates/shackle-shell)

A shell for restricting access on a version control server.

This is intended as a replacement for [Git Shell](https://git-scm.com/docs/git-shell), but with a few opinionated
differences:

- Additional commands, like creating new repos, are built in. No extension with
  shell scripts.
- Strict enforcement of a specified directory structure. Git push / pull
  commands only work for these paths. New repos are created in these paths.
  - Private git repos are created in `~/git/<username>/<reponame>.git`
  - Shared git repos are created in `~/git/<groupname>/<reponame>.git`
- Better interactive UX than Git Shell, including:
  - Command history (limited to the current session).
  - Emacs-style shortcuts (eg `Ctrl+a` to move cursor to the beginning of line).
  - Docs available for all commands, available in the shell itself.
- (coming soon!) Support for other other version control systems.

# Getting Started

## Usage

Shackle Shell is intended to be set as the default shell for a user on a git
server, where the user connects over SSH (see the Installation section below).

When you log in over SSH, you'll see a prompt, ready for you to type commands.

```sh
>
```

You can see the built in help by running the `help` command.

```
> help
Usage: <COMMAND>

Commands:
  init              Create a new repository
  list              List all repositories available
  set-description   Sets the description of a repository, as shown in the CLI listing and web interfaces
  set-branch        Sets the main branch of the repository
  exit              Quit the shell
  git-upload-pack   Server side command required to git fetch from the server
  git-receive-pack  Server side command required by git push to the server
  help              Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
```

The `init` command is used to create a new repo. In its simplest form, you just
provide it with the name of your new repo. This will create a git repo with
individual ownership.

```
> init awesome-project-idea
Successfully created "git/shukkie/awesome-project-idea.git"
```

The path given here is relative to your home directory. So the full URL to clone
this repo is `<username>@<server domain>:<git path>`

```sh
git clone shukkie@example.com:git/shukkie/awesome-project-idea.git
```

You can learn its advanced options by using the `--help` flag. This works for
all of the options, and is a great way to learn what all the commands do.

```
> init --help
Create a new repository

Usage: init [OPTIONS] <REPO_NAME>

Arguments:
  <REPO_NAME>  Name of the new repository

Options:
      --group <GROUP>              Share repository ownership with the specified group (user must be a member of the group)
      --description <DESCRIPTION>  Sets the description of the repository, as shown in the CLI listing and web interfaces
      --branch <BRANCH>            Sets the main branch of the repository [default: main]
  -h, --help                       Print help
```

## Installation

### Background

Shackle is designed to run on a Git server. The process of setting up your own
Git server, which is set up as described in the following two articles:

- [initial server setup](https://www.worthe-it.co.za/blog/2022-06-10-how-to-train-your-git-server.html)
- [sharing repos](https://www.worthe-it.co.za/blog/2023-06-02-leveling-up-your-git-server-sharing-repos.html).

### Prerequisites

The following programs much be installed:

- Git
  - This is used for git operations which are passed through for the operation
    of `git push` and `git fetch`.
  - Git must be installed, with the `git-upload-pack` and `git-receive-pack`
    executables on the path.
- SSH
  - I assume users will be connecting over SSH. This is not enforced by the
    shell, but is the primary use case I have in mind. I have tested this using
    the OpenSSH daemon.


### Building Shackle

Binary releases of Shackle can be downloaded from [Codeberg](https://codeberg.org/worthe-it/shackle-shell/releases/).

You can also build it yourself from source. The easiest way to do this is using
`cargo install`.

This requires a the Rust toolchain and a C compiler. See the Development
Environment Setup section below for more information on environment setup to
build from source.

```sh
# This installs to Cargo's default, which is ~/.cargo/bin. Consider using the
# --root option to install it somewhere that makes more sense for your server.
cargo install shackle-shell
```

### Creating the required directory structure

Next, Shackle expects a specific directory structure. Specifically, personal git
repos will live in `~/git/your-username` and shared repos will live in
`~/git/your-group`.

If you have many users on your server, then consider making `~/git` a symlink to
the actual shared location for your git repos. For example, on my repo, all git
users have a `~/git` symlink in their home directory which actually points at
`/srv/git`.

```sh
mkdir -p ~/git/$USER
chmod --recursive u=rwX,g=,o= ~/git/$USER

# Note that this should be a group you're actually a member of!
GROUP=my-group
mkdir -p ~/git/$GROUP
chown --recursive $USER:$GROUP ~/git/$GROUP
chmod --recursive u=rwX,g=rwXs,o= ~/git/$GROUP
```

### Set Shackle as your default shell

The next step is to set the default shell of your user to Shackle. This will
mean that if you login as the user, for example over ssh, then the default shell
will be Shackle.

```sh
sudo usermod --shell $HOME/.cargo/bin/shackle-shell $USER
```

# Operating System Support

Currently, Shackle Shell only supports running on Linux.

It will likely work on other Unix-like platforms, such as MacOS, but this is not
currently tested, and there are currently no plans to do so. I would not expect
it to work on Windows.


# Development Guide

## Development Environment Setup

- Rust
  - This project is built using the Rust programming language, and its build
    tool Cargo. Information on how to install these tools is available on [the
    Rust website](https://www.rust-lang.org/learn/get-started).
- C Compiler
  - This is used to built one of the dependencies, libgit2. This can be
    obtained from your operating system's package manager.
- Docker
  - Some of the tests use Docker to create a simulated environment. This can be
    obtained from your operating system's package manager, or the [Docker
    website](https://www.docker.com/).
  - Docker must be installed, with the `docker` executable on the path.
  - Your user must have permission to use docker, including building and running
    Docker containers.
- Git
  - Some of the tests use Git to test the end to end functionality of the
    shell. This can be obtained from your operating system's package manager, or
    the [Git website](https://git-scm.com/).
  - Git must be installed, with the `git` executable on the path.
- SSH
  - Some of the tests use an SSH client to test the end to end functionality of
    the shell. I have tested this with OpenSSH, which can be obtained from your
    operating system's package manager, or the [Git website](https://git-scm.com/).
  - with the `ssh` executable on the path.

If you're running Arch Linux, these are the steps you'll need to get your
environment ready.

```sh
sudo pacman -S rustup docker git openssh gcc

# Rust
rustup default stable

# Docker
sudo usermod -a -G docker $USER
sudo systemctl start docker.service

# Note: you need to log out and in again for the new group to take effect
```

## Running Tests

All unit tests are run with Cargo.

```sh
cargo test
```

## Linting

Clippy should be used for linting. This can be installed using Rustup.

```sh
rustup component add clippy
```

And it can be run via Cargo.

```sh
cargo clippy
```

## Building a Release Binary

Release binaries should be built in release mode.

```sh
cargo build --release
```

After running this, the binary is available in `./target/release/shackle-shell`


# Roadmap

## Post-MVP

- [ ] project website
- [ ] functions correctly when the git path isn't created with correct
      permissions yet
- [ ] git archive with git upload-archive
- [ ] git config management around protected branches
- [ ] move a repo to a different group
- [ ] housekeeping git tasks (git fsck, git gc)
- [ ] pijul fetch and pijul push
- [ ] pijul support on other commands


# Support

If you get value from this project, consider supporting me on [Patreon](https://www.patreon.com/worthe_it). Support
via Patreon helps to cover hosting, buying computer stuff, and will allow me to
spend more time writing articles and open source software.

# License

Licensed under [MIT License](./LICENSE).