git_wit 0.0.3 → 0.0.4.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. data/README.md +105 -157
  2. data/app/controllers/git_wit/git_controller.rb +37 -23
  3. data/bin/git_wit +4 -0
  4. data/config/routes.rb +2 -2
  5. data/lib/generators/git_wit/install/install_generator.rb +42 -11
  6. data/lib/generators/git_wit/{templates → install/templates}/README +0 -0
  7. data/lib/generators/git_wit/{templates → install/templates}/git_wit.rb +21 -11
  8. data/lib/generators/git_wit/ssh_user/USAGE +11 -0
  9. data/lib/generators/git_wit/ssh_user/ssh_user_generator.rb +53 -0
  10. data/lib/generators/git_wit/ssh_user/templates/bashrc.tt +7 -0
  11. data/lib/generators/git_wit/ssh_user/templates/sudoers.tt +12 -0
  12. data/lib/git_wit.rb +19 -4
  13. data/lib/git_wit/actions.rb +17 -0
  14. data/lib/git_wit/actions/dscl.rb +15 -0
  15. data/lib/git_wit/actions/dscl/base.rb +75 -0
  16. data/lib/git_wit/actions/dscl/group.rb +20 -0
  17. data/lib/git_wit/actions/dscl/group_membership.rb +30 -0
  18. data/lib/git_wit/actions/dscl/user.rb +39 -0
  19. data/lib/git_wit/actions/ssh.rb +11 -0
  20. data/lib/git_wit/actions/ssh/home.rb +55 -0
  21. data/lib/git_wit/actions/ssh/sudoers.rb +94 -0
  22. data/lib/git_wit/auth.rb +2 -2
  23. data/lib/git_wit/authorized_keys.rb +45 -88
  24. data/lib/git_wit/authorized_keys/file.rb +61 -0
  25. data/lib/git_wit/authorized_keys/key.rb +15 -0
  26. data/lib/git_wit/cli.rb +19 -0
  27. data/lib/git_wit/commands/debug.rb +21 -0
  28. data/lib/git_wit/commands/git_shell.rb +48 -0
  29. data/lib/git_wit/commands/util.rb +37 -0
  30. data/lib/git_wit/errors.rb +1 -0
  31. data/lib/git_wit/version.rb +2 -1
  32. data/lib/tasks/git_wit.rake +46 -0
  33. data/test/dummy/bin/coderay +16 -0
  34. data/test/dummy/bin/erubis +16 -0
  35. data/test/dummy/bin/git_wit +16 -0
  36. data/test/dummy/bin/htmldiff +16 -0
  37. data/test/dummy/bin/ldiff +16 -0
  38. data/test/dummy/bin/posix-spawn-benchmark +16 -0
  39. data/test/dummy/bin/pry +16 -0
  40. data/test/dummy/bin/rackup +16 -0
  41. data/test/dummy/bin/rails +16 -0
  42. data/test/dummy/bin/rake +16 -0
  43. data/test/dummy/bin/rake2thor +16 -0
  44. data/test/dummy/bin/rdoc +16 -0
  45. data/test/dummy/bin/ri +16 -0
  46. data/test/dummy/bin/sprockets +16 -0
  47. data/test/dummy/bin/thor +16 -0
  48. data/test/dummy/bin/tilt +16 -0
  49. data/test/dummy/bin/tt +16 -0
  50. data/test/dummy/bin/tunnels +16 -0
  51. data/test/dummy/config/initializers/git_wit.rb +33 -24
  52. data/test/dummy/db/development.sqlite3 +0 -0
  53. data/test/dummy/db/test.sqlite3 +0 -0
  54. data/test/dummy/log/development.log +1639 -5391
  55. data/test/dummy/log/test.log +108 -2
  56. data/test/dummy/tmp/pids/server.pid +1 -0
  57. data/test/unit/auth_test.rb +10 -6
  58. data/test/unit/authorized_keys_test.rb +5 -5
  59. data/test/unit/config_test.rb +15 -11
  60. data/test/unit/shell_test.rb +5 -5
  61. metadata +84 -278
  62. data/bin/gw-shell +0 -4
  63. data/lib/tasks/git_wit_shell.rake +0 -8
  64. data/test/dummy/tmp/cache/assets/C7E/BC0/sprockets%2Fb7118f368364962573a44054bcfb80d0 +0 -0
  65. data/test/dummy/tmp/cache/assets/C80/840/sprockets%2F562c2d168da585f80579347d10790a0a +0 -0
  66. data/test/dummy/tmp/cache/assets/C8C/B80/sprockets%2F371bf96e99717688ed7313a0c53f4212 +0 -0
  67. data/test/dummy/tmp/cache/assets/C9C/700/sprockets%2Fc7b1373dbf219a8722efc21160641340 +0 -0
  68. data/test/dummy/tmp/cache/assets/C9E/5F0/sprockets%2F2bca2b107bb6c26b720d135270688918 +0 -0
  69. data/test/dummy/tmp/cache/assets/CA9/9C0/sprockets%2F0c1b7ebd087418498ea6037225d33d25 +0 -0
  70. data/test/dummy/tmp/cache/assets/CC8/B00/sprockets%2F9815364bfd49ed907870e270d75a995a +0 -0
  71. data/test/dummy/tmp/cache/assets/CD1/800/sprockets%2Fc044b140dcef533c52712c7b51e21996 +0 -0
  72. data/test/dummy/tmp/cache/assets/CD5/2C0/sprockets%2F166c056119ebdfb8b7104c97b424b423 +0 -0
  73. data/test/dummy/tmp/cache/assets/CD7/380/sprockets%2F4079ce1dbbcf4a599527303670006b6b +0 -0
  74. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  75. data/test/dummy/tmp/cache/assets/CE0/CC0/sprockets%2F2b38c3fb549036de5c4666637a0c80c6 +0 -0
  76. data/test/dummy/tmp/cache/assets/CEC/B70/sprockets%2F7f98753ca8c35e4249363a04389b3caf +0 -0
  77. data/test/dummy/tmp/cache/assets/CF0/1D0/sprockets%2F6fc757c2c8329244ca95d6909865bbc2 +0 -0
  78. data/test/dummy/tmp/cache/assets/CF9/980/sprockets%2Fbd55042e1acd32eb611041444d794d4d +0 -0
  79. data/test/dummy/tmp/cache/assets/CFD/560/sprockets%2Fe4e7fe4ee089382325686f806b939d3e +0 -0
  80. data/test/dummy/tmp/cache/assets/D00/B90/sprockets%2F07c00c80f1ea62d95a01f11f9c728b72 +0 -0
  81. data/test/dummy/tmp/cache/assets/D0D/9A0/sprockets%2F1fce44192cdb30f44b7545a37c9891b2 +0 -0
  82. data/test/dummy/tmp/cache/assets/D0F/390/sprockets%2F9df081609c3449ab40c93b1cf07de357 +0 -0
  83. data/test/dummy/tmp/cache/assets/D25/A60/sprockets%2F0e036061ad22b2e6dce1639b234cf15c +0 -0
  84. data/test/dummy/tmp/cache/assets/D27/DB0/sprockets%2Fa3a0a778855bce9fa47913d389ea9884 +0 -0
  85. data/test/dummy/tmp/cache/assets/D29/5A0/sprockets%2Fdad9e81b43ca12671246ee52a1900d0c +0 -0
  86. data/test/dummy/tmp/cache/assets/D2E/FF0/sprockets%2Fc06112642c994b6b7c2ba6632fad1fd0 +0 -0
  87. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  88. data/test/dummy/tmp/cache/assets/D36/120/sprockets%2Feac54bd3c540af6b964d025e345227d6 +0 -0
  89. data/test/dummy/tmp/cache/assets/D3E/240/sprockets%2F84b96d6b2d2653cb4127b06d8acb990d +0 -0
  90. data/test/dummy/tmp/cache/assets/D3F/830/sprockets%2F18578d4ef3abd6e12d836841dd6b8a00 +0 -0
  91. data/test/dummy/tmp/cache/assets/D4B/E70/sprockets%2F0909bc70e589d40a6cd90dfe6f18257e +0 -0
  92. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  93. data/test/dummy/tmp/cache/assets/D57/3D0/sprockets%2F7bbccc5129a5013b70831ec9ad62ab24 +0 -0
  94. data/test/dummy/tmp/cache/assets/D5A/000/sprockets%2F7d4f67f146b6d7904dfc4edd9135f588 +0 -0
  95. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  96. data/test/dummy/tmp/cache/assets/D5B/BB0/sprockets%2Fba769276c4de14151bc4202cba7f3ad3 +0 -0
  97. data/test/dummy/tmp/cache/assets/D5E/BC0/sprockets%2F2d96fa667066778db858d7b7cb0fce69 +0 -0
  98. data/test/dummy/tmp/cache/assets/D6E/BA0/sprockets%2F5178d3788fe35a52acb5f3bd22ea078a +0 -0
  99. data/test/dummy/tmp/cache/assets/D6F/C20/sprockets%2F22e783a8f5f9224f01e8e62fab6afb40 +0 -0
  100. data/test/dummy/tmp/cache/assets/D76/5C0/sprockets%2Fd8a5669df31f129f355283e6dab4c5ad +0 -0
  101. data/test/dummy/tmp/cache/assets/D79/DE0/sprockets%2F7cfd335e68d881b03f6b7f1bd91f270f +0 -0
  102. data/test/dummy/tmp/cache/assets/D8A/CA0/sprockets%2F656af8b87ad378e8e4f2ec94b6b5c719 +0 -0
  103. data/test/dummy/tmp/cache/assets/D8C/620/sprockets%2Ff37f8e5b8cccd9880276a9f5157d4c7e +0 -0
  104. data/test/dummy/tmp/cache/assets/D92/200/sprockets%2Fb816d858281027bdd3fe2bfac43b4ca1 +0 -0
  105. data/test/dummy/tmp/cache/assets/D92/CE0/sprockets%2Ffca6a13676a2be09234905f9acae22cd +0 -0
  106. data/test/dummy/tmp/cache/assets/D96/9E0/sprockets%2F6fabecd33f7a5a087f4fb6a2d6312443 +0 -0
  107. data/test/dummy/tmp/cache/assets/DA2/D20/sprockets%2Ff5faf079fb660bde5bc9502bde442088 +0 -0
  108. data/test/dummy/tmp/cache/assets/DA5/570/sprockets%2F3517de599b6fd005bc5d5d69ba5ff1e2 +0 -0
  109. data/test/dummy/tmp/cache/assets/DA7/070/sprockets%2F69eadf8c3a94b04fe0b4992ee4a8c821 +0 -0
  110. data/test/dummy/tmp/cache/assets/DBA/BF0/sprockets%2Fe63ea1d7bfb0ee50380debe42360a3b5 +0 -0
  111. data/test/dummy/tmp/cache/assets/DBB/3B0/sprockets%2F6a0aaa6c5b0d10b936e237a7ecb4e4c9 +0 -0
  112. data/test/dummy/tmp/cache/assets/DBC/8E0/sprockets%2F908976cfbcdf6ad4c59737bf3c78e1e8 +0 -0
  113. data/test/dummy/tmp/cache/assets/DD3/FD0/sprockets%2Febf97c76a9ba2a889dd01be2caa75806 +0 -0
  114. data/test/dummy/tmp/cache/assets/DD8/410/sprockets%2Fc02eeb7ea977fd713cc19ca93d838af4 +0 -0
  115. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  116. data/test/dummy/tmp/cache/assets/DEA/E40/sprockets%2F4166d7d00d1e72fed2004debed2bea3e +0 -0
  117. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  118. data/test/dummy/tmp/cache/assets/E05/C70/sprockets%2Fccd814ec859d582ada46e271edfe7ae1 +0 -0
  119. data/test/dummy/tmp/cache/assets/E0C/2A0/sprockets%2F37c59fadd9a21cab7d05d78a7dfe7e85 +0 -0
  120. data/test/dummy/tmp/cache/assets/E28/130/sprockets%2F6f332ca43b7ed658d90b8ba5daaa5ded +0 -0
  121. data/test/dummy/tmp/cache/assets/E3B/080/sprockets%2F09e2a090befacdae0db10cafb1893a0a +0 -0
  122. data/test/dummy/tmp/cache/assets/E65/CD0/sprockets%2F93cdf3fec0e3aa6deefa955c6828fbd0 +0 -0
  123. data/test/dummy/tmp/cache/assets/E9F/450/sprockets%2Fbbfdc5edaaf25dfdb5ee8f9db7895435 +0 -0
  124. data/test/dummy/tmp/git/fuck.git/HEAD +0 -1
  125. data/test/dummy/tmp/git/fuck.git/config +0 -6
  126. data/test/dummy/tmp/git/fuck.git/description +0 -1
  127. data/test/dummy/tmp/git/fuck.git/hooks/applypatch-msg.sample +0 -15
  128. data/test/dummy/tmp/git/fuck.git/hooks/commit-msg.sample +0 -24
  129. data/test/dummy/tmp/git/fuck.git/hooks/post-update.sample +0 -8
  130. data/test/dummy/tmp/git/fuck.git/hooks/pre-applypatch.sample +0 -14
  131. data/test/dummy/tmp/git/fuck.git/hooks/pre-commit.sample +0 -50
  132. data/test/dummy/tmp/git/fuck.git/hooks/pre-rebase.sample +0 -169
  133. data/test/dummy/tmp/git/fuck.git/hooks/prepare-commit-msg.sample +0 -36
  134. data/test/dummy/tmp/git/fuck.git/hooks/update.sample +0 -128
  135. data/test/dummy/tmp/git/fuck.git/info/exclude +0 -6
  136. data/test/dummy/tmp/git/lkasdjf.git/HEAD +0 -1
  137. data/test/dummy/tmp/git/lkasdjf.git/config +0 -6
  138. data/test/dummy/tmp/git/lkasdjf.git/description +0 -1
  139. data/test/dummy/tmp/git/lkasdjf.git/hooks/applypatch-msg.sample +0 -15
  140. data/test/dummy/tmp/git/lkasdjf.git/hooks/commit-msg.sample +0 -24
  141. data/test/dummy/tmp/git/lkasdjf.git/hooks/post-update.sample +0 -8
  142. data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-applypatch.sample +0 -14
  143. data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-commit.sample +0 -50
  144. data/test/dummy/tmp/git/lkasdjf.git/hooks/pre-rebase.sample +0 -169
  145. data/test/dummy/tmp/git/lkasdjf.git/hooks/prepare-commit-msg.sample +0 -36
  146. data/test/dummy/tmp/git/lkasdjf.git/hooks/update.sample +0 -128
  147. data/test/dummy/tmp/git/lkasdjf.git/info/exclude +0 -6
  148. data/test/dummy/tmp/git/new/test.git/HEAD +0 -1
  149. data/test/dummy/tmp/git/new/test.git/config +0 -6
  150. data/test/dummy/tmp/git/new/test.git/description +0 -1
  151. data/test/dummy/tmp/git/new/test.git/hooks/applypatch-msg.sample +0 -15
  152. data/test/dummy/tmp/git/new/test.git/hooks/commit-msg.sample +0 -24
  153. data/test/dummy/tmp/git/new/test.git/hooks/post-update.sample +0 -8
  154. data/test/dummy/tmp/git/new/test.git/hooks/pre-applypatch.sample +0 -14
  155. data/test/dummy/tmp/git/new/test.git/hooks/pre-commit.sample +0 -50
  156. data/test/dummy/tmp/git/new/test.git/hooks/pre-rebase.sample +0 -169
  157. data/test/dummy/tmp/git/new/test.git/hooks/prepare-commit-msg.sample +0 -36
  158. data/test/dummy/tmp/git/new/test.git/hooks/update.sample +0 -128
  159. data/test/dummy/tmp/git/new/test.git/info/exclude +0 -6
  160. data/test/dummy/tmp/git/testing.git/HEAD +0 -1
  161. data/test/dummy/tmp/git/testing.git/config +0 -6
  162. data/test/dummy/tmp/git/testing.git/description +0 -1
  163. data/test/dummy/tmp/git/testing.git/hooks/applypatch-msg.sample +0 -15
  164. data/test/dummy/tmp/git/testing.git/hooks/commit-msg.sample +0 -24
  165. data/test/dummy/tmp/git/testing.git/hooks/post-update.sample +0 -8
  166. data/test/dummy/tmp/git/testing.git/hooks/pre-applypatch.sample +0 -14
  167. data/test/dummy/tmp/git/testing.git/hooks/pre-commit.sample +0 -50
  168. data/test/dummy/tmp/git/testing.git/hooks/pre-rebase.sample +0 -169
  169. data/test/dummy/tmp/git/testing.git/hooks/prepare-commit-msg.sample +0 -36
  170. data/test/dummy/tmp/git/testing.git/hooks/update.sample +0 -128
  171. data/test/dummy/tmp/git/testing.git/info/exclude +0 -6
  172. data/test/dummy/tmp/git/under_scored/sub.git/HEAD +0 -1
  173. data/test/dummy/tmp/git/under_scored/sub.git/config +0 -6
  174. data/test/dummy/tmp/git/under_scored/sub.git/description +0 -1
  175. data/test/dummy/tmp/git/under_scored/sub.git/hooks/applypatch-msg.sample +0 -15
  176. data/test/dummy/tmp/git/under_scored/sub.git/hooks/commit-msg.sample +0 -24
  177. data/test/dummy/tmp/git/under_scored/sub.git/hooks/post-update.sample +0 -8
  178. data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-applypatch.sample +0 -14
  179. data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-commit.sample +0 -50
  180. data/test/dummy/tmp/git/under_scored/sub.git/hooks/pre-rebase.sample +0 -169
  181. data/test/dummy/tmp/git/under_scored/sub.git/hooks/prepare-commit-msg.sample +0 -36
  182. data/test/dummy/tmp/git/under_scored/sub.git/hooks/update.sample +0 -128
  183. data/test/dummy/tmp/git/under_scored/sub.git/info/exclude +0 -6
  184. data/test/dummy/tmp/git/work/pls/thnx.git/HEAD +0 -1
  185. data/test/dummy/tmp/git/work/pls/thnx.git/config +0 -6
  186. data/test/dummy/tmp/git/work/pls/thnx.git/description +0 -1
  187. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/applypatch-msg.sample +0 -15
  188. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/commit-msg.sample +0 -24
  189. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/post-update.sample +0 -8
  190. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-applypatch.sample +0 -14
  191. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-commit.sample +0 -50
  192. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/pre-rebase.sample +0 -169
  193. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/prepare-commit-msg.sample +0 -36
  194. data/test/dummy/tmp/git/work/pls/thnx.git/hooks/update.sample +0 -128
  195. data/test/dummy/tmp/git/work/pls/thnx.git/info/exclude +0 -6
@@ -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
- # config.repositories_path = "/var/git"
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
- # config.ssh_user = "git"
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
- # config.authorized_keys_path = "/var/git/.ssh/authorized_keys"
16
+ <%= maybe_config :authorized_keys_path, "/var/git/.ssh/authorized_keys" %>
17
17
 
18
- # Configure the path to the git-http-backend binary.
19
- # config.git_http_backend_path = "/usr/libexec/git-core/git-http-backend"
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
- # config.realm = "GitWit"
23
+ <%= maybe_config :realm, "GitWit" %>
23
24
 
24
25
  # Allow or disable write operations (push) via non-secure (http) protocols.
25
- # config.insecure_write = false
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
- # config.insecure_auth = false
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
- # config.username_attribute = :login # REMOTE_USER
40
- # config.committer_email_attribute = :email # GIT_COMMITTER_NAME
41
- # config.committer_name_attribute = :name # GIT_COMMITTER_EMAIL
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,11 @@
1
+ Description:
2
+ Creates an SSH-only user for GitWit access.
3
+
4
+ Example:
5
+ rails generate git_wit:ssh_user /home/gitwit
6
+
7
+ This will create:
8
+ /home/gitwit
9
+ /home/gitwit/.ssh
10
+ /home/gitwit/.ssh/authorized_keys
11
+ /home/gitwit/.bashrc
@@ -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
- :git_http_backend_path, :insecure_write, :insecure_auth
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 = "/var/git"
32
- config.ssh_user = "git"
33
- config.git_http_backend_path = "/usr/libexec/git-core/git-http-backend"
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,11 @@
1
+ module GitWit::Actions::Ssh
2
+ module Actions
3
+ def ssh_home(user, home, config = {})
4
+ action Home.new(self, user, home, config)
5
+ end
6
+
7
+ def ssh_sudoers(user, config = {})
8
+ action Sudoers.new(self, user, config)
9
+ end
10
+ end
11
+ 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