praetorian-cli 2.2.14__tar.gz → 2.2.16__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 (110) hide show
  1. {praetorian_cli-2.2.14/praetorian_cli.egg-info → praetorian_cli-2.2.16}/PKG-INFO +1 -1
  2. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/update.py +8 -2
  3. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/risks.py +45 -2
  4. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_risk.py +28 -0
  5. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16/praetorian_cli.egg-info}/PKG-INFO +1 -1
  6. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/setup.cfg +1 -1
  7. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/LICENSE +0 -0
  8. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/MANIFEST.in +0 -0
  9. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/README.md +0 -0
  10. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/__init__.py +0 -0
  11. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/__init__.py +0 -0
  12. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/add.py +0 -0
  13. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/aegis.py +0 -0
  14. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/agent.py +0 -0
  15. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/chariot.py +0 -0
  16. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/cli_decorators.py +0 -0
  17. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/configure.py +0 -0
  18. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/delete.py +0 -0
  19. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/enrich.py +0 -0
  20. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/get.py +0 -0
  21. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/imports.py +0 -0
  22. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/link.py +0 -0
  23. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/list.py +0 -0
  24. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/script.py +0 -0
  25. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/search.py +0 -0
  26. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/ssh_utils.py +0 -0
  27. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/test.py +0 -0
  28. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/unlink.py +0 -0
  29. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/handlers/utils.py +0 -0
  30. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/main.py +0 -0
  31. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/scripts/__init__.py +0 -0
  32. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/scripts/commands/__init__.py +0 -0
  33. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/scripts/commands/nmap-example.py +0 -0
  34. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/scripts/utils.py +0 -0
  35. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/__init__.py +0 -0
  36. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/chariot.py +0 -0
  37. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/__init__.py +0 -0
  38. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/accounts.py +0 -0
  39. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/aegis.py +0 -0
  40. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/agents.py +0 -0
  41. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/assets.py +0 -0
  42. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/attributes.py +0 -0
  43. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/capabilities.py +0 -0
  44. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/configurations.py +0 -0
  45. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/credentials.py +0 -0
  46. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/definitions.py +0 -0
  47. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/files.py +0 -0
  48. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/integrations.py +0 -0
  49. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/jobs.py +0 -0
  50. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/keys.py +0 -0
  51. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/preseeds.py +0 -0
  52. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/scanners.py +0 -0
  53. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/schema.py +0 -0
  54. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/search.py +0 -0
  55. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/seeds.py +0 -0
  56. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/settings.py +0 -0
  57. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/statistics.py +0 -0
  58. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/webhook.py +0 -0
  59. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/entities/webpage.py +0 -0
  60. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/keychain.py +0 -0
  61. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/mcp_server.py +0 -0
  62. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/model/__init__.py +0 -0
  63. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/model/aegis.py +0 -0
  64. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/model/globals.py +0 -0
  65. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/model/query.py +0 -0
  66. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/model/utils.py +0 -0
  67. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/__init__.py +0 -0
  68. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/pytest.ini +0 -0
  69. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_account.py +0 -0
  70. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_agent.py +0 -0
  71. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_asset.py +0 -0
  72. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_attribute.py +0 -0
  73. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_capabilities.py +0 -0
  74. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_configuration.py +0 -0
  75. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_conversation.py +0 -0
  76. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_definition.py +0 -0
  77. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_extend.py +0 -0
  78. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_file.py +0 -0
  79. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_job.py +0 -0
  80. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_key.py +0 -0
  81. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_mcp.py +0 -0
  82. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_preseed.py +0 -0
  83. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_search.py +0 -0
  84. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_seed.py +0 -0
  85. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_setting.py +0 -0
  86. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_webhook.py +0 -0
  87. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_webpage.py +0 -0
  88. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/test_z_cli.py +0 -0
  89. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/ui_mocks.py +0 -0
  90. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/sdk/test/utils.py +0 -0
  91. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/__init__.py +0 -0
  92. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/__init__.py +0 -0
  93. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/__init__.py +0 -0
  94. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/help.py +0 -0
  95. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/info.py +0 -0
  96. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/job.py +0 -0
  97. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/list.py +0 -0
  98. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/set.py +0 -0
  99. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/commands/ssh.py +0 -0
  100. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/constants.py +0 -0
  101. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/menu.py +0 -0
  102. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/aegis/utils.py +0 -0
  103. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/conversation/__init__.py +0 -0
  104. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli/ui/conversation/textual_chat.py +0 -0
  105. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli.egg-info/SOURCES.txt +0 -0
  106. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli.egg-info/dependency_links.txt +0 -0
  107. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli.egg-info/entry_points.txt +0 -0
  108. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli.egg-info/requires.txt +0 -0
  109. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/praetorian_cli.egg-info/top_level.txt +0 -0
  110. {praetorian_cli-2.2.14 → praetorian_cli-2.2.16}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praetorian-cli
3
- Version: 2.2.14
3
+ Version: 2.2.16
4
4
  Summary: For interacting with the Chariot API
5
5
  Home-page: https://github.com/praetorian-inc/praetorian-cli
6
6
  Author: Praetorian
@@ -36,7 +36,8 @@ def asset(chariot, key, status, surface):
36
36
  @click.argument('key', required=True)
37
37
  @click.option('-s', '--status', type=click.Choice([s.value for s in Risk]), help=f'Status of the risk')
38
38
  @click.option('-c', '--comment', default='', help='Comment for the risk')
39
- def risk(chariot, key, status, comment):
39
+ @click.option('-r', '--remove-comment', type=int, default=None, help='Remove comment at index (0, 1, ... or -1 for most recent)')
40
+ def risk(chariot, key, status, comment, remove_comment):
40
41
  """ Update the status and comment of a risk
41
42
 
42
43
  \b
@@ -47,8 +48,13 @@ def risk(chariot, key, status, comment):
47
48
  Example usages:
48
49
  - praetorian chariot update risk "#risk#www.example.com#CVE-2024-23049" --status OH --comment "Open it as a high severity risk"
49
50
  - praetorian chariot update risk "#risk#www.example.com#open-ssh-port" --status RH --comment "John stopped sshd on the server"
51
+ - praetorian chariot update risk "#risk#www.example.com#CVE-2024-23049" --remove-comment 0
52
+ - praetorian chariot update risk "#risk#www.example.com#CVE-2024-23049" --remove-comment -1
50
53
  """
51
- chariot.risks.update(key, status, comment)
54
+ if comment and remove_comment is not None:
55
+ raise click.UsageError("Cannot use --comment and --remove-comment together")
56
+
57
+ chariot.risks.update(key, status, comment, remove_comment)
52
58
 
53
59
 
54
60
  @update.command()
@@ -44,9 +44,9 @@ class Risks:
44
44
  risk['affected_assets'] = self.affected_assets(key)
45
45
  return risk
46
46
 
47
- def update(self, key, status=None, comment=None):
47
+ def update(self, key, status=None, comment=None, remove_comment=None):
48
48
  """
49
- Update a risk's status and/or comment.
49
+ Update a risk's status and/or comment, or remove a comment.
50
50
 
51
51
  :param key: The key of the risk. If you supply a prefix that matches multiple risks, all of them will be updated
52
52
  :type key: str
@@ -54,6 +54,8 @@ class Risks:
54
54
  :type status: str or None
55
55
  :param comment: Comment for the risk update
56
56
  :type comment: str or None
57
+ :param remove_comment: Index of comment to remove (0, 1, ... or -1 for most recent)
58
+ :type remove_comment: int or None
57
59
  :return: API response containing update results
58
60
  :rtype: dict
59
61
  """
@@ -62,6 +64,9 @@ class Risks:
62
64
  params = params | dict(status=status)
63
65
  if comment:
64
66
  params = params | dict(comment=comment)
67
+ if remove_comment is not None:
68
+ index = self.resolve_comment_entry_index(key, remove_comment)
69
+ params = params | dict(remove=index)
65
70
 
66
71
  return self.api.upsert('risk', params)
67
72
 
@@ -159,3 +164,41 @@ class Risks:
159
164
  assets.extend(indirect_assets)
160
165
  assets.extend(web_assets)
161
166
  return assets
167
+
168
+ def resolve_comment_entry_index(self, key, note_index):
169
+ """
170
+ Translate a note index to the actual history array index.
171
+
172
+ :param key: The key of the risk
173
+ :param note_index: Index into note entries (0, 1, ... or -1 for most recent note)
174
+ :return: The actual index in the history array
175
+ """
176
+ risk = self.get(key)
177
+ history = risk.get('history', [])
178
+ note_indices = get_note_entry_indices(history)
179
+
180
+ if len(note_indices) == 0:
181
+ raise Exception(f"Risk {key} has no notes to remove")
182
+
183
+ # Handle negative indexing (e.g., -1 for last note)
184
+ if note_index < 0:
185
+ note_index = len(note_indices) + note_index
186
+
187
+ if note_index < 0 or note_index >= len(note_indices):
188
+ raise Exception(f"Note index {note_index} is out of range (0 to {len(note_indices) - 1})")
189
+
190
+ return note_indices[note_index]
191
+
192
+
193
+ def get_note_entries(risk):
194
+ history = risk.get('history', [])
195
+ return [entry for entry in history if is_note_entry(entry)]
196
+
197
+
198
+ def get_note_entry_indices(history):
199
+ """Return the indices in the history array that are note entries."""
200
+ return [i for i, entry in enumerate(history) if is_note_entry(entry)]
201
+
202
+
203
+ def is_note_entry(entry):
204
+ return entry.get('comment') is not None
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
 
3
3
  from praetorian_cli.sdk.model.globals import Risk, Kind
4
+ from praetorian_cli.sdk.entities.risks import get_note_entries
4
5
  from praetorian_cli.sdk.test.utils import make_test_values, clean_test_entities, setup_chariot
5
6
 
6
7
 
@@ -39,6 +40,33 @@ class TestRisk:
39
40
  self.sdk.risks.update(self.risk_key, Risk.OPEN_CRITICAL.value)
40
41
  assert self.get_risk()['status'] == Risk.OPEN_CRITICAL.value
41
42
 
43
+ def test_remove_comment(self):
44
+ self.sdk.risks.update(self.risk_key, comment='First comment')
45
+ self.sdk.risks.update(self.risk_key, comment='Second comment')
46
+ self.sdk.risks.update(self.risk_key, comment='Third comment')
47
+
48
+ risk = self.get_risk()
49
+ initial_history_len = len(get_note_entries(risk))
50
+ assert initial_history_len == 3
51
+
52
+ self.sdk.risks.update(self.risk_key, remove_comment=-2)
53
+
54
+ risk = self.get_risk()
55
+ new_history_len = len(get_note_entries(risk))
56
+ assert new_history_len == 2
57
+
58
+ self.sdk.risks.update(self.risk_key, remove_comment=-1)
59
+
60
+ risk = self.get_risk()
61
+ final_history_len = len(get_note_entries(risk))
62
+ assert final_history_len == 1
63
+
64
+ self.sdk.risks.update(self.risk_key, remove_comment=0)
65
+
66
+ risk = self.get_risk()
67
+ final_history_len = len(get_note_entries(risk))
68
+ assert final_history_len == 0
69
+
42
70
  def test_delete_risk(self):
43
71
  self.sdk.risks.delete(self.risk_key, Risk.DELETED_DUPLICATE_CRITICAL.value)
44
72
  assert self.get_risk()['status'] == Risk.DELETED_DUPLICATE_CRITICAL.value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praetorian-cli
3
- Version: 2.2.14
3
+ Version: 2.2.16
4
4
  Summary: For interacting with the Chariot API
5
5
  Home-page: https://github.com/praetorian-inc/praetorian-cli
6
6
  Author: Praetorian
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = praetorian-cli
3
- version = 2.2.14
3
+ version = 2.2.16
4
4
  author = Praetorian
5
5
  author_email = support@praetorian.com
6
6
  description = For interacting with the Chariot API
File without changes