raygatherer 0.1.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CLAUDE.md +102 -0
  4. data/CODE_OF_CONDUCT.md +133 -0
  5. data/LICENSE.txt +21 -0
  6. data/Makefile +23 -0
  7. data/README.md +220 -0
  8. data/Rakefile +8 -0
  9. data/exe/raygatherer +5 -0
  10. data/lib/raygatherer/api_client.rb +267 -0
  11. data/lib/raygatherer/cli.rb +193 -0
  12. data/lib/raygatherer/commands/alerts.rb +167 -0
  13. data/lib/raygatherer/commands/analysis/run.rb +81 -0
  14. data/lib/raygatherer/commands/analysis/status.rb +60 -0
  15. data/lib/raygatherer/commands/base.rb +41 -0
  16. data/lib/raygatherer/commands/config/set.rb +76 -0
  17. data/lib/raygatherer/commands/config/show.rb +61 -0
  18. data/lib/raygatherer/commands/config/test_notification.rb +52 -0
  19. data/lib/raygatherer/commands/recording/delete.rb +55 -0
  20. data/lib/raygatherer/commands/recording/download.rb +167 -0
  21. data/lib/raygatherer/commands/recording/list.rb +60 -0
  22. data/lib/raygatherer/commands/recording/start.rb +56 -0
  23. data/lib/raygatherer/commands/recording/stop.rb +56 -0
  24. data/lib/raygatherer/commands/stats.rb +58 -0
  25. data/lib/raygatherer/config.rb +40 -0
  26. data/lib/raygatherer/format_helpers.rb +19 -0
  27. data/lib/raygatherer/formatters/analysis_status_human.rb +38 -0
  28. data/lib/raygatherer/formatters/analysis_status_json.rb +13 -0
  29. data/lib/raygatherer/formatters/config_human.rb +29 -0
  30. data/lib/raygatherer/formatters/config_json.rb +13 -0
  31. data/lib/raygatherer/formatters/human.rb +38 -0
  32. data/lib/raygatherer/formatters/json.rb +22 -0
  33. data/lib/raygatherer/formatters/recording_list_human.rb +72 -0
  34. data/lib/raygatherer/formatters/recording_list_json.rb +13 -0
  35. data/lib/raygatherer/formatters/stats_human.rb +29 -0
  36. data/lib/raygatherer/formatters/stats_json.rb +13 -0
  37. data/lib/raygatherer/spinner.rb +31 -0
  38. data/lib/raygatherer/version.rb +5 -0
  39. data/lib/raygatherer.rb +34 -0
  40. metadata +111 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aef304a404bc427e2d066db7cf8767e73d06dc8c765b15f18b78afc68a78ee1e
4
+ data.tar.gz: e81748ac2ce4443e5a30ff55e63727db50148d7b1402ffebbee280c01f19a8a6
5
+ SHA512:
6
+ metadata.gz: cc2ce523698c34711223d9c88a14360f98850e91650da419acb9b532e6d1e5a8f1bc8db47d418e83acf648878803a4f2811ca65403dbfcbfae071017e0ad6c3b
7
+ data.tar.gz: bde55ec5165b8516d9e6295a2b6215db2c54f2399b9c299497591b9d0ebe212a1d2eac19c0d10ace5324816f1a37f477ca06587125110a858488c39a587f283d
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CLAUDE.md ADDED
@@ -0,0 +1,102 @@
1
+ # PROJECT OVERVIEW
2
+
3
+ Raygatherer: Ruby CLI for fetching and displaying alerts from Rayhunter (cell tower / IMSI catcher analysis device). Ruby >= 3.1.0.
4
+
5
+ # QUICK REFERENCE
6
+
7
+ - Run tests: `bundle exec rspec`
8
+ - Run CLI: `bundle exec ./exe/raygatherer`
9
+ - CI: GitHub Actions on push to master and all PRs
10
+ - `rayhunter` itself is checked out at `/Users/mike/workspace/rayhunter/`
11
+
12
+ # ARCHITECTURE
13
+
14
+ - Entry point: `exe/raygatherer` → `Raygatherer::CLI.run`
15
+ - CLI routing: `lib/raygatherer/cli.rb`
16
+ - Commands: `lib/raygatherer/commands/` (one class per subcommand)
17
+ - API client: `lib/raygatherer/api_client.rb` (HTTP + NDJSON parsing)
18
+ - Formatters: `lib/raygatherer/formatters/` (human and JSON, both accept arrays)
19
+ - Tests mirror `lib/` structure under `spec/`, plus `spec/integration/` for CLI end-to-end tests
20
+
21
+ # KEY CONVENTIONS
22
+
23
+ - Formatters always receive and return arrays (even when empty)
24
+ - JSON output is always a JSON array
25
+ - Exit codes encode alert severity for scripting use (see `show_help` in status.rb)
26
+ - Linter: `bundle exec standardrb` (Ruby Standard Style). Write new code in standardrb style to avoid rework.
27
+
28
+ # ROLE AND EXPERTISE
29
+
30
+ You are a senior software engineer who follows Kent Beck's Test-Driven Development (TDD) and Tidy First principles. Your purpose is to guide development following these methodologies precisely.
31
+
32
+ # CORE DEVELOPMENT PRINCIPLES
33
+
34
+ - Always follow the TDD cycle: Red → Green → Refactor
35
+ - Write the simplest failing test first
36
+ - Implement the minimum code needed to make tests pass
37
+ - Refactor only after tests are passing
38
+ - Follow Beck's "Tidy First" approach by separating structural changes from behavioral changes
39
+ - Maintain high code quality throughout development
40
+
41
+ # TDD METHODOLOGY GUIDANCE
42
+
43
+ - Start by writing a failing test that defines a small increment of functionality
44
+ - Use meaningful test names that describe behavior (e.g., "should sum two positive integers")
45
+ - Make test failures clear and informative
46
+ - Write just enough code to make the test pass - no more
47
+ - Once tests pass, consider if refactoring is needed
48
+ - Repeat the cycle for new functionality
49
+ - When fixing a defect, first write an API-level failing test then write the smallest possible test that replicates the problem then get both tests to pass.
50
+
51
+ # TIDY FIRST APPROACH
52
+
53
+ - Separate all changes into two distinct types:
54
+ 1. STRUCTURAL CHANGES: Rearranging code without changing behavior (renaming, extracting methods, moving code)
55
+ 2. BEHAVIORAL CHANGES: Adding or modifying actual functionality
56
+ - Never mix structural and behavioral changes in the same commit
57
+ - Always make structural changes first when both are needed
58
+ - Validate structural changes do not alter behavior by running tests before and after
59
+
60
+ # COMMIT DISCIPLINE
61
+
62
+ - Only commit when:
63
+ 1. ALL tests are passing (`bundle exec rspec`)
64
+ 2. ALL standardrb issues are resolved (`bundle exec standardrb`); fix any issues before committing
65
+ 3. The change represents a single logical unit of work
66
+ 4. Commit messages clearly state whether the commit contains structural or behavioral changes
67
+ - Use small, frequent commits rather than large, infrequent ones
68
+
69
+ # CODE QUALITY STANDARDS
70
+
71
+ - Eliminate duplication ruthlessly
72
+ - Express intent clearly through naming and structure
73
+ - Make dependencies explicit
74
+ - Keep methods small and focused on a single responsibility
75
+ - Minimize state and side effects
76
+ - Use the simplest solution that could possibly work
77
+
78
+ # REFACTORING GUIDELINES
79
+
80
+ - Refactor only when tests are passing (in the "Green" phase)
81
+ - Use established refactoring patterns with their proper names
82
+ - Make one refactoring change at a time
83
+ - Run tests after each refactoring step
84
+ - Prioritize refactorings that remove duplication or improve clarity
85
+
86
+ # EXAMPLE WORKFLOW
87
+
88
+ When approaching a new feature:
89
+
90
+ 1. Write a simple failing test for a small part of the feature
91
+ 2. Implement the bare minimum to make it pass
92
+ 3. Run tests to confirm they pass (Green)
93
+ 4. Run `bundle exec standardrb` and fix any issues
94
+ 5. Make any necessary structural changes (Tidy First), running tests after each change
95
+ 6. Commit structural changes separately
96
+ 7. Add another test for the next small increment of functionality
97
+ 8. Repeat until the feature is complete, committing behavioral changes separately from structural ones
98
+
99
+ Follow this process precisely, always prioritizing clean, well-tested code over quick implementation.
100
+
101
+ Always write one test at a time, make it run, then improve structure. Always run all the tests (except long-running tests) each time.
102
+
@@ -0,0 +1,133 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ prelate-33.requiem@icloud.com.
64
+
65
+ All complaints will be reviewed and investigated promptly and fairly.
66
+
67
+ All community leaders are obligated to respect the privacy and security of the
68
+ reporter of any incident.
69
+
70
+ ## Enforcement Guidelines
71
+
72
+ Community leaders will follow these Community Impact Guidelines in determining
73
+ the consequences for any action they deem in violation of this Code of Conduct:
74
+
75
+ ### 1. Correction
76
+
77
+ **Community Impact**: Use of inappropriate language or other behavior deemed
78
+ unprofessional or unwelcome in the community.
79
+
80
+ **Consequence**: A private, written warning from community leaders, providing
81
+ clarity around the nature of the violation and an explanation of why the
82
+ behavior was inappropriate. A public apology may be requested.
83
+
84
+ ### 2. Warning
85
+
86
+ **Community Impact**: A violation through a single incident or series of
87
+ actions.
88
+
89
+ **Consequence**: A warning with consequences for continued behavior. No
90
+ interaction with the people involved, including unsolicited interaction with
91
+ those enforcing the Code of Conduct, for a specified period of time. This
92
+ includes avoiding interactions in community spaces as well as external channels
93
+ like social media. Violating these terms may lead to a temporary or permanent
94
+ ban.
95
+
96
+ ### 3. Temporary Ban
97
+
98
+ **Community Impact**: A serious violation of community standards, including
99
+ sustained inappropriate behavior.
100
+
101
+ **Consequence**: A temporary ban from any sort of interaction or public
102
+ communication with the community for a specified period of time. No public or
103
+ private interaction with the people involved, including unsolicited interaction
104
+ with those enforcing the Code of Conduct, is allowed during this period.
105
+ Violating these terms may lead to a permanent ban.
106
+
107
+ ### 4. Permanent Ban
108
+
109
+ **Community Impact**: Demonstrating a pattern of violation of community
110
+ standards, including sustained inappropriate behavior, harassment of an
111
+ individual, or aggression toward or disparagement of classes of individuals.
112
+
113
+ **Consequence**: A permanent ban from any sort of public interaction within the
114
+ community.
115
+
116
+ ## Attribution
117
+
118
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119
+ version 2.1, available at
120
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
121
+
122
+ Community Impact Guidelines were inspired by
123
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124
+
125
+ For answers to common questions about this code of conduct, see the FAQ at
126
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
127
+ [https://www.contributor-covenant.org/translations][translations].
128
+
129
+ [homepage]: https://www.contributor-covenant.org
130
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
131
+ [Mozilla CoC]: https://github.com/mozilla/diversity
132
+ [FAQ]: https://www.contributor-covenant.org/faq
133
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Mike Stallard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,23 @@
1
+ GEM = raygatherer-$(shell ruby -e "require_relative 'lib/raygatherer/version'; puts Raygatherer::VERSION").gem
2
+
3
+ build: $(GEM)
4
+
5
+ $(GEM): raygatherer.gemspec lib/**/*.rb exe/*
6
+ gem build raygatherer.gemspec
7
+
8
+ install: $(GEM)
9
+ gem install $(GEM)
10
+
11
+ uninstall:
12
+ gem uninstall raygatherer
13
+
14
+ clean:
15
+ rm -f raygatherer-*.gem
16
+
17
+ lint:
18
+ bundle exec standardrb
19
+
20
+ test:
21
+ bundle exec rspec
22
+
23
+ .PHONY: install uninstall clean test
data/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # Raygatherer
2
+
3
+ ![Build Pipeline Status](https://github.com/mjstallard/raygatherer/actions/workflows/main.yml/badge.svg)
4
+
5
+ This is a CLI to interact with [Rayhunter](https://github.com/EFForg/rayhunter/). It was built with the intent of giving myself the ability to automate alerting and recording management on a Rayhunter that is not-mobile (ie., it is plugged in 24/7 in my attic). If you too wish to script or otherwise automate using your Rayhunter, you might find this to be helpful!
6
+
7
+ **Important:** This is a personal side-project, and has no affiliation with or endorsement from the Rayhunter project, or the EFF. It is entirely unofficial, and without warranty.
8
+
9
+ ## What It Does
10
+
11
+ Currently implemented:
12
+
13
+ - alerts from live analysis, with severity-based exit codes
14
+ - recording list/start/stop/delete/download
15
+ - system stats
16
+ - analysis queue status and triggering analysis runs
17
+ - config show/set/test-notification
18
+ - JSON output mode for scriptable commands
19
+ - optional basic auth and config file support
20
+
21
+ ## Installation
22
+
23
+ ### Ruby version
24
+
25
+ `raygatherer` requires Ruby `>= 3.1.0`.
26
+
27
+ ### Install from this repo
28
+
29
+ ```bash
30
+ bundle install
31
+ make build
32
+ make install
33
+ ```
34
+
35
+ Or install directly with RubyGems:
36
+
37
+ ```bash
38
+ gem build raygatherer.gemspec
39
+ gem install ./raygatherer-*.gem
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ Check CLI help:
45
+
46
+ ```bash
47
+ raygatherer --help
48
+ ```
49
+
50
+ Check live alerts:
51
+
52
+ ```bash
53
+ raygatherer --host http://rayhunter.local alerts
54
+ ```
55
+
56
+ Check live alerts as JSON:
57
+
58
+ ```bash
59
+ raygatherer --host http://rayhunter.local --json alerts
60
+ ```
61
+
62
+ List recordings:
63
+
64
+ ```bash
65
+ raygatherer --host http://rayhunter.local recording list
66
+ ```
67
+
68
+ Download a recording:
69
+
70
+ ```bash
71
+ raygatherer --host http://rayhunter.local recording download 1738950000
72
+ ```
73
+
74
+ Show analysis queue status:
75
+
76
+ ```bash
77
+ raygatherer --host http://rayhunter.local analysis status
78
+ ```
79
+
80
+ Show system stats:
81
+
82
+ ```bash
83
+ raygatherer --host http://rayhunter.local stats
84
+ ```
85
+
86
+ ## Global Flags
87
+
88
+ These can be used with any command:
89
+
90
+ - `--host HOST` (required unless provided in config file)
91
+ - `--basic-auth-user USER`
92
+ - `--basic-auth-password PASS`
93
+ - `--verbose`
94
+ - `--json` (only applies to commands that support JSON output)
95
+
96
+ ## Configuration File
97
+
98
+ By default, config is loaded from:
99
+
100
+ - `~/.config/raygatherer/config.yml`
101
+ - or `$XDG_CONFIG_HOME/raygatherer/config.yml` if `XDG_CONFIG_HOME` is set
102
+
103
+ Supported keys:
104
+
105
+ - `host`
106
+ - `basic_auth_user`
107
+ - `basic_auth_password`
108
+ - `json`
109
+ - `verbose`
110
+
111
+ CLI flags always override config values.
112
+
113
+ Example:
114
+
115
+ ```yaml
116
+ host: http://rayhunter.local
117
+ basic_auth_user: admin
118
+ basic_auth_password: replace-me
119
+ json: false
120
+ verbose: false
121
+ ```
122
+
123
+ ## Commands
124
+
125
+ Main commands:
126
+
127
+ - `alerts`
128
+ - `recording list`
129
+ - `recording download <name> [--qmdl|--pcap|--zip] [--download-dir DIR|--save-as PATH]`
130
+ - `recording delete <name>`
131
+ - `recording stop`
132
+ - `recording start`
133
+ - `analysis status`
134
+ - `analysis run [NAME|--all]`
135
+ - `config show`
136
+ - `config set` (reads JSON from stdin)
137
+ - `config test-notification`
138
+ - `stats`
139
+
140
+ For command-specific help:
141
+
142
+ ```bash
143
+ raygatherer COMMAND --help
144
+ ```
145
+
146
+ Examples:
147
+
148
+ ```bash
149
+ raygatherer alerts --help
150
+ raygatherer recording download --help
151
+ raygatherer analysis run --help
152
+ ```
153
+
154
+ ## Alerts Exit Codes
155
+
156
+ `alerts` returns severity-based codes so shell scripts can react:
157
+
158
+ - `0`: no alerts
159
+ - `1`: error
160
+ - `10`: low severity alert
161
+ - `11`: medium severity alert
162
+ - `12`: high severity alert
163
+
164
+ Example:
165
+
166
+ ```bash
167
+ raygatherer --host http://rayhunter.local alerts
168
+ code=$?
169
+ [ "$code" -ge 11 ] && echo "medium or high alert"
170
+ ```
171
+
172
+ ## JSON Output
173
+
174
+ Commands that support `--json` return machine-readable output to `stdout`. This is intended for `jq` and/or scripts.
175
+
176
+ Example:
177
+
178
+ ```bash
179
+ raygatherer --host http://rayhunter.local --json config show | jq '.analyzers'
180
+ ```
181
+
182
+ ## Development
183
+
184
+ Install dependencies:
185
+
186
+ ```bash
187
+ bundle install
188
+ ```
189
+
190
+ Run tests:
191
+
192
+ ```bash
193
+ make test
194
+ ```
195
+
196
+ Run linter:
197
+
198
+ ```bash
199
+ make lint
200
+ ```
201
+
202
+ Build gem:
203
+
204
+ ```bash
205
+ make build
206
+ ```
207
+
208
+ ## Security Notes
209
+
210
+ - This tool can send credentials over plaintext via HTTP if you point it at `http://...`.
211
+ - Config files may contain credentials. Restrict permissions appropriately.
212
+ - This is an unofficial tool. Verify behavior in your environment before relying on it.
213
+
214
+ ## License
215
+
216
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
217
+
218
+ ## Code of Conduct
219
+
220
+ Everyone interacting in the Raygatherer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/mjstallard/raygatherer/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/exe/raygatherer ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "raygatherer"
4
+
5
+ exit Raygatherer::CLI.run(ARGV)