secretsweep 0.1.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30c1e981a0b2a61d6e3a3a27310bf9452bd73f9514b2ed157db4cdf1a71f9f2a
4
- data.tar.gz: ddd1724fb438ca24e233bd0fd6880eb9e9bcc1e5aab2bb3914148f958eddd211
3
+ metadata.gz: 8c6eacc4e23dcefebe23dac26989b385da1309472b664a5ee740ec168a935042
4
+ data.tar.gz: 250156cd89f9de57d6a426afe0838bbae9edecae1f9783c3627836448e959c5f
5
5
  SHA512:
6
- metadata.gz: 145620e757aba1463d59a4133abe25a86be73130bb2ac4f695f4f904103f80d871940d29cd694bdd1909df5ea031a7468bad3861d82f1e3ab68ef2388b4949a7
7
- data.tar.gz: 93aab1bc3fb8a6e94692c28cde906af94c6d42f59333f165e336e3075dea45adcdc74d204e4aadb91a37e595d7aa4580bbea545ef6cc721f08b00062a3686214
6
+ metadata.gz: b1970d66615a8ad00bacb071ecf6627733b5b24c2ce9552343f7c0c889317835f74a16a53ed22085a75be1472fdfe25fb32f389c25c61e91e2bfb1c9f6361e5e
7
+ data.tar.gz: dba748c56fb40b5afb8739d4e994631a85fac2e1ad8b497a123041289537f885c19d4c74e76007918115775cf079c283679a9f9b07c427a5544e8f7d6f4937a4
data/CHANGELOG.md ADDED
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.2] - 2026-09-09
9
+
10
+ ### Added
11
+
12
+ - GitHub Actions CI workflow (`.github/workflows/ci.yml`) running RSpec, Rubocop, and RBS signature validation on every push and pull request, across Ruby 3.0–3.3.
13
+ - `metadata` in the gemspec (`homepage_uri`, `source_code_uri`, `changelog_uri`, `bug_tracker_uri`) for better discoverability on RubyGems.org.
14
+
15
+ ### Fixed
16
+
17
+ - Gemspec development dependencies corrected: `rspec` and `rbs` replace the stale `minitest` reference left over from the pre-migration scaffold.
18
+ - `sig/**/*.rbs` and `CHANGELOG.md` are now actually included in the packaged gem — previous versions omitted the type signatures entirely despite them existing in the repo.
19
+
20
+ ## [0.1.1] - 2026-09-07
21
+
22
+ ### Fixed
23
+
24
+ - Corrected the homepage/source code URL in `secretsweep.gemspec` to point to the actual GitHub repository.
25
+
26
+ ## [0.1.0] - 2026-09-05
27
+
28
+ ### Added
29
+
30
+ - Core secret-detection engine combining two independent methods:
31
+ - Pattern matching (`PatternRegistry`) for known formats: AWS keys, GitHub/Slack/Stripe tokens, PEM private key headers, Google API keys, JWTs, and a generic key-assignment heuristic.
32
+ - Shannon entropy analysis (`Entropy`) to catch high-entropy strings that don't match any known format.
33
+ - `FileScanner` — scans a directory tree for secrets in the current working tree, skipping binary files and common noise directories (`node_modules`, `.git`, `vendor`, etc.).
34
+ - `GitHistoryScanner` — scans full git history across all branches (`git log -p --all`) to catch secrets that were committed and later removed but are still readable in history.
35
+ - `IgnoreList` / `.secretsweepignore` support with two levels of granularity: path globs (skip a directory entirely) and per-finding fingerprints (allowlist one confirmed false positive without silencing the whole rule).
36
+ - Stable, content-based fingerprinting (`Finding#fingerprint`) so ignore-list entries survive unrelated edits to the same file.
37
+ - CLI (`bin/secretsweep`) with `--history`, `--format [text|json]`, and `--ignore-file` flags, and meaningful exit codes (0 clean / 1 secrets found / 2 error).
38
+ - Text and JSON report output via `Reporter`.
39
+ - Full RSpec test suite (37 examples), including an end-to-end test that creates a real throwaway git repo, commits a secret, removes it in a later commit, and verifies history scanning still finds it.
40
+ - RBS type signatures for the full public API.
41
+ - Zero runtime dependencies — pure Ruby standard library (`optparse`, `json`, `open3`, `digest`, `pathname`, `find`).
42
+
43
+ ### Known limitations
44
+
45
+ - The same secret can be reported twice (once per detection method) if it satisfies both pattern matching and entropy analysis. This is intentional — see README for reasoning.
46
+ - Entropy thresholds are heuristic, not yet validated against a large real-world sample.
data/README.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  **A dependency-free Ruby CLI that scans files and full git history for leaked secrets — API keys, tokens, private keys — using known-format patterns plus entropy analysis for everything else.**
4
4
 
5
+ ![CI](https://github.com/Majd2404/SecretSweep/actions/workflows/ci.yml/badge.svg)
6
+ ![Gem Version](https://badge.fury.io/rb/secretsweep.svg)
5
7
  ![Ruby](https://img.shields.io/badge/Ruby-3.0%2B-CC342D?logo=ruby&logoColor=white)
6
8
  ![Dependencies](https://img.shields.io/badge/runtime_deps-zero-brightgreen)
7
- ![Tests](https://img.shields.io/badge/tests-36_passing-brightgreen)
8
9
  ![License](https://img.shields.io/badge/license-MIT-blue)
9
10
 
10
11
  ## Why this exists
@@ -34,12 +35,20 @@ rather than "fixed."
34
35
 
35
36
  ## Installation
36
37
 
38
+ SecretSweep is published on RubyGems:
39
+
40
+ ```bash
41
+ gem install secretsweep
42
+ ```
43
+
44
+ Or from source:
45
+
37
46
  ```bash
38
47
  git clone https://github.com/Majd2404/SecretSweep.git
39
48
  cd SecretSweep
40
49
  bundle install
41
50
  gem build secretsweep.gemspec
42
- gem install ./secretsweep-0.1.0.gem
51
+ gem install ./secretsweep-*.gem
43
52
  ```
44
53
 
45
54
  ## Usage
@@ -84,7 +93,7 @@ directory you're scanning. Two kinds of entries:
84
93
 
85
94
  ```
86
95
  # Skip scanning these paths entirely
87
- test/fixtures/**
96
+ spec/fixtures/**
88
97
 
89
98
  # Allowlist ONE specific confirmed false positive by its fingerprint
90
99
  # (does NOT silence the whole rule — just that exact file+type+snippet)
@@ -120,12 +129,9 @@ a1b2c3d4e5f6
120
129
  GitHub token is both a recognized format *and* high-entropy). This is
121
130
  left as-is rather than deduplicated across types: two independent
122
131
  detectors agreeing is a legitimate confidence signal, and collapsing
123
- it would hide which detector(s) actually fired. See
124
- `docs/COMMIT_PLAN.md` for a possible future confidence-scoring
125
- approach instead of outright deduplication.
126
- - **Entropy thresholds are heuristic**, not universally tuned — see
127
- `docs/COMMIT_PLAN.md` Week 2 for the plan to validate them against a
128
- larger real-world sample.
132
+ it would hide which detector(s) actually fired.
133
+ - **Entropy thresholds are heuristic**, not yet validated against a
134
+ large real-world sample.
129
135
  - **History scanning reads the full diff of every commit on every
130
136
  branch** (`git log -p --all`) — this is thorough but can be slow on
131
137
  very large, long-lived repositories. No pagination/depth limit yet.
@@ -133,23 +139,28 @@ a1b2c3d4e5f6
133
139
  ## Testing
134
140
 
135
141
  ```bash
136
- rake test
142
+ bundle exec rspec
137
143
  ```
138
144
 
139
- 36 tests, zero dependencies beyond Ruby's bundled Minitest — no network
140
- access or external services required to run the suite. Includes a real
141
- integration test (`git_history_scanner_test.rb`) that creates an actual
142
- throwaway git repo, commits a secret, removes it in a later commit, and
143
- verifies `--history` still catches it.
145
+ 37 RSpec examples, including a real end-to-end test
146
+ (`git_history_scanner_spec.rb`) that creates an actual throwaway git
147
+ repo, commits a secret, removes it in a later commit, and verifies
148
+ `--history` still catches it.
149
+
150
+ Type signatures are validated separately:
144
151
 
145
- ## Roadmap
152
+ ```bash
153
+ bundle exec rbs -I sig validate
154
+ ```
146
155
 
147
- See [`docs/COMMIT_PLAN.md`](docs/COMMIT_PLAN.md) for the week-by-week build-out plan.
156
+ Both run automatically on every push via GitHub Actions across Ruby
157
+ 3.0–3.3 — see the CI badge above.
148
158
 
149
159
  ## Tech stack
150
160
 
151
- Ruby 3.0+, standard library only. Minitest + Rake for testing.
161
+ Ruby 3.0+, standard library only. RSpec for testing, RBS for type
162
+ signatures, Rubocop for style, GitHub Actions for CI.
152
163
 
153
164
  ## License
154
165
 
155
- MIT — see [LICENSE](LICENSE).
166
+ MIT — see [LICENSE](LICENSE).
@@ -18,28 +18,33 @@ module SecretSweep
18
18
 
19
19
  def run(argv)
20
20
  options = parse(argv)
21
- path = options[:path] || "."
22
-
23
- scanner = Scanner.new(path, ignore_file: options[:ignore_file], include_history: options[:history])
24
- findings = scanner.run
21
+ findings = scan(options)
25
22
 
26
23
  puts Reporter.render(findings, format: options[:format])
27
-
28
24
  findings.empty? ? EXIT_CLEAN : EXIT_SECRETS_FOUND
29
- rescue GitHistoryScanner::NotAGitRepoError => e
30
- warn "Error: #{e.message}"
31
- EXIT_ERROR
32
- rescue Errno::ENOENT => e
25
+ rescue GitHistoryScanner::NotAGitRepoError, Errno::ENOENT => e
33
26
  warn "Error: #{e.message}"
34
27
  EXIT_ERROR
35
28
  end
36
29
 
37
30
  private
38
31
 
32
+ def scan(options)
33
+ path = options[:path] || "."
34
+ Scanner.new(path, ignore_file: options[:ignore_file], include_history: options[:history]).run
35
+ end
36
+
39
37
  def parse(argv)
40
38
  options = { format: :text, history: false }
39
+ parser = build_option_parser(options)
41
40
 
42
- parser = OptionParser.new do |opts|
41
+ remaining = parser.parse(argv)
42
+ options[:path] = remaining.first
43
+ options
44
+ end
45
+
46
+ def build_option_parser(options)
47
+ OptionParser.new do |opts|
43
48
  opts.banner = "Usage: secretsweep [path] [options]"
44
49
 
45
50
  opts.on("--history", "Also scan full git history, not just the working tree") do
@@ -64,10 +69,6 @@ module SecretSweep
64
69
  exit(0)
65
70
  end
66
71
  end
67
-
68
- remaining = parser.parse(argv)
69
- options[:path] = remaining.first
70
- options
71
72
  end
72
73
  end
73
74
  end
@@ -50,17 +50,7 @@ module SecretSweep
50
50
  findings = []
51
51
 
52
52
  File.foreach(path).with_index(1) do |line, line_number|
53
- # Guard per-line, not per-file: one malformed line (bad encoding,
54
- # unexpected control characters) should never discard matches
55
- # already found earlier in the same file.
56
- begin
57
- PatternRegistry.scan_line(line).each do |match|
58
- findings << Finding.new(relative_path, line_number, match[:type], match[:snippet], nil)
59
- end
60
- check_high_entropy_tokens(line, relative_path, line_number, findings)
61
- rescue ArgumentError, Encoding::InvalidByteSequenceError
62
- next
63
- end
53
+ findings.concat(scan_line_safely(line, relative_path, line_number))
64
54
  end
65
55
 
66
56
  findings
@@ -70,13 +60,26 @@ module SecretSweep
70
60
  findings
71
61
  end
72
62
 
63
+ # Guards per-line, not per-file: one malformed line (bad encoding,
64
+ # unexpected control characters) should never discard matches already
65
+ # found earlier in the same file.
66
+ def scan_line_safely(line, relative_path, line_number)
67
+ findings = PatternRegistry.scan_line(line).map do |match|
68
+ Finding.new(relative_path, line_number, match[:type], match[:snippet], nil)
69
+ end
70
+ check_high_entropy_tokens(line, relative_path, line_number, findings)
71
+ findings
72
+ rescue ArgumentError, Encoding::InvalidByteSequenceError
73
+ []
74
+ end
75
+
73
76
  # Beyond known patterns, flag bare high-entropy tokens assigned to a
74
77
  # variable — catches secrets in formats we don't have a specific regex
75
78
  # for yet (a new provider's token format, an internal auth token).
76
79
  def check_high_entropy_tokens(line, relative_path, line_number, findings)
77
80
  return unless line.match?(/=|:/)
78
81
 
79
- line.scan(/['"]([A-Za-z0-9\/+_-]{20,})['"]/) do |match|
82
+ line.scan(%r{['"]([A-Za-z0-9/+_-]{20,})['"]}) do |match|
80
83
  token = match[0]
81
84
  next unless Entropy.high_entropy?(token)
82
85
 
@@ -10,6 +10,16 @@ module SecretSweep
10
10
  class GitHistoryScanner
11
11
  class NotAGitRepoError < StandardError; end
12
12
 
13
+ # Tracks the small bit of state needed while walking `git log -p`
14
+ # output line by line: which commit and file we're currently inside,
15
+ # plus the findings accumulated so far. Extracted from Scanner so
16
+ # #scan itself stays a short, readable dispatch loop.
17
+ State = Struct.new(:commit, :file, :findings) do
18
+ def initialize
19
+ super(nil, nil, [])
20
+ end
21
+ end
22
+
13
23
  def initialize(repo_path, ignore_list: IgnoreList.new([], []))
14
24
  @repo_path = repo_path
15
25
  @ignore_list = ignore_list
@@ -18,41 +28,43 @@ module SecretSweep
18
28
  def scan
19
29
  raise NotAGitRepoError, "#{@repo_path} is not a git repository" unless git_repo?
20
30
 
21
- findings = []
22
- current_file = nil
23
- current_commit = nil
24
-
25
- each_diff_line do |line|
26
- if line.start_with?("commit ")
27
- current_commit = line.split(" ", 2).last[0, 12]
28
- elsif line.start_with?("+++ b/")
29
- current_file = line.sub("+++ b/", "").strip
30
- elsif line.start_with?("+") && !line.start_with?("+++")
31
- content = line[1..]
32
- next if current_file.nil? || @ignore_list.path_ignored?(current_file)
33
-
34
- PatternRegistry.scan_line(content).each do |match|
35
- findings << Finding.new(current_file, nil, match[:type], match[:snippet], current_commit)
36
- end
37
- end
38
- end
39
-
40
- findings
31
+ state = State.new
32
+ each_diff_line { |line| process_line(line, state) }
33
+ state.findings
41
34
  end
42
35
 
43
36
  private
44
37
 
38
+ def process_line(line, state)
39
+ case line
40
+ when /\Acommit /
41
+ state.commit = line.split(" ", 2).last[0, 12]
42
+ when %r{\A\+\+\+ b/}
43
+ state.file = line.sub("+++ b/", "").strip
44
+ when /\A\+(?!\+\+)/
45
+ record_added_line(line[1..], state)
46
+ end
47
+ end
48
+
49
+ def record_added_line(content, state)
50
+ return if state.file.nil? || @ignore_list.path_ignored?(state.file)
51
+
52
+ PatternRegistry.scan_line(content).each do |match|
53
+ state.findings << Finding.new(state.file, nil, match[:type], match[:snippet], state.commit)
54
+ end
55
+ end
56
+
45
57
  def git_repo?
46
58
  _out, status = Open3.capture2("git", "-C", @repo_path, "rev-parse", "--is-inside-work-tree")
47
59
  status.success?
48
60
  end
49
61
 
50
- def each_diff_line
62
+ def each_diff_line(&block)
51
63
  # -p: show patches (actual added/removed lines), --all: every branch,
52
64
  # not just the currently checked-out one — a secret on a stale
53
65
  # feature branch is still a leak.
54
66
  Open3.popen2("git", "-C", @repo_path, "log", "-p", "--all", "--no-color") do |_in, out, _thread|
55
- out.each_line { |line| yield line }
67
+ out.each_line(&block)
56
68
  end
57
69
  end
58
70
  end
@@ -13,22 +13,24 @@ module SecretSweep
13
13
  def self.load(path)
14
14
  return new([], []) unless path && File.exist?(path)
15
15
 
16
+ globs, fingerprints = partition_lines(File.readlines(path))
17
+ new(globs, fingerprints)
18
+ end
19
+
20
+ def self.partition_lines(raw_lines)
16
21
  globs = []
17
22
  fingerprints = []
18
23
 
19
- File.readlines(path).each do |raw_line|
24
+ raw_lines.each do |raw_line|
20
25
  line = raw_line.strip
21
26
  next if line.empty? || line.start_with?("#")
22
27
 
23
- if line.match?(/\A[0-9a-f]{12}\z/)
24
- fingerprints << line
25
- else
26
- globs << line
27
- end
28
+ line.match?(/\A[0-9a-f]{12}\z/) ? fingerprints << line : globs << line
28
29
  end
29
30
 
30
- new(globs, fingerprints)
31
+ [globs, fingerprints]
31
32
  end
33
+ private_class_method :partition_lines
32
34
 
33
35
  def initialize(path_globs, fingerprints)
34
36
  @path_globs = path_globs
@@ -8,7 +8,7 @@ module SecretSweep
8
8
  module PatternRegistry
9
9
  PATTERNS = {
10
10
  "aws_access_key_id" => /\bAKIA[0-9A-Z]{16}\b/,
11
- "aws_secret_access_key" => /\baws(.{0,20})?(secret|access)[_-]?key\b.{0,5}['"]([A-Za-z0-9\/+=]{40})['"]/i,
11
+ "aws_secret_access_key" => %r{\baws(.{0,20})?(secret|access)[_-]?key\b.{0,5}['"]([A-Za-z0-9/+=]{40})['"]}i,
12
12
  "github_token" => /\bgh[pousr]_[A-Za-z0-9]{36,}\b/,
13
13
  "slack_token" => /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/,
14
14
  "stripe_live_key" => /\bsk_live_[A-Za-z0-9]{24,}\b/,
@@ -16,7 +16,7 @@ module SecretSweep
16
16
  "generic_private_key" => /-----BEGIN (RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/,
17
17
  "google_api_key" => /\bAIza[0-9A-Za-z\-_]{35}\b/,
18
18
  "generic_api_key_assignment" =>
19
- /\b(api[_-]?key|secret|token|password|passwd|pwd)\b\s*[:=]\s*['"][A-Za-z0-9\/+=_\-]{16,}['"]/i,
19
+ %r{\b(api[_-]?key|secret|token|password|passwd|pwd)\b\s*[:=]\s*['"][A-Za-z0-9/+=_-]{16,}['"]}i,
20
20
  "jwt" => /\bey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/
21
21
  }.freeze
22
22
 
@@ -15,9 +15,7 @@ module SecretSweep
15
15
  def run
16
16
  findings = FileScanner.new(@path, ignore_list: @ignore_list).scan
17
17
 
18
- if @include_history
19
- findings.concat(GitHistoryScanner.new(@path, ignore_list: @ignore_list).scan)
20
- end
18
+ findings.concat(GitHistoryScanner.new(@path, ignore_list: @ignore_list).scan) if @include_history
21
19
 
22
20
  dedupe(@ignore_list.reject_ignored(findings))
23
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SecretSweep
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -0,0 +1,15 @@
1
+ module SecretSweep
2
+ class CLI
3
+ EXIT_CLEAN: Integer
4
+ EXIT_SECRETS_FOUND: Integer
5
+ EXIT_ERROR: Integer
6
+
7
+ def self.start: (Array[String] argv) -> Integer
8
+
9
+ def run: (Array[String] argv) -> Integer
10
+
11
+ private
12
+
13
+ def parse: (Array[String] argv) -> Hash[Symbol, untyped]
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module SecretSweep
2
+ module Entropy
3
+ DEFAULT_THRESHOLD: Float
4
+
5
+ def self.shannon: (String? str) -> Float
6
+
7
+ def self.high_entropy?: (String? str, ?threshold: Float, ?min_length: Integer) -> bool
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ module SecretSweep
2
+ class FileScanner
3
+ SKIP_DIRS: Array[String]
4
+ MAX_FILE_SIZE: Integer
5
+
6
+ def initialize: (String root, ?ignore_list: IgnoreList) -> void
7
+
8
+ def scan: () -> Array[Finding]
9
+
10
+ private
11
+
12
+ def each_scannable_file: () { (String path) -> void } -> void
13
+
14
+ def scan_file: (String path, String relative_path) -> Array[Finding]
15
+
16
+ def check_high_entropy_tokens: (String line, String relative_path, Integer line_number, Array[Finding] findings) -> void
17
+
18
+ def relative: (String path) -> String
19
+
20
+ def binary?: (String path) -> bool
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module SecretSweep
2
+ class Finding
3
+ attr_reader source: String
4
+ attr_reader line_number: Integer?
5
+ attr_reader type: String
6
+ attr_reader snippet: String
7
+ attr_reader commit: String?
8
+
9
+ def initialize: (String source, Integer? line_number, String type, String snippet, String? commit) -> void
10
+
11
+ def fingerprint: () -> String
12
+
13
+ def redacted_snippet: () -> String
14
+
15
+ def to_h: () -> Hash[Symbol, untyped]
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module SecretSweep
2
+ class GitHistoryScanner
3
+ class NotAGitRepoError < StandardError
4
+ end
5
+
6
+ def initialize: (String repo_path, ?ignore_list: IgnoreList) -> void
7
+
8
+ def scan: () -> Array[Finding]
9
+
10
+ private
11
+
12
+ def git_repo?: () -> bool
13
+
14
+ def each_diff_line: () { (String line) -> void } -> void
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module SecretSweep
2
+ class IgnoreList
3
+ def self.load: (String? path) -> IgnoreList
4
+
5
+ def initialize: (Array[String] path_globs, Array[String] fingerprints) -> void
6
+
7
+ def path_ignored?: (String path) -> bool
8
+
9
+ def finding_ignored?: (Finding finding) -> bool
10
+
11
+ def reject_ignored: (Array[Finding] findings) -> Array[Finding]
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module SecretSweep
2
+ module PatternRegistry
3
+ type match = { type: String, snippet: String }
4
+
5
+ PATTERNS: Hash[String, Regexp]
6
+ PLACEHOLDER_HINTS: Regexp
7
+
8
+ def self.scan_line: (String line) -> Array[match]
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module SecretSweep
2
+ module Reporter
3
+ def self.render: (Array[Finding] findings, ?format: Symbol) -> String
4
+
5
+ def self.render_text: (Array[Finding] findings) -> String
6
+
7
+ def self.render_json: (Array[Finding] findings) -> String
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module SecretSweep
2
+ class Scanner
3
+ def initialize: (String path, ?ignore_file: String?, ?include_history: bool) -> void
4
+
5
+ def run: () -> Array[Finding]
6
+
7
+ private
8
+
9
+ def default_ignore_path: () -> String?
10
+
11
+ def dedupe: (Array[Finding] findings) -> Array[Finding]
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module SecretSweep
2
+ VERSION: String
3
+
4
+ class Error < StandardError
5
+ end
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secretsweep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Majd
@@ -10,33 +10,47 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: minitest
13
+ name: rake
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '5.20'
18
+ version: '13.0'
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '5.20'
25
+ version: '13.0'
26
26
  - !ruby/object:Gem::Dependency
27
- name: rake
27
+ name: rbs
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '13.0'
32
+ version: '3.0'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '13.0'
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.13'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.13'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: rubocop
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -61,6 +75,7 @@ executables:
61
75
  extensions: []
62
76
  extra_rdoc_files: []
63
77
  files:
78
+ - CHANGELOG.md
64
79
  - LICENSE
65
80
  - README.md
66
81
  - bin/secretsweep
@@ -75,10 +90,24 @@ files:
75
90
  - lib/secretsweep/reporter.rb
76
91
  - lib/secretsweep/scanner.rb
77
92
  - lib/secretsweep/version.rb
93
+ - sig/secretsweep.rbs
94
+ - sig/secretsweep/cli.rbs
95
+ - sig/secretsweep/entropy.rbs
96
+ - sig/secretsweep/file_scanner.rbs
97
+ - sig/secretsweep/finding.rbs
98
+ - sig/secretsweep/git_history_scanner.rbs
99
+ - sig/secretsweep/ignore_list.rbs
100
+ - sig/secretsweep/pattern_registry.rbs
101
+ - sig/secretsweep/reporter.rbs
102
+ - sig/secretsweep/scanner.rbs
78
103
  homepage: https://github.com/Majd2404/SecretSweep
79
104
  licenses:
80
105
  - MIT
81
- metadata: {}
106
+ metadata:
107
+ homepage_uri: https://github.com/Majd2404/SecretSweep
108
+ source_code_uri: https://github.com/Majd2404/SecretSweep
109
+ changelog_uri: https://github.com/Majd2404/SecretSweep/blob/main/CHANGELOG.md
110
+ bug_tracker_uri: https://github.com/Majd2404/SecretSweep/issues
82
111
  rdoc_options: []
83
112
  require_paths:
84
113
  - lib