praetorian-cli 2.2.2__tar.gz → 2.2.4__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 (111) hide show
  1. {praetorian_cli-2.2.2/praetorian_cli.egg-info → praetorian_cli-2.2.4}/PKG-INFO +1 -1
  2. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/add.py +47 -7
  3. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/cli_decorators.py +1 -1
  4. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/delete.py +15 -2
  5. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/get.py +48 -2
  6. praetorian_cli-2.2.4/praetorian_cli/handlers/link.py +60 -0
  7. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/list.py +30 -9
  8. praetorian_cli-2.2.4/praetorian_cli/handlers/unlink.py +55 -0
  9. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/update.py +3 -3
  10. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/chariot.py +6 -12
  11. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/assets.py +30 -12
  12. praetorian_cli-2.2.4/praetorian_cli/sdk/entities/schema.py +27 -0
  13. praetorian_cli-2.2.4/praetorian_cli/sdk/entities/seeds.py +166 -0
  14. praetorian_cli-2.2.4/praetorian_cli/sdk/entities/webpage.py +180 -0
  15. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/mcp_server.py +2 -3
  16. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/model/globals.py +2 -0
  17. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/model/query.py +8 -1
  18. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/model/utils.py +2 -8
  19. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_asset.py +38 -2
  20. praetorian_cli-2.2.4/praetorian_cli/sdk/test/test_seed.py +40 -0
  21. praetorian_cli-2.2.4/praetorian_cli/sdk/test/test_webpage.py +46 -0
  22. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_z_cli.py +53 -24
  23. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/utils.py +21 -4
  24. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4/praetorian_cli.egg-info}/PKG-INFO +1 -1
  25. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli.egg-info/SOURCES.txt +3 -0
  26. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/setup.cfg +1 -1
  27. praetorian_cli-2.2.2/praetorian_cli/handlers/link.py +0 -32
  28. praetorian_cli-2.2.2/praetorian_cli/handlers/unlink.py +0 -27
  29. praetorian_cli-2.2.2/praetorian_cli/sdk/entities/seeds.py +0 -114
  30. praetorian_cli-2.2.2/praetorian_cli/sdk/test/test_seed.py +0 -41
  31. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/LICENSE +0 -0
  32. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/MANIFEST.in +0 -0
  33. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/README.md +0 -0
  34. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/__init__.py +0 -0
  35. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/__init__.py +0 -0
  36. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/aegis.py +0 -0
  37. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/agent.py +0 -0
  38. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/chariot.py +0 -0
  39. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/configure.py +0 -0
  40. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/enrich.py +0 -0
  41. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/imports.py +0 -0
  42. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/script.py +0 -0
  43. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/search.py +0 -0
  44. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/ssh_utils.py +0 -0
  45. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/test.py +0 -0
  46. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/handlers/utils.py +0 -0
  47. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/main.py +0 -0
  48. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/scripts/__init__.py +0 -0
  49. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/scripts/commands/__init__.py +0 -0
  50. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/scripts/commands/nmap-example.py +0 -0
  51. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/scripts/utils.py +0 -0
  52. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/__init__.py +0 -0
  53. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/__init__.py +0 -0
  54. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/accounts.py +0 -0
  55. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/aegis.py +0 -0
  56. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/agents.py +0 -0
  57. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/attributes.py +0 -0
  58. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/capabilities.py +0 -0
  59. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/configurations.py +0 -0
  60. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/credentials.py +0 -0
  61. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/definitions.py +0 -0
  62. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/files.py +0 -0
  63. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/integrations.py +0 -0
  64. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/jobs.py +0 -0
  65. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/keys.py +0 -0
  66. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/preseeds.py +0 -0
  67. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/risks.py +0 -0
  68. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/scanners.py +0 -0
  69. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/search.py +0 -0
  70. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/settings.py +0 -0
  71. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/statistics.py +0 -0
  72. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/entities/webhook.py +0 -0
  73. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/keychain.py +0 -0
  74. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/model/__init__.py +0 -0
  75. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/model/aegis.py +0 -0
  76. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/__init__.py +0 -0
  77. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/pytest.ini +0 -0
  78. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_account.py +0 -0
  79. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_agent.py +0 -0
  80. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_attribute.py +0 -0
  81. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_capabilities.py +0 -0
  82. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_configuration.py +0 -0
  83. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_definition.py +0 -0
  84. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_extend.py +0 -0
  85. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_file.py +0 -0
  86. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_job.py +0 -0
  87. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_key.py +0 -0
  88. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_mcp.py +0 -0
  89. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_preseed.py +0 -0
  90. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_risk.py +0 -0
  91. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_search.py +0 -0
  92. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_setting.py +0 -0
  93. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/test_webhook.py +0 -0
  94. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/sdk/test/ui_mocks.py +0 -0
  95. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/__init__.py +0 -0
  96. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/__init__.py +0 -0
  97. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/__init__.py +0 -0
  98. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/help.py +0 -0
  99. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/info.py +0 -0
  100. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/job.py +0 -0
  101. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/list.py +0 -0
  102. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/set.py +0 -0
  103. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/commands/ssh.py +0 -0
  104. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/constants.py +0 -0
  105. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/menu.py +0 -0
  106. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli/ui/aegis/utils.py +0 -0
  107. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli.egg-info/dependency_links.txt +0 -0
  108. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli.egg-info/entry_points.txt +0 -0
  109. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli.egg-info/requires.txt +0 -0
  110. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/praetorian_cli.egg-info/top_level.txt +0 -0
  111. {praetorian_cli-2.2.2 → praetorian_cli-2.2.4}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praetorian-cli
3
- Version: 2.2.2
3
+ Version: 2.2.4
4
4
  Summary: For interacting with the Chariot API
5
5
  Home-page: https://github.com/praetorian-inc/praetorian-cli
6
6
  Author: Praetorian
@@ -29,6 +29,9 @@ def asset(sdk, name, dns, asset_type, status, surface):
29
29
  Add an asset to the Chariot database. This command requires a DNS name for the asset.
30
30
  Optionally, a name can be provided to give the asset more specific information,
31
31
  such as IP address. If no name is provided, the DNS name will be used as the name.
32
+ The DNS is the group and the name is the specific identifier. This is for legacy reasons.
33
+
34
+ The type can be one of the following: asset, addomain, repository, webapplication.
32
35
 
33
36
  \b
34
37
  Example assets:
@@ -41,6 +44,7 @@ def asset(sdk, name, dns, asset_type, status, surface):
41
44
  - praetorian chariot add asset --dns example.com
42
45
  - praetorian chariot add asset --dns example.com --name 1.2.3.4
43
46
  - praetorian chariot add asset --dns internal.example.com --name 10.2.3.4 --surface internal
47
+ - praetorian chariot add asset --dns https://example.com --name 'Example Web Application' --type webapplication
44
48
  """
45
49
  if not name:
46
50
  name = dns
@@ -196,21 +200,39 @@ def attribute(sdk, key, name, value):
196
200
 
197
201
  @add.command()
198
202
  @cli_handler
199
- @click.option('-d', '--dns', required=True, help='The DNS of the asset')
203
+ @click.option('-t', '--type', 'seed_type', default='asset', help='Asset type (e.g., asset, addomain)')
200
204
  @click.option('-s', '--status', type=click.Choice([s.value for s in Seed]),
201
205
  default=Seed.PENDING.value, help='The status of the seed', show_default=True)
202
- def seed(sdk, dns, status):
206
+ @click.option('-f', '--field', 'field_list', multiple=True,
207
+ help='Field in format name:value (can be specified multiple times)')
208
+ def seed(sdk, seed_type, status, field_list):
203
209
  """ Add a seed
204
210
 
205
- Add a seed to the Chariot database. This command requires DNS of the seed to be
206
- specified. When status is not specified, the seed is added as PENDING.
211
+ Add a seed to the Chariot database. Seeds are now assets with special labeling.
212
+ You can specify the asset type and provide dynamic fields using --fields.
207
213
 
208
214
  \b
209
215
  Example usages:
210
- - praetorian chariot add seed --dns example.com
211
- - praetorian chariot add seed --dns example.com --status A
216
+ - praetorian chariot add seed --type asset --field dns:example.com
217
+ - praetorian chariot add seed --type asset --field dns:example.com --status A
218
+ - praetorian chariot add seed --type asset --field dns:example.com --field name:1.2.3.4
219
+ - praetorian chariot add seed --type addomain --field domain:corp.local --field objectid:S-1-5-21-2701466056-1043032755-2418290285
212
220
  """
213
- sdk.seeds.add(dns, status)
221
+ # Collect dynamic fields from the --fields option
222
+ dynamic_fields = {}
223
+
224
+ # Parse field_list entries (name:value format)
225
+ for field in field_list:
226
+ if ':' in field:
227
+ # Split only once to allow colons in the value
228
+ name, value = field.split(':', 1)
229
+ dynamic_fields[name] = value
230
+ else:
231
+ error(f"Field '{field}' is not in the format name:value")
232
+ return
233
+
234
+ # Call the updated add method with type and dynamic fields
235
+ sdk.seeds.add(status=status, seed_type=seed_type, **dynamic_fields)
214
236
 
215
237
 
216
238
  @add.command()
@@ -310,3 +332,21 @@ def key(sdk, name, expires):
310
332
  return
311
333
  click.echo(f'API key created: {result.get("key", "N/A")}')
312
334
  click.echo(f'Secret (save this, it will not be shown again): {result["secret"]}')
335
+
336
+
337
+ @add.command()
338
+ @cli_handler
339
+ @click.option('-u', '--url', required=True, help='The full URL of the page')
340
+ @click.option('-p', '--parent', required=False, help='Optional key of the parent WebApplication')
341
+ def webpage(sdk, url, parent):
342
+ """ Add a Webpage
343
+
344
+ Add a web page to the Chariot database. Webpages can optionally be associated
345
+ with a parent WebApplication or exist independently.
346
+
347
+ \b
348
+ Example usages:
349
+ - praetorian chariot add webpage --url https://app.example.com/login
350
+ - praetorian chariot add webpage --url https://app.example.com/admin --parent "#webapplication#https://app.example.com"
351
+ """
352
+ sdk.webpage.add(url, parent)
@@ -68,7 +68,7 @@ def list_params(filter_by, has_details=True, has_filter=True, has_type=False):
68
68
 
69
69
 
70
70
  def pagination(func):
71
- func = click.option('-o', '--offset', default='', help='List results from an offset')(func)
71
+ func = click.option('-o', '--offset', default=0, help='List results from an offset')(func)
72
72
  func = click.option('-p', '--page', type=click.Choice(('first', 'all')), default='first',
73
73
  help='Pagination mode. "all" pages up to 10,000 pages.', show_default=True)(func)
74
74
  return func
@@ -88,11 +88,12 @@ def seed(chariot, key):
88
88
 
89
89
  \b
90
90
  Arguments:
91
- - KEY: the key of an existing seed
91
+ - KEY: the key of an existing seed (now uses asset key format)
92
92
 
93
93
  \b
94
94
  Example usage:
95
- - praetorian chariot delete seed "#seed#domain#example.com"
95
+ - praetorian chariot delete seed "#asset#example.com#example.com"
96
+ - praetorian chariot delete seed "#addomain#corp.local#corp.local"
96
97
  """
97
98
  chariot.seeds.delete(key)
98
99
 
@@ -181,3 +182,15 @@ def key(chariot, key):
181
182
  - praetorian chariot delete key "#key#550e8400-e29b-41d4-a716-446655440000"
182
183
  """
183
184
  chariot.keys.delete(key)
185
+
186
+ @delete.command()
187
+ @cli_handler
188
+ @click.argument('key', required=True)
189
+ def webpage(chariot, key):
190
+ """ Delete a webpage
191
+
192
+ \b
193
+ Arguments:
194
+ - KEY: the key of an existing webpage
195
+ """
196
+ chariot.webpage.delete(key)
@@ -186,11 +186,12 @@ def seed(chariot, key):
186
186
 
187
187
  \b
188
188
  Argument:
189
- - KEY: the key of an existing pre-seed
189
+ - KEY: the key of an existing seed (now uses asset key format)
190
190
 
191
191
  \b
192
192
  Example usages:
193
- - praetorian chariot get preseed "#preseed#domain#example.com"
193
+ - praetorian chariot get seed "#asset#example.com#example.com"
194
+ - praetorian chariot get seed "#addomain#corp.local#corp.local"
194
195
  """
195
196
  print_json(chariot.seeds.get(key))
196
197
 
@@ -295,3 +296,48 @@ def scanner(chariot, key):
295
296
  - praetorian chariot get scanner "#scanner#127.0.0.1"
296
297
  """
297
298
  print_json(chariot.scanners.get(key))
299
+
300
+
301
+ @get.command()
302
+ @cli_handler
303
+ @click.argument('key', required=True)
304
+ def webpage(chariot, key):
305
+ """ Get Webpage details
306
+
307
+ Retrieve detailed information about a specific web page, including
308
+ its URL, method, authentication requirements, and other metadata.
309
+
310
+ \b
311
+ Argument:
312
+ - KEY: the key of an existing Webpage
313
+
314
+ \b
315
+ Example usages:
316
+ - praetorian chariot get webpage "#webpage#https://app.example.com/dashboard"
317
+ """
318
+ print_json(chariot.webpage.get(key))
319
+
320
+ @click.option('-t', '--type', help='Optional specific entity type (e.g., asset, risk, attribute)')
321
+ @click.option('-d', '--details', is_flag=True, help='Further retrieve the details of the schema')
322
+ def schema(chariot, type, details):
323
+ """ Get Chariot entity schema
324
+
325
+ \b
326
+ Returns the JSON schema for Chariot entities. Optionally filter for a
327
+ specific entity type.
328
+
329
+ \b
330
+ Example usages:
331
+ - praetorian chariot get schema
332
+ - praetorian chariot get schema --type asset
333
+ - praetorian chariot get schema --type asset --details
334
+ """
335
+ data = chariot.schema.get(type)
336
+ if type:
337
+ data = {type: data[type]}
338
+
339
+ if details:
340
+ print_json(data)
341
+ else:
342
+ for hit in data:
343
+ click.echo(hit)
@@ -0,0 +1,60 @@
1
+ import click
2
+
3
+ from praetorian_cli.handlers.chariot import chariot
4
+ from praetorian_cli.handlers.cli_decorators import cli_handler
5
+
6
+
7
+ @chariot.group()
8
+ def link():
9
+ """ Link resources to other entities """
10
+ pass
11
+
12
+
13
+ @link.command()
14
+ @cli_handler
15
+ @click.argument('username')
16
+ def account(chariot, username):
17
+ """ Add a collaborator account to your account
18
+
19
+ This allows them to assume access into your account
20
+ and perform actions on your behalf.
21
+
22
+ \b
23
+ Arguments:
24
+ - NAME: their email address
25
+
26
+
27
+
28
+ \b
29
+ Example usages:
30
+ - praetorian chariot link account john@praetorian.com
31
+ """
32
+ chariot.accounts.add_collaborator(username)
33
+
34
+
35
+ @link.command('webpage-source')
36
+ @cli_handler
37
+ @click.argument('webpage_key')
38
+ @click.argument('entity_key')
39
+ def webpage_source(chariot, webpage_key, entity_key):
40
+ """ Link a file or repository to a webpage as source code
41
+
42
+ This associates source code files or repositories with webpages
43
+ to track where webpage content originates from.
44
+
45
+ \b
46
+ Arguments:
47
+ - WEBPAGE_KEY: The webpage key in format #webpage#{url}
48
+ - ENTITY_KEY: The file or repository key to link
49
+ Format: #file#{path} or #repository#{url}#{name}
50
+
51
+ \b
52
+ Example usages:
53
+ - praetorian chariot link webpage-source "#webpage#https://example.com" "#file#proofs/scan.txt"
54
+ - praetorian chariot link webpage-source "#webpage#https://example.com/login" "#repository#https://github.com/org/repo.git#repo.git"
55
+ """
56
+ result = chariot.webpage.link_source(webpage_key, entity_key)
57
+ if result:
58
+ click.echo(f"Successfully linked {entity_key} to {webpage_key}")
59
+ if 'artifacts' in result:
60
+ click.echo(f"Webpage now has {len(result['artifacts'])} linked artifacts")
@@ -26,7 +26,7 @@ def assets(chariot, filter, model_type, details, offset, page):
26
26
  - praetorian chariot list assets --page all
27
27
  - praetorian chariot list assets --type repository
28
28
  """
29
- render_list_results(chariot.assets.list(filter, model_type, offset, pagination_size(page)), details)
29
+ render_list_results(chariot.assets.list(filter, model_type, pagination_size(page)), details)
30
30
 
31
31
 
32
32
  @list.command()
@@ -178,24 +178,23 @@ def attributes(chariot, filter, key, details, offset, page):
178
178
 
179
179
  @list.command()
180
180
  @list_params('DNS')
181
- @click.option('-t', '--type', type=click.Choice(['ip', 'domain']), help=f'Filter by type of the seeds')
181
+ @click.option('-t', '--type', help='Filter by seed type (e.g., asset, addomain)')
182
182
  def seeds(chariot, type, filter, details, offset, page):
183
183
  """ List seeds
184
184
 
185
- Retrieve and display a list of seeds.
185
+ Retrieve and display a list of seeds. Seeds are now assets with the 'Seed' label.
186
186
 
187
187
  \b
188
188
  Example usages:
189
189
  - praetorian chariot list seeds
190
- - praetorian chariot list seeds --type ip
191
- - praetorian chariot list seeds --type domain --filter example.com
190
+ - praetorian chariot list seeds --type asset
191
+ - praetorian chariot list seeds --type addomain
192
+ - praetorian chariot list seeds --type asset --filter example.com
192
193
  - praetorian chariot list seeds --details
193
194
  - praetorian chariot list seeds --page all
194
195
  """
195
- if filter and not type:
196
- error('When the DNS filter is specified, you also need to specify the type of the filter: ip or domain.')
197
-
198
- render_list_results(chariot.seeds.list(type, filter, offset, pagination_size(page)), details)
196
+ # Note: filter restriction removed since we're using different key format now
197
+ render_list_results(chariot.seeds.list(type, filter, pagination_size(page)), details)
199
198
 
200
199
 
201
200
  @list.command()
@@ -369,3 +368,25 @@ def scanners(chariot, filter, details, offset, page):
369
368
  - praetorian chariot list scanners --page all
370
369
  """
371
370
  render_list_results(chariot.scanners.list(filter, offset, pagination_size(page)), details)
371
+
372
+
373
+ @list.command()
374
+ @click.option('--parent', required=False, help='Optional WebApp key to filter pages')
375
+ @click.option('-f', '--filter', required=False, help='Optional URL to filter pages')
376
+ @click.option('-d', '--details', is_flag=True, default=False, help='Show detailed information')
377
+ @pagination
378
+ @cli_handler
379
+ def webpages(chariot, parent, filter, details, offset, page):
380
+ """ List WebPages
381
+
382
+ Retrieve and display a list of pages/URLs. Can optionally filter by specific WebApplication.
383
+
384
+ \b
385
+ Example usages:
386
+ - praetorian chariot list webpages
387
+ - praetorian chariot list webpages --parent "#webapplication#https://app.example.com"
388
+ - praetorian chariot list webpages --filter /login
389
+ - praetorian chariot list webpages --parent "#webapplication#https://app.example.com" --details
390
+ - praetorian chariot list webpages --page all
391
+ """
392
+ render_list_results(chariot.webpage.list(parent, filter, offset, pagination_size(page)), details)
@@ -0,0 +1,55 @@
1
+ import click
2
+
3
+ from praetorian_cli.handlers.chariot import chariot
4
+ from praetorian_cli.handlers.cli_decorators import cli_handler
5
+
6
+
7
+ @chariot.group()
8
+ def unlink():
9
+ """ Remove links between resources """
10
+ pass
11
+
12
+
13
+ @unlink.command()
14
+ @cli_handler
15
+ @click.argument('username')
16
+ def account(chariot, username):
17
+ """ Remove a collaborator account from your account. This will
18
+ revoke their access to your account.
19
+
20
+ Arguments:
21
+ - NAME: Their email address.
22
+
23
+ \b
24
+ Example usages:
25
+ - praetorian chariot unlink account john@praetorian.com
26
+ """
27
+ chariot.accounts.delete_collaborator(username)
28
+
29
+
30
+ @unlink.command('webpage-source')
31
+ @cli_handler
32
+ @click.argument('webpage_key')
33
+ @click.argument('entity_key')
34
+ def webpage_source(chariot, webpage_key, entity_key):
35
+ """ Unlink a file or repository from a webpage's source code
36
+
37
+ This removes the association between source code files or
38
+ repositories and webpages.
39
+
40
+ \b
41
+ Arguments:
42
+ - WEBPAGE_KEY: The webpage key in format #webpage#{url}
43
+ - ENTITY_KEY: The file or repository key to unlink
44
+ Format: #file#{path} or #repository#{url}#{name}
45
+
46
+ \b
47
+ Example usages:
48
+ - praetorian chariot unlink webpage-source "#webpage#https://example.com" "#file#proofs/scan.txt"
49
+ - praetorian chariot unlink webpage-source "#webpage#https://example.com/login" "#repository#https://github.com/org/repo.git#repo.git"
50
+ """
51
+ result = chariot.webpage.unlink_source(webpage_key, entity_key)
52
+ if result:
53
+ click.echo(f"Successfully unlinked {entity_key} from {webpage_key}")
54
+ if 'artifacts' in result:
55
+ click.echo(f"Webpage now has {len(result['artifacts'])} linked artifacts")
@@ -65,12 +65,12 @@ def seed(chariot, key, status):
65
65
 
66
66
  \b
67
67
  Example usages:
68
- - praetorian chariot update seed "#seed#domain#example.com" -s A
69
- - praetorian chariot update seed "#seed#ip#1.1.1.0/24" -s F
68
+ - praetorian chariot update seed "#asset#example.com#example.com" -s A
69
+ - praetorian chariot update seed "#asset#1.1.1.0/24#1.1.1.0/24" -s F
70
70
  """
71
+
71
72
  chariot.seeds.update(key, status)
72
73
 
73
-
74
74
  @update.command()
75
75
  @cli_handler
76
76
  @click.argument('key', required=True)
@@ -16,10 +16,12 @@ from praetorian_cli.sdk.entities.keys import Keys
16
16
  from praetorian_cli.sdk.entities.preseeds import Preseeds
17
17
  from praetorian_cli.sdk.entities.risks import Risks
18
18
  from praetorian_cli.sdk.entities.scanners import Scanners
19
+ from praetorian_cli.sdk.entities.schema import Schema
19
20
  from praetorian_cli.sdk.entities.search import Search
20
21
  from praetorian_cli.sdk.entities.seeds import Seeds
21
22
  from praetorian_cli.sdk.entities.settings import Settings
22
23
  from praetorian_cli.sdk.entities.statistics import Statistics
24
+ from praetorian_cli.sdk.entities.webpage import Webpage
23
25
  from praetorian_cli.sdk.entities.webhook import Webhook
24
26
  from praetorian_cli.sdk.keychain import Keychain
25
27
  from praetorian_cli.sdk.model.globals import GLOBAL_FLAG
@@ -51,6 +53,8 @@ class Chariot:
51
53
  self.keys = Keys(self)
52
54
  self.capabilities = Capabilities(self)
53
55
  self.credentials = Credentials(self)
56
+ self.webpage = Webpage(self)
57
+ self.schema = Schema(self)
54
58
  self.proxy = proxy
55
59
 
56
60
  if self.proxy == '' and os.environ.get('CHARIOT_PROXY'):
@@ -70,26 +74,16 @@ class Chariot:
70
74
  kwargs['proxies'] = {'http': self.proxy, 'https': self.proxy}
71
75
  kwargs['verify'] = False
72
76
 
73
- self._add_beta_filter(method, kwargs)
77
+ self.add_beta_url_param(kwargs)
74
78
 
75
79
  return requests.request(method, url, headers=self.keychain.headers(), **kwargs)
76
80
 
77
- def _add_beta_filter(self, method: str, kwargs: dict):
78
- if method == 'GET' or method == 'DELETE':
79
- self._add_beta_url_param(kwargs)
80
- else:
81
- self._add_beta_json_param(kwargs)
82
-
83
- def _add_beta_url_param(self, kwargs: dict):
81
+ def add_beta_url_param(self, kwargs: dict):
84
82
  if 'params' in kwargs:
85
83
  kwargs['params']['beta'] = 'true'
86
84
  else:
87
85
  kwargs['params'] = {'beta': 'true'}
88
86
 
89
- def _add_beta_json_param(self, kwargs: dict):
90
- if 'json' in kwargs:
91
- kwargs['json']['beta'] = True
92
-
93
87
  def my(self, params: dict, pages=1) -> dict:
94
88
  final_resp = dict()
95
89
 
@@ -1,5 +1,6 @@
1
+ from praetorian_cli.handlers.utils import error
1
2
  from praetorian_cli.sdk.model.globals import Asset, Kind
2
- from praetorian_cli.sdk.model.query import Relationship, Node, Query, asset_of_key, RISK_NODE, ATTRIBUTE_NODE
3
+ from praetorian_cli.sdk.model.query import Relationship, Node, Query, Filter, KIND_TO_LABEL, asset_of_key, RISK_NODE, ATTRIBUTE_NODE
3
4
 
4
5
 
5
6
  class Assets:
@@ -76,27 +77,44 @@ class Assets:
76
77
  """
77
78
  return self.api.delete_by_key('asset', key)
78
79
 
79
- def list(self, prefix_filter='', asset_type='', offset=None, pages=100000) -> tuple:
80
+ def list(self, key_prefix='', asset_type='', pages=100000) -> tuple:
80
81
  """
81
82
  List assets.
82
83
 
83
- :param prefix_filter: Supply this to perform prefix-filtering of the asset keys after the "#asset#" portion of the asset key. Asset keys read '#asset#{dns}#{name}'
84
- :type prefix_filter: str
84
+ :param key_prefix: Supply this to perform prefix-filtering of the asset key. E.g., '#asset#example.com' or '#addomain#sevenkingdoms'
85
+ :type key_prefix: str
85
86
  :param asset_type: The type of asset to filter by
86
87
  :type asset_type: str
87
- :param offset: The offset of the page you want to retrieve results. If this is not supplied, this function retrieves from the first page
88
- :type offset: str or None
89
88
  :param pages: The number of pages of results to retrieve. <mcp>Start with one page of results unless specifically requested.</mcp>
90
89
  :type pages: int
91
90
  :return: A tuple containing (list of assets, next page offset)
92
91
  :rtype: tuple
93
92
  """
94
- dns_prefix = ''
95
- if prefix_filter:
96
- dns_prefix = f'group:{prefix_filter}'
97
- if asset_type == '':
98
- asset_type = Kind.ASSET.value
99
- return self.api.search.by_term(dns_prefix, asset_type, offset, pages)
93
+
94
+ if asset_type in KIND_TO_LABEL:
95
+ asset_type = KIND_TO_LABEL[asset_type]
96
+ elif not asset_type:
97
+ asset_type = Node.Label.ASSET
98
+ else:
99
+ raise ValueError(f'Invalid asset type: {asset_type}')
100
+
101
+ node = Node(
102
+ labels=[asset_type],
103
+ filters=[]
104
+ )
105
+
106
+ key_filter = Filter(
107
+ field=Filter.Field.KEY,
108
+ operator=Filter.Operator.STARTS_WITH,
109
+ value=key_prefix
110
+ )
111
+
112
+ if key_prefix:
113
+ node.filters.append(key_filter)
114
+
115
+ query = Query(node=node)
116
+
117
+ return self.api.search.by_query(query, pages)
100
118
 
101
119
  def attributes(self, key):
102
120
  """
@@ -0,0 +1,27 @@
1
+ class Schema:
2
+ """Access Chariot entity schemas via the SDK.
3
+
4
+ Methods in this class are accessed from `sdk.schema`, where `sdk` is an
5
+ instance of `Chariot`.
6
+ """
7
+
8
+ def __init__(self, api):
9
+ self.api = api
10
+
11
+ def get(self, entity_type: str | None = None) -> dict:
12
+ """Get schema information for entity types.
13
+
14
+ Args:
15
+ entity_type: Optional specific entity type. If provided and it exists,
16
+ only that schema is returned. If not provided, all schemas are returned.
17
+
18
+ Returns:
19
+ dict: Schema information.
20
+ """
21
+ result = self.api.get('schema', )
22
+ if entity_type:
23
+ if entity_type not in result:
24
+ return {}
25
+ return {entity_type: result[entity_type]}
26
+ return result
27
+