git_wit 0.0.3 → 0.0.4.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +105 -157
- data/app/controllers/git_wit/git_controller.rb +37 -23
- data/bin/git_wit +4 -0
- data/config/routes.rb +2 -2
- data/lib/generators/git_wit/install/install_generator.rb +42 -11
- data/lib/generators/git_wit/{templates → install/templates}/README +0 -0
- data/lib/generators/git_wit/{templates → install/templates}/git_wit.rb +21 -11
- data/lib/generators/git_wit/ssh_user/USAGE +11 -0
- data/lib/generators/git_wit/ssh_user/ssh_user_generator.rb +53 -0
- data/lib/generators/git_wit/ssh_user/templates/bashrc.tt +7 -0
- data/lib/generators/git_wit/ssh_user/templates/sudoers.tt +12 -0
- data/lib/git_wit.rb +19 -4
- data/lib/git_wit/actions.rb +17 -0
- data/lib/git_wit/actions/dscl.rb +15 -0
- data/lib/git_wit/actions/dscl/base.rb +75 -0
- data/lib/git_wit/actions/dscl/group.rb +20 -0
- data/lib/git_wit/actions/dscl/group_membership.rb +30 -0
- data/lib/git_wit/actions/dscl/user.rb +39 -0
- data/lib/git_wit/actions/ssh.rb +11 -0
- data/lib/git_wit/actions/ssh/home.rb +55 -0
- data/lib/git_wit/actions/ssh/sudoers.rb +94 -0
- data/lib/git_wit/auth.rb +2 -2
- data/lib/git_wit/authorized_keys.rb +45 -88
- data/lib/git_wit/authorized_keys/file.rb +61 -0
- data/lib/git_wit/authorized_keys/key.rb +15 -0
- data/lib/git_wit/cli.rb +19 -0
- data/lib/git_wit/commands/debug.rb +21 -0
- data/lib/git_wit/commands/git_shell.rb +48 -0
- data/lib/git_wit/commands/util.rb +37 -0
- data/lib/git_wit/errors.rb +1 -0
- data/lib/git_wit/version.rb +2 -1
- data/lib/tasks/git_wit.rake +46 -0
- data/test/dummy/bin/coderay +16 -0
- data/test/dummy/bin/erubis +16 -0
- data/test/dummy/bin/git_wit +16 -0
- data/test/dummy/bin/htmldiff +16 -0
- data/test/dummy/bin/ldiff +16 -0
- data/test/dummy/bin/posix-spawn-benchmark +16 -0
- data/test/dummy/bin/pry +16 -0
- data/test/dummy/bin/rackup +16 -0
- data/test/dummy/bin/rails +16 -0
- data/test/dummy/bin/rake +16 -0
- data/test/dummy/bin/rake2thor +16 -0
- data/test/dummy/bin/rdoc +16 -0
- data/test/dummy/bin/ri +16 -0
- data/test/dummy/bin/sprockets +16 -0
- data/test/dummy/bin/thor +16 -0
- data/test/dummy/bin/tilt +16 -0
- data/test/dummy/bin/tt +16 -0
- data/test/dummy/bin/tunnels +16 -0
- data/test/dummy/config/initializers/git_wit.rb +33 -24
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +1639 -5391
- data/test/dummy/log/test.log +108 -2
- data/test/dummy/tmp/pids/server.pid +1 -0
- data/test/unit/auth_test.rb +10 -6
- data/test/unit/authorized_keys_test.rb +5 -5
- data/test/unit/config_test.rb +15 -11
- data/test/unit/shell_test.rb +5 -5
- metadata +84 -278
- data/bin/gw-shell +0 -4
- data/lib/tasks/git_wit_shell.rake +0 -8
- data/test/dummy/tmp/cache/assets/C7E/BC0/sprockets%2Fb7118f368364962573a44054bcfb80d0 +0 -0
- data/test/dummy/tmp/cache/assets/C80/840/sprockets%2F562c2d168da585f80579347d10790a0a +0 -0
- data/test/dummy/tmp/cache/assets/C8C/B80/sprockets%2F371bf96e99717688ed7313a0c53f4212 +0 -0
- data/test/dummy/tmp/cache/assets/C9C/700/sprockets%2Fc7b1373dbf219a8722efc21160641340 +0 -0
- data/test/dummy/tmp/cache/assets/C9E/5F0/sprockets%2F2bca2b107bb6c26b720d135270688918 +0 -0
- data/test/dummy/tmp/cache/assets/CA9/9C0/sprockets%2F0c1b7ebd087418498ea6037225d33d25 +0 -0
- data/test/dummy/tmp/cache/assets/CC8/B00/sprockets%2F9815364bfd49ed907870e270d75a995a +0 -0
- data/test/dummy/tmp/cache/assets/CD1/800/sprockets%2Fc044b140dcef533c52712c7b51e21996 +0 -0
- data/test/dummy/tmp/cache/assets/CD5/2C0/sprockets%2F166c056119ebdfb8b7104c97b424b423 +0 -0
- data/test/dummy/tmp/cache/assets/CD7/380/sprockets%2F4079ce1dbbcf4a599527303670006b6b +0 -0
- data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/CE0/CC0/sprockets%2F2b38c3fb549036de5c4666637a0c80c6 +0 -0
- data/test/dummy/tmp/cache/assets/CEC/B70/sprockets%2F7f98753ca8c35e4249363a04389b3caf +0 -0
- data/test/dummy/tmp/cache/assets/CF0/1D0/sprockets%2F6fc757c2c8329244ca95d6909865bbc2 +0 -0
- data/test/dummy/tmp/cache/assets/CF9/980/sprockets%2Fbd55042e1acd32eb611041444d794d4d +0 -0
- data/test/dummy/tmp/cache/assets/CFD/560/sprockets%2Fe4e7fe4ee089382325686f806b939d3e +0 -0
- data/test/dummy/tmp/cache/assets/D00/B90/sprockets%2F07c00c80f1ea62d95a01f11f9c728b72 +0 -0
- data/test/dummy/tmp/cache/assets/D0D/9A0/sprockets%2F1fce44192cdb30f44b7545a37c9891b2 +0 -0
- data/test/dummy/tmp/cache/assets/D0F/390/sprockets%2F9df081609c3449ab40c93b1cf07de357 +0 -0
- data/test/dummy/tmp/cache/assets/D25/A60/sprockets%2F0e036061ad22b2e6dce1639b234cf15c +0 -0
- data/test/dummy/tmp/cache/assets/D27/DB0/sprockets%2Fa3a0a778855bce9fa47913d389ea9884 +0 -0
- data/test/dummy/tmp/cache/assets/D29/5A0/sprockets%2Fdad9e81b43ca12671246ee52a1900d0c +0 -0
- data/test/dummy/tmp/cache/assets/D2E/FF0/sprockets%2Fc06112642c994b6b7c2ba6632fad1fd0 +0 -0
- data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/D36/120/sprockets%2Feac54bd3c540af6b964d025e345227d6 +0 -0
- data/test/dummy/tmp/cache/assets/D3E/240/sprockets%2F84b96d6b2d2653cb4127b06d8acb990d +0 -0
- data/test/dummy/tmp/cache/assets/D3F/830/sprockets%2F18578d4ef3abd6e12d836841dd6b8a00 +0 -0
- data/test/dummy/tmp/cache/assets/D4B/E70/sprockets%2F0909bc70e589d40a6cd90dfe6f18257e +0 -0
- data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/D57/3D0/sprockets%2F7bbccc5129a5013b70831ec9ad62ab24 +0 -0
- data/test/dummy/tmp/cache/assets/D5A/000/sprockets%2F7d4f67f146b6d7904dfc4edd9135f588 +0 -0
- data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/D5B/BB0/sprockets%2Fba769276c4de14151bc4202cba7f3ad3 +0 -0
- data/test/dummy/tmp/cache/assets/D5E/BC0/sprockets%2F2d96fa667066778db858d7b7cb0fce69 +0 -0
- data/test/dummy/tmp/cache/assets/D6E/BA0/sprockets%2F5178d3788fe35a52acb5f3bd22ea078a +0 -0
- data/test/dummy/tmp/cache/assets/D6F/C20/sprockets%2F22e783a8f5f9224f01e8e62fab6afb40 +0 -0
- data/test/dummy/tmp/cache/assets/D76/5C0/sprockets%2Fd8a5669df31f129f355283e6dab4c5ad +0 -0
- data/test/dummy/tmp/cache/assets/D79/DE0/sprockets%2F7cfd335e68d881b03f6b7f1bd91f270f +0 -0
- data/test/dummy/tmp/cache/assets/D8A/CA0/sprockets%2F656af8b87ad378e8e4f2ec94b6b5c719 +0 -0
- data/test/dummy/tmp/cache/assets/D8C/620/sprockets%2Ff37f8e5b8cccd9880276a9f5157d4c7e +0 -0
- data/test/dummy/tmp/cache/assets/D92/200/sprockets%2Fb816d858281027bdd3fe2bfac43b4ca1 +0 -0
- data/test/dummy/tmp/cache/assets/D92/CE0/sprockets%2Ffca6a13676a2be09234905f9acae22cd +0 -0
- data/test/dummy/tmp/cache/assets/D96/9E0/sprockets%2F6fabecd33f7a5a087f4fb6a2d6312443 +0 -0
- data/test/dummy/tmp/cache/assets/DA2/D20/sprockets%2Ff5faf079fb660bde5bc9502bde442088 +0 -0
- data/test/dummy/tmp/cache/assets/DA5/570/sprockets%2F3517de599b6fd005bc5d5d69ba5ff1e2 +0 -0
- data/test/dummy/tmp/cache/assets/DA7/070/sprockets%2F69eadf8c3a94b04fe0b4992ee4a8c821 +0 -0
- data/test/dummy/tmp/cache/assets/DBA/BF0/sprockets%2Fe63ea1d7bfb0ee50380debe42360a3b5 +0 -0
- data/test/dummy/tmp/cache/assets/DBB/3B0/sprockets%2F6a0aaa6c5b0d10b936e237a7ecb4e4c9 +0 -0
- data/test/dummy/tmp/cache/assets/DBC/8E0/sprockets%2F908976cfbcdf6ad4c59737bf3c78e1e8 +0 -0
- data/test/dummy/tmp/cache/assets/DD3/FD0/sprockets%2Febf97c76a9ba2a889dd01be2caa75806 +0 -0
- data/test/dummy/tmp/cache/assets/DD8/410/sprockets%2Fc02eeb7ea977fd713cc19ca93d838af4 +0 -0
- data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/DEA/E40/sprockets%2F4166d7d00d1e72fed2004debed2bea3e +0 -0
- data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/E05/C70/sprockets%2Fccd814ec859d582ada46e271edfe7ae1 +0 -0
- data/test/dummy/tmp/cache/assets/E0C/2A0/sprockets%2F37c59fadd9a21cab7d05d78a7dfe7e85 +0 -0
- data/test/dummy/tmp/cache/assets/E28/130/sprockets%2F6f332ca43b7ed658d90b8ba5daaa5ded +0 -0
- data/test/dummy/tmp/cache/assets/E3B/080/sprockets%2F09e2a090befacdae0db10cafb1893a0a +0 -0
- data/test/dummy/tmp/cache/assets/E65/CD0/sprockets%2F93cdf3fec0e3aa6deefa955c6828fbd0 +0 -0
- data/test/dummy/tmp/cache/assets/E9F/450/sprockets%2Fbbfdc5edaaf25dfdb5ee8f9db7895435 +0 -0
- data/test/dummy/tmp/git/fuck.git/HEAD +0 -1
- data/test/dummy/tmp/git/fuck.git/config +0 -6
- data/test/dummy/tmp/git/fuck.git/description +0 -1
- data/test/dummy/tmp/git/fuck.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/fuck.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/fuck.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/fuck.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/fuck.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/fuck.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/fuck.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/fuck.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/fuck.git/info/exclude +0 -6
- data/test/dummy/tmp/git/lkasdjf.git/HEAD +0 -1
- data/test/dummy/tmp/git/lkasdjf.git/config +0 -6
- data/test/dummy/tmp/git/lkasdjf.git/description +0 -1
- data/test/dummy/tmp/git/lkasdjf.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/lkasdjf.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/lkasdjf.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/lkasdjf.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/lkasdjf.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/lkasdjf.git/info/exclude +0 -6
- data/test/dummy/tmp/git/new/test.git/HEAD +0 -1
- data/test/dummy/tmp/git/new/test.git/config +0 -6
- data/test/dummy/tmp/git/new/test.git/description +0 -1
- data/test/dummy/tmp/git/new/test.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/new/test.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/new/test.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/new/test.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/new/test.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/new/test.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/new/test.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/new/test.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/new/test.git/info/exclude +0 -6
- data/test/dummy/tmp/git/testing.git/HEAD +0 -1
- data/test/dummy/tmp/git/testing.git/config +0 -6
- data/test/dummy/tmp/git/testing.git/description +0 -1
- data/test/dummy/tmp/git/testing.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/testing.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/testing.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/testing.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/testing.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/testing.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/testing.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/testing.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/testing.git/info/exclude +0 -6
- data/test/dummy/tmp/git/under_scored/sub.git/HEAD +0 -1
- data/test/dummy/tmp/git/under_scored/sub.git/config +0 -6
- data/test/dummy/tmp/git/under_scored/sub.git/description +0 -1
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/under_scored/sub.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/under_scored/sub.git/info/exclude +0 -6
- data/test/dummy/tmp/git/work/pls/thnx.git/HEAD +0 -1
- data/test/dummy/tmp/git/work/pls/thnx.git/config +0 -6
- data/test/dummy/tmp/git/work/pls/thnx.git/description +0 -1
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/applypatch-msg.sample +0 -15
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/commit-msg.sample +0 -24
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/post-update.sample +0 -8
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-applypatch.sample +0 -14
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-commit.sample +0 -50
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-rebase.sample +0 -169
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/prepare-commit-msg.sample +0 -36
- data/test/dummy/tmp/git/work/pls/thnx.git/hooks/update.sample +0 -128
- data/test/dummy/tmp/git/work/pls/thnx.git/info/exclude +0 -6
data/README.md
CHANGED
|
@@ -5,99 +5,132 @@
|
|
|
5
5
|
|
|
6
6
|
Dead simple Git hosting for Rails apps.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Crash Course
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
Start hosting git repositories in seconds. Create a new Rails app and
|
|
11
|
+
install GitWit:
|
|
12
12
|
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
gem "git_wit"
|
|
13
|
+
```console
|
|
14
|
+
$ rails new example --skip-bundle; cd example # New Rails app
|
|
15
|
+
$ echo 'gem "git_wit"' >> Gemfile; bundle # Install git_wit gem
|
|
16
|
+
$ rails g git_wit:install insecure_auth insecure_write authenticate authorize_read authorize_write
|
|
17
|
+
$ rails s -d # <- Start Rails server # ^- Install/config GitWit
|
|
18
|
+
```
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
That's it - your app is hosting git repositories. Create a repositories folder,
|
|
21
|
+
init a bare repo, and push to it:
|
|
22
|
+
|
|
23
|
+
```console
|
|
24
|
+
$ git init
|
|
25
|
+
$ git add .
|
|
26
|
+
$ git commit -m "That was easy"
|
|
27
|
+
$ mkdir repositories # Hosted repos folder
|
|
28
|
+
$ git init --bare repositories/example.git # Example bare repo
|
|
29
|
+
$ git remote add origin http://localhost:3000/example.git
|
|
30
|
+
$ git push origin master # Push example app to itself to store in itself!
|
|
19
31
|
```
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
[`config/initializers/git_wit.rb`](https://github.com/xdissent/git_wit/blob/master/lib/generators/git_wit/templates/git_wit.rb).
|
|
23
|
-
You'll want to first change `config.repositories_path` to a folder where you'd
|
|
24
|
-
like to store your repositories. Let's use "tmp/repositories" in our app root
|
|
25
|
-
for fun:
|
|
33
|
+
HTTPS? That works too:
|
|
26
34
|
|
|
27
|
-
```
|
|
28
|
-
|
|
35
|
+
```console
|
|
36
|
+
$ sudo echo "pre-loading sudo so we can background tunnels in a moment"
|
|
37
|
+
$ rails g git_wit:install authenticate authorize_read authorize_write -f
|
|
38
|
+
$ gem install tunnels
|
|
39
|
+
$ sudo tunnels 443 3000 & # or `rvmsudo tunnels...` if using RVM
|
|
40
|
+
$ git remote add https https://localhost/example.git
|
|
41
|
+
$ GIT_SSL_NO_VERIFY=1 git push https master:https-master # Trust yourself
|
|
29
42
|
```
|
|
30
43
|
|
|
31
|
-
|
|
32
|
-
credentials over an insecure protocol like HTTP, because they'll be sent in
|
|
33
|
-
plain text over the wire. And since anonymous write access is always disallowed,
|
|
34
|
-
that means you can't safely push over HTTP without SSL. To disable these
|
|
35
|
-
protections, something you'd **never** do in a production environment, change
|
|
36
|
-
the following config values in the initializer:
|
|
44
|
+
Still not impressed? Try SSH (OS X only currently):
|
|
37
45
|
|
|
46
|
+
```console
|
|
47
|
+
$ rails g git_wit:install authenticate authorize_read authorize_write ssh_user:git_wit -f
|
|
48
|
+
$ rails g git_wit:ssh_user # Creates/configs git_wit SSH user
|
|
49
|
+
$ rake git_wit:ssh:add_key # Grant access for ~/.ssh/id_rsa.pub
|
|
50
|
+
$ git remote add ssh git_wit@localhost:example.git
|
|
51
|
+
$ git push ssh master:ssh-master
|
|
38
52
|
```
|
|
53
|
+
|
|
54
|
+
You might want to get rid of that system user you just created:
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
$ rails d git_wit:ssh_user
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Overview
|
|
62
|
+
|
|
63
|
+
GitWit adds git hosting abilities to any Rails app. It provides configurable
|
|
64
|
+
authentication and authorization methods that can be integrated with any
|
|
65
|
+
user/repository access model you'd like. All configuration is handled through a
|
|
66
|
+
single initializer,
|
|
67
|
+
[`config/initializers/git_wit.rb`](https://github.com/xdissent/git_wit/blob/master/lib/generators/git_wit/templates/git_wit.rb).
|
|
68
|
+
Run `rails g git_wit:install` to generate a default configuration for
|
|
69
|
+
modification. All configuration details are contained within comments inside
|
|
70
|
+
the initializer, or read on for the highlights.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## Authentication
|
|
74
|
+
|
|
75
|
+
Normally GitWit prevents the user from sending authentication credentials in
|
|
76
|
+
plaintext (via HTTP without SSL). To disable these protections, something you'd
|
|
77
|
+
**never** do in a production environment, change the following config values
|
|
78
|
+
in the initializer:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
39
81
|
config.insecure_auth = true
|
|
40
82
|
config.insecure_write = true
|
|
41
83
|
```
|
|
42
84
|
|
|
43
|
-
|
|
85
|
+
Authentication is handled by the `config.authenticate` attribute. A valid
|
|
86
|
+
authenticator is any callable that accepts a user model instance and a
|
|
87
|
+
clear-text password. The authenticator should return a boolean response
|
|
88
|
+
indicating whether the user is authenticated for the given password. To allow
|
|
89
|
+
any user as long as the password matches the username:
|
|
44
90
|
|
|
45
91
|
```ruby
|
|
46
92
|
config.authenticate = ->(user, password) do
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
config.authorize_read = ->(user, repository) do
|
|
51
|
-
%w(reader writer).include?(user)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
config.authorize_write = ->(user, repository) do
|
|
55
|
-
user == "writer"
|
|
93
|
+
user == password
|
|
56
94
|
end
|
|
57
95
|
```
|
|
58
96
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Now your app is ready to start serving git repos over HTTP. Just create the
|
|
64
|
-
repositories folder, initialize a repo and start the server:
|
|
97
|
+
The user model is simply the username as a string by default. Before passing
|
|
98
|
+
the user to the authenticator, GitWit will call `config.user_for_authenication`,
|
|
99
|
+
passing it the username and expecting a new user model instance in return. For
|
|
100
|
+
example:
|
|
65
101
|
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
102
|
+
```ruby
|
|
103
|
+
config.user_for_authentication = ->(username) do
|
|
104
|
+
User.active.find_by_login username: username
|
|
105
|
+
end
|
|
70
106
|
```
|
|
71
107
|
|
|
72
|
-
|
|
108
|
+
Now the `config.authenticate` authenticator will recieve the `User` instance:
|
|
73
109
|
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
$ git add README
|
|
79
|
-
$ git commit -m "First"
|
|
80
|
-
$ git push origin master
|
|
110
|
+
```ruby
|
|
111
|
+
config.authenticate = ->(user, password) do
|
|
112
|
+
user.valid_password? password # user is a User
|
|
113
|
+
end
|
|
81
114
|
```
|
|
82
115
|
|
|
83
|
-
Your server will ask you for a username and password when you push - use
|
|
84
|
-
`writer` for both and it should accept your changes.
|
|
85
116
|
|
|
117
|
+
## Authorization
|
|
86
118
|
|
|
87
|
-
|
|
119
|
+
Two configuration attributes are responsible for authorization:
|
|
120
|
+
`config.authorize_read` and `config.authorize_write`. They're passed the user
|
|
121
|
+
instance (already authenticated) and the repository path as a string. The
|
|
122
|
+
repository path is relative to `config.repositories_path`
|
|
123
|
+
(`<app root>/repositories` by default). The authorizers should return a boolean
|
|
124
|
+
to grant or deny access accordingly. A simple example:
|
|
88
125
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
[tunnels](https://github.com/jugyo/tunnels) gem to run your app with SSL in
|
|
94
|
-
development. Just add it to the Gemfile and run `bundle install` followed by
|
|
95
|
-
`sudo tunnels` (or `rvmsudo tunnels` for RVM). For `rails s`, which runs on
|
|
96
|
-
port 3000 by default, run `sudo tunnels 443 3000`. Now you may clone
|
|
97
|
-
repositories over HTTPS:
|
|
126
|
+
```ruby
|
|
127
|
+
config.authorize_read = ->(user, repository) do
|
|
128
|
+
%w(reader writer).include?(user)
|
|
129
|
+
end
|
|
98
130
|
|
|
99
|
-
|
|
100
|
-
|
|
131
|
+
config.authorize_write = ->(user, repository) do
|
|
132
|
+
user == "writer"
|
|
133
|
+
end
|
|
101
134
|
```
|
|
102
135
|
|
|
103
136
|
|
|
@@ -133,110 +166,25 @@ authenticating, the SSH user will `sudo` to the application user to continue
|
|
|
133
166
|
with the git operation. This eliminates the need for all the bat-shit crazy git
|
|
134
167
|
pulls/pushes and SSH wrappers and crap that are typical of gitolite/gitosis
|
|
135
168
|
setups. Your application user owns everything except the `authorized_keys` file
|
|
136
|
-
and the `ssh_user` only needs to know how to call the `
|
|
169
|
+
and the `ssh_user` only needs to know how to call the `git_wit git-shell`
|
|
170
|
+
command.
|
|
137
171
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```console
|
|
141
|
-
$ sudo dscl . -create /Groups/gitwit
|
|
142
|
-
$ sudo dscl . -create /Groups/gitwit PrimaryGroupID 333
|
|
143
|
-
$ sudo dscl . -create /Groups/gitwit RealName "GitWit Server"
|
|
144
|
-
$ sudo dscl . -create /Users/gitwit UniqueID 333
|
|
145
|
-
$ sudo dscl . -create /Users/gitwit PrimaryGroupID 333
|
|
146
|
-
$ sudo dscl . -create /Users/gitwit NFSHomeDirectory /var/gitwit
|
|
147
|
-
$ sudo dscl . -create /Users/gitwit UserShell /bin/bash
|
|
148
|
-
$ sudo dscl . -create /Users/gitwit RealName "GitWit Server"
|
|
149
|
-
$ sudo mkdir -p ~gitwit
|
|
150
|
-
$ sudo chown -R gitwit:gitwit ~gitwit
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Enable the `ssh_user` config value in `config/initializers/git_wit.rb`:
|
|
172
|
+
GitWit comes with an initializer to set everything up for you. First, enable the
|
|
173
|
+
`ssh_user` config in `config/initializers/git_wit.rb`:
|
|
154
174
|
|
|
155
175
|
```ruby
|
|
156
|
-
config.ssh_user = "
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Now your application user needs to be allowed to `sudo` as `ssh_user` and vice
|
|
160
|
-
versa. Edit `/etc/sudoers` using `sudo visudo` and add the following lines:
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
rails_user ALL=(gitwit) NOPASSWD:ALL
|
|
164
|
-
gitwit ALL=(rails_user) NOPASSWD:ALL
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Replace `rails_user` with the application under which your Rails app runs, which
|
|
168
|
-
will be your personal username if using `rails s` or Pow.
|
|
169
|
-
|
|
170
|
-
Test your `sudo` rights and initialize the `ssh_user` environment:
|
|
171
|
-
|
|
172
|
-
```console
|
|
173
|
-
$ sudo -u gitwit -i
|
|
174
|
-
$ mkdir .ssh
|
|
175
|
-
$ chmod 700 .ssh
|
|
176
|
-
$ touch .ssh/authorized_keys
|
|
177
|
-
$ chmod 600 .ssh/authorized_keys
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
If you're using RVM or some other wacky environment manipulating tool, you're
|
|
181
|
-
going to want to adjust the login environment for `ssh_user` by creating a
|
|
182
|
-
`~ssh_user/.bashrc` file. For example, to load a specific RVM gemset:
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
source "/Users/xdissent/.rvm/environments/ruby-1.9.3-p385@git_wit"
|
|
176
|
+
config.ssh_user = "git_wit"
|
|
186
177
|
```
|
|
187
178
|
|
|
188
|
-
|
|
189
|
-
executable. If you're using `bundle --binstubs` for example:
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
export PATH="/path/to/app/bin:$PATH"
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
The `gw-shell` command handles the authentication and authorization for the SSH
|
|
196
|
-
protocol. It is initially called by `ssh_user` upon login (git operation) and it
|
|
197
|
-
will attempt to `sudo` to the application user and re-run itself with the same
|
|
198
|
-
environment. It determines which user is the "application user" by looking at
|
|
199
|
-
who owns the rails app root folder. To determine where the app root is actually
|
|
200
|
-
located, it looks for the ENV variables `RAILS_ROOT` and `BUNDLE_GEMFILE` in
|
|
201
|
-
order. When in doubt, set `RAILS_ROOT` in `~ssh_user/.bashrc`:
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
export RAILS_ROOT="/path/to/app"
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**Remember to add `export RAILS_ENV="production"` for production deployments!**
|
|
208
|
-
|
|
209
|
-
You can easily sanity check your environment using `sudo` as your app user:
|
|
179
|
+
Now run the initializer:
|
|
210
180
|
|
|
211
181
|
```console
|
|
212
|
-
$
|
|
213
|
-
$ source .bashrc
|
|
214
|
-
$ which gw-shell
|
|
215
|
-
/Users/xdissent/Code/git_wit/stubs/gw-shell
|
|
216
|
-
$ echo $RAILS_ROOT
|
|
217
|
-
/Users/xdissent/Code/git_wit/test/dummy
|
|
182
|
+
$ rails g git_wit:ssh_user
|
|
218
183
|
```
|
|
219
184
|
|
|
220
|
-
|
|
221
|
-
This can be done from the rails console (`rails c`):
|
|
222
|
-
|
|
223
|
-
```ruby
|
|
224
|
-
GitWit.add_authorized_key "writer", "ssh-rsa long-ass-key-string writer@example.com"
|
|
225
|
-
# => nil
|
|
226
|
-
GitWit.authorized_keys_file.keys
|
|
227
|
-
# => [command="gw-shell writer",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa long-ass-key-string writer@example.com]
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
You may now clone/push/pull over SSH - assuming the key you installed for
|
|
231
|
-
`writer` is known to your ssh agent (ie `~/.ssh/id_rsa`):
|
|
232
|
-
|
|
233
|
-
```console
|
|
234
|
-
$ git clone gitwit@localhost:example.git
|
|
235
|
-
```
|
|
185
|
+
To add a public key: `rake git_wit:ssh:add_key`
|
|
236
186
|
|
|
237
|
-
|
|
238
|
-
[`test/dummy`](https://github.com/xdissent/git_wit/tree/master/test/dummy) for
|
|
239
|
-
a more advanced example of `authorized_keys` management.
|
|
187
|
+
Something not working? `rake git_wit:ssh:debug`
|
|
240
188
|
|
|
241
189
|
|
|
242
190
|
## Git hooks and configs and umasks and everything
|
|
@@ -11,38 +11,50 @@ module GitWit
|
|
|
11
11
|
|
|
12
12
|
def service
|
|
13
13
|
# Shell out to git-http-backend.
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
self.status, self.headers, self.response_body = run_shell
|
|
15
|
+
end
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
private
|
|
18
|
+
def run_shell
|
|
19
|
+
out, err, status = Open3.capture3 shell_env, shell_command, shell_opts
|
|
18
20
|
raise GitError, err unless status.success?
|
|
21
|
+
parse_cgi_response out
|
|
22
|
+
end
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
def parse_cgi_response(cgi_response)
|
|
25
|
+
cgi_headers, body = cgi_response.split("\r\n\r\n", 2)
|
|
26
|
+
headers = parse_cgi_headers(cgi_headers)
|
|
27
|
+
[parse_cgi_status(headers), headers, body]
|
|
28
|
+
end
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
def parse_cgi_headers(cgi_headers)
|
|
31
|
+
Hash[cgi_headers.split("\r\n").map { |l| l.split(/\s*\:\s*/, 2) }]
|
|
32
|
+
end
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
def parse_cgi_status(cgi_headers)
|
|
35
|
+
cgi_headers.key?("Status") ? cgi_headers.delete("Status").to_i : 200
|
|
31
36
|
end
|
|
32
37
|
|
|
33
|
-
private
|
|
34
38
|
def shell_env
|
|
35
39
|
request.headers.dup.extract!(*ENV_KEEPERS).merge(http_env).merge(git_env)
|
|
36
40
|
end
|
|
37
41
|
|
|
42
|
+
def shell_command
|
|
43
|
+
[GitWit.git_path, "http-backend"].join " "
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def shell_opts
|
|
47
|
+
{stdin_data: request.raw_post, binmode: true}
|
|
48
|
+
end
|
|
49
|
+
|
|
38
50
|
def git_env
|
|
39
51
|
{
|
|
40
52
|
GIT_HTTP_EXPORT_ALL: "uknoit",
|
|
41
53
|
GIT_PROJECT_ROOT: GitWit.repositories_path,
|
|
42
54
|
PATH_INFO: "/#{params[:repository]}/#{params[:refs] || params[:service]}",
|
|
43
55
|
REMOTE_USER: (user_attr(:username) || @username),
|
|
44
|
-
GIT_COMMITTER_NAME: user_attr(:
|
|
45
|
-
GIT_COMMITTER_EMAIL: user_attr(:
|
|
56
|
+
GIT_COMMITTER_NAME: user_attr(:name),
|
|
57
|
+
GIT_COMMITTER_EMAIL: user_attr(:email)
|
|
46
58
|
}.reject { |_, v| v.nil? }.stringify_keys
|
|
47
59
|
end
|
|
48
60
|
|
|
@@ -63,7 +75,7 @@ module GitWit
|
|
|
63
75
|
end
|
|
64
76
|
|
|
65
77
|
# Request credentials again if provided and no user was authenticated.
|
|
66
|
-
if
|
|
78
|
+
if !@user.present? && request.authorization.present?
|
|
67
79
|
request_http_basic_authentication_if_allowed
|
|
68
80
|
end
|
|
69
81
|
end
|
|
@@ -79,7 +91,7 @@ module GitWit
|
|
|
79
91
|
|
|
80
92
|
def authorize_write
|
|
81
93
|
# Never allow anonymous write operations.
|
|
82
|
-
return request_http_basic_authentication_if_allowed
|
|
94
|
+
return request_http_basic_authentication_if_allowed unless @user.present?
|
|
83
95
|
|
|
84
96
|
# Disallow write operations over insecure protocol per configuration.
|
|
85
97
|
raise ForbiddenError if !GitWit.insecure_write && !request.ssl?
|
|
@@ -89,9 +101,9 @@ module GitWit
|
|
|
89
101
|
end
|
|
90
102
|
|
|
91
103
|
def authorize_read
|
|
92
|
-
return if GitWit.authorize_read(@user, params[:repository])
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
return true if GitWit.authorize_read(@user, params[:repository])
|
|
105
|
+
raise UnauthorizedError if @user.present?
|
|
106
|
+
request_http_basic_authentication_if_allowed
|
|
95
107
|
end
|
|
96
108
|
|
|
97
109
|
# TODO: Sure about this?
|
|
@@ -105,12 +117,14 @@ module GitWit
|
|
|
105
117
|
end
|
|
106
118
|
|
|
107
119
|
def user_attr(sym)
|
|
108
|
-
try_user GitWit.
|
|
120
|
+
try_user GitWit.send("#{sym}_attribute")
|
|
109
121
|
end
|
|
110
122
|
|
|
111
123
|
def try_user(sym_or_proc)
|
|
112
|
-
return @user
|
|
113
|
-
sym_or_proc.
|
|
124
|
+
return sym_or_proc.call(@user) if sym_or_proc.respond_to? :call
|
|
125
|
+
if sym_or_proc.is_a?(Symbol) && @user.respond_to?(sym_or_proc)
|
|
126
|
+
@user.try(sym_or_proc)
|
|
127
|
+
end
|
|
114
128
|
end
|
|
115
129
|
end
|
|
116
130
|
end
|
data/bin/git_wit
ADDED
data/config/routes.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
GitWit::Engine.routes.draw do
|
|
2
|
-
get ":repository/*refs"
|
|
3
|
-
post ":repository/:service"
|
|
2
|
+
get ":repository/*refs", to: "git#service", repository: /[\-\/\w\.]+\.git/
|
|
3
|
+
post ":repository/:service", to: "git#service", repository: /[\-\/\w\.]+\.git/,
|
|
4
4
|
service: /git-[\w\-]+/
|
|
5
5
|
end
|
|
@@ -1,15 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
module GitWit
|
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
template "git_wit.rb", "config/initializers/git_wit.rb"
|
|
6
|
-
end
|
|
5
|
+
argument :attributes, type: :array, default: [], banner: "config[:value] config[:value]"
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
def initialize(args, *options)
|
|
8
|
+
super
|
|
9
|
+
parse_attributes! if respond_to?(:attributes)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def copy_initializer
|
|
13
|
+
template "git_wit.rb", "config/initializers/git_wit.rb"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def show_readme
|
|
17
|
+
readme "README" if behavior == :invoke
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def mount_route
|
|
21
|
+
route 'mount GitWit::Engine => "/"'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
def parse_attributes!
|
|
26
|
+
attrs = (attributes || [])
|
|
27
|
+
self.attributes = Hash[attrs.map { |attr| parse_attribute(attr) }.compact]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parse_attribute(attr)
|
|
31
|
+
k, v = attr.split(":", 2)
|
|
32
|
+
v ||= true
|
|
33
|
+
v = false if v == "false"
|
|
34
|
+
[k.to_sym, v] if k.present?
|
|
35
|
+
end
|
|
11
36
|
|
|
12
|
-
|
|
13
|
-
|
|
37
|
+
def maybe_config(name, default)
|
|
38
|
+
given = attributes.key?(name)
|
|
39
|
+
value = given ? attributes[name] : default
|
|
40
|
+
value = %("#{value}") if value.is_a? String
|
|
41
|
+
value = ":#{value}" if value.is_a? Symbol
|
|
42
|
+
pre = given ? "" : "# "
|
|
43
|
+
"#{pre}config.#{name} = #{value}"
|
|
44
|
+
end
|
|
14
45
|
end
|
|
15
|
-
end
|
|
46
|
+
end
|