bastille 0.0.1
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/.gitignore +18 -0
- data/.travis.yml +12 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +96 -0
- data/Rakefile +1 -0
- data/bastille.gemspec +33 -0
- data/bin/bastille +7 -0
- data/config.ru +4 -0
- data/features/bastille.feature +15 -0
- data/features/support/aruba.rb +7 -0
- data/features/support/octokit.rb +69 -0
- data/features/support/server.rb +55 -0
- data/features/token.feature +71 -0
- data/features/vault.feature +79 -0
- data/lib/bastille.rb +2 -0
- data/lib/bastille/cli.rb +29 -0
- data/lib/bastille/cli/common.rb +19 -0
- data/lib/bastille/cli/token.rb +69 -0
- data/lib/bastille/cli/vault.rb +87 -0
- data/lib/bastille/client.rb +131 -0
- data/lib/bastille/hub.rb +32 -0
- data/lib/bastille/server.rb +120 -0
- data/lib/bastille/space.rb +31 -0
- data/lib/bastille/store.rb +123 -0
- data/lib/bastille/version.rb +3 -0
- metadata +271 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ryan Moran
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Bastille
|
2
|
+
Bastille is a fortress for your configuration. It is a way to store environment variables
|
3
|
+
that you can use in your application in a distributable and secure way. Bastille consists
|
4
|
+
of a few pieces, a server, a command-line client, and a Ruby API that give you the ability
|
5
|
+
to store and retrieve these environment variables in a simple fashion. Since Bastille encrypts
|
6
|
+
all of your configuration on the client-side, the server is a simple KV store backed up by Redis.
|
7
|
+
The server has no way of decrypting your keys, so they will remain secure should the server ever
|
8
|
+
be compromised.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'bastille'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install bastille
|
22
|
+
|
23
|
+
## CLI Usage
|
24
|
+
Here is what you can do with bastille:
|
25
|
+
|
26
|
+
$ bastille token new
|
27
|
+
This action will require you to authenticate with Github. Are you sure you want to generate a new token? yes
|
28
|
+
Github username: ryanmoran
|
29
|
+
Password:
|
30
|
+
Where is the bastille server?: http://localhost:9000
|
31
|
+
What should we call this bastille token? This can be anything: bastille
|
32
|
+
Your token has been generated and authorized with github. It is stored in ~/.bastille. <3
|
33
|
+
|
34
|
+
$ bastille token show
|
35
|
+
username : ryanmoran
|
36
|
+
token : abc123
|
37
|
+
domain : http://localhost:9000
|
38
|
+
name : bastille
|
39
|
+
key : sekret
|
40
|
+
|
41
|
+
$ bastille token validate
|
42
|
+
Validating your token with the bastille server...
|
43
|
+
Your token is valid. \m/
|
44
|
+
|
45
|
+
$ bastille vault list
|
46
|
+
ryanmoran:
|
47
|
+
optimis:
|
48
|
+
|
49
|
+
$ bastille vault set ryanmoran:bastille KEY=value
|
50
|
+
"KEY => value" has been added to the ryanmoran:bastille vault.
|
51
|
+
|
52
|
+
$ bastille vault list
|
53
|
+
ryanmoran:
|
54
|
+
bastille
|
55
|
+
optimis:
|
56
|
+
|
57
|
+
$ bastille vault get ryanmoran:bastille
|
58
|
+
KEY=value
|
59
|
+
|
60
|
+
$ bastille vault set ryanmoran:bastille RAILS_ENV=production
|
61
|
+
"RAILS_ENV => production" has been added to the ryanmoran:bastille vault.
|
62
|
+
|
63
|
+
$ bastille vault get ryanmoran:bastille
|
64
|
+
KEY=value
|
65
|
+
RAILS_ENV=production
|
66
|
+
|
67
|
+
$ bastille vault delete ryanmoran:bastille KEY
|
68
|
+
Are you sure you want to remove the KEY key from the ryanmoran:bastille vault? yes
|
69
|
+
OK!
|
70
|
+
|
71
|
+
$ bastille vault get ryanmoran:bastille
|
72
|
+
RAILS_ENV=production
|
73
|
+
|
74
|
+
$ bastille vault delete ryanmoran:bastille
|
75
|
+
Are you sure you want to delete the ryanmoran:bastille vault? yes
|
76
|
+
OK!
|
77
|
+
|
78
|
+
$ bastille vault list
|
79
|
+
ryanmoran:
|
80
|
+
optimis:
|
81
|
+
|
82
|
+
## Server
|
83
|
+
Hosting bastille is very simple. Here is an example `config.ru`.
|
84
|
+
|
85
|
+
require 'rubygems'
|
86
|
+
require 'bastille/server'
|
87
|
+
|
88
|
+
run Bastille::Server
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
1. Fork it
|
93
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
94
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
95
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
96
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bastille.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bastille/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'bastille'
|
8
|
+
gem.version = Bastille::VERSION
|
9
|
+
gem.authors = ['Ryan Moran']
|
10
|
+
gem.email = ['ryan.moran@gmail.com']
|
11
|
+
gem.description = %q{KV Storage As a Service, LOLz}
|
12
|
+
gem.summary = %q{KV Storage As a Service, LOLz}
|
13
|
+
gem.homepage = 'https://github.com/ryanmoran/bastille'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'gibberish'
|
21
|
+
gem.add_dependency 'highline'
|
22
|
+
gem.add_dependency 'httparty'
|
23
|
+
gem.add_dependency 'multi_json'
|
24
|
+
gem.add_dependency 'octokit'
|
25
|
+
gem.add_dependency 'redis'
|
26
|
+
gem.add_dependency 'redis-namespace'
|
27
|
+
gem.add_dependency 'sinatra'
|
28
|
+
gem.add_dependency 'thor'
|
29
|
+
|
30
|
+
gem.add_development_dependency 'aruba'
|
31
|
+
gem.add_development_dependency 'mimic'
|
32
|
+
gem.add_development_dependency 'fakeredis'
|
33
|
+
end
|
data/bin/bastille
ADDED
data/config.ru
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: Run `bastille`
|
2
|
+
In order to view the commands available for this application
|
3
|
+
As a user
|
4
|
+
I want to have the `bastille` command print a lising of the subcommands it supports
|
5
|
+
|
6
|
+
Scenario: list all subcommands
|
7
|
+
When I run `bastille`
|
8
|
+
Then the output should contain:
|
9
|
+
"""
|
10
|
+
Tasks:
|
11
|
+
bastille help [TASK] # Describe available tasks or one specific task
|
12
|
+
bastille token [TASK] # Provides the user with tools to create and view th...
|
13
|
+
bastille vault [TASK] # Provides access to your vaults
|
14
|
+
"""
|
15
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'mimic'
|
2
|
+
|
3
|
+
OCTOKIT_DOMAIN = 'http://localhost:9999'
|
4
|
+
|
5
|
+
Aruba.configure do |config|
|
6
|
+
config.before_cmd do |cmd|
|
7
|
+
set_env 'OCTOKIT_API_ENDPOINT', OCTOKIT_DOMAIN
|
8
|
+
set_env 'OCTOKIT_WEB_ENDPOINT', OCTOKIT_DOMAIN
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Mimic.mimic :port => 9999 do
|
13
|
+
set :rate_limit, 5000
|
14
|
+
set :raise_errors, Proc.new { false }
|
15
|
+
set :show_exceptions, false
|
16
|
+
|
17
|
+
before do
|
18
|
+
headers 'X-RateLimit-Limit' => settings.rate_limit.to_s,
|
19
|
+
'X-RateLimit-Remaining' => (settings.rate_limit - 1).to_s,
|
20
|
+
'Content-Type' => 'application/json'
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
settings.rate_limit = settings.rate_limit - 1
|
25
|
+
end
|
26
|
+
|
27
|
+
post '/authorizations' do
|
28
|
+
headers 'Location' => "#{OCTOKIT_DOMAIN}/authorizations/1"
|
29
|
+
body = {
|
30
|
+
'id' => 1,
|
31
|
+
'url' => "#{OCTOKIT_DOMAIN}/authorizations/1",
|
32
|
+
'scopes' => [
|
33
|
+
'public_repo'
|
34
|
+
],
|
35
|
+
'token' => 'abc123',
|
36
|
+
'app' => {
|
37
|
+
'url' => 'http://my-github-app.com',
|
38
|
+
'name' => 'my github app'
|
39
|
+
},
|
40
|
+
'note' => 'optional note',
|
41
|
+
'note_url' => 'http://optional/note/url',
|
42
|
+
'updated_at' => '2011-09-06T20:39:23Z',
|
43
|
+
'created_at' => '2011-09-06T17:26:27Z'
|
44
|
+
}.to_json
|
45
|
+
[201, headers, body]
|
46
|
+
end
|
47
|
+
|
48
|
+
get '/rate_limit' do
|
49
|
+
json = {
|
50
|
+
'rate' => {
|
51
|
+
'remaining' => (settings.rate_limit - 1),
|
52
|
+
'limit' => settings.rate_limit
|
53
|
+
}
|
54
|
+
}.to_json
|
55
|
+
[200, headers, json]
|
56
|
+
end
|
57
|
+
|
58
|
+
get '/user/orgs' do
|
59
|
+
json =[
|
60
|
+
{
|
61
|
+
'login' => 'something',
|
62
|
+
'id' => 2,
|
63
|
+
"url" => "#{OCTOKIT_DOMAIN}/orgs/something"
|
64
|
+
}
|
65
|
+
].to_json
|
66
|
+
[200, headers, json]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'bastille/server'
|
2
|
+
require 'fakeredis'
|
3
|
+
|
4
|
+
module TestServer
|
5
|
+
extend self
|
6
|
+
|
7
|
+
HOST = '127.0.0.1'
|
8
|
+
PORT = 9000
|
9
|
+
SERVER = 'webrick'
|
10
|
+
|
11
|
+
def run!
|
12
|
+
@thread = Thread.fork do
|
13
|
+
ENV['RACK_ENV'] = 'test'
|
14
|
+
Rack::Server.start :app => Bastille::Server.new,
|
15
|
+
:Host => HOST,
|
16
|
+
:Port => PORT,
|
17
|
+
:server => SERVER,
|
18
|
+
:Logger => WEBrick::Log::new("/dev/null", 7),
|
19
|
+
:AccessLog => []
|
20
|
+
end
|
21
|
+
wait_for_service
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop!
|
25
|
+
@thread.kill
|
26
|
+
end
|
27
|
+
|
28
|
+
def listening?
|
29
|
+
begin
|
30
|
+
socket = TCPSocket.new(HOST, PORT)
|
31
|
+
socket.close unless socket.nil?
|
32
|
+
true
|
33
|
+
rescue Errno::ECONNREFUSED, SocketError
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def wait_for_service(timeout = 5)
|
39
|
+
start_time = Time.now
|
40
|
+
|
41
|
+
until listening?
|
42
|
+
if timeout && (Time.now > (start_time + timeout))
|
43
|
+
raise SocketError.new("Socket did not open within #{timeout} seconds")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
at_exit do
|
50
|
+
TestServer.stop!
|
51
|
+
end
|
52
|
+
|
53
|
+
Octokit.api_endpoint = OCTOKIT_DOMAIN
|
54
|
+
Octokit.web_endpoint = OCTOKIT_DOMAIN
|
55
|
+
TestServer.run!
|
@@ -0,0 +1,71 @@
|
|
1
|
+
Feature: Run `bastille token`
|
2
|
+
In order to generate a valid token set for authenticating with the bastille server
|
3
|
+
As a user
|
4
|
+
I want to have the `bastille tokenize` command prompt me to authenticate with Github
|
5
|
+
And then serialize this the resulting OAuth token and data from Github
|
6
|
+
And store that data in a file at ~/.bastille
|
7
|
+
|
8
|
+
Scenario: list token subcommands
|
9
|
+
When I run `bastille token`
|
10
|
+
Then the output should contain:
|
11
|
+
"""
|
12
|
+
Tasks:
|
13
|
+
bastille token delete # Deletes the token
|
14
|
+
bastille token help [COMMAND] # Describe subcommands or one specific subco...
|
15
|
+
bastille token new # Generates an OAuth token from github to au...
|
16
|
+
bastille token show # Prints your credentials out to the command...
|
17
|
+
bastille token validate # Validates your token with the bastille ser...
|
18
|
+
"""
|
19
|
+
|
20
|
+
Scenario: run `token new`, `token validate`, and `token delete`
|
21
|
+
When I run `bastille token new` interactively
|
22
|
+
And I wait for output to contain "Are you sure you want to generate a new token?"
|
23
|
+
And I type "yes"
|
24
|
+
And I wait for output to contain "Github username:"
|
25
|
+
And I type "mister.happy"
|
26
|
+
And I wait for output to contain "Password:"
|
27
|
+
And I type "sekret"
|
28
|
+
And I wait for output to contain "Where is the bastille server?"
|
29
|
+
And I type "http://localhost:9000"
|
30
|
+
And I wait for output to contain "What should we call this bastille token?"
|
31
|
+
And I type "banana"
|
32
|
+
Then the output should not contain "The username and password entered do not match."
|
33
|
+
And the exit status should be 0
|
34
|
+
And a file named ".bastille" should exist
|
35
|
+
When I run `bastille token validate`
|
36
|
+
Then the output should contain:
|
37
|
+
"""
|
38
|
+
Validating your token with the bastille server...
|
39
|
+
Your token is valid. \m/
|
40
|
+
"""
|
41
|
+
When I run `bastille token delete` interactively
|
42
|
+
And I wait for output to contain "Are you sure you want to delete your token? This cannot be undone."
|
43
|
+
And I type "yes"
|
44
|
+
Then a file named ".bastille" should not exist
|
45
|
+
|
46
|
+
Scenario: run `token show`
|
47
|
+
Given a file named ".bastille" with:
|
48
|
+
"""
|
49
|
+
---
|
50
|
+
:username: mister.happy
|
51
|
+
:token: abc123
|
52
|
+
:domain: http://localhost:9000
|
53
|
+
:name: banana
|
54
|
+
"""
|
55
|
+
When I run `bastille token show`
|
56
|
+
Then the output should contain:
|
57
|
+
"""
|
58
|
+
domain : http://localhost:9000
|
59
|
+
name : banana
|
60
|
+
token : abc123
|
61
|
+
username : mister.happy
|
62
|
+
"""
|
63
|
+
Then the exit status should be 0
|
64
|
+
|
65
|
+
Scenario: decide not to generate new token
|
66
|
+
When I run `bastille token new` interactively
|
67
|
+
And I wait for output to contain "Are you sure you want to generate a new token?"
|
68
|
+
And I type "no"
|
69
|
+
Then the output should not contain "Github username"
|
70
|
+
And the exit status should be 0
|
71
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
Feature: Run `bastille tokenize`
|
2
|
+
In order to generate a valid token set for authenticating with the bastille server
|
3
|
+
As a user
|
4
|
+
I want to have the `bastille tokenize` command prompt me to authenticate with Github
|
5
|
+
And then serialize this the resulting OAuth token and data from Github
|
6
|
+
And store that data in a file at ~/.bastille
|
7
|
+
|
8
|
+
Background:
|
9
|
+
Given a file named ".bastille" with:
|
10
|
+
"""
|
11
|
+
---
|
12
|
+
:username: mister.happy
|
13
|
+
:token: abc123
|
14
|
+
:domain: http://localhost:9000
|
15
|
+
:name: banana
|
16
|
+
"""
|
17
|
+
|
18
|
+
Scenario: list subcommands
|
19
|
+
When I run `bastille vault`
|
20
|
+
Then the output should contain:
|
21
|
+
"""
|
22
|
+
Tasks:
|
23
|
+
bastille vault delete [SPACE]:[VAULT] (KEY) # Deletes the given vault...
|
24
|
+
bastille vault get [SPACE]:[VAULT] # Retrieves the contents ...
|
25
|
+
bastille vault help [COMMAND] # Describe subcommands or...
|
26
|
+
bastille vault list # List out existing vaults
|
27
|
+
bastille vault set [SPACE]:[VAULT] [KEY]=[VALUE] # Sets a key in the given...
|
28
|
+
"""
|
29
|
+
|
30
|
+
Scenario: list existing vaults
|
31
|
+
When I run `bastille vault list`
|
32
|
+
Then the output should contain:
|
33
|
+
"""
|
34
|
+
mister.happy:
|
35
|
+
something:
|
36
|
+
"""
|
37
|
+
|
38
|
+
Scenario: set and get a key from a vault, list vaults, delete vault
|
39
|
+
When I run `bastille vault set mister.happy:test RAILS_ENV=production`
|
40
|
+
Then the output should contain:
|
41
|
+
"""
|
42
|
+
"RAILS_ENV => production" has been added to the mister.happy:test vault.
|
43
|
+
"""
|
44
|
+
When I run `bastille vault get mister.happy:test`
|
45
|
+
Then the output should contain:
|
46
|
+
"""
|
47
|
+
RAILS_ENV=production
|
48
|
+
"""
|
49
|
+
When I run `bastille vault list`
|
50
|
+
Then the output should contain:
|
51
|
+
"""
|
52
|
+
mister.happy:
|
53
|
+
test
|
54
|
+
something:
|
55
|
+
"""
|
56
|
+
When I run `bastille vault delete mister.happy:test` interactively
|
57
|
+
And I wait for output to contain "Are you sure you want to delete the mister.happy:test vault?"
|
58
|
+
And I type "yes"
|
59
|
+
Then the output should contain "OK!"
|
60
|
+
When I run `bastille vault list`
|
61
|
+
Then the output should contain:
|
62
|
+
"""
|
63
|
+
mister.happy:
|
64
|
+
something:
|
65
|
+
"""
|
66
|
+
|
67
|
+
Scenario: try to get a vault you don't own
|
68
|
+
When I run `bastille vault get defunkt:resque`
|
69
|
+
Then the output should contain:
|
70
|
+
"""
|
71
|
+
Github is saying that you are not the owner of this space. Your spaces are ["mister.happy", "something"]
|
72
|
+
"""
|
73
|
+
|
74
|
+
Scenario: try to set a key you don't own
|
75
|
+
When I run `bastille vault set defunkt:resque BANANA=yummy`
|
76
|
+
Then the output should contain:
|
77
|
+
"""
|
78
|
+
Github is saying that you are not the owner of this space. Your spaces are ["mister.happy", "something"]
|
79
|
+
"""
|