hypershield 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -2
- data/LICENSE.txt +1 -1
- data/README.md +50 -27
- data/lib/generators/hypershield/install_generator.rb +13 -0
- data/lib/generators/hypershield/templates/initializer.rb +17 -0
- data/lib/hypershield.rb +39 -22
- data/lib/hypershield/version.rb +1 -1
- data/lib/tasks/hypershield.rake +10 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00b099534fb260d68ee6bbca50a415d78f82d7fe9024775d27b49ead519b1e52
|
4
|
+
data.tar.gz: 9bb5c84b8a84404f787f385c141fcfb862a41df9a76366f9d7dbb3c2b762c352
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 192f7058ccaf64897274e24ceffef1623fb192aae272f8930a5681ed7f6a07f0bb5161964b9eb2cc278415c35c70e831cede4a58d332f476610c44720533c436
|
7
|
+
data.tar.gz: 9268101459ca8d4f45c51e9be2dec4b60786c22d5c2fd69d83bd7d0f7174ac5f18ae3f308aeb949146cdb189563db8fe7fb3c7b20d569c21fe59927ea27e4ff2
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.2.0 (2020-03-12)
|
2
|
+
|
3
|
+
- Only update views that have changed
|
4
|
+
- Added `hypershield:refresh:dry_run` rake task
|
5
|
+
- Added `enabled` option
|
6
|
+
- Added generator
|
7
|
+
|
8
|
+
## 0.1.1 (2019-09-20)
|
2
9
|
|
3
10
|
- Fixed error with MySQL 8
|
4
11
|
- Added `log_sql` option
|
5
12
|
|
6
|
-
## 0.1.0
|
13
|
+
## 0.1.0 (2018-04-01)
|
7
14
|
|
8
15
|
- First release
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,39 @@ By default, it hides columns with:
|
|
19
19
|
|
20
20
|
Give database users access to these views instead of the original tables.
|
21
21
|
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
Add this line to your application’s Gemfile:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
gem 'hypershield'
|
28
|
+
```
|
29
|
+
|
30
|
+
And run:
|
31
|
+
|
32
|
+
```sh
|
33
|
+
rails generate hypershield:install
|
34
|
+
```
|
35
|
+
|
36
|
+
Hypershield is disabled in non-production environments by default. You can do a dry run with:
|
37
|
+
|
38
|
+
```sh
|
39
|
+
rake hypershield:refresh:dry_run
|
40
|
+
```
|
41
|
+
|
42
|
+
Next, set up your production database.
|
43
|
+
|
44
|
+
- [Postgres](#postgres)
|
45
|
+
- [MySQL](#mysql)
|
46
|
+
|
47
|
+
When that’s done, deploy to production and run:
|
48
|
+
|
49
|
+
```sh
|
50
|
+
rails db:migrate
|
51
|
+
```
|
52
|
+
|
53
|
+
The schema will automatically refresh.
|
54
|
+
|
22
55
|
## Database Setup
|
23
56
|
|
24
57
|
### Postgres
|
@@ -69,50 +102,32 @@ And connect as the user and make sure there’s no access the original tables
|
|
69
102
|
SELECT * FROM mydb.users LIMIT 1;
|
70
103
|
```
|
71
104
|
|
72
|
-
## Installation
|
73
|
-
|
74
|
-
Add this line to your application’s Gemfile:
|
75
|
-
|
76
|
-
```ruby
|
77
|
-
gem 'hypershield', group: :production
|
78
|
-
```
|
79
|
-
|
80
|
-
Refresh the schema
|
81
|
-
|
82
|
-
```sh
|
83
|
-
rake hypershield:refresh
|
84
|
-
```
|
85
|
-
|
86
|
-
And query away on your shielded views
|
87
|
-
|
88
|
-
```sql
|
89
|
-
SELECT * FROM users LIMIT 1;
|
90
|
-
```
|
91
|
-
|
92
|
-
When you run database migrations, the schema is automatically refreshed.
|
93
|
-
|
94
105
|
## Configuration
|
95
106
|
|
107
|
+
Set configuration in `config/initializers/hypershield.rb`.
|
108
|
+
|
96
109
|
Specify the schema to use and columns to show and hide
|
97
110
|
|
98
111
|
```ruby
|
99
112
|
Hypershield.schemas = {
|
100
113
|
hypershield: {
|
101
|
-
hide:
|
102
|
-
show:
|
114
|
+
hide: ["encrypted", "password", "token", "secret"],
|
115
|
+
show: ["ahoy_visits.visitor_token", "ahoy_visits.visit_token"]
|
103
116
|
}
|
104
117
|
}
|
105
118
|
```
|
106
119
|
|
107
|
-
Log Hypershield SQL statements
|
120
|
+
Log Hypershield SQL statements
|
108
121
|
|
109
122
|
```ruby
|
110
123
|
Hypershield.log_sql = true
|
111
124
|
```
|
112
125
|
|
113
|
-
|
126
|
+
Enable or disable Hypershield in an environment
|
114
127
|
|
115
|
-
|
128
|
+
```ruby
|
129
|
+
Hypershield.enabled = Rails.env.production?
|
130
|
+
```
|
116
131
|
|
117
132
|
## History
|
118
133
|
|
@@ -126,3 +141,11 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
126
141
|
- Fix bugs and [submit pull requests](https://github.com/ankane/hypershield/pulls)
|
127
142
|
- Write, clarify, or fix documentation
|
128
143
|
- Suggest or add new features
|
144
|
+
|
145
|
+
To get started with development:
|
146
|
+
|
147
|
+
```sh
|
148
|
+
git clone https://github.com/ankane/hypershield.git
|
149
|
+
cd hypershield
|
150
|
+
bundle install
|
151
|
+
```
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Hypershield
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.join(__dir__, "templates")
|
7
|
+
|
8
|
+
def create_initializer
|
9
|
+
template "initializer.rb", "config/initializers/hypershield.rb"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Specify which environments to use Hypershield
|
2
|
+
Hypershield.enabled = Rails.env.production?
|
3
|
+
|
4
|
+
# Specify the schema to use and columns to show and hide
|
5
|
+
Hypershield.schemas = {
|
6
|
+
hypershield: {
|
7
|
+
# columns to hide
|
8
|
+
# matches table.column
|
9
|
+
hide: ["encrypted", "password", "token", "secret"],
|
10
|
+
# overrides hide
|
11
|
+
# matches table.column
|
12
|
+
show: []
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
# Log SQL statements
|
17
|
+
Hypershield.log_sql = false
|
data/lib/hypershield.rb
CHANGED
@@ -10,15 +10,16 @@ require "hypershield/engine" if defined?(Rails)
|
|
10
10
|
|
11
11
|
module Hypershield
|
12
12
|
class << self
|
13
|
-
attr_accessor :
|
13
|
+
attr_accessor :enabled, :log_sql, :schemas
|
14
14
|
end
|
15
|
+
self.enabled = true
|
16
|
+
self.log_sql = false
|
15
17
|
self.schemas = {
|
16
18
|
hypershield: {
|
17
19
|
hide: %w(encrypted password token secret),
|
18
20
|
show: []
|
19
21
|
}
|
20
22
|
}
|
21
|
-
self.log_sql = false
|
22
23
|
|
23
24
|
class << self
|
24
25
|
def drop_view(view)
|
@@ -27,7 +28,7 @@ module Hypershield
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
def refresh
|
31
|
+
def refresh(dry_run: false)
|
31
32
|
if adapter_name =~ /sqlite/i
|
32
33
|
raise "Adapter not supported: #{adapter_name}"
|
33
34
|
end
|
@@ -39,31 +40,40 @@ module Hypershield
|
|
39
40
|
hide = config[:hide].to_a
|
40
41
|
show = config[:show].to_a
|
41
42
|
|
43
|
+
hypershield_tables = tables(schema)
|
44
|
+
|
42
45
|
tables.sort_by { |k, _| k }.each do |table, columns|
|
43
46
|
next if table == "pg_stat_statements"
|
44
47
|
|
45
|
-
statements << "DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(table)} CASCADE"
|
46
|
-
|
47
48
|
columns.reject! do |column|
|
48
49
|
hide.any? { |m| "#{table}.#{column}".include?(m) } &&
|
49
50
|
!show.any? { |m| "#{table}.#{column}".include?(m) }
|
50
51
|
end
|
51
52
|
|
53
|
+
# if the hypershield view has the same columns, assume it doesn't need updated
|
54
|
+
# this may not necessarily be true if someone manually updates the view
|
55
|
+
# we could check the view definition, but this is harder as the database normalizes it
|
56
|
+
next if hypershield_tables[table] == columns
|
57
|
+
|
58
|
+
statements << "DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(table)} CASCADE"
|
59
|
+
|
52
60
|
if columns.any?
|
53
61
|
statements << "CREATE VIEW #{quote_ident(schema)}.#{quote_ident(table)} AS SELECT #{columns.map { |c| quote_ident(c) }.join(", ")} FROM #{quote_ident(table)}"
|
54
62
|
end
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
58
|
-
if
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
66
|
+
if dry_run
|
67
|
+
if statements.any?
|
68
|
+
puts statements.map { |v| "#{v};" }.join("\n")
|
69
|
+
end
|
70
|
+
else
|
71
|
+
# originally this was performed in a transaction
|
72
|
+
# however, this appears to cause issues in certain situations - see #5 and #6
|
73
|
+
# this shouldn't be a huge issue now that we only update specific views
|
74
|
+
# we already drop views outside of the transaction when migrations are run
|
75
|
+
statements.each do |statement|
|
76
|
+
execute(statement)
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
@@ -97,14 +107,17 @@ module Hypershield
|
|
97
107
|
adapter_name =~ /mysql/i
|
98
108
|
end
|
99
109
|
|
100
|
-
def tables
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
110
|
+
def tables(schema = nil)
|
111
|
+
if schema
|
112
|
+
schema = quote(schema)
|
113
|
+
else
|
114
|
+
schema =
|
115
|
+
if mysql?
|
116
|
+
"database()"
|
117
|
+
else
|
118
|
+
"'public'"
|
119
|
+
end
|
120
|
+
end
|
108
121
|
|
109
122
|
query = <<-SQL
|
110
123
|
SELECT
|
@@ -133,6 +146,10 @@ module Hypershield
|
|
133
146
|
connection.execute(sql)
|
134
147
|
end
|
135
148
|
|
149
|
+
def quote(literal)
|
150
|
+
connection.quote(literal)
|
151
|
+
end
|
152
|
+
|
136
153
|
def quote_ident(ident)
|
137
154
|
connection.quote_table_name(ident.to_s)
|
138
155
|
end
|
data/lib/hypershield/version.rb
CHANGED
data/lib/tasks/hypershield.rake
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
namespace :hypershield do
|
2
2
|
task refresh: :environment do
|
3
|
+
abort "Hypershield is not enabled in this environment. Do a dry run with: rake hypershield:refresh:dry_run" unless Hypershield.enabled
|
4
|
+
|
3
5
|
$stderr.puts "[hypershield] Refreshing schemas"
|
4
6
|
Hypershield.refresh
|
5
7
|
$stderr.puts "[hypershield] Success!"
|
6
8
|
end
|
9
|
+
|
10
|
+
namespace :refresh do
|
11
|
+
task dry_run: :environment do
|
12
|
+
Hypershield.refresh(dry_run: true)
|
13
|
+
end
|
14
|
+
end
|
7
15
|
end
|
8
16
|
|
9
17
|
Rake::Task["db:migrate"].enhance do
|
10
|
-
Rake::Task["hypershield:refresh"].invoke
|
18
|
+
Rake::Task["hypershield:refresh"].invoke if Hypershield.enabled
|
11
19
|
end
|
12
20
|
|
13
21
|
Rake::Task["db:rollback"].enhance do
|
14
|
-
Rake::Task["hypershield:refresh"].invoke
|
22
|
+
Rake::Task["hypershield:refresh"].invoke if Hypershield.enabled
|
15
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hypershield
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -117,6 +117,8 @@ files:
|
|
117
117
|
- CHANGELOG.md
|
118
118
|
- LICENSE.txt
|
119
119
|
- README.md
|
120
|
+
- lib/generators/hypershield/install_generator.rb
|
121
|
+
- lib/generators/hypershield/templates/initializer.rb
|
120
122
|
- lib/hypershield.rb
|
121
123
|
- lib/hypershield/engine.rb
|
122
124
|
- lib/hypershield/migration.rb
|
@@ -141,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
143
|
- !ruby/object:Gem::Version
|
142
144
|
version: '0'
|
143
145
|
requirements: []
|
144
|
-
rubygems_version: 3.
|
146
|
+
rubygems_version: 3.1.2
|
145
147
|
signing_key:
|
146
148
|
specification_version: 4
|
147
149
|
summary: Shield sensitive data in Postgres and MySQL
|