leakferret 0.1.9 → 0.1.10
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/.yardopts +8 -0
- data/README.md +3 -0
- data/lib/leakferret/binary.rb +23 -2
- data/lib/leakferret/client.rb +42 -2
- data/lib/leakferret/error.rb +15 -1
- data/lib/leakferret/platform.rb +12 -0
- data/lib/leakferret/version.rb +7 -5
- data/lib/leakferret.rb +66 -12
- metadata +5 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e2273979e57b9e1e415bc9dc13be44e17382d0fb4dfde43b71e3e21d496f379b
|
|
4
|
+
data.tar.gz: 73bf40a88cdb03f4fa1d8cdb1ec852db6348d45439a88dad0a61501ff519977c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60465cdf6da291268f439dfb9864e15a54460eb93b9b974b4071e38399cc2eed78b1b5a506dad18cd63a6ab069819841dcaca9bd6cc6f0a20388fc3b654cc8de
|
|
7
|
+
data.tar.gz: 3e2de8a23b90a1fae5e5bb01d312e6495a3274908eb8c18c9169edb8e24fbc4a2b1e493e45976e25e8082dc0418777d1e724022d1ef1065c8f38170555098781
|
data/.yardopts
ADDED
data/README.md
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
> MCP-native secret scanner — verified findings, agent-applied rewrites.
|
|
8
8
|
|
|
9
|
+
[](https://rubygems.org/gems/leakferret)
|
|
10
|
+
[](https://github.com/leakferrethq/leakferret/blob/master/LICENSE.txt)
|
|
11
|
+
|
|
9
12
|
<p align="center">
|
|
10
13
|
<img src="https://raw.githubusercontent.com/leakferrethq/leakferret/master/brand/demo.gif" alt="leakferret finds, verifies, and rewrites a leaked secret" width="760">
|
|
11
14
|
</p>
|
data/lib/leakferret/binary.rb
CHANGED
|
@@ -14,6 +14,8 @@ module Leakferret
|
|
|
14
14
|
# throwaway temp dir, so anything written relative to the gem during
|
|
15
15
|
# `gem install` is discarded — the cache path sidesteps that entirely and
|
|
16
16
|
# also lets a plain `gem install` (no extension) work.
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
17
19
|
module Binary
|
|
18
20
|
# A binary vendored inside the gem, if one was shipped (normally empty).
|
|
19
21
|
BUNDLED_DIR = Pathname.new(__dir__).join('bin').freeze
|
|
@@ -40,6 +42,10 @@ module Leakferret
|
|
|
40
42
|
# 2. lib/leakferret/bin/ — a binary vendored in the gem
|
|
41
43
|
# 3. the per-version cache — fetched on a prior run or at install
|
|
42
44
|
# 4. download into the cache now
|
|
45
|
+
#
|
|
46
|
+
# @return [String] absolute path to the executable
|
|
47
|
+
# @raise [BinaryNotFoundError] if the override is missing, or the binary is
|
|
48
|
+
# absent and cannot be downloaded
|
|
43
49
|
def path
|
|
44
50
|
override = ENV['LEAKFERRET_BIN']
|
|
45
51
|
unless override.nil? || override.empty?
|
|
@@ -63,6 +69,8 @@ module Leakferret
|
|
|
63
69
|
|
|
64
70
|
# User-writable cache directory, namespaced by the binary version so a
|
|
65
71
|
# gem upgrade fetches a fresh binary instead of reusing a stale one.
|
|
72
|
+
#
|
|
73
|
+
# @return [Pathname] the per-version cache directory
|
|
66
74
|
def cache_dir
|
|
67
75
|
base =
|
|
68
76
|
if Platform.windows?
|
|
@@ -73,17 +81,25 @@ module Leakferret
|
|
|
73
81
|
Pathname.new(base).join('leakferret', BINARY_VERSION)
|
|
74
82
|
end
|
|
75
83
|
|
|
84
|
+
# @return [Pathname] the cached binary's full path for this platform
|
|
76
85
|
def cache_path
|
|
77
86
|
cache_dir.join(Platform.binary_name)
|
|
78
87
|
end
|
|
79
88
|
|
|
89
|
+
# @return [String] the GitHub release download URL for this platform's tarball
|
|
80
90
|
def download_url
|
|
81
91
|
'https://github.com/leakferrethq/leakferret/releases/download/' \
|
|
82
92
|
"v#{BINARY_VERSION}/leakferret-#{BINARY_VERSION}-#{Platform.triple}.tar.gz"
|
|
83
93
|
end
|
|
84
94
|
|
|
85
|
-
# Download and unpack the binary into the cache.
|
|
86
|
-
# the binary is already cached.
|
|
95
|
+
# Download, checksum-verify, and unpack the binary into the cache.
|
|
96
|
+
# Idempotent: a no-op when the binary is already cached. The SHA256 is
|
|
97
|
+
# checked against the pinned {CHECKSUMS} value before anything is written
|
|
98
|
+
# or marked executable, so a tampered or truncated asset is rejected.
|
|
99
|
+
#
|
|
100
|
+
# @return [String] absolute path to the cached binary
|
|
101
|
+
# @raise [BinaryNotFoundError] on an unknown platform, a checksum mismatch,
|
|
102
|
+
# or a binary missing from the downloaded archive
|
|
87
103
|
def ensure!
|
|
88
104
|
dest = cache_path
|
|
89
105
|
return dest.to_s if dest.file?
|
|
@@ -138,6 +154,11 @@ module Leakferret
|
|
|
138
154
|
dest.to_s
|
|
139
155
|
end
|
|
140
156
|
|
|
157
|
+
# Human-readable fallback message shown when the binary is absent and the
|
|
158
|
+
# automatic download failed.
|
|
159
|
+
#
|
|
160
|
+
# @param candidate [Pathname] the cache path the binary was expected at
|
|
161
|
+
# @return [String] multi-line manual-install instructions
|
|
141
162
|
def install_instructions(candidate)
|
|
142
163
|
<<~MSG
|
|
143
164
|
leakferret native binary not found, and the automatic download failed.
|
data/lib/leakferret/client.rb
CHANGED
|
@@ -4,18 +4,47 @@ require 'json'
|
|
|
4
4
|
require 'open3'
|
|
5
5
|
|
|
6
6
|
module Leakferret
|
|
7
|
-
# Thin shell-out wrapper. Each public method invokes
|
|
8
|
-
#
|
|
7
|
+
# Thin shell-out wrapper around the native binary. Each public method invokes
|
|
8
|
+
# `leakferret <verb> --format json` and parses the resulting array. You
|
|
9
|
+
# normally call the module-level {Leakferret.scan}, {Leakferret.verify}, and
|
|
10
|
+
# {Leakferret.rewrite} helpers instead of constructing this directly.
|
|
9
11
|
class Client
|
|
12
|
+
# Run a scan-only pass (regex pre-filter, offline).
|
|
13
|
+
#
|
|
14
|
+
# @param path [String] file or directory to scan
|
|
15
|
+
# @param exclude [Array<String>] glob(s) to skip
|
|
16
|
+
# @param only [Array<String>, String, nil] restrict the scan to these path(s)
|
|
17
|
+
# @param show_fixtures [Boolean] include catalog fixtures in the result
|
|
18
|
+
# @return [Array<Hash>] candidate finding hashes
|
|
19
|
+
# @raise [BinaryInvocationError] on an unexpected exit status
|
|
10
20
|
def scan(path, exclude: [], only: nil, show_fixtures: false)
|
|
11
21
|
run(['scan', path, '--format', 'json'] + format_flags(exclude:, only:, show_fixtures:))
|
|
12
22
|
end
|
|
13
23
|
|
|
24
|
+
# Run scan + classify + provider verification.
|
|
25
|
+
#
|
|
26
|
+
# @param path [String] file or directory to scan
|
|
27
|
+
# @param mode [String] verify mode passed to `--verify-mode`
|
|
28
|
+
# @param timeout [Integer] per-verifier timeout in seconds
|
|
29
|
+
# @option opts [Array<String>] :exclude glob(s) to skip
|
|
30
|
+
# @option opts [Array<String>, String] :only restrict the scan to these path(s)
|
|
31
|
+
# @option opts [Boolean] :show_fixtures include catalog fixtures
|
|
32
|
+
# @return [Array<Hash>] findings with verification and verdict filled in
|
|
33
|
+
# @raise [BinaryInvocationError] on an unexpected exit status
|
|
14
34
|
def verify(path, mode: 'best-effort', timeout: 10, **opts)
|
|
15
35
|
run(['verify', path, '--format', 'json', '--verify-mode', mode,
|
|
16
36
|
'--verifier-timeout-secs', timeout.to_s] + format_flags(**opts))
|
|
17
37
|
end
|
|
18
38
|
|
|
39
|
+
# Run scan + classify + rewrite proposal.
|
|
40
|
+
#
|
|
41
|
+
# @param path [String] file or directory to scan
|
|
42
|
+
# @param apply [Boolean] write the rewrites in place when true
|
|
43
|
+
# @param backend [String] rewrite backend (e.g. `env`, `doppler`)
|
|
44
|
+
# @option opts [Array<String>] :exclude glob(s) to skip
|
|
45
|
+
# @option opts [Array<String>, String] :only restrict the scan to these path(s)
|
|
46
|
+
# @return [Array<Hash>] findings, each with a proposed replacement
|
|
47
|
+
# @raise [BinaryInvocationError] on an unexpected exit status
|
|
19
48
|
def rewrite(path, apply: false, backend: 'env', **opts)
|
|
20
49
|
args = ['rewrite', path, '--format', 'json', '--backend', backend]
|
|
21
50
|
args << '--apply' if apply
|
|
@@ -24,6 +53,10 @@ module Leakferret
|
|
|
24
53
|
|
|
25
54
|
private
|
|
26
55
|
|
|
56
|
+
# Build the shared `--exclude` / `--only` / `--show-fixtures` flag list.
|
|
57
|
+
#
|
|
58
|
+
# @return [Array<String>] CLI flags
|
|
59
|
+
# @api private
|
|
27
60
|
def format_flags(exclude: [], only: nil, show_fixtures: false)
|
|
28
61
|
flags = []
|
|
29
62
|
Array(exclude).each { |g| flags.push('--exclude', g) }
|
|
@@ -32,6 +65,13 @@ module Leakferret
|
|
|
32
65
|
flags
|
|
33
66
|
end
|
|
34
67
|
|
|
68
|
+
# Invoke the binary and parse its JSON output. Exit codes 0 (clean) and 1
|
|
69
|
+
# (findings present) are both treated as success; any other status raises.
|
|
70
|
+
#
|
|
71
|
+
# @param args [Array<String>] argv passed to the binary
|
|
72
|
+
# @return [Array<Hash>] the parsed findings (empty array when output is blank)
|
|
73
|
+
# @raise [BinaryInvocationError] if the binary exits with a status other than 0 or 1
|
|
74
|
+
# @api private
|
|
35
75
|
def run(args)
|
|
36
76
|
out, err, status = Open3.capture3(Binary.path, *args)
|
|
37
77
|
unless [0, 1].include?(status.exitstatus)
|
data/lib/leakferret/error.rb
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Leakferret
|
|
4
|
+
# Base class for every error this gem raises. Rescue this to catch them all.
|
|
4
5
|
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Raised when the native binary cannot be located or downloaded (no pinned
|
|
8
|
+
# checksum for the platform, a failed download, or a bad `LEAKFERRET_BIN`).
|
|
5
9
|
class BinaryNotFoundError < Error; end
|
|
10
|
+
|
|
11
|
+
# Raised when the binary runs but exits with an unexpected status (anything
|
|
12
|
+
# other than 0 for a clean run or 1 for findings present).
|
|
6
13
|
class BinaryInvocationError < Error
|
|
7
|
-
|
|
14
|
+
# @return [Integer] the binary's process exit status
|
|
15
|
+
attr_reader :exit_status
|
|
16
|
+
|
|
17
|
+
# @return [String] captured standard error from the failed invocation
|
|
18
|
+
attr_reader :stderr
|
|
8
19
|
|
|
20
|
+
# @param message [String] human-readable error message
|
|
21
|
+
# @param exit_status [Integer] the binary's exit status
|
|
22
|
+
# @param stderr [String] captured standard error
|
|
9
23
|
def initialize(message, exit_status:, stderr:)
|
|
10
24
|
super(message)
|
|
11
25
|
@exit_status = exit_status
|
data/lib/leakferret/platform.rb
CHANGED
|
@@ -5,9 +5,18 @@ require 'rbconfig'
|
|
|
5
5
|
require_relative 'error'
|
|
6
6
|
|
|
7
7
|
module Leakferret
|
|
8
|
+
# Host detection for picking the right release asset. Maps the running
|
|
9
|
+
# Ruby's `RbConfig` host to a Rust target triple and binary name.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
8
12
|
module Platform
|
|
9
13
|
module_function
|
|
10
14
|
|
|
15
|
+
# The Rust target triple for the current host (e.g.
|
|
16
|
+
# `x86_64-unknown-linux-gnu`).
|
|
17
|
+
#
|
|
18
|
+
# @return [String] the target triple
|
|
19
|
+
# @raise [Error] on an unsupported CPU or OS, or aarch64-linux (no asset yet)
|
|
11
20
|
def triple
|
|
12
21
|
cpu = case RbConfig::CONFIG['host_cpu']
|
|
13
22
|
when /x86_64|amd64|x64/ then 'x86_64'
|
|
@@ -29,10 +38,13 @@ module Leakferret
|
|
|
29
38
|
end
|
|
30
39
|
end
|
|
31
40
|
|
|
41
|
+
# Executable name for the current OS.
|
|
42
|
+
# @return [String] `"leakferret.exe"` on Windows, otherwise `"leakferret"`
|
|
32
43
|
def binary_name
|
|
33
44
|
windows? ? 'leakferret.exe' : 'leakferret'
|
|
34
45
|
end
|
|
35
46
|
|
|
47
|
+
# @return [Integer, nil] truthy when the host OS is Windows
|
|
36
48
|
def windows?
|
|
37
49
|
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
|
38
50
|
end
|
data/lib/leakferret/version.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Leakferret
|
|
4
|
-
# The gem's own version.
|
|
5
|
-
|
|
4
|
+
# The gem's own version (what `gem install leakferret` resolves).
|
|
5
|
+
# @return [String]
|
|
6
|
+
VERSION = '0.1.10'
|
|
6
7
|
|
|
7
|
-
# The native binary release this gem downloads. Tracks the
|
|
8
|
-
# core release
|
|
9
|
-
# (e.g. a gem-only bugfix).
|
|
8
|
+
# The native binary release this gem downloads and runs. Tracks the
|
|
9
|
+
# leakferret core release and can move independently of {VERSION}
|
|
10
|
+
# (e.g. a gem-only bugfix keeps the same binary).
|
|
11
|
+
# @return [String]
|
|
10
12
|
BINARY_VERSION = '0.1.6'
|
|
11
13
|
end
|
data/lib/leakferret.rb
CHANGED
|
@@ -9,37 +9,91 @@ require 'leakferret/platform'
|
|
|
9
9
|
require 'leakferret/binary'
|
|
10
10
|
require 'leakferret/client'
|
|
11
11
|
|
|
12
|
-
# Ruby wrapper around the native `leakferret`
|
|
12
|
+
# Ruby wrapper around the native `leakferret` secret scanner.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
14
|
+
# leakferret finds hardcoded secrets, confirms which ones are actually live by
|
|
15
|
+
# calling the provider, and rewrites them to read from environment variables.
|
|
16
|
+
# This gem is a thin wrapper: the native binary (written in Rust) is downloaded
|
|
17
|
+
# once per platform on first use and cached, then each call shells out to it
|
|
18
|
+
# and parses the JSON it prints. The full secret value never leaves your
|
|
19
|
+
# machine; every finding carries only a redacted `first4...last4` preview.
|
|
20
|
+
#
|
|
21
|
+
# The three top-level methods mirror the CLI verbs and each return an array of
|
|
22
|
+
# finding hashes.
|
|
23
|
+
#
|
|
24
|
+
# @example Scan the working tree
|
|
25
|
+
# Leakferret.scan(".").each do |f|
|
|
26
|
+
# puts "#{f['path']}:#{f['line']} #{f['pattern']} [#{f['verdict']}]"
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# @example Fail a script on any live secret
|
|
30
|
+
# exit(1) unless Leakferret.verify(".", mode: "only-verified").empty?
|
|
31
|
+
#
|
|
32
|
+
# @see https://leakferret.com
|
|
33
|
+
# @see https://github.com/leakferrethq/leakferret
|
|
17
34
|
module Leakferret
|
|
18
35
|
class << self
|
|
19
|
-
# Scan a
|
|
36
|
+
# Scan a path for candidate secrets. This is the regex pre-filter only (no
|
|
37
|
+
# classification, no verification): the fastest, fully offline pass.
|
|
38
|
+
#
|
|
39
|
+
# @param path [String] file or directory to scan, relative or absolute
|
|
40
|
+
# @option opts [Array<String>] :exclude glob(s) to skip
|
|
41
|
+
# @option opts [Array<String>, String] :only restrict the scan to these path(s)
|
|
42
|
+
# @option opts [Boolean] :show_fixtures (false) include catalog fixtures in the result
|
|
43
|
+
# @return [Array<Hash>] candidate findings, each with `path`, `line`,
|
|
44
|
+
# `pattern`, `verdict`, and `match_redacted` keys
|
|
45
|
+
# @raise [BinaryInvocationError] if the binary exits with an unexpected status
|
|
46
|
+
# @example
|
|
47
|
+
# Leakferret.scan("app/", exclude: ["**/*_test.rb"])
|
|
20
48
|
def scan(path = '.', **opts)
|
|
21
49
|
Client.new.scan(path, **opts)
|
|
22
50
|
end
|
|
23
51
|
|
|
24
|
-
# Scan
|
|
25
|
-
#
|
|
52
|
+
# Scan, classify, and verify. Real findings are confirmed live with a
|
|
53
|
+
# harmless API call to the provider (AWS, GitHub, Stripe, and others), so
|
|
54
|
+
# this method makes outbound network requests.
|
|
55
|
+
#
|
|
56
|
+
# @param path [String] file or directory to scan
|
|
57
|
+
# @option opts [String] :mode ("best-effort") verify mode: `none`,
|
|
58
|
+
# `best-effort`, `only-verified`, or `ever-verified`
|
|
59
|
+
# @option opts [Integer] :timeout (10) per-verifier timeout in seconds
|
|
60
|
+
# @option opts [Array<String>] :exclude glob(s) to skip
|
|
61
|
+
# @option opts [Array<String>, String] :only restrict the scan to these path(s)
|
|
62
|
+
# @return [Array<Hash>] findings with `verdict` and `verification` filled in
|
|
63
|
+
# @raise [BinaryInvocationError] if the binary exits with an unexpected status
|
|
64
|
+
# @example Only return secrets confirmed live
|
|
65
|
+
# Leakferret.verify(".", mode: "only-verified")
|
|
26
66
|
def verify(path = '.', **opts)
|
|
27
67
|
Client.new.verify(path, **opts)
|
|
28
68
|
end
|
|
29
69
|
|
|
30
|
-
# Scan
|
|
31
|
-
# apply: true to write the rewrites in place.
|
|
70
|
+
# Scan, classify, and propose environment-variable rewrites for real
|
|
71
|
+
# findings. Pass `apply: true` to write the rewrites to disk in place.
|
|
72
|
+
#
|
|
73
|
+
# @param path [String] file or directory to scan
|
|
74
|
+
# @param apply [Boolean] when true, edit files in place; otherwise only
|
|
75
|
+
# propose the replacements
|
|
76
|
+
# @option opts [String] :backend ("env") rewrite backend, e.g. `env`, `doppler`
|
|
77
|
+
# @return [Array<Hash>] findings, each with a `replacement` proposal attached
|
|
78
|
+
# @raise [BinaryInvocationError] if the binary exits with an unexpected status
|
|
79
|
+
# @example Apply rewrites and seed Doppler
|
|
80
|
+
# Leakferret.rewrite(".", apply: true, backend: "doppler")
|
|
32
81
|
def rewrite(path = '.', apply: false, **opts)
|
|
33
82
|
Client.new.rewrite(path, apply: apply, **opts)
|
|
34
83
|
end
|
|
35
84
|
|
|
36
|
-
#
|
|
85
|
+
# Absolute path to the native binary, downloading it on first use.
|
|
86
|
+
#
|
|
87
|
+
# @return [String] absolute filesystem path to the `leakferret` executable
|
|
88
|
+
# @raise [BinaryNotFoundError] if the binary is missing and cannot be fetched
|
|
37
89
|
def binary_path
|
|
38
90
|
Binary.path
|
|
39
91
|
end
|
|
40
92
|
|
|
41
|
-
# Version reported by the bundled binary
|
|
42
|
-
# the gem version during pre-release.
|
|
93
|
+
# Version string reported by the bundled native binary. May differ from
|
|
94
|
+
# {VERSION} (the gem's own version) during pre-release; see {BINARY_VERSION}.
|
|
95
|
+
#
|
|
96
|
+
# @return [String] the binary's `--version` output, stripped
|
|
43
97
|
def binary_version
|
|
44
98
|
out, _err, _status = Open3.capture3(binary_path, '--version')
|
|
45
99
|
out.strip
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leakferret
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maria Khan
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: |
|
|
14
13
|
Context-aware secret scanning for Ruby projects. A thin wrapper around the
|
|
@@ -27,6 +26,7 @@ extensions:
|
|
|
27
26
|
- ext/leakferret/extconf.rb
|
|
28
27
|
extra_rdoc_files: []
|
|
29
28
|
files:
|
|
29
|
+
- ".yardopts"
|
|
30
30
|
- LICENSE.txt
|
|
31
31
|
- README.md
|
|
32
32
|
- exe/leakferret
|
|
@@ -44,8 +44,8 @@ metadata:
|
|
|
44
44
|
homepage_uri: https://github.com/leakferrethq/leakferret-ruby
|
|
45
45
|
source_code_uri: https://github.com/leakferrethq/leakferret-ruby
|
|
46
46
|
changelog_uri: https://github.com/leakferrethq/leakferret-ruby/blob/main/CHANGELOG.md
|
|
47
|
+
documentation_uri: https://rubydoc.info/gems/leakferret
|
|
47
48
|
rubygems_mfa_required: 'true'
|
|
48
|
-
post_install_message:
|
|
49
49
|
rdoc_options: []
|
|
50
50
|
require_paths:
|
|
51
51
|
- lib
|
|
@@ -60,8 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '0'
|
|
62
62
|
requirements: []
|
|
63
|
-
rubygems_version: 3.
|
|
64
|
-
signing_key:
|
|
63
|
+
rubygems_version: 3.6.9
|
|
65
64
|
specification_version: 4
|
|
66
65
|
summary: Context-aware secret detection (Ruby wrapper for the leakferret binary).
|
|
67
66
|
test_files: []
|