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
|
File without changes
|
|
@@ -4,41 +4,42 @@ GitWit.configure do |config|
|
|
|
4
4
|
# Configure the path to the repositories. This folder should be readable
|
|
5
5
|
# and writable by your application. Use an absolute path for best results.
|
|
6
6
|
# No trailing slash necessary.
|
|
7
|
-
|
|
7
|
+
<%= maybe_config :repositories_path, "/var/git" %>
|
|
8
8
|
|
|
9
9
|
# Configure the user for which to manage SSH keys (if enabled.) This user
|
|
10
10
|
# must be allowed to run gw-ssh (or bundle exec or rvm or whatever) via sudo
|
|
11
11
|
# as the application user.
|
|
12
|
-
|
|
12
|
+
<%= maybe_config :ssh_user, "git" %>
|
|
13
13
|
|
|
14
14
|
# Configure the absolute path to the authorized_keys file for ssh_user. By
|
|
15
15
|
# default, this will be calculated as "~ssh_user/.ssh/authorized_keys".
|
|
16
|
-
|
|
16
|
+
<%= maybe_config :authorized_keys_path, "/var/git/.ssh/authorized_keys" %>
|
|
17
17
|
|
|
18
|
-
# Configure the path to the git
|
|
19
|
-
#
|
|
18
|
+
# Configure the path to the git binary. Defaults to "git". Use a full path if
|
|
19
|
+
# the "git" command is not found in the PATH environment variable.
|
|
20
|
+
<%= maybe_config :git_path, "/path/to/bin/git" %>
|
|
20
21
|
|
|
21
22
|
# Configure the HTTP Basic Auth Realm. Go nuts.
|
|
22
|
-
|
|
23
|
+
<%= maybe_config :realm, "GitWit" %>
|
|
23
24
|
|
|
24
25
|
# Allow or disable write operations (push) via non-secure (http) protocols.
|
|
25
|
-
|
|
26
|
+
<%= maybe_config :insecure_write, false %>
|
|
26
27
|
|
|
27
28
|
# Allow or disable authentication via non-secure (http) protocols. GitWit uses
|
|
28
29
|
# HTTP Basic authentication, which sends your password in cleartext. This is
|
|
29
30
|
# bad behaviour so the default is to completely disallow authentication
|
|
30
31
|
# without SSL. Note that this will effectively disable insecure write
|
|
31
32
|
# operations as well when set to false, since writes require authentication.
|
|
32
|
-
|
|
33
|
+
<%= maybe_config :insecure_auth, false %>
|
|
33
34
|
|
|
34
35
|
# Configure git user attributes. GitWit will "try" these attributes when
|
|
35
36
|
# discerning the user information to pass to git. These may be callables that
|
|
36
37
|
# accept the user model (if authenticated) and should return a string value.
|
|
37
38
|
# If nil (or return nil), reasonable defaults will be used.
|
|
38
39
|
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
<%= maybe_config :username_attribute, :login %>
|
|
41
|
+
<%= maybe_config :email_attribute, :email %>
|
|
42
|
+
<%= maybe_config :name_attribute, :name %>
|
|
42
43
|
|
|
43
44
|
# Customize how the user is derived from the username. Below is an example for
|
|
44
45
|
# devise. Your callable should accept a username return a user model. A string
|
|
@@ -60,6 +61,9 @@ GitWit.configure do |config|
|
|
|
60
61
|
# config.authenticate = ->(user, password) do
|
|
61
62
|
# user.try :valid_password, password
|
|
62
63
|
# end
|
|
64
|
+
<% if attributes[:authenticate] -%>
|
|
65
|
+
config.authenticate = true
|
|
66
|
+
<% end -%>
|
|
63
67
|
|
|
64
68
|
# Customize the authorization handlers. There are two - one for read and one
|
|
65
69
|
# for write operations. They will receive the user model (if authenticated)
|
|
@@ -70,9 +74,15 @@ GitWit.configure do |config|
|
|
|
70
74
|
# repo = Repository.find_by_path repository
|
|
71
75
|
# repo.public? || repo.user_id = user.id
|
|
72
76
|
# end
|
|
77
|
+
<% if attributes[:authorize_read] -%>
|
|
78
|
+
config.authorize_read = true
|
|
79
|
+
<% end -%>
|
|
73
80
|
#
|
|
74
81
|
# config.authorize_write = ->(user, repository) do
|
|
75
82
|
# repo = Repository.find_by_path repository
|
|
76
83
|
# repo.user_id = user.id || user.admin?
|
|
77
84
|
# end
|
|
85
|
+
<% if attributes[:authorize_write] -%>
|
|
86
|
+
config.authorize_write = true
|
|
87
|
+
<% end -%>
|
|
78
88
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "git_wit/actions"
|
|
2
|
+
|
|
3
|
+
module GitWit
|
|
4
|
+
class SshUserGenerator < Rails::Generators::Base
|
|
5
|
+
include GitWit::Actions
|
|
6
|
+
|
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
8
|
+
|
|
9
|
+
argument :home, type: :string, required: false
|
|
10
|
+
|
|
11
|
+
def check_user
|
|
12
|
+
raise Thor::Error, "GitWit ssh_user is not configured." unless ssh_user.present?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_user
|
|
16
|
+
@home = dscl_user ssh_user, home
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create_group
|
|
20
|
+
dscl_group ssh_group
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def add_user_to_group
|
|
24
|
+
dscl_group_membership ssh_user, ssh_group
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build_home
|
|
28
|
+
ssh_home ssh_user, home
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add_user_to_sudoers
|
|
32
|
+
ssh_sudoers ssh_user
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
protected
|
|
36
|
+
def ssh_user
|
|
37
|
+
GitWit.ssh_user
|
|
38
|
+
end
|
|
39
|
+
alias_method :ssh_group, :ssh_user
|
|
40
|
+
|
|
41
|
+
def rails_user
|
|
42
|
+
@rails_user ||= `whoami`.strip
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def git_wit_bindir
|
|
46
|
+
bin_path = Rails.root.join("bin", "git_wit")
|
|
47
|
+
return bin_path.dirname.to_s if bin_path.exist?
|
|
48
|
+
bin_path = `which git_wit`.strip
|
|
49
|
+
return File.dirname(bin_path) if bin_path.present?
|
|
50
|
+
raise Thor::Error, "Could not determine path to git_wit executable"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Generated by git_wit
|
|
2
|
+
export PATH="<%= git_wit_bindir %>:<%= RbConfig::CONFIG['bindir'] %>:$PATH"
|
|
3
|
+
export RAILS_ENV="<%= ENV["RAILS_ENV"].presence || "development" %>"
|
|
4
|
+
export RAILS_ROOT="<%= Rails.root %>"
|
|
5
|
+
<% %w(GEM_HOME GEM_PATH BUNDLE_GEMFILE).each do |k| ; next unless ENV[k].present? -%>
|
|
6
|
+
export <%= k %>="<%= ENV[k] %>"
|
|
7
|
+
<% end -%>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
# Note: The following lines *must* appear *after* `Defaults env_reset`!
|
|
3
|
+
# Allow gitwit to pass the following environment variables to sudo processes:
|
|
4
|
+
Defaults:<%= ssh_user %> env_keep += "SSH_ORIGINAL_COMMAND GEM_HOME GEM_PATH"
|
|
5
|
+
Defaults:<%= ssh_user %> env_keep += "BUNDLE_GEMFILE RAILS_ENV RAILS_ROOT"
|
|
6
|
+
|
|
7
|
+
# Allow <%= rails_user %> to run any command as <%= ssh_user %>
|
|
8
|
+
<%= rails_user %> ALL=(<%= ssh_user %>) NOPASSWD:ALL
|
|
9
|
+
|
|
10
|
+
# Allow <%= ssh_user %> to run *only* gw-shell as <%= rails_user %>
|
|
11
|
+
<%= ssh_user %> ALL=(<%= rails_user %>) NOPASSWD:<%= File.join(git_wit_bindir, "git_wit") %>
|
|
12
|
+
|
data/lib/git_wit.rb
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
require "authorized_keys"
|
|
1
2
|
require "active_support/configurable"
|
|
2
3
|
require "git_wit/engine"
|
|
3
4
|
require "git_wit/errors"
|
|
4
5
|
require "git_wit/auth"
|
|
5
6
|
require "git_wit/shell"
|
|
6
7
|
require "git_wit/authorized_keys"
|
|
8
|
+
require "git_wit/authorized_keys/key"
|
|
9
|
+
require "git_wit/authorized_keys/file"
|
|
10
|
+
require "git_wit/cli"
|
|
7
11
|
|
|
8
12
|
module GitWit
|
|
9
13
|
include ActiveSupport::Configurable
|
|
10
14
|
|
|
11
15
|
config_accessor :repositories_path, :ssh_user, :realm,
|
|
12
|
-
:
|
|
16
|
+
:git_path, :insecure_write, :insecure_auth, :username_attribute,
|
|
17
|
+
:email_attribute, :name_attribute
|
|
13
18
|
|
|
14
19
|
def self.reset_config!
|
|
15
20
|
@_config = nil
|
|
@@ -28,11 +33,21 @@ module GitWit
|
|
|
28
33
|
reset_config!
|
|
29
34
|
configure do |config|
|
|
30
35
|
config.realm = "GitWit"
|
|
31
|
-
config.repositories_path = "
|
|
32
|
-
config.ssh_user =
|
|
33
|
-
config.
|
|
36
|
+
config.repositories_path = Rails.root.join("repositories").to_s
|
|
37
|
+
config.ssh_user = nil
|
|
38
|
+
config.git_path = "git"
|
|
34
39
|
config.insecure_write = false
|
|
35
40
|
config.insecure_auth = false
|
|
41
|
+
config.authenticate = false
|
|
42
|
+
config.authorize_read = false
|
|
43
|
+
config.authorize_write = false
|
|
44
|
+
config.username_attribute = :login
|
|
45
|
+
config.email_attribute = :email
|
|
46
|
+
config.name_attribute = :name
|
|
36
47
|
end
|
|
37
48
|
end
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
private :config
|
|
52
|
+
end
|
|
38
53
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module GitWit; module Actions; end; end
|
|
2
|
+
|
|
3
|
+
require "git_wit/actions/ssh"
|
|
4
|
+
require "git_wit/actions/ssh/home"
|
|
5
|
+
require "git_wit/actions/ssh/sudoers"
|
|
6
|
+
require "git_wit/actions/dscl"
|
|
7
|
+
require "git_wit/actions/dscl/base"
|
|
8
|
+
require "git_wit/actions/dscl/user"
|
|
9
|
+
require "git_wit/actions/dscl/group"
|
|
10
|
+
require "git_wit/actions/dscl/group_membership"
|
|
11
|
+
|
|
12
|
+
module GitWit
|
|
13
|
+
module Actions
|
|
14
|
+
include Dscl::Actions
|
|
15
|
+
include Ssh::Actions
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module GitWit::Actions::Dscl
|
|
2
|
+
module Actions
|
|
3
|
+
def dscl_user(name, home, config = {})
|
|
4
|
+
action User.new(self, name, home, config)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def dscl_group(name, config = {})
|
|
8
|
+
action Group.new(self, name, config)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def dscl_group_membership(user, group, config = {})
|
|
12
|
+
action GroupMembership.new(self, user, group, config)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module GitWit::Actions::Dscl
|
|
2
|
+
class Base < Thor::Actions::EmptyDirectory
|
|
3
|
+
|
|
4
|
+
attr_reader :base, :type, :name
|
|
5
|
+
|
|
6
|
+
def initialize(base, type, name, config = {})
|
|
7
|
+
@base, @type, @name = base, type, name
|
|
8
|
+
@config = {verbose: true}.merge config
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def invoke!
|
|
12
|
+
invoke_with_conflict_check do
|
|
13
|
+
create
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def revoke!
|
|
18
|
+
say_status :remove, :red
|
|
19
|
+
destroy if !pretend? && exists?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def exists?
|
|
23
|
+
dscl_exists?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
def id_exists?(check_id)
|
|
28
|
+
dscl_key_exists? "#{type.to_s.first}id", check_id
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def dscl_key_exists?(key, value)
|
|
32
|
+
results = dscl "list /#{type.to_s.capitalize}s #{key}"
|
|
33
|
+
!!(results =~ Regexp.new("#{Regexp.escape(value.to_s)}\n"))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dscl_exists?
|
|
37
|
+
results = dscl "list /#{type.to_s.capitalize}s"
|
|
38
|
+
!!(results =~ Regexp.new("#{Regexp.escape(name)}\n"))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def next_id
|
|
42
|
+
guess = 200
|
|
43
|
+
while id_exists?(guess) && guess < 1000
|
|
44
|
+
guess += 1
|
|
45
|
+
end
|
|
46
|
+
return guess unless id_exists? guess
|
|
47
|
+
raise Thor::Error, "Could not get next #{type.to_s.first}id."
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def dscl(command, config = {})
|
|
51
|
+
command = "dscl . #{command}"
|
|
52
|
+
desc = "#{command} from #{type}"
|
|
53
|
+
|
|
54
|
+
if config[:with]
|
|
55
|
+
desc = "#{File.basename(config[:with].to_s)} #{desc}"
|
|
56
|
+
command = "#{config[:with]} #{command}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
say_status :run, :green, desc if config[:verbose]
|
|
60
|
+
|
|
61
|
+
output = `#{command}`
|
|
62
|
+
raise Thor::Error, "dscl command failed: #{desc}" unless $?.success?
|
|
63
|
+
output
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def sudo_dscl(command, config = {})
|
|
67
|
+
dscl command, config.merge(with: "sudo")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def say_status(status, color, msg = nil)
|
|
71
|
+
msg ||= "#{type} #{name}"
|
|
72
|
+
base.shell.say_status status, msg, color if config[:verbose]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module GitWit::Actions::Dscl
|
|
2
|
+
class Group < Base
|
|
3
|
+
def initialize(base, name, config = {})
|
|
4
|
+
super base, :group, name, config
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
protected
|
|
8
|
+
def create
|
|
9
|
+
gid = next_id
|
|
10
|
+
sudo_dscl "create /Groups/#{name}"
|
|
11
|
+
sudo_dscl "create /Groups/#{name} Password '*'"
|
|
12
|
+
sudo_dscl "create /Groups/#{name} PrimaryGroupID #{gid}"
|
|
13
|
+
sudo_dscl "create /Groups/#{name} GroupMembers ''"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def destroy
|
|
17
|
+
sudo_dscl "delete /Groups/#{name}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module GitWit::Actions::Dscl
|
|
2
|
+
class GroupMembership < Base
|
|
3
|
+
attr_reader :user, :group
|
|
4
|
+
|
|
5
|
+
def initialize(base, user, group, config = {})
|
|
6
|
+
super base, :group_membership, "#{user} #{group}", config
|
|
7
|
+
@user, @group = user, group
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def exists?
|
|
11
|
+
check = `dsmemberutil checkmembership -U '#{user}' -G '#{group}' 2>/dev/null`
|
|
12
|
+
$?.success? && !!(check =~ /is a member/)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
def create
|
|
17
|
+
sudo_dscl "create /Users/#{user} PrimaryGroupID #{gid}"
|
|
18
|
+
sudo_dscl "append /Groups/#{group} GroupMembership #{user}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def destroy
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def gid
|
|
25
|
+
gid = dscl "read /Groups/#{group} gid".split("gid: ", 2).last
|
|
26
|
+
raise Thor::Error, "Could not find gid for group #{group}" unless gid.present?
|
|
27
|
+
gid.to_i
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module GitWit::Actions::Dscl
|
|
2
|
+
class User < Base
|
|
3
|
+
def initialize(base, name, home, config = {})
|
|
4
|
+
super base, :user, name, config
|
|
5
|
+
@home = home
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def invoke!
|
|
9
|
+
invoke_with_conflict_check do
|
|
10
|
+
create
|
|
11
|
+
end
|
|
12
|
+
home
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def revoke!
|
|
16
|
+
say_status :remove, :red
|
|
17
|
+
destroy if !pretend? && exists?
|
|
18
|
+
home
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
def home
|
|
23
|
+
@home || "/Users/#{name}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def create
|
|
27
|
+
uid = next_id
|
|
28
|
+
sudo_dscl "create /Users/#{name}"
|
|
29
|
+
sudo_dscl "create /Users/#{name} RealName '#{name}'"
|
|
30
|
+
sudo_dscl "create /Users/#{name} UniqueID #{uid}"
|
|
31
|
+
sudo_dscl "create /Users/#{name} NFSHomeDirectory '#{home}'"
|
|
32
|
+
sudo_dscl "create /Users/#{name} UserShell '/bin/bash'"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def destroy
|
|
36
|
+
sudo_dscl "delete /Users/#{name}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module GitWit::Actions::Ssh
|
|
2
|
+
class Home < Thor::Actions::EmptyDirectory
|
|
3
|
+
attr_reader :base, :user, :home
|
|
4
|
+
|
|
5
|
+
def initialize(base, user, home, config = {})
|
|
6
|
+
@base, @user, @home = base, user, File.expand_path(home)
|
|
7
|
+
@config = {verbose: true}.merge config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def invoke!
|
|
11
|
+
invoke_with_conflict_check do
|
|
12
|
+
create
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def revoke!
|
|
17
|
+
say_status :remove, :red
|
|
18
|
+
destroy if !pretend? && exists?
|
|
19
|
+
home
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def exists?
|
|
23
|
+
Dir.exists? home
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
def create
|
|
28
|
+
old_destination = base.destination_root
|
|
29
|
+
Dir.mktmpdir do |dir|
|
|
30
|
+
base.destination_root = dir
|
|
31
|
+
base.chmod ".", 0755
|
|
32
|
+
base.inside "." do
|
|
33
|
+
base.empty_directory ".ssh"
|
|
34
|
+
base.chmod ".ssh", 0700
|
|
35
|
+
base.inside ".ssh" do
|
|
36
|
+
base.create_file "authorized_keys", ""
|
|
37
|
+
base.chmod "authorized_keys", 0600
|
|
38
|
+
end
|
|
39
|
+
base.template "bashrc.tt", ".bashrc"
|
|
40
|
+
end
|
|
41
|
+
`sudo cp -R '#{dir}' '#{home}'`
|
|
42
|
+
`sudo chown -R #{user}:#{user} '#{home}'`
|
|
43
|
+
end
|
|
44
|
+
base.destination_root = old_destination
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def destroy
|
|
48
|
+
`sudo rm -rf '#{home}'`
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def relative_destination
|
|
52
|
+
home
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|