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.
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