gritano 0.1.2

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 (47) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +20 -0
  4. data/Gemfile.lock +72 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +51 -0
  7. data/Rakefile +62 -0
  8. data/TODO +0 -0
  9. data/VERSION +1 -0
  10. data/bin/gritano +74 -0
  11. data/bin/gritano-check +17 -0
  12. data/db/database.yml +2 -0
  13. data/db/migrate/001_create_users.rb +8 -0
  14. data/db/migrate/002_create_repositories.rb +9 -0
  15. data/db/migrate/003_create_permissions.rb +10 -0
  16. data/db/migrate/004_create_keys.rb +11 -0
  17. data/features/command.feature +12 -0
  18. data/features/console.feature +59 -0
  19. data/features/data/keys/full_authorized_keys +2 -0
  20. data/features/data/keys/igorbonadio.pub +1 -0
  21. data/features/data/keys/igorbonadio_authorized_keys +1 -0
  22. data/features/data/keys/jessicaeto.pub +1 -0
  23. data/features/data/keys/jessicaeto_authorized_keys +1 -0
  24. data/features/keys.feature +31 -0
  25. data/features/polices.feature +55 -0
  26. data/features/step_definitions/command_step.rb +8 -0
  27. data/features/step_definitions/console_step.rb +14 -0
  28. data/features/step_definitions/keys_steps.rb +23 -0
  29. data/features/step_definitions/polices_steps.rb +54 -0
  30. data/features/support/database_cleaner.rb +15 -0
  31. data/features/support/env.rb +25 -0
  32. data/lib/gritano.rb +5 -0
  33. data/lib/gritano/command.rb +16 -0
  34. data/lib/gritano/console.rb +119 -0
  35. data/lib/gritano/models.rb +7 -0
  36. data/lib/gritano/models/key.rb +21 -0
  37. data/lib/gritano/models/permission.rb +39 -0
  38. data/lib/gritano/models/repository.rb +24 -0
  39. data/lib/gritano/models/user.rb +41 -0
  40. data/spec/command_spec.rb +17 -0
  41. data/spec/console_spec.rb +51 -0
  42. data/spec/model_key_spec.rb +18 -0
  43. data/spec/model_repository_spec.rb +23 -0
  44. data/spec/model_user_spec.rb +84 -0
  45. data/spec/spec_helper.rb +32 -0
  46. data/tmp/.gitignore +4 -0
  47. metadata +260 -0
@@ -0,0 +1,2 @@
1
+ command="gritano-check igorbonadio" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFW6Du1iXTyo44g+7R4DNgm4P1fQIiW/iGRFwHJTV1jaPX74VwNq7tC1kBSdPS4+Q9f24wJC1MhWzLxB40BFdqn519JhhV+/1IWZdY/UJ0D5KiUw38U7QPzMM2uA0l0JeB+FwZAl/Oiu/ty3Fq0JsuqsolehIbRRLeiJiwrn1XC5LdhA81b2WBzM8SSFgAaXPimuLBXYJyYrcTR5SXczZvgkWojQEvk7wCavvDzFpy/DtXUFv0ZwUJILhN23cW3mg1IsGMXg7hOQfp67J6cX212YYXhDe+5sI3UpFWKCHcyxv3EdL8rQ/3DLSELkTwWHPRqDhn1wnPmfJlj8ZfbpyX git2@debian-ror
2
+ command="gritano-check jessicaeto" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ4WqIu8XwnHwBz220/1Kbgi1IR7aanq8hW1dB0LD2dmCSyojBvduoht4p7+3k2R6A5y2DZvTetzEios9OFUnCC+4U8g2GTc+zGM0W+msCb6yWnpfYaIwHVuFtsid7lyWOCEYLi2WbNZxfAx0PbwIcHMoYWc9sil3R/YwLGorvQDGH0rFcf6BOMzVMDRD0yPvuN3xgAtBOxrSRl0U4dH+3fAQ9oKLePmouzLrrKvRmyVwl/rHNod8ae5VmmAalC+wXIsiQAI92Hwew757HzhY45wWtjOsdBBf45Psv7BkB1OqGxMfwysO5iwhY3HPTJs70K22K2DARpejFq8Bd8PyV git2@debian-ror
@@ -0,0 +1 @@
1
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFW6Du1iXTyo44g+7R4DNgm4P1fQIiW/iGRFwHJTV1jaPX74VwNq7tC1kBSdPS4+Q9f24wJC1MhWzLxB40BFdqn519JhhV+/1IWZdY/UJ0D5KiUw38U7QPzMM2uA0l0JeB+FwZAl/Oiu/ty3Fq0JsuqsolehIbRRLeiJiwrn1XC5LdhA81b2WBzM8SSFgAaXPimuLBXYJyYrcTR5SXczZvgkWojQEvk7wCavvDzFpy/DtXUFv0ZwUJILhN23cW3mg1IsGMXg7hOQfp67J6cX212YYXhDe+5sI3UpFWKCHcyxv3EdL8rQ/3DLSELkTwWHPRqDhn1wnPmfJlj8ZfbpyX git2@debian-ror
@@ -0,0 +1 @@
1
+ command="gritano-check igorbonadio" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFW6Du1iXTyo44g+7R4DNgm4P1fQIiW/iGRFwHJTV1jaPX74VwNq7tC1kBSdPS4+Q9f24wJC1MhWzLxB40BFdqn519JhhV+/1IWZdY/UJ0D5KiUw38U7QPzMM2uA0l0JeB+FwZAl/Oiu/ty3Fq0JsuqsolehIbRRLeiJiwrn1XC5LdhA81b2WBzM8SSFgAaXPimuLBXYJyYrcTR5SXczZvgkWojQEvk7wCavvDzFpy/DtXUFv0ZwUJILhN23cW3mg1IsGMXg7hOQfp67J6cX212YYXhDe+5sI3UpFWKCHcyxv3EdL8rQ/3DLSELkTwWHPRqDhn1wnPmfJlj8ZfbpyX git2@debian-ror
@@ -0,0 +1 @@
1
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ4WqIu8XwnHwBz220/1Kbgi1IR7aanq8hW1dB0LD2dmCSyojBvduoht4p7+3k2R6A5y2DZvTetzEios9OFUnCC+4U8g2GTc+zGM0W+msCb6yWnpfYaIwHVuFtsid7lyWOCEYLi2WbNZxfAx0PbwIcHMoYWc9sil3R/YwLGorvQDGH0rFcf6BOMzVMDRD0yPvuN3xgAtBOxrSRl0U4dH+3fAQ9oKLePmouzLrrKvRmyVwl/rHNod8ae5VmmAalC+wXIsiQAI92Hwew757HzhY45wWtjOsdBBf45Psv7BkB1OqGxMfwysO5iwhY3HPTJs70K22K2DARpejFq8Bd8PyV git2@debian-ror
@@ -0,0 +1 @@
1
+ command="gritano-check jessicaeto" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ4WqIu8XwnHwBz220/1Kbgi1IR7aanq8hW1dB0LD2dmCSyojBvduoht4p7+3k2R6A5y2DZvTetzEios9OFUnCC+4U8g2GTc+zGM0W+msCb6yWnpfYaIwHVuFtsid7lyWOCEYLi2WbNZxfAx0PbwIcHMoYWc9sil3R/YwLGorvQDGH0rFcf6BOMzVMDRD0yPvuN3xgAtBOxrSRl0U4dH+3fAQ9oKLePmouzLrrKvRmyVwl/rHNod8ae5VmmAalC+wXIsiQAI92Hwew757HzhY45wWtjOsdBBf45Psv7BkB1OqGxMfwysO5iwhY3HPTJs70K22K2DARpejFq8Bd8PyV git2@debian-ror
@@ -0,0 +1,31 @@
1
+ Feature: Keys
2
+ In Order to restrict access to repositories
3
+ As Gritano
4
+ I want to manage user's keys
5
+
6
+ Background:
7
+ Given the following users exist:
8
+ | login |
9
+ | igorbonadio |
10
+ | jessicaeto |
11
+
12
+ Scenario Outline: Add user key
13
+ Given I add "<key>" key to "<user>"
14
+ When I generate the authorized_keys
15
+ Then I should see "<authorized_keys>" authorized_keys
16
+ Examples:
17
+ | user | key | authorized_keys |
18
+ | igorbonadio | igorbonadio.pub | igorbonadio_authorized_keys |
19
+ | jessicaeto | jessicaeto.pub | jessicaeto_authorized_keys |
20
+
21
+ Scenario: Generate autorized_keys
22
+ Given I add "igorbonadio.pub" key to "igorbonadio"
23
+ And I add "jessicaeto.pub" key to "jessicaeto"
24
+ When I generate the authorized_keys
25
+ Then I should see "full_authorized_keys" authorized_keys
26
+
27
+ Scenario: Duplicated keys
28
+ Given I add "igorbonadio.pub" key to "igorbonadio"
29
+ When I add "igorbonadio.pub" key to "igorbonadio"
30
+ Then I should see that "igorbonadio" has only one key
31
+
@@ -0,0 +1,55 @@
1
+ Feature: Policies
2
+ In order to restrict access to repositories
3
+ As Gritano
4
+ I want to create policies
5
+
6
+ Background:
7
+ Given the following users exist:
8
+ | login |
9
+ | igorbonadio |
10
+ | jessicaeto |
11
+
12
+ And the following repositories exist:
13
+ | name |
14
+ | tmp/gritano.git |
15
+ | tmp/jeka.git |
16
+
17
+ And the following permissions exist:
18
+ | user | repo | access |
19
+ | igorbonadio | tmp/gritano.git | read |
20
+ | igorbonadio | tmp/gritano.git | write |
21
+ | igorbonadio | tmp/jeka.git | read |
22
+ | jessicaeto | tmp/jeka.git | read |
23
+ | jessicaeto | tmp/jeka.git | write |
24
+
25
+ Scenario Outline: Create a new user
26
+ Given I create a new user called "<user>"
27
+ When I check if "<user>" has <access> access to "<repo>"
28
+ Then I should see that the access is <result>
29
+ Examples:
30
+ | user | access | repo | result |
31
+ | arybonadio | read | tmp/gritano.git | denied |
32
+ | arybonadio | write | tmp/gritano.git | denied |
33
+
34
+ Scenario Outline: Create a new repository
35
+ Given I create a new repository called "<repo>" to "<user>"
36
+ Then I should see that only "<user>" has access to "<repo>"
37
+ Examples:
38
+ | user | repo |
39
+ | igorbonadio | tmp/p-lang.git |
40
+ | jessicaeto | tmp/pabel.git |
41
+
42
+ Scenario Outline: Edit access permission
43
+ Given I <op> "<user>" <permission> access to "<repo>"
44
+ When I check if "<user>" has <access> access to "<repo>"
45
+ Then I should see that the access is <result>
46
+ Examples:
47
+ | op | user | permission | repo | access | result |
48
+ | add | igorbonadio | read | tmp/jeka.git | read | allowed |
49
+ | add | igorbonadio | read | tmp/jeka.git | write | denied |
50
+ | add | igorbonadio | write | tmp/jeka.git | read | allowed |
51
+ | add | igorbonadio | write | tmp/jeka.git | write | allowed |
52
+ | remove | jessicaeto | read | tmp/jeka.git | read | denied |
53
+ | remove | jessicaeto | read | tmp/jeka.git | write | allowed |
54
+ | remove | jessicaeto | write | tmp/jeka.git | read | allowed |
55
+ | remove | jessicaeto | write | tmp/jeka.git | write | denied |
@@ -0,0 +1,8 @@
1
+ When /^I receive a "(.*?)" command$/ do |cmd|
2
+ @access, @git_command, @repo = Gritano::Command.eval(cmd)
3
+ end
4
+
5
+ Then /^I should see that it is a "(.*?)" access to "(.*?)"$/ do |access, repo|
6
+ @access.to_s.should be == access
7
+ @repo.to_s.should be == repo
8
+ end
@@ -0,0 +1,14 @@
1
+ Given /^I start the gritano console$/ do
2
+ @console = Gritano::Console.new
3
+ @console.ssh_path = 'tmp'
4
+ end
5
+
6
+ When /^I execute "(.*?)"$/ do |command|
7
+ @output = @console.execute(command.split(' '))
8
+ end
9
+
10
+ Then /^I should see a (success|error) message$/ do |ret|
11
+ expected_output = true if ret == 'success'
12
+ expected_output = false if ret == 'error'
13
+ @output.should be == expected_output
14
+ end
@@ -0,0 +1,23 @@
1
+ Given /^the following keys exist:$/ do |table|
2
+ table.hashes.each do |key|
3
+ Gritano::User.find_by_login(key['login']).keys.create(name: key["key"], key: "key")
4
+ end
5
+ end
6
+
7
+ Given /^I add "(.*?)" key to "(.*?)"$/ do |key, login|
8
+ ssh_key = File.open(File.join("features/data/keys/", key)).readlines.join
9
+ Gritano::User.find_by_login(login).keys.create({name: key, key: ssh_key})
10
+ end
11
+
12
+ When /^I generate the authorized_keys$/ do
13
+ @authorized_keys = Gritano::Key.authorized_keys
14
+ end
15
+
16
+ Then /^I should see "(.*?)" authorized_keys$/ do |authorized_keys|
17
+ expected_authorized_keys = File.open(File.join("features/data/keys/", authorized_keys)).readlines.join
18
+ @authorized_keys.should be == expected_authorized_keys
19
+ end
20
+
21
+ Then /^I should see that "(.*?)" has only one key$/ do |login|
22
+ Gritano::User.find_by_login(login).keys.count.should be == 1
23
+ end
@@ -0,0 +1,54 @@
1
+ Given /^the following users exist:$/ do |table|
2
+ table.hashes.each do |user|
3
+ Gritano::User.create(user)
4
+ end
5
+ end
6
+
7
+ Given /^the following repositories exist:$/ do |table|
8
+ table.hashes.each do |repo|
9
+ Gritano::Repository.create(repo)
10
+ end
11
+ end
12
+
13
+ Given /^the following permissions exist:$/ do |table|
14
+ table.hashes.each do |permission|
15
+ Gritano::User.find_by_login(permission['user'])
16
+ .add_access(Gritano::Repository.find_by_name(permission['repo']), permission['access'].to_sym)
17
+ end
18
+ end
19
+
20
+ Given /^I create a new user called "(.*?)"$/ do |login|
21
+ @user = Gritano::User.create(login: login)
22
+ end
23
+
24
+ When /^I check if "(.*?)" has (read|write) access to "(.*?)"$/ do |login, access, repo|
25
+ @access_result = @user.check_access(Gritano::Repository.find_by_name(repo), access.to_sym)
26
+ end
27
+
28
+ Then /^I should see that the access is (denied|allowed)$/ do |result|
29
+ @expected_result = false if result == 'denied'
30
+ @expected_result = true if result == 'allowed'
31
+ @access_result.should be == @expected_result
32
+ end
33
+
34
+ Given /^I create a new repository called "(.*?)" to "(.*?)"$/ do |repo, login|
35
+ Gritano::User.find_by_login(login).create_repository(name: repo)
36
+ end
37
+
38
+ Then /^I should see that only "(.*?)" has access to "(.*?)"$/ do |login, repo|
39
+ repository = Gritano::Repository.find_by_name(repo)
40
+ user = Gritano::User.find_by_login(login)
41
+ user.check_access(repository, :read).should be_true
42
+ user.check_access(repository, :write).should be_true
43
+ Gritano::User.all.each do |u|
44
+ unless u.login == user.login
45
+ u.check_access(repository, :read).should be_false
46
+ u.check_access(repository, :write).should be_false
47
+ end
48
+ end
49
+ end
50
+
51
+ Given /^I (add|remove) "(.*?)" (read|write) access to "(.*?)"$/ do |op, user, permission, repo|
52
+ @user = Gritano::User.find_by_login(user)
53
+ @user.send("#{op}_access", Gritano::Repository.find_by_name(repo), permission.to_sym)
54
+ end
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'database_cleaner'
3
+ require 'database_cleaner/cucumber'
4
+ DatabaseCleaner.strategy = :truncation
5
+ rescue NameError
6
+ raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
7
+ end
8
+
9
+ Before do
10
+ DatabaseCleaner.start
11
+ end
12
+
13
+ After do |scenario|
14
+ DatabaseCleaner.clean
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "/features/"
4
+ add_filter "/spec/"
5
+ end
6
+
7
+ require 'bundler'
8
+ begin
9
+ Bundler.setup(:default, :development)
10
+ rescue Bundler::BundlerError => e
11
+ $stderr.puts e.message
12
+ $stderr.puts "Run `bundle install` to install missing gems"
13
+ exit e.status_code
14
+ end
15
+
16
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
17
+ require 'gritano'
18
+
19
+ require 'rspec/expectations'
20
+
21
+ require 'active_record'
22
+
23
+ Before do
24
+ ActiveRecord::Base.establish_connection(YAML::load(File.open('db/database.yml')))
25
+ end
data/lib/gritano.rb ADDED
@@ -0,0 +1,5 @@
1
+ ROOT_PATH = File.expand_path(File.dirname(__FILE__))
2
+
3
+ require File.join(ROOT_PATH, '/gritano/models')
4
+ require File.join(ROOT_PATH, '/gritano/console')
5
+ require File.join(ROOT_PATH, '/gritano/command')
@@ -0,0 +1,16 @@
1
+ module Gritano
2
+ class Command
3
+ def self.eval(cmd)
4
+ case cmd
5
+ when /^git-receive-pack/ then
6
+ return :write, "git-receive-pack", self.repo(cmd)
7
+ when /^git-upload-pack/ then
8
+ return :read, "git-upload-pack", self.repo(cmd)
9
+ end
10
+ end
11
+
12
+ def self.repo(cmd)
13
+ cmd.gsub(/^git-receive-pack/, '').gsub(/^git-upload-pack/, '').gsub("'", '').strip
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,119 @@
1
+ module Gritano
2
+ class Console
3
+
4
+ attr_accessor :repo_path
5
+ attr_accessor :ssh_path
6
+
7
+ def initialize
8
+ @repo_path = nil
9
+ @ssh_path = nil
10
+ end
11
+
12
+ def execute(argv)
13
+ send(argv[0..1].join('_').gsub('+', 'add_').gsub('-', 'remove_'), argv[2..-1])
14
+ end
15
+
16
+ def user_add(argv)
17
+ login, = argv
18
+ user = User.new(login: login)
19
+ return true if user.save
20
+ return false
21
+ end
22
+
23
+ def user_rm(argv)
24
+ login, = argv
25
+ user = User.find_by_login(login)
26
+ if user
27
+ if user.destroy
28
+ return true
29
+ end
30
+ end
31
+ return false
32
+ end
33
+
34
+ def repo_add(argv)
35
+ name, = argv
36
+ repo = Repository.new(name: name, path: @repo_path)
37
+ return true if repo.save
38
+ return false
39
+ end
40
+
41
+ def repo_rm(argv)
42
+ name, = argv
43
+ repo = Repository.find_by_name(name)
44
+ if repo
45
+ if repo.destroy
46
+ return true
47
+ end
48
+ end
49
+ return false
50
+ end
51
+
52
+ def repo_add_read(argv)
53
+ repo_name, login = argv
54
+ user = User.find_by_login(login)
55
+ repo = Repository.find_by_name(repo_name)
56
+ if repo and user
57
+ return user.add_access(repo, :read)
58
+ end
59
+ return false
60
+ end
61
+
62
+ def repo_add_write(argv)
63
+ repo_name, login = argv
64
+ user = User.find_by_login(login)
65
+ repo = Repository.find_by_name(repo_name)
66
+ if repo and user
67
+ return user.add_access(repo, :write)
68
+ end
69
+ return false
70
+ end
71
+
72
+ def repo_remove_read(argv)
73
+ repo_name, login = argv
74
+ user = User.find_by_login(login)
75
+ repo = Repository.find_by_name(repo_name)
76
+ if repo and user
77
+ return user.remove_access(repo, :read)
78
+ end
79
+ return false
80
+ end
81
+
82
+ def repo_remove_write(argv)
83
+ repo_name, login = argv
84
+ user = User.find_by_login(login)
85
+ repo = Repository.find_by_name(repo_name)
86
+ if repo and user
87
+ return user.remove_access(repo, :write)
88
+ end
89
+ return false
90
+ end
91
+
92
+ def user_add_key(argv)
93
+ login, key_name, key_file = argv
94
+ user = User.find_by_login(login)
95
+ if File.exist?(key_file)
96
+ if user
97
+ key = user.keys.create(name: key_name, key: File.open(key_file).readlines.join)
98
+ if key.valid?
99
+ File.open(File.join(@ssh_path, 'authorized_keys'), 'w').write(Key.authorized_keys)
100
+ return true
101
+ end
102
+ end
103
+ end
104
+ return false
105
+ end
106
+
107
+ def user_remove_key(argv)
108
+ login, key_name = argv
109
+ key = Key.where(name: key_name).includes(:user).where("users.login" => login).limit(1)[0]
110
+ if key
111
+ if key.destroy
112
+ File.open(File.join(@ssh_path, 'authorized_keys'), 'w').write(Key.authorized_keys)
113
+ return true
114
+ end
115
+ end
116
+ return false
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_record'
2
+ require 'grit'
3
+
4
+ require File.join(ROOT_PATH, 'gritano/models/user')
5
+ require File.join(ROOT_PATH, 'gritano/models/repository')
6
+ require File.join(ROOT_PATH, 'gritano/models/permission')
7
+ require File.join(ROOT_PATH, 'gritano/models/key')
@@ -0,0 +1,21 @@
1
+ module Gritano
2
+ class Key < ActiveRecord::Base
3
+ validates :name, :key, presence: true
4
+ validates :name, :uniqueness => { :scope => :user_id, :message => "should happen once per user" }
5
+
6
+ belongs_to :user
7
+
8
+ def self.authorized_keys
9
+ authorized_keys = ""
10
+ keys = Key.find(:all)
11
+ keys.each do |k|
12
+ user_key = k.key
13
+ unless k.key[-1] == "\n"
14
+ user_key = user_key + "\n"
15
+ end
16
+ authorized_keys += "command=\"gritano-check #{k.user.login}\" #{user_key}"
17
+ end
18
+ return authorized_keys
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module Gritano
2
+ class Permission < ActiveRecord::Base
3
+ belongs_to :user
4
+ belongs_to :repository
5
+
6
+ READ = 1
7
+ WRITE = 2
8
+
9
+ def add_access(access)
10
+ if access == :read
11
+ self.access = READ | (self.access || 0)
12
+ elsif access == :write
13
+ self.access = WRITE | (self.access || 0)
14
+ else
15
+ return false
16
+ end
17
+ return true
18
+ end
19
+
20
+ def remove_access(access)
21
+ if access == :read
22
+ self.access = (self.access || 0) & (~ READ)
23
+ elsif access == :write
24
+ self.access = (self.access || 0) & (~ WRITE)
25
+ else
26
+ return false
27
+ end
28
+ return true
29
+ end
30
+
31
+ def is(access)
32
+ if access == :read
33
+ return (self.access & READ) == READ
34
+ elsif access == :write
35
+ return (self.access & WRITE) == WRITE
36
+ end
37
+ end
38
+ end
39
+ end