safer_redis 1.0.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 +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +62 -0
- data/Rakefile +8 -0
- data/data/redis-doc/commands.json +17103 -0
- data/lib/safer_redis/command_doc.rb +61 -0
- data/lib/safer_redis/danger.rb +21 -0
- data/lib/safer_redis/interceptor.rb +13 -0
- data/lib/safer_redis/version.rb +5 -0
- data/lib/safer_redis.rb +35 -0
- data/safer_redis.gemspec +35 -0
- data/sig/safer_redis.rbs +4 -0
- metadata +91 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module SaferRedis
|
6
|
+
class CommandDoc
|
7
|
+
CATEGORY_SLOW = "@slow"
|
8
|
+
CATEGORY_DANGEROUS = "@dangerous"
|
9
|
+
|
10
|
+
# JSON-parsed Redis command data from the embedded copy of
|
11
|
+
# https://github.com/redis/redis-doc/blob/master/commands.json
|
12
|
+
def self.commands_data
|
13
|
+
@commands_data ||= begin
|
14
|
+
base_dir = File.absolute_path(File.join(__dir__, "..", ".."))
|
15
|
+
path = File.join(base_dir, "data", "redis-doc", "commands.json")
|
16
|
+
|
17
|
+
JSON.parse(File.read(path))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# The `redis` gem represents commands internally as an array with the command name
|
22
|
+
# as a lower-case symbol as the first item, e.g. [:del, "foo", "bar"]
|
23
|
+
def self.from_command_array(a)
|
24
|
+
new(a.first.to_s.upcase)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(name)
|
28
|
+
@name = name
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :name
|
32
|
+
|
33
|
+
def url
|
34
|
+
slug = name.downcase.gsub(" ", "-")
|
35
|
+
|
36
|
+
"https://redis.io/commands/#{slug}/"
|
37
|
+
end
|
38
|
+
|
39
|
+
def slow?
|
40
|
+
acl_categories.include?(CATEGORY_SLOW)
|
41
|
+
end
|
42
|
+
|
43
|
+
def dangerous?
|
44
|
+
acl_categories.include?(CATEGORY_DANGEROUS)
|
45
|
+
end
|
46
|
+
|
47
|
+
def acl_categories
|
48
|
+
command.fetch("acl_categories", [])
|
49
|
+
end
|
50
|
+
|
51
|
+
def complexity
|
52
|
+
command.fetch("complexity", nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def command
|
58
|
+
@command ||= (self.class.commands_data[name] || {})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SaferRedis
|
4
|
+
class Danger < Error
|
5
|
+
def initialize(doc)
|
6
|
+
message = <<~MESSAGE
|
7
|
+
The #{doc.name} Redis command might be dangerous.
|
8
|
+
|
9
|
+
#{doc.url}
|
10
|
+
|
11
|
+
ACL categories: #{doc.acl_categories.join(" ")}
|
12
|
+
|
13
|
+
Complexity: #{doc.complexity}
|
14
|
+
|
15
|
+
If you're sure this is okay, you can try again within `SaferRedis.really { ... }`
|
16
|
+
MESSAGE
|
17
|
+
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/safer_redis.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zeitwerk"
|
4
|
+
Zeitwerk::Loader.for_gem.setup
|
5
|
+
|
6
|
+
module SaferRedis
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
def self.activate!(klass: Redis)
|
10
|
+
klass.prepend(SaferRedis::Interceptor)
|
11
|
+
@active = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.deactivate!
|
15
|
+
@active = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.active?
|
19
|
+
defined?(@active) ? @active : false
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.really
|
23
|
+
was = active?
|
24
|
+
@active = false
|
25
|
+
yield
|
26
|
+
ensure
|
27
|
+
@active = was
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.assess!(doc)
|
31
|
+
if doc.dangerous? || doc.slow?
|
32
|
+
raise SaferRedis::Danger.new(doc)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/safer_redis.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/safer_redis/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "safer_redis"
|
7
|
+
spec.version = SaferRedis::VERSION
|
8
|
+
spec.authors = ["Paul Annesley"]
|
9
|
+
spec.email = ["paul@annesley.cc"]
|
10
|
+
|
11
|
+
spec.summary = "Catch unsafe Redis commands in production"
|
12
|
+
spec.description = "SaferRedis warns you before letting through commands that could impact production availability by being marked `@slow` or `@dangerous` in the Redis documentation"
|
13
|
+
spec.homepage = "https://github.com/buildkite/safer_redis"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/buildkite/safer_redis"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/buildkite/safer_redis/blob/main/CHANGELOG.md"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
# The only strategy implemented so far is intercepting the private Redis#send_command method,
|
31
|
+
# which was introduced in v4.6.0 via https://github.com/redis/redis-rb/pull/1058 and remains
|
32
|
+
# in the latest release (v5.0.5) at time of writing.
|
33
|
+
spec.add_dependency "redis", ">= 4.6.0"
|
34
|
+
spec.add_dependency "zeitwerk"
|
35
|
+
end
|
data/sig/safer_redis.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: safer_redis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Annesley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.6.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: zeitwerk
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: SaferRedis warns you before letting through commands that could impact
|
42
|
+
production availability by being marked `@slow` or `@dangerous` in the Redis documentation
|
43
|
+
email:
|
44
|
+
- paul@annesley.cc
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".rspec"
|
50
|
+
- CHANGELOG.md
|
51
|
+
- CODE_OF_CONDUCT.md
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
54
|
+
- LICENSE.txt
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- data/redis-doc/commands.json
|
58
|
+
- lib/safer_redis.rb
|
59
|
+
- lib/safer_redis/command_doc.rb
|
60
|
+
- lib/safer_redis/danger.rb
|
61
|
+
- lib/safer_redis/interceptor.rb
|
62
|
+
- lib/safer_redis/version.rb
|
63
|
+
- safer_redis.gemspec
|
64
|
+
- sig/safer_redis.rbs
|
65
|
+
homepage: https://github.com/buildkite/safer_redis
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata:
|
69
|
+
homepage_uri: https://github.com/buildkite/safer_redis
|
70
|
+
source_code_uri: https://github.com/buildkite/safer_redis
|
71
|
+
changelog_uri: https://github.com/buildkite/safer_redis/blob/main/CHANGELOG.md
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.6.0
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubygems_version: 3.1.6
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Catch unsafe Redis commands in production
|
91
|
+
test_files: []
|