greynoise 3.0.3__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 (91) hide show
  1. {greynoise-3.0.3 → greynoise-3.2.0}/.bumpversion.cfg +3 -3
  2. {greynoise-3.0.3 → greynoise-3.2.0}/.circleci/config.yml +1 -1
  3. {greynoise-3.0.3 → greynoise-3.2.0}/.gitignore +3 -0
  4. {greynoise-3.0.3 → greynoise-3.2.0}/.pre-commit-config.yaml +1 -0
  5. {greynoise-3.0.3 → greynoise-3.2.0}/CHANGELOG.rst +73 -1
  6. {greynoise-3.0.3 → greynoise-3.2.0}/PKG-INFO +25 -13
  7. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/conf.py +2 -2
  8. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/sample.py +1 -3
  9. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/tutorial.rst +145 -28
  10. {greynoise-3.0.3 → greynoise-3.2.0}/pyproject.toml +29 -13
  11. greynoise-3.2.0/requirements/common.txt +24 -0
  12. greynoise-3.2.0/requirements/dev.txt +11 -0
  13. greynoise-3.2.0/requirements/docs.txt +12 -0
  14. greynoise-3.2.0/requirements/test.txt +25 -0
  15. {greynoise-3.0.3 → greynoise-3.2.0}/reset_changelog.py +3 -4
  16. {greynoise-3.0.3 → greynoise-3.2.0}/setup.cfg +3 -3
  17. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/__init__.py +6 -0
  18. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/__version__.py +1 -1
  19. greynoise-3.2.0/src/greynoise/api/__init__.py +2174 -0
  20. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/api/filter.py +6 -12
  21. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/__init__.py +8 -1
  22. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/decorator.py +52 -88
  23. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/formatter.py +85 -35
  24. greynoise-3.2.0/src/greynoise/cli/subcommand.py +806 -0
  25. greynoise-3.2.0/src/greynoise/cli/templates/callback_ip.txt.j2 +73 -0
  26. greynoise-3.2.0/src/greynoise/cli/templates/feeds_consumers.txt.j2 +40 -0
  27. greynoise-3.2.0/src/greynoise/cli/templates/feeds_events.txt.j2 +78 -0
  28. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_context_result.txt.j2 +24 -2
  29. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/macros.txt.j2 +11 -0
  30. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/personadetails.txt.j2 +3 -1
  31. greynoise-3.2.0/src/greynoise/cli/templates/recall_stats.txt.j2 +63 -0
  32. greynoise-3.2.0/src/greynoise/cli/templates/recall_timeseries.txt.j2 +38 -0
  33. greynoise-3.2.0/src/greynoise/cli/templates/timelinedaily.txt.j2 +23 -0
  34. greynoise-3.2.0/src/greynoise/exceptions.py +53 -0
  35. greynoise-3.2.0/src/greynoise/greynoise_timeline.py +527 -0
  36. greynoise-3.2.0/src/greynoise/psychic.py +1257 -0
  37. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/util.py +207 -31
  38. {greynoise-3.0.3 → greynoise-3.2.0}/tests/cli/test_formatter.py +138 -140
  39. {greynoise-3.0.3 → greynoise-3.2.0}/tests/cli/test_subcommand.py +435 -331
  40. greynoise-3.2.0/tests/test_api.py +1834 -0
  41. greynoise-3.2.0/tests/test_exceptions.py +63 -0
  42. greynoise-3.2.0/tests/test_greynoise_timeline.py +75 -0
  43. greynoise-3.2.0/tests/test_psychic.py +589 -0
  44. {greynoise-3.0.3 → greynoise-3.2.0}/tests/test_util.py +191 -40
  45. greynoise-3.0.3/requirements/common.txt +0 -11
  46. greynoise-3.0.3/requirements/dev.txt +0 -5
  47. greynoise-3.0.3/requirements/docs.txt +0 -5
  48. greynoise-3.0.3/requirements/test.txt +0 -16
  49. greynoise-3.0.3/src/greynoise/api/__init__.py +0 -1124
  50. greynoise-3.0.3/src/greynoise/cli/subcommand.py +0 -505
  51. greynoise-3.0.3/src/greynoise/cli/templates/ip_community.txt.j2 +0 -16
  52. greynoise-3.0.3/src/greynoise/cli/templates/riot.txt.j2 +0 -32
  53. greynoise-3.0.3/src/greynoise/cli/templates/sensoractivity.txt.j2 +0 -25
  54. greynoise-3.0.3/src/greynoise/cli/templates/similarity.txt.j2 +0 -28
  55. greynoise-3.0.3/src/greynoise/cli/templates/timelinehourly.txt.j2 +0 -26
  56. greynoise-3.0.3/src/greynoise/exceptions.py +0 -13
  57. greynoise-3.0.3/tests/test_api.py +0 -1228
  58. {greynoise-3.0.3 → greynoise-3.2.0}/.dockerignore +0 -0
  59. {greynoise-3.0.3 → greynoise-3.2.0}/.editorconfig +0 -0
  60. {greynoise-3.0.3 → greynoise-3.2.0}/.github/CODEOWNERS +0 -0
  61. {greynoise-3.0.3 → greynoise-3.2.0}/.github/dependabot.yml +0 -0
  62. {greynoise-3.0.3 → greynoise-3.2.0}/.github/workflows/slack_release_notice.yml +0 -0
  63. {greynoise-3.0.3 → greynoise-3.2.0}/.readthedocs.yml +0 -0
  64. {greynoise-3.0.3 → greynoise-3.2.0}/.yamllint +0 -0
  65. {greynoise-3.0.3 → greynoise-3.2.0}/Dockerfile +0 -0
  66. {greynoise-3.0.3 → greynoise-3.2.0}/LICENSE +0 -0
  67. {greynoise-3.0.3 → greynoise-3.2.0}/MANIFEST.in +0 -0
  68. {greynoise-3.0.3 → greynoise-3.2.0}/Makefile +0 -0
  69. {greynoise-3.0.3 → greynoise-3.2.0}/README.rst +0 -0
  70. {greynoise-3.0.3 → greynoise-3.2.0}/docs/Makefile +0 -0
  71. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/changelog.rst +0 -0
  72. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/index.rst +0 -0
  73. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/introduction.rst +0 -0
  74. {greynoise-3.0.3 → greynoise-3.2.0}/docs/source/reference.rst +0 -0
  75. {greynoise-3.0.3 → greynoise-3.2.0}/pytest.ini +0 -0
  76. {greynoise-3.0.3 → greynoise-3.2.0}/release.md +0 -0
  77. {greynoise-3.0.3 → greynoise-3.2.0}/sonar-project.properties +0 -0
  78. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/helper.py +0 -0
  79. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/parameter.py +0 -0
  80. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/analyze.txt.j2 +0 -0
  81. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/cvedetails.txt.j2 +0 -0
  82. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/gnql_query.txt.j2 +0 -0
  83. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/gnql_stats.txt.j2 +0 -0
  84. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_context.txt.j2 +0 -0
  85. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_multi_context.txt.j2 +0 -0
  86. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/ip_quick_check.txt.j2 +0 -0
  87. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/sensorlist.txt.j2 +0 -0
  88. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/stats.txt.j2 +0 -0
  89. {greynoise-3.0.3 → greynoise-3.2.0}/src/greynoise/cli/templates/timeline.txt.j2 +0 -0
  90. {greynoise-3.0.3 → greynoise-3.2.0}/tests/cli/test_init.py +0 -0
  91. {greynoise-3.0.3 → greynoise-3.2.0}/tox.ini +0 -0
@@ -1,11 +1,11 @@
1
1
  [bumpversion]
2
- current_version = 3.0.3
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}"
@@ -68,7 +68,7 @@ jobs:
68
68
  command: yamllint .
69
69
  - run:
70
70
  name: Style check (black)
71
- command: black --check src tests docs
71
+ command: black --check --target-version py310 src tests docs
72
72
  - run:
73
73
  name: Style check (isort)
74
74
  command: isort --check-only src/**/*.py tests/**/*.py docs/**/*.py
@@ -89,6 +89,7 @@ celerybeat-schedule
89
89
  venv/
90
90
  venv_py2/
91
91
  venv3/
92
+ venv312/
92
93
  ENV/
93
94
  bin/
94
95
  pyvenv.cfg
@@ -111,3 +112,5 @@ pyvenv.cfg
111
112
  workspace/
112
113
 
113
114
  .DS_Store
115
+ .vscode/
116
+ scratch.py
@@ -14,6 +14,7 @@ repos:
14
14
  language: system
15
15
  types:
16
16
  - python
17
+ args: [--target-version, py310]
17
18
  - id: isort
18
19
  name: Style check (isort)
19
20
  entry: isort
@@ -2,6 +2,76 @@
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
+
39
+ Version `3.1.0`_
40
+ ================
41
+ **Date**: July 9, 2026
42
+
43
+ * API client:
44
+
45
+ * Added `psychic_lookup`, `psychic_lookup_ips`, `psychic_stats` functions to support Psychic API endpoints
46
+ * Added `psychic_download_mmdb`, `psychic_download_bin`, `psychic_download_csv`, `psychic_generate_bitmap` functions to support Psychic file downloads
47
+ * Added `cves` function to support bulk CVE lookup API endpoints
48
+ * Added `callback_ip`, `callback_list`, `callback_export_ips`, `callback_overview` functions to support Callback API endpoints
49
+ * Added `recall`, `recall_stats`, `recall_timeseries` functions to support Recall API endpoints
50
+ * Updated the `timeline` and `timelinehourly` function
51
+ * Updated the `filter` function to correctly handle v3 API response format
52
+ * The `tags` function is now used instead of `metadata`, but is still available for backwards compatibility.
53
+ * The `similar` function is deprecated and will be removed in a future version.
54
+ * The `sensor_activity` and `sensor_activity_ips` functions are deprecated and will be removed in a future version.
55
+ * The `timelinehourly` function is deprecated and will be removed in a future version.
56
+
57
+ * CLI:
58
+ * Added `psychic-download` and `psychic-generate` commands to support Psychic file downloads
59
+ * Updated `ip` command to support Psychic API endpoints with new `-p/--psychic` option
60
+ * Added `callback` commands to support Callback API endpoints
61
+ * Added `recall` commands to support Recall API endpoints
62
+ * Removed `sensor-activity` command as it is deprecated and will be removed in a future version.
63
+ * Removed `timelinehourly` command as it is deprecated and will be removed in a future version.
64
+ * Removed not implemented commands `alerts`, `account`, `feedback`, `signature`, `interesting`.
65
+
66
+ * Dependencies:
67
+ * Updated `requests` to version 2.34.2
68
+ * Updated `more-itertools` to version 11.1.0
69
+ * Updated `cachetools` to version 7.0.5
70
+ * Updated `Click` to version 8.3.1
71
+ * Updated `ansimarkup` to version 2.2.0
72
+ * Updated `dict2xml` to version 1.7.8
73
+ * Added `maxminddb` to version 3.1.1
74
+
5
75
  Version `3.0.3`_
6
76
  ================
7
77
  **Date**: May 15, 2026
@@ -492,4 +562,6 @@ Version `0.2.0`_
492
562
  .. _`3.0.0`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v2.3.0...v3.0.0
493
563
  .. _`3.0.1`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.0...v3.0.1
494
564
  .. _`3.0.2`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.1...v3.0.2
495
- .. _`3.0.3`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.2...HEAD
565
+ .. _`3.0.3`: https://github.com/GreyNoise-Intelligence/pygreynoise/compare/v3.0.2...v3.0.3
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.0.3
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,17 +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
26
- Requires-Dist: cachetools
27
- Requires-Dist: click-default-group
28
- Requires-Dist: click-repl
29
- Requires-Dist: click<=8.1.8
30
- Requires-Dist: colorama
31
- Requires-Dist: dict2xml
32
- Requires-Dist: jinja2
33
- Requires-Dist: more-itertools>=8.14.0
34
- Requires-Dist: requests
35
- Requires-Dist: six
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
36
48
  Description-Content-Type: text/x-rst
37
49
 
38
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.0.3"
28
+ release = "3.2.0"
29
29
 
30
30
 
31
31
  # -- General configuration ---------------------------------------------------
@@ -2,9 +2,7 @@ from greynoise.api import APIConfig, GreyNoise
2
2
 
3
3
  api_key = "<enter-api-key-here>"
4
4
  ip_addresses = ["108.168.3.151", "8.8.8.8", "318.1.1.1"]
5
- api_config = APIConfig(
6
- api_key=api_key, integration_name="greynoise-sampleapp-v1.0.0-beta"
7
- )
5
+ api_config = APIConfig(api_key=api_key, integration_name="greynoise-sampleapp-v1.0.0-beta")
8
6
  api_client = GreyNoise(api_config)
9
7
 
10
8
  for ip_address in ip_addresses:
@@ -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
  ======================
@@ -752,36 +823,33 @@ subcommands, use the *--help* option::
752
823
  $ greynoise -h
753
824
  Usage: greynoise [OPTIONS] COMMAND [ARGS]...
754
825
 
755
- GreyNoise CLI.
826
+ GreyNoise CLI.
756
827
 
757
828
  Options:
758
829
  -h, --help Show this message and exit.
759
830
 
760
831
  Commands:
761
- account View information about your GreyNoise account.
762
- alerts List, create, delete, and manage your GreyNoise alerts.
763
- analyze Analyze the IP addresses in a log file, stdin, etc.
764
- cve Retrieve Details of a CVE.
765
- feedback Send feedback directly to the GreyNoise team.
766
- filter Filter the noise from a log file, stdin, etc.
767
- help Show this message and exit.
768
- ip Query GreyNoise for all information on a given IP.
769
- ip-multi Perform Context lookup for multiple IPs at once.
770
- persona-details Retrieve Details of a Sensor Persona.
771
- query Run a GNQL (GreyNoise Query Language) query.
772
- quick Quickly check whether or not one or many IPs are "noise".
773
- repl Start an interactive shell.
774
- riot Query GreyNoise IP to see if it is in the RIOT dataset.
775
- sensor-activity Retrieve Sensor Activity.
776
- sensor-list Retrieve list of current Sensors in Workspace.
777
- setup Configure API client.
778
- signature Submit an IDS signature to GreyNoise to be deployed to...
779
- similar Query GreyNoise IP to identify Similar IPs.
780
- stats Get aggregate stats from a given GNQL query.
781
- timeline Query GreyNoise IP Timeline for events based on a...
782
- timelinedaily Query GreyNoise IP Timeline to get daily event details.
783
- timelinehourly Query GreyNoise IP Timeline to get hourly event details.
784
- version Get version and OS information for your GreyNoise...
832
+ analyze Analyze the IP addresses in a log file, stdin, etc.
833
+ callback GreyNoise Callback — scanner callback intelligence...
834
+ cve Retrieve Details of a CVE.
835
+ feeds Search retained feed events, pull a batch, or manage...
836
+ filter Filter the noise from a log file, stdin, etc.
837
+ help Show this message and exit.
838
+ ip Query GreyNoise for all information on a given IP.
839
+ ip-multi Perform Context lookup for multiple IPs at once.
840
+ persona-details Retrieve Details of a Sensor Persona.
841
+ psychic-download Download a Psychic bitmap (.bin), MMDB, or CSV file...
842
+ psychic-generate Generate a Psychic bitmap (.bin) for a date range...
843
+ query Run a GNQL (GreyNoise Query Language) query.
844
+ quick Quickly check whether or not one or many IPs are...
845
+ recall GreyNoise Recall — GNQL activity over time.
846
+ repl Start an interactive shell.
847
+ sensor-list Retrieve list of current Sensors in Workspace.
848
+ setup Configure API client.
849
+ stats Get aggregate stats from a given GNQL query.
850
+ timeline Query GreyNoise IP Timeline for events based on a...
851
+ timelinedaily Query GreyNoise IP Timeline to get daily event details.
852
+ version Get version and OS information for your GreyNoise...
785
853
 
786
854
 
787
855
  Setup
@@ -942,6 +1010,19 @@ this (a comma separated list is also supported::
942
1010
  Last Updated: 2025-05-23T13:11:02Z
943
1011
  Reference: https://developers.google.com/speed/public-dns/docs/isp#alternative
944
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
+
945
1026
  Check for Similar IPs to a given IP::
946
1027
 
947
1028
  $ greynoise similar 69.160.160.55
@@ -1008,6 +1089,40 @@ Check the Timeline of a given IP::
1008
1089
  2025-05-11 1 suspicious
1009
1090
  2025-04-27 1 suspicious
1010
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
+
1011
1126
  GNQL
1012
1127
  ----
1013
1128
 
@@ -1015,7 +1130,7 @@ Run a query
1015
1130
  ~~~~~~~~~~~
1016
1131
 
1017
1132
  A GNQL (GreyNoise Query Language) query can be executed to dig deeper into the GreyNoise
1018
- 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
1019
1134
  as malicious and tagged as a Bluekeep Exploit::
1020
1135
 
1021
1136
  $ greynoise query "classification:malicious tags:Bluekeep Exploit"
@@ -1073,6 +1188,8 @@ as malicious and tagged as a Bluekeep Exploit::
1073
1188
  This is the default command, that is, you can save some typing by just
1074
1189
  writing ``greynoise <query>`` instead of ``greynoise query <query>``.
1075
1190
 
1191
+ ``--exclude`` is a comma-separated list of fields to omit from the results.
1192
+
1076
1193
 
1077
1194
  Get statistics
1078
1195
  ~~~~~~~~~~~~~~
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "greynoise"
7
- version = "3.0.3"
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,17 +28,29 @@ classifiers = [
28
28
  ]
29
29
  keywords = ["internet", "scanning", "threat intelligence", "security"]
30
30
  dependencies = [
31
- "Click<=8.1.8",
32
- "ansimarkup",
33
- "cachetools",
34
- "colorama",
35
- "click-default-group",
36
- "click-repl",
37
- "dict2xml",
38
- "jinja2",
39
- "more-itertools>=8.14.0",
40
- "requests",
41
- "six",
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",
42
54
  ]
43
55
 
44
56
  [project.urls]
@@ -53,4 +65,8 @@ greynoise = "greynoise.cli:main"
53
65
  packages = ["src/greynoise"]
54
66
 
55
67
  [tool.hatch.build.targets.wheel.shared-data]
56
- "src/greynoise/cli/templates/*.j2" = "greynoise/cli/templates"
68
+ "src/greynoise/cli/templates/*.j2" = "greynoise/cli/templates"
69
+
70
+ [tool.black]
71
+ line-length = 120
72
+ target-version = ["py310"]
@@ -0,0 +1,24 @@
1
+ Click<=8.1.8;python_version=="3.8"
2
+ Click<=8.1.8;python_version=="3.9"
3
+ Click==8.5.0;python_version>="3.10"
4
+ ansimarkup==2.2.0
5
+ cachetools==5.5.2;python_version=="3.8"
6
+ cachetools==6.2.6;python_version=="3.9"
7
+ cachetools==7.2.8;python_version>="3.10"
8
+ colorama==0.4.6
9
+ click-default-group==1.2.4
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
13
+ jinja2==3.1.6
14
+ maxminddb==2.6.3;python_version=="3.8"
15
+ maxminddb==2.8.2;python_version=="3.9"
16
+ maxminddb==3.2.0;python_version>="3.10"
17
+ more-itertools==10.5.0;python_version=="3.8"
18
+ more-itertools==10.8.0;python_version=="3.9"
19
+ more-itertools==11.1.0;python_version=="3.10"
20
+ more-itertools==11.2.1;python_version>="3.11"
21
+ requests==2.32.4;python_version=="3.8"
22
+ requests==2.32.5;python_version=="3.9"
23
+ requests==2.34.2;python_version>="3.10"
24
+ six==1.17.0
@@ -0,0 +1,11 @@
1
+ # Requirements needed to develop the application
2
+ -r test.txt
3
+ advbumpversion==1.2.0
4
+ ipython==8.12.3;python_version=="3.8"
5
+ ipython==8.18.1;python_version=="3.9"
6
+ ipython==8.39.0;python_version=="3.10"
7
+ ipython==9.17.1;python_version>="3.11"
8
+ tox==4.25.0;python_version=="3.8"
9
+ tox==4.30.3;python_version=="3.9"
10
+ tox==4.65.0;python_version=="3.10"
11
+ tox==4.67.1;python_version>="3.11"
@@ -0,0 +1,12 @@
1
+ # Requirements needed to build the documentation
2
+ -r common.txt
3
+ Sphinx==7.1.2;python_version=="3.8"
4
+ Sphinx==7.4.7;python_version=="3.9"
5
+ Sphinx==8.1.3;python_version=="3.10"
6
+ Sphinx==9.0.4;python_version=="3.11"
7
+ Sphinx==9.1.1;python_version=="3.12"
8
+ Sphinx==9.2.0;python_version>="3.13"
9
+ sphinx-click==6.0.0;python_version=="3.8"
10
+ sphinx-click==6.0.0;python_version=="3.9"
11
+ sphinx-click==6.2.0;python_version>="3.10"
12
+ sphinx-rtd-theme==3.1.0
@@ -0,0 +1,25 @@
1
+ black==24.8.0;python_version=="3.8"
2
+ black==25.11.0;python_version=="3.9"
3
+ black==26.10.1;python_version>="3.10"
4
+ flake8==7.1.2;python_version=="3.8"
5
+ flake8==7.3.0;python_version=="3.9"
6
+ flake8==7.4.1;python_version>="3.10"
7
+ isort==5.13.2;python_version=="3.8"
8
+ isort==6.1.0;python_version=="3.9"
9
+ isort==9.0.2;python_version>="3.10"
10
+ mock==5.2.0
11
+ pylint==3.2.7;python_version=="3.8"
12
+ pylint==3.3.9;python_version=="3.9"
13
+ pylint==4.1.3;python_version>="3.10"
14
+ pytest-cov==5.0.0;python_version=="3.8"
15
+ pytest-cov==7.1.0;python_version>="3.9"
16
+ pytest==8.3.5;python_version=="3.8"
17
+ pytest==8.4.2;python_version=="3.9"
18
+ pytest==9.1.1;python_version>="3.10"
19
+ restructuredtext-lint==2.0.2
20
+ twine==6.1.0;python_version=="3.8"
21
+ twine==6.2.0;python_version=="3.9"
22
+ twine==7.0.0;python_version>="3.10"
23
+ yamllint==1.35.1;python_version=="3.8"
24
+ yamllint==1.37.1;python_version=="3.9"
25
+ yamllint==1.38.0;python_version>="3.10"
@@ -43,10 +43,9 @@ if not match:
43
43
  )
44
44
  f.seek(0)
45
45
  f.write(text)
46
- LINK_STRING = (
47
- ".. _`dev`: https://github.com/GreyNoise-Intelligence/pygreynoise/"
48
- "compare/v{}...HEAD"
49
- ).format(ver)
46
+ LINK_STRING = (".. _`dev`: https://github.com/GreyNoise-Intelligence/pygreynoise/" "compare/v{}...HEAD").format(
47
+ ver
48
+ )
50
49
  f.write(LINK_STRING)
51
50
  f.truncate()
52
51
  else:
@@ -1,13 +1,13 @@
1
1
  [flake8]
2
- max-line-length = 88
2
+ max-line-length = 120
3
3
  max-complexity = 10
4
- ignore = C901,W503
4
+ ignore = C901,W503,E203
5
5
 
6
6
  [isort]
7
7
  multi_line_output = 3
8
8
  include_trailing_comma = True
9
9
  use_parentheses = True
10
- line_length = 88
10
+ line_length = 120
11
11
 
12
12
  [tool:pytest]
13
13
  addopts = --pdbcls=IPython.terminal.debugger:TerminalPdb
@@ -10,4 +10,10 @@ from greynoise.__version__ import ( # noqa
10
10
  __status__,
11
11
  __version__,
12
12
  )
13
+
14
+ USER_AGENT = "GreyNoise/{}".format(__version__)
15
+ PSYCHIC_USER_AGENT = "{} (psychic)".format(USER_AGENT)
16
+
13
17
  from greynoise.api import GreyNoise # noqa
18
+ from greynoise.greynoise_timeline import get_greynoise_timeline # noqa
19
+ from greynoise.psychic import Psychic # noqa
@@ -5,4 +5,4 @@ __license__ = "MIT"
5
5
  __maintainer__ = "GreyNoise Intelligence"
6
6
  __email__ = "support@greynoise.io"
7
7
  __status__ = "BETA"
8
- __version__ = "3.0.3"
8
+ __version__ = "3.2.0"