greynoise 3.1.0__tar.gz → 3.2.0__tar.gz

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 (80) hide show
  1. {greynoise-3.1.0 → greynoise-3.2.0}/.bumpversion.cfg +3 -3
  2. {greynoise-3.1.0 → greynoise-3.2.0}/CHANGELOG.rst +37 -2
  3. {greynoise-3.1.0 → greynoise-3.2.0}/PKG-INFO +25 -23
  4. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/conf.py +2 -2
  5. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/tutorial.rst +125 -3
  6. {greynoise-3.1.0 → greynoise-3.2.0}/pyproject.toml +24 -22
  7. {greynoise-3.1.0 → greynoise-3.2.0}/requirements/common.txt +9 -7
  8. {greynoise-3.1.0 → greynoise-3.2.0}/requirements/dev.txt +5 -5
  9. {greynoise-3.1.0 → greynoise-3.2.0}/requirements/docs.txt +2 -1
  10. {greynoise-3.1.0 → greynoise-3.2.0}/requirements/test.txt +8 -6
  11. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/__version__.py +1 -1
  12. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/api/__init__.py +580 -54
  13. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/decorator.py +7 -2
  14. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/formatter.py +23 -0
  15. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/subcommand.py +197 -11
  16. greynoise-3.2.0/src/greynoise/cli/templates/feeds_consumers.txt.j2 +40 -0
  17. greynoise-3.2.0/src/greynoise/cli/templates/feeds_events.txt.j2 +78 -0
  18. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_context_result.txt.j2 +13 -3
  19. greynoise-3.2.0/src/greynoise/exceptions.py +53 -0
  20. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/greynoise_timeline.py +20 -3
  21. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/psychic.py +145 -77
  22. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/util.py +22 -0
  23. {greynoise-3.1.0 → greynoise-3.2.0}/tests/cli/test_formatter.py +128 -0
  24. {greynoise-3.1.0 → greynoise-3.2.0}/tests/cli/test_subcommand.py +220 -11
  25. {greynoise-3.1.0 → greynoise-3.2.0}/tests/test_api.py +738 -22
  26. greynoise-3.2.0/tests/test_exceptions.py +63 -0
  27. greynoise-3.2.0/tests/test_greynoise_timeline.py +75 -0
  28. greynoise-3.2.0/tests/test_psychic.py +589 -0
  29. {greynoise-3.1.0 → greynoise-3.2.0}/tests/test_util.py +21 -0
  30. greynoise-3.1.0/src/greynoise/exceptions.py +0 -13
  31. greynoise-3.1.0/tests/test_psychic.py +0 -272
  32. {greynoise-3.1.0 → greynoise-3.2.0}/.circleci/config.yml +0 -0
  33. {greynoise-3.1.0 → greynoise-3.2.0}/.dockerignore +0 -0
  34. {greynoise-3.1.0 → greynoise-3.2.0}/.editorconfig +0 -0
  35. {greynoise-3.1.0 → greynoise-3.2.0}/.github/CODEOWNERS +0 -0
  36. {greynoise-3.1.0 → greynoise-3.2.0}/.github/dependabot.yml +0 -0
  37. {greynoise-3.1.0 → greynoise-3.2.0}/.github/workflows/slack_release_notice.yml +0 -0
  38. {greynoise-3.1.0 → greynoise-3.2.0}/.gitignore +0 -0
  39. {greynoise-3.1.0 → greynoise-3.2.0}/.pre-commit-config.yaml +0 -0
  40. {greynoise-3.1.0 → greynoise-3.2.0}/.readthedocs.yml +0 -0
  41. {greynoise-3.1.0 → greynoise-3.2.0}/.yamllint +0 -0
  42. {greynoise-3.1.0 → greynoise-3.2.0}/Dockerfile +0 -0
  43. {greynoise-3.1.0 → greynoise-3.2.0}/LICENSE +0 -0
  44. {greynoise-3.1.0 → greynoise-3.2.0}/MANIFEST.in +0 -0
  45. {greynoise-3.1.0 → greynoise-3.2.0}/Makefile +0 -0
  46. {greynoise-3.1.0 → greynoise-3.2.0}/README.rst +0 -0
  47. {greynoise-3.1.0 → greynoise-3.2.0}/docs/Makefile +0 -0
  48. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/changelog.rst +0 -0
  49. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/index.rst +0 -0
  50. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/introduction.rst +0 -0
  51. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/reference.rst +0 -0
  52. {greynoise-3.1.0 → greynoise-3.2.0}/docs/source/sample.py +0 -0
  53. {greynoise-3.1.0 → greynoise-3.2.0}/pytest.ini +0 -0
  54. {greynoise-3.1.0 → greynoise-3.2.0}/release.md +0 -0
  55. {greynoise-3.1.0 → greynoise-3.2.0}/reset_changelog.py +0 -0
  56. {greynoise-3.1.0 → greynoise-3.2.0}/setup.cfg +0 -0
  57. {greynoise-3.1.0 → greynoise-3.2.0}/sonar-project.properties +0 -0
  58. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/__init__.py +0 -0
  59. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/api/filter.py +0 -0
  60. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/__init__.py +0 -0
  61. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/helper.py +0 -0
  62. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/parameter.py +0 -0
  63. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/analyze.txt.j2 +0 -0
  64. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/callback_ip.txt.j2 +0 -0
  65. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/cvedetails.txt.j2 +0 -0
  66. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/gnql_query.txt.j2 +0 -0
  67. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/gnql_stats.txt.j2 +0 -0
  68. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_context.txt.j2 +0 -0
  69. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_multi_context.txt.j2 +0 -0
  70. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_quick_check.txt.j2 +0 -0
  71. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/macros.txt.j2 +0 -0
  72. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/personadetails.txt.j2 +0 -0
  73. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/recall_stats.txt.j2 +0 -0
  74. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/recall_timeseries.txt.j2 +0 -0
  75. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/sensorlist.txt.j2 +0 -0
  76. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/stats.txt.j2 +0 -0
  77. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/timeline.txt.j2 +0 -0
  78. {greynoise-3.1.0 → greynoise-3.2.0}/src/greynoise/cli/templates/timelinedaily.txt.j2 +0 -0
  79. {greynoise-3.1.0 → greynoise-3.2.0}/tests/cli/test_init.py +0 -0
  80. {greynoise-3.1.0 → greynoise-3.2.0}/tox.ini +0 -0
@@ -1,11 +1,11 @@
1
1
  [bumpversion]
2
- current_version = 3.1.0
2
+ current_version = 3.2.0
3
3
  tag = False
4
4
  commit = False
5
5
 
6
6
  [bumpversion:file:pyproject.toml]
7
- search = version="{current_version}"
8
- replace = version="{new_version}"
7
+ search = version = "{current_version}"
8
+ replace = version = "{new_version}"
9
9
 
10
10
  [bumpversion:file:src/greynoise/__version__.py]
11
11
  search = __version__ = "{current_version}"
@@ -2,9 +2,43 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Version `3.2.0`_
6
+ ================
7
+ **Date**: November 4, 2026
8
+
9
+ * API client:
10
+
11
+ * Corrected proxy settings for Psychic downloads/generation and IP Timeline
12
+ * Psychic downloads and daily timeline lookups use the configured API server
13
+ * `RateLimitError` now includes the API's 429 explanation, and the CLI prints it
14
+ * Added Event Feed search, pull (fetch and optional acknowledge), and consumer management
15
+ * `ip`, `quick`, and `ip_multi` send `workspace_labels`, defaulting to `greynoise,community`
16
+ * Added `callback_file` and `gnql_file` functions to download the pre-built callback and GNQL SIEM files
17
+ * Added `callback_file_metadata` and `gnql_file_metadata` functions to describe the pre-built files without downloading them
18
+
19
+ * CLI:
20
+
21
+ * `feeds search` searches retained feed history without moving a consumer checkpoint
22
+ * `feeds pull` fetches the next batch for a feed consumer and can acknowledge that batch
23
+ * `feeds consumers` lists consumers, or creates, resets, or deletes one checkpoint
24
+ * `ip`, `quick`, and `ip-multi` accept `--workspace-labels` and pass the value through to the API
25
+ * IP text output lists the `source_workspaces` returned for the scopes that were queried
26
+ * `ip --psychic --days` looks up an IP in a Psychic bitmap covering the last N days
27
+ * Psychic text output shows the bitmap date, and says when the IP was not in that file
28
+ * `psychic-download` and `psychic-generate` accept any model number and warn when it is not 1, 2, or 3
29
+
30
+ * Dependencies:
31
+
32
+ * Runtime dependencies now declare a minimum version instead of an exact pin, so applications can install a newer compatible release
33
+ * Updated `Click` to 8.5.0 on Python 3.10 and newer
34
+ * Updated `click-repl` to 0.4.1 on Python 3.9 and newer
35
+ * Updated `cachetools` to 7.2.8 on Python 3.10 and newer
36
+ * Updated `maxminddb` to 3.2.0 on Python 3.10 and newer
37
+ * Updated `more-itertools` to 11.2.1 on Python 3.11 and newer
38
+
5
39
  Version `3.1.0`_
6
40
  ================
7
- **Date**: unreleased
41
+ **Date**: July 9, 2026
8
42
 
9
43
  * API client:
10
44
 
@@ -529,4 +563,5 @@ Version `0.2.0`_
529
563
  .. _`3.0.1`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.0...v3.0.1
530
564
  .. _`3.0.2`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.1...v3.0.2
531
565
  .. _`3.0.3`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.2...v3.0.3
532
- .. _`3.1.0`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.3...HEAD
566
+ .. _`3.1.0`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.3...v3.1.0
567
+ .. _`3.2.0`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.1.0...3.2.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: greynoise
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: Abstraction to interact with GreyNoise API.
5
5
  Project-URL: Homepage, https://greynoise.io/
6
6
  Project-URL: Repository, https://github.com/GreyNoise-Intelligence/pygreynoise
@@ -22,27 +22,29 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Topic :: Software Development :: Libraries
24
24
  Requires-Python: >=3.8
25
- Requires-Dist: ansimarkup==2.2.0
26
- Requires-Dist: cachetools==5.5.2; python_version == '3.8'
27
- Requires-Dist: cachetools==6.2.6; python_version == '3.9'
28
- Requires-Dist: cachetools==7.0.5; python_version >= '3.10'
29
- Requires-Dist: click-default-group==1.2.4
30
- Requires-Dist: click-repl==0.3.0
31
- Requires-Dist: click<=8.1.8; python_version < '3.10'
32
- Requires-Dist: click==8.4.1; python_version >= '3.10'
33
- Requires-Dist: colorama==0.4.6
34
- Requires-Dist: dict2xml==1.7.8
35
- Requires-Dist: jinja2==3.1.6
36
- Requires-Dist: maxminddb==2.6.3; python_version == '3.8'
37
- Requires-Dist: maxminddb==2.8.2; python_version == '3.9'
38
- Requires-Dist: maxminddb==3.1.1; python_version >= '3.10'
39
- Requires-Dist: more-itertools==10.5.0; python_version == '3.8'
40
- Requires-Dist: more-itertools==10.8.0; python_version == '3.9'
41
- Requires-Dist: more-itertools==11.1.0; python_version >= '3.10'
42
- Requires-Dist: requests==2.32.4; python_version == '3.8'
43
- Requires-Dist: requests==2.32.5; python_version == '3.9'
44
- Requires-Dist: requests==2.34.2; python_version >= '3.10'
45
- Requires-Dist: six==1.17.0
25
+ Requires-Dist: ansimarkup>=2.2.0
26
+ Requires-Dist: cachetools>=5.5.2; python_version == '3.8'
27
+ Requires-Dist: cachetools>=6.2.6; python_version == '3.9'
28
+ Requires-Dist: cachetools>=7.2.8; python_version >= '3.10'
29
+ Requires-Dist: click-default-group>=1.2.4
30
+ Requires-Dist: click-repl>=0.3.0; python_version == '3.8'
31
+ Requires-Dist: click-repl>=0.4.1; python_version >= '3.9'
32
+ Requires-Dist: click<8.2,>=8.1.8; python_version < '3.10'
33
+ Requires-Dist: click>=8.5.0; python_version >= '3.10'
34
+ Requires-Dist: colorama>=0.4.6
35
+ Requires-Dist: dict2xml>=1.7.8
36
+ Requires-Dist: jinja2>=3.1.6
37
+ Requires-Dist: maxminddb>=2.6.3; python_version == '3.8'
38
+ Requires-Dist: maxminddb>=2.8.2; python_version == '3.9'
39
+ Requires-Dist: maxminddb>=3.2.0; python_version >= '3.10'
40
+ Requires-Dist: more-itertools>=10.5.0; python_version == '3.8'
41
+ Requires-Dist: more-itertools>=10.8.0; python_version == '3.9'
42
+ Requires-Dist: more-itertools>=11.1.0; python_version == '3.10'
43
+ Requires-Dist: more-itertools>=11.2.1; python_version >= '3.11'
44
+ Requires-Dist: requests>=2.32.4; python_version == '3.8'
45
+ Requires-Dist: requests>=2.32.5; python_version == '3.9'
46
+ Requires-Dist: requests>=2.34.2; python_version >= '3.10'
47
+ Requires-Dist: six>=1.17.0
46
48
  Description-Content-Type: text/x-rst
47
49
 
48
50
  ================
@@ -21,11 +21,11 @@ sys.path.insert(0, os.path.abspath("."))
21
21
  # -- Project information -----------------------------------------------------
22
22
 
23
23
  project = "greynoise"
24
- copyright = "2018-2025, GreyNoise Intelligence"
24
+ copyright = "2018-2026, GreyNoise Intelligence"
25
25
  author = "GreyNoise Intelligence"
26
26
 
27
27
  # The full version, including alpha/beta/rc tags
28
- release = "3.1.0"
28
+ release = "3.2.0"
29
29
 
30
30
 
31
31
  # -- General configuration ---------------------------------------------------
@@ -408,6 +408,21 @@ this (this method also supports the include_invalid flag::
408
408
  }
409
409
  ]
410
410
 
411
+ Dataset scopes
412
+ --------------
413
+
414
+ ``ip``, ``quick``, and ``ip_multi`` send a ``workspace_labels`` query parameter.
415
+ When the argument is omitted, the client sends ``greynoise,community``. Pass a
416
+ comma-separated string to choose a different set. The values are forwarded as
417
+ given; the API accepts ``greynoise``, ``community``, and ``personal``::
418
+
419
+ >>> api_client.ip('8.8.8.8', workspace_labels='greynoise')
420
+
421
+ ``quick`` and ``ip_multi`` take the same argument. A response includes
422
+ ``internet_scanner_intelligence.source_workspaces`` for the scopes that contained
423
+ the IP. Successful lookups are cached by IP address and label set, so a later
424
+ call with a different set is not served from the earlier result.
425
+
411
426
  Any IP can also be checked to see if there are any Similar IPs in the Noise Dataset::
412
427
 
413
428
  >>> api_client.similar('45.83.66.65')
@@ -469,8 +484,10 @@ Run a query
469
484
  ~~~~~~~~~~~
470
485
 
471
486
  A GNQL (GreyNoise Query Language) query can be executed to dig deeper into the GreyNoise
472
- dataset. For example, to get context information related to activity has been classified
473
- as malicious and tagged as a Bluekeep Exploit::
487
+ dataset. Pass ``exclude_fields`` as a comma-separated string or a list of field names
488
+ to omit those fields from the response (the API ``exclude`` parameter). For example, to
489
+ get context information related to activity that has been classified as malicious and
490
+ tagged as a Bluekeep Exploit::
474
491
 
475
492
  >>> api_client.query('last_seen:1d classification:"suspicious" actor:"NiceCrawler"')
476
493
  {
@@ -741,6 +758,60 @@ operating system, etc.::
741
758
  }
742
759
  }
743
760
 
761
+ Event feeds
762
+ -----------
763
+
764
+ Retained feed events can be searched without moving a consumer checkpoint. Feeds are
765
+ created in the GreyNoise Visualizer. An empty search covers enabled non-session feeds
766
+ over the previous hour. ``event_types`` is limited to ``ip-classification-change``,
767
+ ``cve-status-change``, ``cve-activity-spike``, ``vendor-cve-spike``, ``tag-spike``,
768
+ ``new-callback-ip``, ``new-callback-file``, and ``credential-observed``::
769
+
770
+ >>> api_client.feed_search(event_types=['tag-spike'], ip='8.8.8.8', from_time='24h', limit=100)
771
+
772
+ Pass the returned ``cursor`` by itself, with an optional ``limit``, to read the next page.
773
+ ``feed_pull`` reads the next batch for one consumer and does not advance that checkpoint
774
+ unless ``ack=True``. ``cursor`` acknowledges a batch that was already fetched::
775
+
776
+ >>> api_client.feed_pull('<feed_uuid>', consumer='worker-1', limit=100, ack=True)
777
+
778
+ ``feed_consumers`` lists checkpoints, or creates, resets, or deletes one. A new consumer
779
+ starts at the beginning of retained history. Reset replays that history. Delete removes
780
+ only that checkpoint::
781
+
782
+ >>> api_client.feed_consumers('<feed_uuid>', action='create', consumer='worker-1')
783
+
784
+ These methods are not available with the community offering.
785
+
786
+ Pre-built files
787
+ ---------------
788
+
789
+ GreyNoise builds SIEM lookup files server-side and refreshes them hourly. Both downloads
790
+ request the only file the API serves (CSV, NG-SIEM profile), stream the body to a path or
791
+ a binary file object, and return a ``FileResult``. A path is written to a temporary file
792
+ and moved into place only when the status is ``ok``, so a failed download leaves an
793
+ existing file in place.
794
+
795
+ ``callback_file`` downloads the callback IP file. ``days`` is the lookback window, from
796
+ 1 to 7, and defaults to 7. Callback files do not report ``truncated``::
797
+
798
+ >>> api_client.callback_file('callback.csv', days=7)
799
+ FileResult(status='ok', generated_at='2026-10-29T10:00:00Z', row_count=100000, total_count=None, truncated=None, feed_status=None, retry_after=None)
800
+
801
+ ``gnql_file`` downloads the file for a GNQL query::
802
+
803
+ >>> api_client.gnql_file('last_seen:1d -classification:unknown', 'feed.csv', limit=100000)
804
+ FileResult(status='ok', generated_at='2026-10-29T10:00:00Z', row_count=100000, total_count=250000, truncated=True, feed_status='enabled', retry_after=None)
805
+
806
+ The first request for a new query subscribes to it and returns status ``provisioning``
807
+ until the file is built. Nothing is written in that case; retry after
808
+ ``result.retry_after`` seconds. Integrations should identify themselves with
809
+ ``integration='name/version'``, which is sent as ``X-GreyNoise-Integration``.
810
+ ``callback_file_metadata`` and ``gnql_file_metadata`` take the same arguments as the
811
+ download functions (without ``output``) and return the same fields without downloading
812
+ the file. Error responses raise ``RequestFailure`` (``RateLimitError`` for HTTP 429)
813
+ with the status code and the API's explanation.
814
+
744
815
 
745
816
  Command line interface
746
817
  ======================
@@ -761,12 +832,14 @@ subcommands, use the *--help* option::
761
832
  analyze Analyze the IP addresses in a log file, stdin, etc.
762
833
  callback GreyNoise Callback — scanner callback intelligence...
763
834
  cve Retrieve Details of a CVE.
835
+ feeds Search retained feed events, pull a batch, or manage...
764
836
  filter Filter the noise from a log file, stdin, etc.
765
837
  help Show this message and exit.
766
838
  ip Query GreyNoise for all information on a given IP.
767
839
  ip-multi Perform Context lookup for multiple IPs at once.
768
840
  persona-details Retrieve Details of a Sensor Persona.
769
841
  psychic-download Download a Psychic bitmap (.bin), MMDB, or CSV file...
842
+ psychic-generate Generate a Psychic bitmap (.bin) for a date range...
770
843
  query Run a GNQL (GreyNoise Query Language) query.
771
844
  quick Quickly check whether or not one or many IPs are...
772
845
  recall GreyNoise Recall — GNQL activity over time.
@@ -937,6 +1010,19 @@ this (a comma separated list is also supported::
937
1010
  Last Updated: 2025-05-23T13:11:02Z
938
1011
  Reference: https://developers.google.com/speed/public-dns/docs/isp#alternative
939
1012
 
1013
+ ``ip``, ``quick``, and ``ip-multi`` accept ``--workspace-labels``. The default is
1014
+ ``greynoise,community``. The value is sent unchanged, and text output lists the
1015
+ ``source_workspaces`` the API returned::
1016
+
1017
+ $ greynoise ip 8.8.8.8 --workspace-labels greynoise
1018
+
1019
+ ``ip --psychic`` looks the address up in a Psychic bitmap instead of calling the IP
1020
+ lookup API. ``--days`` builds that bitmap for the last N days through today and
1021
+ requires ``--psychic``. Text output shows the bitmap date, and says when the IP was
1022
+ not in that file. ``--workspace-labels`` is not applied to a Psychic lookup::
1023
+
1024
+ $ greynoise ip 1.2.3.4 --psychic --days 7
1025
+
940
1026
  Check for Similar IPs to a given IP::
941
1027
 
942
1028
  $ greynoise similar 69.160.160.55
@@ -1003,6 +1089,40 @@ Check the Timeline of a given IP::
1003
1089
  2025-05-11 1 suspicious
1004
1090
  2025-04-27 1 suspicious
1005
1091
 
1092
+ Event feeds
1093
+ -----------
1094
+
1095
+ ``feeds search`` reads retained history and does not move a consumer checkpoint.
1096
+ Repeat ``--feed-id`` and ``--event-type`` to pass more than one value. ``--from``
1097
+ accepts a relative window such as ``24h`` or ``7d``, a UTC date, or an RFC3339
1098
+ timestamp. ``--cursor`` continues a previous page and cannot be combined with
1099
+ other filters::
1100
+
1101
+ $ greynoise feeds search --event-type tag-spike --ip 8.8.8.8 --from 24h --limit 100
1102
+
1103
+ ``feeds pull`` fetches the next batch for one consumer. The checkpoint stays put
1104
+ unless ``--ack`` is set. Text output for a pull without ``--ack`` shows the first
1105
+ 25 events (100 with ``-v``). An acknowledged pull prints the full batch and states
1106
+ that the checkpoint advanced past every event in it. ``--cursor`` acknowledges a
1107
+ previously fetched batch without fetching again::
1108
+
1109
+ $ greynoise feeds pull <feed_uuid> --consumer worker-1 --limit 100 --ack
1110
+
1111
+ ``feeds consumers`` lists checkpoints for a feed. ``--action create`` starts a
1112
+ consumer at the beginning of retained history, ``reset`` replays that history,
1113
+ and ``delete`` removes one checkpoint::
1114
+
1115
+ $ greynoise feeds consumers <feed_uuid> --action create --consumer worker-1
1116
+
1117
+ Psychic files
1118
+ -------------
1119
+
1120
+ ``psychic-download`` writes a bitmap (``.bin``), MMDB, or CSV for one date into
1121
+ the current directory. ``psychic-generate`` builds a bitmap for a date range::
1122
+
1123
+ $ greynoise psychic-download --format mmdb --date 2026-10-26
1124
+ $ greynoise psychic-generate --start-date 2026-10-20 --end-date 2026-10-26
1125
+
1006
1126
  GNQL
1007
1127
  ----
1008
1128
 
@@ -1010,7 +1130,7 @@ Run a query
1010
1130
  ~~~~~~~~~~~
1011
1131
 
1012
1132
  A GNQL (GreyNoise Query Language) query can be executed to dig deeper into the GreyNoise
1013
- dataset. For example, to get context information related to activity has been classified
1133
+ dataset. For example, to get context information related to activity that has been classified
1014
1134
  as malicious and tagged as a Bluekeep Exploit::
1015
1135
 
1016
1136
  $ greynoise query "classification:malicious tags:Bluekeep Exploit"
@@ -1068,6 +1188,8 @@ as malicious and tagged as a Bluekeep Exploit::
1068
1188
  This is the default command, that is, you can save some typing by just
1069
1189
  writing ``greynoise <query>`` instead of ``greynoise query <query>``.
1070
1190
 
1191
+ ``--exclude`` is a comma-separated list of fields to omit from the results.
1192
+
1071
1193
 
1072
1194
  Get statistics
1073
1195
  ~~~~~~~~~~~~~~
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "greynoise"
7
- version = "3.1.0"
7
+ version = "3.2.0"
8
8
  description = "Abstraction to interact with GreyNoise API."
9
9
  readme = {file = "README.rst", content-type = "text/x-rst"}
10
10
  requires-python = ">=3.8"
@@ -28,27 +28,29 @@ classifiers = [
28
28
  ]
29
29
  keywords = ["internet", "scanning", "threat intelligence", "security"]
30
30
  dependencies = [
31
- "Click<=8.1.8; python_version < '3.10'",
32
- "Click==8.4.1; python_version >= '3.10'",
33
- "ansimarkup==2.2.0",
34
- "cachetools==5.5.2; python_version == '3.8'",
35
- "cachetools==6.2.6; python_version == '3.9'",
36
- "cachetools==7.0.5; python_version >= '3.10'",
37
- "colorama==0.4.6",
38
- "click-default-group==1.2.4",
39
- "click-repl==0.3.0",
40
- "dict2xml==1.7.8",
41
- "jinja2==3.1.6",
42
- "maxminddb==2.6.3; python_version == '3.8'",
43
- "maxminddb==2.8.2; python_version == '3.9'",
44
- "maxminddb==3.1.1; python_version >= '3.10'",
45
- "more-itertools==10.5.0; python_version == '3.8'",
46
- "more-itertools==10.8.0; python_version == '3.9'",
47
- "more-itertools==11.1.0; python_version >= '3.10'",
48
- "requests==2.32.4; python_version == '3.8'",
49
- "requests==2.32.5; python_version == '3.9'",
50
- "requests==2.34.2; python_version >= '3.10'",
51
- "six==1.17.0",
31
+ "Click>=8.1.8,<8.2; python_version < '3.10'",
32
+ "Click>=8.5.0; python_version >= '3.10'",
33
+ "ansimarkup>=2.2.0",
34
+ "cachetools>=5.5.2; python_version == '3.8'",
35
+ "cachetools>=6.2.6; python_version == '3.9'",
36
+ "cachetools>=7.2.8; python_version >= '3.10'",
37
+ "colorama>=0.4.6",
38
+ "click-default-group>=1.2.4",
39
+ "click-repl>=0.3.0; python_version == '3.8'",
40
+ "click-repl>=0.4.1; python_version >= '3.9'",
41
+ "dict2xml>=1.7.8",
42
+ "jinja2>=3.1.6",
43
+ "maxminddb>=2.6.3; python_version == '3.8'",
44
+ "maxminddb>=2.8.2; python_version == '3.9'",
45
+ "maxminddb>=3.2.0; python_version >= '3.10'",
46
+ "more-itertools>=10.5.0; python_version == '3.8'",
47
+ "more-itertools>=10.8.0; python_version == '3.9'",
48
+ "more-itertools>=11.1.0; python_version == '3.10'",
49
+ "more-itertools>=11.2.1; python_version >= '3.11'",
50
+ "requests>=2.32.4; python_version == '3.8'",
51
+ "requests>=2.32.5; python_version == '3.9'",
52
+ "requests>=2.34.2; python_version >= '3.10'",
53
+ "six>=1.17.0",
52
54
  ]
53
55
 
54
56
  [project.urls]
@@ -1,22 +1,24 @@
1
1
  Click<=8.1.8;python_version=="3.8"
2
2
  Click<=8.1.8;python_version=="3.9"
3
- Click==8.4.1;python_version>="3.10"
3
+ Click==8.5.0;python_version>="3.10"
4
4
  ansimarkup==2.2.0
5
5
  cachetools==5.5.2;python_version=="3.8"
6
6
  cachetools==6.2.6;python_version=="3.9"
7
- cachetools==7.0.5;python_version>="3.10"
7
+ cachetools==7.2.8;python_version>="3.10"
8
8
  colorama==0.4.6
9
9
  click-default-group==1.2.4
10
- click-repl==0.3.0
11
- dict2xml==1.7.8;python_version>='3'
10
+ click-repl==0.3.0;python_version=="3.8"
11
+ click-repl==0.4.1;python_version>="3.9"
12
+ dict2xml==1.7.8
12
13
  jinja2==3.1.6
13
14
  maxminddb==2.6.3;python_version=="3.8"
14
15
  maxminddb==2.8.2;python_version=="3.9"
15
- maxminddb==3.1.1;python_version>="3.10"
16
+ maxminddb==3.2.0;python_version>="3.10"
16
17
  more-itertools==10.5.0;python_version=="3.8"
17
18
  more-itertools==10.8.0;python_version=="3.9"
18
- more-itertools==11.1.0;python_version>="3.10"
19
+ more-itertools==11.1.0;python_version=="3.10"
20
+ more-itertools==11.2.1;python_version>="3.11"
19
21
  requests==2.32.4;python_version=="3.8"
20
22
  requests==2.32.5;python_version=="3.9"
21
23
  requests==2.34.2;python_version>="3.10"
22
- six==1.17.0
24
+ six==1.17.0
@@ -1,11 +1,11 @@
1
1
  # Requirements needed to develop the application
2
2
  -r test.txt
3
3
  advbumpversion==1.2.0
4
- ipython==8.13.0;python_version=="3.8"
4
+ ipython==8.12.3;python_version=="3.8"
5
5
  ipython==8.18.1;python_version=="3.9"
6
- ipython==8.38.0;python_version=="3.10"
7
- ipython==9.10.0;python_version=="3.11"
8
- ipython==9.12.0;python_version>="3.12"
6
+ ipython==8.39.0;python_version=="3.10"
7
+ ipython==9.17.1;python_version>="3.11"
9
8
  tox==4.25.0;python_version=="3.8"
10
9
  tox==4.30.3;python_version=="3.9"
11
- tox==4.52.0;python_version>="3.10"
10
+ tox==4.65.0;python_version=="3.10"
11
+ tox==4.67.1;python_version>="3.11"
@@ -4,7 +4,8 @@ Sphinx==7.1.2;python_version=="3.8"
4
4
  Sphinx==7.4.7;python_version=="3.9"
5
5
  Sphinx==8.1.3;python_version=="3.10"
6
6
  Sphinx==9.0.4;python_version=="3.11"
7
- Sphinx==9.1.0;python_version>="3.12"
7
+ Sphinx==9.1.1;python_version=="3.12"
8
+ Sphinx==9.2.0;python_version>="3.13"
8
9
  sphinx-click==6.0.0;python_version=="3.8"
9
10
  sphinx-click==6.0.0;python_version=="3.9"
10
11
  sphinx-click==6.2.0;python_version>="3.10"
@@ -1,23 +1,25 @@
1
1
  black==24.8.0;python_version=="3.8"
2
2
  black==25.11.0;python_version=="3.9"
3
- black==26.3.1;python_version>="3.10"
3
+ black==26.10.1;python_version>="3.10"
4
4
  flake8==7.1.2;python_version=="3.8"
5
- flake8==7.3.0;python_version>="3.9"
5
+ flake8==7.3.0;python_version=="3.9"
6
+ flake8==7.4.1;python_version>="3.10"
6
7
  isort==5.13.2;python_version=="3.8"
7
8
  isort==6.1.0;python_version=="3.9"
8
- isort==8.0.1;python_version>="3.10"
9
+ isort==9.0.2;python_version>="3.10"
9
10
  mock==5.2.0
10
11
  pylint==3.2.7;python_version=="3.8"
11
12
  pylint==3.3.9;python_version=="3.9"
12
- pylint==4.0.5;python_version>="3.10"
13
+ pylint==4.1.3;python_version>="3.10"
13
14
  pytest-cov==5.0.0;python_version=="3.8"
14
15
  pytest-cov==7.1.0;python_version>="3.9"
15
16
  pytest==8.3.5;python_version=="3.8"
16
17
  pytest==8.4.2;python_version=="3.9"
17
- pytest==9.0.3;python_version>="3.10"
18
+ pytest==9.1.1;python_version>="3.10"
18
19
  restructuredtext-lint==2.0.2
19
20
  twine==6.1.0;python_version=="3.8"
20
- twine==6.2.0;python_version>="3.9"
21
+ twine==6.2.0;python_version=="3.9"
22
+ twine==7.0.0;python_version>="3.10"
21
23
  yamllint==1.35.1;python_version=="3.8"
22
24
  yamllint==1.37.1;python_version=="3.9"
23
25
  yamllint==1.38.0;python_version>="3.10"
@@ -5,4 +5,4 @@ __license__ = "MIT"
5
5
  __maintainer__ = "GreyNoise Intelligence"
6
6
  __email__ = "support@greynoise.io"
7
7
  __status__ = "BETA"
8
- __version__ = "3.1.0"
8
+ __version__ = "3.2.0"