praetorian-cli 2.2.2__py3-none-any.whl → 2.2.3__py3-none-any.whl

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.
@@ -196,21 +196,39 @@ def attribute(sdk, key, name, value):
196
196
 
197
197
  @add.command()
198
198
  @cli_handler
199
- @click.option('-d', '--dns', required=True, help='The DNS of the asset')
199
+ @click.option('-t', '--type', 'seed_type', default='asset', help='Asset type (e.g., asset, addomain)')
200
200
  @click.option('-s', '--status', type=click.Choice([s.value for s in Seed]),
201
201
  default=Seed.PENDING.value, help='The status of the seed', show_default=True)
202
- def seed(sdk, dns, status):
202
+ @click.option('-f', '--field', 'field_list', multiple=True,
203
+ help='Field in format name:value (can be specified multiple times)')
204
+ def seed(sdk, seed_type, status, field_list):
203
205
  """ Add a seed
204
206
 
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.
207
+ Add a seed to the Chariot database. Seeds are now assets with special labeling.
208
+ You can specify the asset type and provide dynamic fields using --fields.
207
209
 
208
210
  \b
209
211
  Example usages:
210
- - praetorian chariot add seed --dns example.com
211
- - praetorian chariot add seed --dns example.com --status A
212
+ - praetorian chariot add seed --type asset --field dns:example.com
213
+ - praetorian chariot add seed --type asset --field dns:example.com --status A
214
+ - praetorian chariot add seed --type asset --field dns:example.com --field name:1.2.3.4
215
+ - praetorian chariot add seed --type addomain --field domain:corp.local --field objectid:S-1-5-21-2701466056-1043032755-2418290285
212
216
  """
213
- sdk.seeds.add(dns, status)
217
+ # Collect dynamic fields from the --fields option
218
+ dynamic_fields = {}
219
+
220
+ # Parse field_list entries (name:value format)
221
+ for field in field_list:
222
+ if ':' in field:
223
+ # Split only once to allow colons in the value
224
+ name, value = field.split(':', 1)
225
+ dynamic_fields[name] = value
226
+ else:
227
+ error(f"Field '{field}' is not in the format name:value")
228
+ return
229
+
230
+ # Call the updated add method with type and dynamic fields
231
+ sdk.seeds.add(status=status, seed_type=seed_type, **dynamic_fields)
214
232
 
215
233
 
216
234
  @add.command()
@@ -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
 
@@ -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,31 @@ 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.option('-t', '--type', help='Optional specific entity type (e.g., asset, risk, attribute)')
304
+ @click.option('-d', '--details', is_flag=True, help='Further retrieve the details of the schema')
305
+ def schema(chariot, type, details):
306
+ """ Get Chariot entity schema
307
+
308
+ \b
309
+ Returns the JSON schema for Chariot entities. Optionally filter for a
310
+ specific entity type.
311
+
312
+ \b
313
+ Example usages:
314
+ - praetorian chariot get schema
315
+ - praetorian chariot get schema --type asset
316
+ - praetorian chariot get schema --type asset --details
317
+ """
318
+ data = chariot.schema.get(type)
319
+ if type:
320
+ data = {type: data[type]}
321
+
322
+ if details:
323
+ print_json(data)
324
+ else:
325
+ for hit in data:
326
+ click.echo(hit)
@@ -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()
@@ -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,6 +16,7 @@ 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
@@ -51,6 +52,7 @@ class Chariot:
51
52
  self.keys = Keys(self)
52
53
  self.capabilities = Capabilities(self)
53
54
  self.credentials = Credentials(self)
55
+ self.schema = Schema(self)
54
56
  self.proxy = proxy
55
57
 
56
58
  if self.proxy == '' and os.environ.get('CHARIOT_PROXY'):
@@ -70,26 +72,16 @@ class Chariot:
70
72
  kwargs['proxies'] = {'http': self.proxy, 'https': self.proxy}
71
73
  kwargs['verify'] = False
72
74
 
73
- self._add_beta_filter(method, kwargs)
75
+ self.add_beta_url_param(kwargs)
74
76
 
75
77
  return requests.request(method, url, headers=self.keychain.headers(), **kwargs)
76
78
 
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):
79
+ def add_beta_url_param(self, kwargs: dict):
84
80
  if 'params' in kwargs:
85
81
  kwargs['params']['beta'] = 'true'
86
82
  else:
87
83
  kwargs['params'] = {'beta': 'true'}
88
84
 
89
- def _add_beta_json_param(self, kwargs: dict):
90
- if 'json' in kwargs:
91
- kwargs['json']['beta'] = True
92
-
93
85
  def my(self, params: dict, pages=1) -> dict:
94
86
  final_resp = dict()
95
87
 
@@ -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
+
@@ -1,5 +1,6 @@
1
1
  from praetorian_cli.handlers.utils import error
2
2
  from praetorian_cli.sdk.model.globals import Seed, Kind
3
+ from praetorian_cli.sdk.model.query import Query, Node, Filter, KIND_TO_LABEL
3
4
 
4
5
 
5
6
  class Seeds:
@@ -9,97 +10,148 @@ class Seeds:
9
10
  def __init__(self, api):
10
11
  self.api = api
11
12
 
12
- def add(self, dns, status=Seed.PENDING.value):
13
+ def add(self, status=Seed.PENDING.value, seed_type=Kind.ASSET.value, **kwargs):
13
14
  """
14
- Add a seed to the account.
15
-
16
- :param dns: The DNS name, IP address, or CIDR range to add as a seed. Accepts domain names (e.g., 'example.com'), IP addresses (e.g., '192.168.1.1'), or CIDR ranges (e.g., '192.168.1.0/24')
17
- :type dns: str
18
- :param status: Seed status from Seed enum ('A' for Active, 'F' for Frozen, 'D' for Deleted, 'P' for Pending, 'FR' for Frozen Rejected)
19
- :type status: str
15
+ Add a seed of specified type with dynamic fields.
16
+
17
+ :param status: Status for backward compatibility
18
+ :type status: str or None
19
+ :param type: Asset type (e.g., 'asset', 'addomain', etc.)
20
+ :type type: str
21
+ :param kwargs: Dynamic fields for the asset type
20
22
  :return: The seed that was added
21
23
  :rtype: dict
22
24
  """
23
- return self.api.upsert('seed', dict(dns=dns, status=status))
25
+ # Handle status if provided
26
+ kwargs['status'] = status
27
+
28
+ # Build payload with type wrapper
29
+ payload = {
30
+ 'type': seed_type,
31
+ 'model': kwargs
32
+ }
33
+
34
+ return self.api.upsert('seed', payload)
24
35
 
25
36
  def get(self, key):
26
37
  """
27
38
  Get details of a seed by key.
28
39
 
29
- :param key: Entity key in format #seed#{type}#{dns} where type is 'domain', 'ip', or 'cidr' and dns is the seed value
40
+ :param key: Entity key (e.g., '#asset#example.com#example.com')
30
41
  :type key: str
31
42
  :return: The seed matching the specified key, or None if not found
32
43
  :rtype: dict or None
33
44
  """
34
- return self.api.search.by_exact_key(key, False)
35
-
36
- def update(self, key, status):
45
+
46
+ # Create a Filter for the key field
47
+ key_filter = Filter(
48
+ field=Filter.Field.KEY,
49
+ operator=Filter.Operator.EQUAL,
50
+ value=key
51
+ )
52
+
53
+ # Create a Node with Seed label and key filter
54
+ node = Node(
55
+ labels=[Node.Label.SEED],
56
+ filters=[key_filter]
57
+ )
58
+
59
+ # Create the Query object
60
+ query = Query(node=node)
61
+
62
+ # Call by_query with the constructed Query object
63
+ results_tuple = self.api.search.by_query(query)
64
+ if not results_tuple:
65
+ return None
66
+
67
+ results, _ = results_tuple
68
+ if len(results) == 0:
69
+ return None
70
+ return results[0]
71
+
72
+ def update(self, key, status=None):
37
73
  """
38
- Update a seed's status.
39
-
40
- Note: The seed PUT endpoint is different from other PUT endpoints. This method
41
- internally uses the DNS of the original seed rather than the key for the update operation.
42
-
43
- :param key: Entity key in format #seed#{type}#{dns} where type is 'domain', 'ip', or 'cidr' and dns is the seed value
74
+ Update seed fields dynamically.
75
+
76
+ :param key: Seed/Asset key (e.g., '#seed#domain#example.com' or '#asset#domain#example.com')
44
77
  :type key: str
45
- :param status: Seed status from Seed enum ('A' for Active, 'F' for Frozen, 'D' for Deleted, 'P' for Pending, 'FR' for Frozen Rejected)
46
- :type status: str
78
+ :param status: Status for backward compatibility (can be positional)
79
+ :type status: str or None
80
+ :param kwargs: Fields to update
47
81
  :return: The updated seed, or None if the seed was not found
48
82
  :rtype: dict or None
49
83
  """
50
- seed = self.api.search.by_exact_key(key)
84
+
85
+ seed = self.get(key) # This already handles old key format conversion
51
86
  if seed:
52
- # the seed PUT endpoint is different from other PUT endpoints. This one has to
53
- # take the DNS of the original seed, instead of the key of the seed record.
54
- # TODO, 2024-12-23, peter: check with Noah as to why. Ideally, we should
55
- # standardize to how other endpoints do it
56
- return self.api.upsert('seed', dict(dns=seed['dns'], status=status))
87
+ update_payload = {
88
+ 'key': key,
89
+ 'status': status
90
+ }
91
+
92
+ return self.api.upsert('seed', update_payload)
57
93
  else:
58
- error(f'Seed {key} is not found.')
94
+ error(f'Seed {key} not found.')
59
95
 
60
96
  def delete(self, key):
61
97
  """
62
- Delete a seed by setting its status to DELETED.
63
-
64
- Note: This method does not actually delete the seed from the database. Instead,
65
- it sets the seed's status to DELETED ('D'), which marks it as deleted while
66
- preserving the record for audit purposes.
67
-
68
- :param key: Entity key in format #seed#{type}#{dns} where type is 'domain', 'ip', or 'cidr' and dns is the seed value
98
+ Delete seed (supports both old and new key formats).
99
+
100
+ :param key: Seed/Asset key (e.g., '#asset#domain#example.com')
69
101
  :type key: str
70
102
  :return: The seed that was marked as deleted, or None if the seed was not found
71
103
  :rtype: dict or None
72
104
  """
73
- seed = self.api.search.by_exact_key(key)
105
+ seed = self.get(key) # This already handles old key format conversion
106
+
74
107
  if seed:
75
- # TODO, 2024-12-23, peter: check with Noah why this is different from
76
- # deleting assets and risks
77
- return self.api.upsert('seed', dict(dns=seed['dns'], status=Seed.DELETED.value))
108
+ delete_payload = {
109
+ 'key': key,
110
+ 'status': Seed.DELETED.value
111
+ }
112
+
113
+ return self.api.upsert('seed', delete_payload)
78
114
  else:
79
- error(f'Seed {key} is not found.')
115
+ error(f'Seed {key} not found.')
80
116
 
81
- def list(self, type='', prefix_filter='', offset=None, pages=100000) -> tuple:
117
+ def list(self, seed_type=Kind.SEED.value, key_prefix='', pages=100000) -> tuple:
82
118
  """
83
- List seeds with optional filtering.
84
-
85
- :param type: The type of seed to filter by ('domain', 'ip', 'cidr'). If empty, returns all seed types
86
- :type type: str
87
- :param prefix_filter: Supply this to perform prefix-filtering of the seed DNS/IP values after the seed type portion of the key
88
- :type prefix_filter: str
89
- :param offset: The offset of the page you want to retrieve results. If this is not supplied, this function retrieves from the first page
90
- :type offset: str or None
119
+ List seeds by querying assets with 'Seed' label.
120
+
121
+ :param seed_type: Optional asset seed_type filter (e.g., 'asset', 'addomain')
122
+ :seed_type seed_type: str or None
123
+ :param key_prefix: Filter by key prefix
124
+ :seed_type key_prefix: str
91
125
  :param pages: The number of pages of results to retrieve. <mcp>Start with one page of results unless specifically requested.</mcp>
92
- :type pages: int
126
+ :seed_type pages: int
93
127
  :return: A tuple containing (list of seeds, next page offset)
94
- :rtype: tuple
128
+ :rseed_type: tuple
95
129
  """
96
- prefix_term = '#seed#'
97
- if type:
98
- prefix_term = f'{prefix_term}{type}#'
99
- if prefix_filter:
100
- prefix_term = f'{prefix_term}{prefix_filter}'
101
130
 
102
- return self.api.search.by_key_prefix(prefix_term, offset, pages)
131
+ if seed_type in KIND_TO_LABEL:
132
+ seed_type = KIND_TO_LABEL[seed_type]
133
+ elif not seed_type:
134
+ seed_type = Node.Label.SEED
135
+ else:
136
+ raise ValueError(f'Invalid seed type: {seed_type}')
137
+
138
+ node = Node(
139
+ labels=[seed_type],
140
+ filters=[]
141
+ )
142
+
143
+ key_filter = Filter(
144
+ field=Filter.Field.KEY,
145
+ operator=Filter.Operator.STARTS_WITH,
146
+ value=key_prefix
147
+ )
148
+
149
+ if key_prefix:
150
+ node.filters.append(key_filter)
151
+
152
+ query = Query(node=node)
153
+
154
+ return self.api.search.by_query(query, pages)
103
155
 
104
156
  def attributes(self, key):
105
157
  """
@@ -8,7 +8,6 @@ from mcp.server.lowlevel import Server
8
8
  from mcp.server.stdio import stdio_server
9
9
  from mcp.types import Tool, TextContent
10
10
 
11
-
12
11
  class MCPServer:
13
12
  def __init__(self, chariot_instance, allowable_tools: Optional[List[str]] = None):
14
13
  self.chariot = chariot_instance
@@ -157,7 +156,7 @@ class MCPServer:
157
156
  tools = []
158
157
  for tool_name, tool_info in self.discovered_tools.items():
159
158
  parameters = self._extract_parameters_from_doc(tool_info['doc'], tool_info['signature'])
160
-
159
+
161
160
  properties = {}
162
161
  required = []
163
162
 
@@ -170,7 +169,7 @@ class MCPServer:
170
169
  "description": param_info["description"]
171
170
  }
172
171
 
173
- if param_info["required"]:
172
+ if param_info.get("required", False):
174
173
  required.append(param_name)
175
174
 
176
175
  tool_schema = {
@@ -91,7 +91,7 @@ class Node:
91
91
  ASSET = 'Asset'
92
92
  REPOSITORY = 'Repository'
93
93
  INTEGRATION = 'Integration'
94
- ADDOMAIN = 'Addomain'
94
+ ADDOMAIN = 'ADDomain'
95
95
  ATTRIBUTE = 'Attribute'
96
96
  RISK = 'Risk'
97
97
  PRESEED = 'Preseed'
@@ -15,14 +15,11 @@ def integration_key(dns, name):
15
15
  def risk_key(dns, name):
16
16
  return f'#risk#{dns}#{name}'
17
17
 
18
-
19
18
  def attribute_key(name, value, source_key):
20
19
  return f'#attribute#{name}#{value}{source_key}'
21
20
 
22
-
23
- def seed_key(type, dns):
24
- return f'#seed#{type}#{dns}'
25
-
21
+ def seed_asset_key(dns):
22
+ return f'#asset#{dns}#{dns}'
26
23
 
27
24
  def preseed_key(type, title, value):
28
25
  return f'#preseed#{type}#{title}#{value}'
@@ -32,6 +29,3 @@ def setting_key(name):
32
29
 
33
30
  def configuration_key(name):
34
31
  return f'#configuration#{name}'
35
-
36
- def seed_status(type, status_code):
37
- return f'{type}#{status_code}'
@@ -42,7 +42,7 @@ class TestAsset:
42
42
  assert any([a['group'] == self.asset_dns for a in deleted_assets])
43
43
 
44
44
  def test_add_ad_domain(self):
45
- asset = self.sdk.assets.add(self.ad_domain_name, self.ad_domain_name, status=Asset.ACTIVE.value, surface='test-surface', type=Kind.ADDOMAIN.value)
45
+ asset = self.sdk.assets.add(self.ad_domain_name, self.ad_object_id, status=Asset.ACTIVE.value, surface='test-surface', type=Kind.ADDOMAIN.value)
46
46
  assert asset['key'] == self.ad_domain_key
47
47
  assert len(asset['attackSurface']) == 1
48
48
  assert 'test-surface' in asset['attackSurface']
@@ -51,7 +51,7 @@ class TestAsset:
51
51
  def test_get_ad_domain(self):
52
52
  asset = self.sdk.assets.get(self.ad_domain_key)
53
53
  assert asset['key'] == self.ad_domain_key
54
- assert asset['name'] == self.ad_domain_name
54
+ assert asset['domain'] == self.ad_domain_name
55
55
  assert asset['status'] == Asset.ACTIVE.value
56
56
 
57
57
  def test_list_ad_domain(self):
@@ -1,7 +1,6 @@
1
1
  import pytest
2
2
 
3
- from praetorian_cli.sdk.model.globals import Seed
4
- from praetorian_cli.sdk.model.utils import seed_status
3
+ from praetorian_cli.sdk.model.globals import Seed, Kind
5
4
  from praetorian_cli.sdk.test.utils import make_test_values, clean_test_entities, setup_chariot
6
5
 
7
6
 
@@ -12,30 +11,30 @@ class TestSeed:
12
11
  self.sdk = setup_chariot()
13
12
  make_test_values(self)
14
13
 
15
- def test_add_seed(self):
16
- seed = self.sdk.seeds.add(self.seed_dns)
17
- assert seed['key'] == self.seed_key
14
+ def test_add_asset_seed(self):
15
+ seed = self.sdk.seeds.add(dns=self.seed_asset_dns)
16
+ assert seed['key'] == self.seed_asset_key
18
17
 
19
18
  def test_get_seed(self):
20
19
  a = self.get_seed()
21
- assert a['dns'] == self.seed_dns
22
- assert a['status'] == seed_status('domain', Seed.PENDING.value)
20
+ assert a['dns'] == self.seed_asset_dns
21
+ assert a['status'] == Seed.PENDING.value
23
22
 
24
23
  def test_list_seed(self):
25
- results, _ = self.sdk.seeds.list('domain', self.seed_dns)
24
+ results, _ = self.sdk.seeds.list(Kind.ASSET.value, f"#asset#{self.seed_asset_dns}")
26
25
  assert len(results) == 1
27
- assert results[0]['dns'] == self.seed_dns
26
+ assert results[0]['dns'] == self.seed_asset_dns
28
27
 
29
28
  def test_update_seed(self):
30
- self.sdk.seeds.update(self.seed_key, Seed.ACTIVE.value)
31
- assert self.get_seed()['status'] == seed_status('domain', Seed.ACTIVE.value)
29
+ self.sdk.seeds.update(self.seed_asset_key, Seed.ACTIVE.value)
30
+ assert self.get_seed()['status'] == Seed.ACTIVE.value
32
31
 
33
32
  def test_delete_seed(self):
34
- self.sdk.seeds.delete(self.seed_key)
35
- assert self.sdk.seeds.get(self.seed_key)['status'] == seed_status('domain', Seed.DELETED.value)
33
+ self.sdk.seeds.delete(self.seed_asset_key)
34
+ assert self.sdk.seeds.get(self.seed_asset_key)['status'] == Seed.DELETED.value
36
35
 
37
36
  def get_seed(self):
38
- return self.sdk.seeds.get(self.seed_key)
37
+ return self.sdk.seeds.get(self.seed_asset_key)
39
38
 
40
39
  def teardown_class(self):
41
40
  clean_test_entities(self.sdk, self)
@@ -5,7 +5,6 @@ from subprocess import run
5
5
  import pytest
6
6
 
7
7
  from praetorian_cli.sdk.model.globals import AddRisk, Asset, Risk, Seed, Preseed
8
- from praetorian_cli.sdk.model.utils import seed_status
9
8
  from praetorian_cli.sdk.test.utils import epoch_micro, random_ip, make_test_values, clean_test_entities, setup_chariot
10
9
 
11
10
 
@@ -21,11 +20,12 @@ class TestZCli:
21
20
  self.verify(f'add asset -n {o.asset_name} -d {o.asset_dns}')
22
21
 
23
22
  self.verify('list assets -p all', [o.asset_key])
24
- self.verify(f'list assets -f "{o.asset_dns}"', [o.asset_key])
25
- self.verify(f'list assets -f "{o.asset_dns}" -p first', [o.asset_key])
26
- self.verify(f'list assets -f "{o.asset_dns}" -p all', [o.asset_key])
27
- self.verify(f'list assets -f "{o.asset_dns}" -d', [o.asset_key, '"key"', '"data"'])
23
+ self.verify(f'list assets -f "#asset#{o.asset_dns}"', [o.asset_key])
24
+ self.verify(f'list assets -f "#asset#{o.asset_dns}" -p first', [o.asset_key])
25
+ self.verify(f'list assets -f "#asset#{o.asset_dns}" -p all', [o.asset_key])
26
+ self.verify(f'list assets -f "#asset#{o.asset_dns}" -d', [o.asset_key, '"key"', '"data"'])
28
27
 
28
+ self.verify(f'list assets -f "#asset#{epoch_micro()}"')
29
29
  self.verify(f'list assets -f {epoch_micro()}')
30
30
 
31
31
  self.verify(f'get asset "{o.asset_key}"', [o.asset_key, f'"status": "{Asset.ACTIVE.value}"'])
@@ -43,30 +43,28 @@ class TestZCli:
43
43
  def test_seed_cli(self):
44
44
  o = make_test_values(lambda: None)
45
45
 
46
- self.verify(f'add seed -d {o.seed_dns}')
46
+ self.verify(f'add seed --field dns:{o.seed_asset_dns}')
47
47
 
48
- self.verify('list seeds -p all', [o.seed_key])
49
- self.verify('list seeds -t domain -p all', [o.seed_key])
50
- self.verify(f'list seeds -t domain -f "{o.seed_dns}"', [o.seed_key])
51
- self.verify(f'list seeds -t domain -f "{o.seed_dns}" -p first', [o.seed_key])
52
- self.verify(f'list seeds -t domain -f "{o.seed_dns}" -p all', [o.seed_key])
53
- self.verify(f'list seeds -t domain -f "{o.seed_dns}" -p first', [o.seed_key])
54
- self.verify(f'list seeds -t domain -f "{o.seed_dns}" -d', [o.seed_dns, '"key"', '"data"'])
55
- self.verify(f'list seeds -t ip -f "{o.seed_dns}"')
56
- self.verify(f'list seeds -f "{o.seed_dns}"', [],
57
- ["When the DNS filter is specified, you also need to specify the type of the filter"])
48
+ self.verify('list seeds -p all', [o.seed_asset_key])
49
+ self.verify('list seeds -t asset -p all', [o.seed_asset_key])
50
+ self.verify(f'list seeds -t asset -f "#asset#{o.seed_asset_dns}"', [o.seed_asset_key])
51
+ self.verify(f'list seeds -t asset -f "#asset#{o.seed_asset_dns}" -p first', [o.seed_asset_key])
52
+ self.verify(f'list seeds -t asset -f "#asset#{o.seed_asset_dns}" -p all', [o.seed_asset_key])
53
+ self.verify(f'list seeds -t asset -f "#asset#{o.seed_asset_dns}" -d', [o.seed_asset_dns, '"key"', '"data"'])
54
+ self.verify(f'list seeds -t notatype -f "#asset#{o.seed_asset_dns}"', [], ['Invalid seed type: notatype'])
55
+ self.verify(f'list seeds -f "#asset#{o.seed_asset_dns}"', [o.seed_asset_key])
58
56
 
59
- self.verify(f'list seeds -t domain -f {epoch_micro()}')
57
+ self.verify(f'list seeds -t asset -f {epoch_micro()}')
60
58
 
61
- self.verify(f'get seed "{o.seed_key}"',
62
- [o.seed_key, f'"status": "{seed_status("domain", Seed.PENDING.value)}"'])
59
+ self.verify(f'get seed "{o.seed_asset_key}"',
60
+ [o.seed_asset_key, f'"status": "{Seed.PENDING.value}"'])
63
61
 
64
- self.verify(f'update seed -s {Seed.ACTIVE.value} "{o.seed_key}"')
65
- self.verify(f'get seed "{o.seed_key}"',
66
- [o.seed_key, f'"status": "{seed_status("domain", Seed.ACTIVE.value)}"'])
62
+ self.verify(f'update seed -s {Seed.ACTIVE.value} "{o.seed_asset_key}"')
63
+ self.verify(f'get seed "{o.seed_asset_key}"',
64
+ [o.seed_asset_key, f'"status": "{Seed.ACTIVE.value}"'])
67
65
 
68
- self.verify(f'delete seed "{o.seed_key}"')
69
- self.verify(f'get seed "{o.seed_key}"', [f'"status": "{seed_status("domain", Seed.DELETED.value)}"'])
66
+ self.verify(f'delete seed "{o.seed_asset_key}"')
67
+ self.verify(f'get seed "{o.seed_asset_key}"', [f'"status": "{Seed.DELETED.value}"'])
70
68
 
71
69
  clean_test_entities(self.sdk, o)
72
70
 
@@ -5,7 +5,7 @@ from random import randint
5
5
  from praetorian_cli.sdk.chariot import Chariot
6
6
  from praetorian_cli.sdk.keychain import Keychain
7
7
  from praetorian_cli.sdk.model.globals import Risk, Preseed
8
- from praetorian_cli.sdk.model.utils import risk_key, asset_key, ad_domain_key, attribute_key, seed_key, preseed_key, setting_key, configuration_key
8
+ from praetorian_cli.sdk.model.utils import risk_key, asset_key, ad_domain_key, attribute_key, seed_asset_key, preseed_key, setting_key, configuration_key
9
9
 
10
10
 
11
11
  def epoch_micro():
@@ -27,14 +27,26 @@ def random_dns():
27
27
  def random_ad_domain():
28
28
  return f'test-{epoch_micro()}.local'
29
29
 
30
+ def random_object_id():
31
+ domain_id_1 = randint(1000000000, 4294967295) # Start from 1 billion for realism
32
+ domain_id_2 = randint(1000000000, 4294967295)
33
+ domain_id_3 = randint(1000000000, 4294967295)
34
+
35
+ # Generate a random relative identifier (RID)
36
+ # Common ranges: 500-999 for built-in accounts, 1000+ for user accounts
37
+ relative_id = randint(1000, 999999)
38
+ return f"S-1-5-21-{domain_id_1}-{domain_id_2}-{domain_id_3}-{relative_id}"
39
+
40
+
30
41
  def make_test_values(o):
31
42
  o.asset_dns = random_dns()
32
43
  o.asset_name = random_ip()
33
44
  o.asset_key = asset_key(o.asset_dns, o.asset_name)
34
45
  o.ad_domain_name = random_ad_domain()
35
- o.ad_domain_key = ad_domain_key(o.ad_domain_name, o.ad_domain_name)
36
- o.seed_dns = random_dns()
37
- o.seed_key = seed_key('domain', o.seed_dns)
46
+ o.ad_object_id = random_object_id()
47
+ o.ad_domain_key = ad_domain_key(o.ad_domain_name, o.ad_object_id)
48
+ o.seed_asset_dns = random_dns()
49
+ o.seed_asset_key = seed_asset_key(o.seed_asset_dns)
38
50
  o.risk_name = f'test-risk-name-{epoch_micro()}'
39
51
  o.risk_key = risk_key(o.asset_dns, o.risk_name)
40
52
  o.comment = f'Test comment {epoch_micro()}'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praetorian-cli
3
- Version: 2.2.2
3
+ Version: 2.2.3
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,38 +1,38 @@
1
1
  praetorian_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  praetorian_cli/main.py,sha256=AVrOCQgioLDKm-Y8-b3lLLdLtaO1WwOAzUfs0obe5Nw,1451
3
3
  praetorian_cli/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- praetorian_cli/handlers/add.py,sha256=DOd1iKxRsMaID_3RiZvuEUlTy49G-YGZdqHTn2TpC_g,11447
4
+ praetorian_cli/handlers/add.py,sha256=alaP5QvMJ63H7kMD00JDKUkLjZNJYTacmCMy-TA6DOM,12461
5
5
  praetorian_cli/handlers/aegis.py,sha256=1259bNmoUOVhcs7GqI8TyTyCI_ZvKzEPvfUVvAHcTzU,3936
6
6
  praetorian_cli/handlers/agent.py,sha256=8lmb_R1aWe9bhk-4NPOfXXxaE8E_U97DFNEvJ2mcteg,2291
7
7
  praetorian_cli/handlers/chariot.py,sha256=HClwYdsgFKlLY68RhV65W1Y4g-JgbBDdI4PdP4s8MgI,611
8
8
  praetorian_cli/handlers/cli_decorators.py,sha256=lb-MDVwSxyoKF-f7ObRKO2TxNom7upEPSNZgP-gTcqA,2885
9
9
  praetorian_cli/handlers/configure.py,sha256=8ABvisb_a4WekVVZ5kEhT1m4Mn2xV5RsO_xO_7f6TkM,1317
10
- praetorian_cli/handlers/delete.py,sha256=Ul61O6ZEZhKFawYrKuo_xGEzCSamh8t7pvtlY5NA0_0,4094
10
+ praetorian_cli/handlers/delete.py,sha256=si6LDW7HmD4RPrOEVDKki6en1a0m5qywiSDlw3X3Rgg,4203
11
11
  praetorian_cli/handlers/enrich.py,sha256=KRvOAuW7mQdYg_k_XOTwtPmnf8rxOAtoL00Bb0e-N-s,485
12
- praetorian_cli/handlers/get.py,sha256=ci9yRaX8LFYYxme65ecEjnJe1JNUSe3ROdukQELAWio,8000
12
+ praetorian_cli/handlers/get.py,sha256=py_twLvnK71FK-C8hHcpk9pRH7-Q-j6-kgEJzBWTO0I,8881
13
13
  praetorian_cli/handlers/imports.py,sha256=u1TK4w3eCMD5ASPFare2NgTX1_m0_F1ELCmvV7OF-PI,1653
14
14
  praetorian_cli/handlers/link.py,sha256=TnURm3Zrv6afJI2XHKRTRHpW9Vh-T_chGgxnhs7JrAg,663
15
- praetorian_cli/handlers/list.py,sha256=HjA3qijLRs199Tyxc34S4yxNpO7IbKiYqzMAUm4wUyE,12230
15
+ praetorian_cli/handlers/list.py,sha256=2Bik7BzXnFGbIP-8eewouMeTF-WjpC0wI6ApOMIuZzY,12233
16
16
  praetorian_cli/handlers/script.py,sha256=x_nWTlv0_9dLrQ4KulzKX11QwJHdtm6hWtZYgKzKcs4,2040
17
17
  praetorian_cli/handlers/search.py,sha256=wPXiHrBx4NpNB8a79S9wE6TMArBjg5WsEFKzDoUAR-0,2633
18
18
  praetorian_cli/handlers/ssh_utils.py,sha256=53Kke-iFH4sJoCcweiT8q4WVRlaA7SvR5CCqdGFxHps,5903
19
19
  praetorian_cli/handlers/test.py,sha256=uhARoRolaJf6DMRNX-1aj8SDYe1wAvhYDOBYWH39sqo,932
20
20
  praetorian_cli/handlers/unlink.py,sha256=PJoT0T6yuE8Hs2JyIX9P0mi6_CAA32IE698oxCOaK_0,628
21
- praetorian_cli/handlers/update.py,sha256=W38MU4NrA9vwVWeKmC-5Y2QKEAmeW3EAilxwkFMa2bs,2827
21
+ praetorian_cli/handlers/update.py,sha256=rgdOsFTaEivTdTUjUxPNEo13XR7uoIpBFRUqUdFVjaI,2846
22
22
  praetorian_cli/handlers/utils.py,sha256=2WA_50l6bWo-00cpxsHtqZYF10pSVxwly94qjl_tutY,858
23
23
  praetorian_cli/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  praetorian_cli/scripts/utils.py,sha256=lGCf4trEpsfECa9U42pDJ-f48EimlS-hG6AjnKjNt4I,501
25
25
  praetorian_cli/scripts/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  praetorian_cli/scripts/commands/nmap-example.py,sha256=varKTkHKG4DAs9Ssf0c6SygP9GfuCG01aFxhfvixLM0,2727
27
27
  praetorian_cli/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- praetorian_cli/sdk/chariot.py,sha256=okF_p4P_5gN5tguDTWO4kjwJ2rct8_m00rj2DSPkOX8,13526
28
+ praetorian_cli/sdk/chariot.py,sha256=FuMZTTqRPUbvD3AIUxaUrENn-1g60O0CFTgzKtPKdOQ,13271
29
29
  praetorian_cli/sdk/keychain.py,sha256=yWm4ohMHXD1I_hEDuuBh-F9EO-tssRLMb2xreDa65k4,7305
30
- praetorian_cli/sdk/mcp_server.py,sha256=T5Bt51D1W1NZU9tsoNaGug_ekVKXW9W3-glyLYPS-To,8756
30
+ praetorian_cli/sdk/mcp_server.py,sha256=8UoTotD4UVl-tp1gqMjkOVpO__KeGCvy7mIpKXVc8Rg,8750
31
31
  praetorian_cli/sdk/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  praetorian_cli/sdk/entities/accounts.py,sha256=DxVqUXMZu4m87Ryl2m0h4RkcJEqhGZmIGFsaFmJ97_A,4621
33
33
  praetorian_cli/sdk/entities/aegis.py,sha256=RRpeaV6MKinE229v0tngjTVkSGTeYOZKLzH4uZTFcvw,17298
34
34
  praetorian_cli/sdk/entities/agents.py,sha256=tJXTBkU7EpLVfhKo7g5pQfcXJeylLEfeLIpRW-lEn-M,1560
35
- praetorian_cli/sdk/entities/assets.py,sha256=yhi7VvpR7steSaASmeeo0zNmQ1dj864EcBzs1rrTgqw,5694
35
+ praetorian_cli/sdk/entities/assets.py,sha256=z8ErleQQ-BdnYkwPWOp2EQ8eJI4YB8qi45XQMokDFK8,5930
36
36
  praetorian_cli/sdk/entities/attributes.py,sha256=AyWsYyjUFNbHTCN7j-OYA7YD1Y0z_LmnlcME5y74je8,3573
37
37
  praetorian_cli/sdk/entities/capabilities.py,sha256=WeNlPrhVgLQPbpqYvS4nHmIX697ITpoZkJeLYxG5bmY,2808
38
38
  praetorian_cli/sdk/entities/configurations.py,sha256=rIChKvkaHUv9XRtQJ6OYH3gDDMcN8OPVsM_ylPnPEoI,4255
@@ -45,21 +45,22 @@ praetorian_cli/sdk/entities/keys.py,sha256=PgoGa3xyLMzWrIIQ8zgi7bfZiUFFumPtMDo64
45
45
  praetorian_cli/sdk/entities/preseeds.py,sha256=SeSY4K6diJMQzsjCBxYK3N9Lz0fUz3B_LMBOAAcBSLg,8890
46
46
  praetorian_cli/sdk/entities/risks.py,sha256=ZJ9_S8Zf3RwB7wGRjGEpf8j1jTB_leJiyHlFWeXsefc,5953
47
47
  praetorian_cli/sdk/entities/scanners.py,sha256=QCr5QlBy4jfBh8HRvZt9CoZTgNqLNnKNrI4sdfJf0jE,423
48
+ praetorian_cli/sdk/entities/schema.py,sha256=CPVws1CdRHyOAI7oT9A20WGOCZozTFqZnfo5ox3v0HQ,807
48
49
  praetorian_cli/sdk/entities/search.py,sha256=hFoANI_arlEmFPQwDiEF7lU-kPgXk0z3VyjubOULhRE,16843
49
- praetorian_cli/sdk/entities/seeds.py,sha256=DX06RS-Kc-TPNpHgDXj0-w_Az75wLmKGdZoC3RytmQo,5063
50
+ praetorian_cli/sdk/entities/seeds.py,sha256=eYDFtfgzIX_o9c5wuPiz9I2xDfTz7k9PZPzL7A7x1CM,5404
50
51
  praetorian_cli/sdk/entities/settings.py,sha256=F-pRCA6UvbdtnjHOLpEG2lN9ws8dcnBNcep-DFlXeTY,2750
51
52
  praetorian_cli/sdk/entities/statistics.py,sha256=gtX-NN7r_RsNjDjlQ-zspmzG_0bzBqBFarCuM4NO-EA,7085
52
53
  praetorian_cli/sdk/entities/webhook.py,sha256=7Bqt20GlJFbZTlmQwYTuUadsUQvydym6S4kGn9zYa50,6220
53
54
  praetorian_cli/sdk/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
55
  praetorian_cli/sdk/model/aegis.py,sha256=KNeynkCJtaR5bIhv3-VNirjxq4i-6JhCZGTb5rmxkQ4,5344
55
56
  praetorian_cli/sdk/model/globals.py,sha256=Z3l5VViagyEb9hbpOowJH0njVSIFPFBS8sYMGhltA4k,2899
56
- praetorian_cli/sdk/model/query.py,sha256=YwUVLHmtVysQlpA-jH_2tOBhVcmjgflzbJg5JaWTKf4,6259
57
- praetorian_cli/sdk/model/utils.py,sha256=yqJ08tXUmG4r-Qy7T_QLuIvOTG_MugZyYMKJRURykJc,856
57
+ praetorian_cli/sdk/model/query.py,sha256=yZL7needgiIuJv5y4rDgB4JiUQL1wqhj7ZtO9zwUw34,6259
58
+ praetorian_cli/sdk/model/utils.py,sha256=G8cU7K2uG0-J0GanjcCrzDuUtKzDOucFWF6hGtfOsTM,781
58
59
  praetorian_cli/sdk/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
60
  praetorian_cli/sdk/test/pytest.ini,sha256=uM552lJOoxWRplXtonIeo2v7M2kHZmJKis7OgnvoLxg,213
60
61
  praetorian_cli/sdk/test/test_account.py,sha256=OHYiiD8Ks2aeFq3Y9btgxG51qLweubPlYY17Ec7qPWM,886
61
62
  praetorian_cli/sdk/test/test_agent.py,sha256=I7-NcmsNyw-nLqbdzEUbTSfUTKVIrYOlo0pM5PZqe7o,997
62
- praetorian_cli/sdk/test/test_asset.py,sha256=8wTAtDiOgv2Hvod4GhR4arVRNhopt2ezQMJioO-53ck,3336
63
+ praetorian_cli/sdk/test/test_asset.py,sha256=sg7rylWFJJxgzJOXV-BKc7WXwWRQh0t-Rvi38ZXPi08,3336
63
64
  praetorian_cli/sdk/test/test_attribute.py,sha256=AwD_w488rKhc1mxTBwSJcItmhcIYHJHX5DjgQYE3uPo,1169
64
65
  praetorian_cli/sdk/test/test_capabilities.py,sha256=HoAu_WFjqVkwciPgrLp5z0-UbkuqKdqD46jb_8o1PbM,407
65
66
  praetorian_cli/sdk/test/test_configuration.py,sha256=ysyWpt7iq_tNkdvLU8gULCuwbXVqt2HMXgZpWLnWccg,2174
@@ -72,12 +73,12 @@ praetorian_cli/sdk/test/test_mcp.py,sha256=Ltg283j4Q12dcfCgUgDMKk6neRdDaThcndyyw
72
73
  praetorian_cli/sdk/test/test_preseed.py,sha256=VhKSbSB6OmCYnVOrI6RDsYKBs1PekEuv0KOjbTt_k14,1186
73
74
  praetorian_cli/sdk/test/test_risk.py,sha256=S428ZF9Sot6_F8vvXFL-1a5FxtmsFct4rBewTAgm0mE,1992
74
75
  praetorian_cli/sdk/test/test_search.py,sha256=SB9Tgo_N3CCpfvla898oLB9IZyGK9Dju1r9REK6Wmek,1996
75
- praetorian_cli/sdk/test/test_seed.py,sha256=HOp2eOX1NAvftLzNy52ILGLT24TqvkrI4AcKGuEtDYY,1337
76
+ praetorian_cli/sdk/test/test_seed.py,sha256=WfnEPZwMXHFtt4jyVT-1JitIW1zTrl7rwlX8jXz22vY,1303
76
77
  praetorian_cli/sdk/test/test_setting.py,sha256=hdPQj71rjSYxa-PODG2D-kJd8C9gkAg1jQXnqYU4P6A,1326
77
78
  praetorian_cli/sdk/test/test_webhook.py,sha256=FQJY76QQ6Yg2iLCGpxgKiXGI8TtmB4zTpMIM2SpYKCc,2228
78
- praetorian_cli/sdk/test/test_z_cli.py,sha256=JteaYNhVDWEvmtdiu5z3zNM2ODIafr1nNf2VtdI9gz0,17548
79
+ praetorian_cli/sdk/test/test_z_cli.py,sha256=FZ2g5NsvaM_fIXBf6AfYut5PZtIjVi3pu3pEEqGcC3k,17547
79
80
  praetorian_cli/sdk/test/ui_mocks.py,sha256=kiqAPxaM-_T0NQ-HgOZupNiUoJa5mE2CsyK2cXWiPws,4146
80
- praetorian_cli/sdk/test/utils.py,sha256=2-SH0mXnXso5qGXwdNU2k_rYVOatI5tSraxB4KwIoMY,2715
81
+ praetorian_cli/sdk/test/utils.py,sha256=k0cByQYGg5PIfQFS1n0LmQ3bDYLKvAQT_87sbXzIDrw,3231
81
82
  praetorian_cli/ui/__init__.py,sha256=wEgkrgIaoOguH1VVp2FndaGIxWmZ5CfAynXtNtZ6iTo,81
82
83
  praetorian_cli/ui/aegis/__init__.py,sha256=1HE5aQ6C6Qruf1X-KmKvDw1M3lzaUbPZoz9QOp4Lofs,123
83
84
  praetorian_cli/ui/aegis/constants.py,sha256=trr62uBwdBwm4LrFVms7_moThdtOPJi2uzCeIv4m3VU,578
@@ -90,9 +91,9 @@ praetorian_cli/ui/aegis/commands/job.py,sha256=BUcp47K-4PBIYq9nyUQTKhOakZwXM4fOf
90
91
  praetorian_cli/ui/aegis/commands/list.py,sha256=puIiy0skYE59Q2hVSMsla1tKiYYAFTOaz8oPM17tCyI,352
91
92
  praetorian_cli/ui/aegis/commands/set.py,sha256=ODa9u_6yW2dbKVQBuV9YeiS_ty_R_Xk_vPz7YrW3OWs,1101
92
93
  praetorian_cli/ui/aegis/commands/ssh.py,sha256=KGsNlN0i-Cwp6gWyr-cjML9_L13oE7xFenysF2pC8Rc,3045
93
- praetorian_cli-2.2.2.dist-info/licenses/LICENSE,sha256=Zv97QripiVALv-WokW_Elsiz9vtOfbtNt1aLZhhk67I,1067
94
- praetorian_cli-2.2.2.dist-info/METADATA,sha256=EcwR_vnm99hUBdYfjPwXkcw7gg1QF-rfhRh_rrRZa7g,7751
95
- praetorian_cli-2.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
- praetorian_cli-2.2.2.dist-info/entry_points.txt,sha256=uJbDvZdkYaLiCh2DMvXPUGKFm2p5ZfzJCizUK3-PUEE,56
97
- praetorian_cli-2.2.2.dist-info/top_level.txt,sha256=QbUdRPGEj_TyHO-E7AD5BxFfR8ore37i273jP4Gn43c,15
98
- praetorian_cli-2.2.2.dist-info/RECORD,,
94
+ praetorian_cli-2.2.3.dist-info/licenses/LICENSE,sha256=Zv97QripiVALv-WokW_Elsiz9vtOfbtNt1aLZhhk67I,1067
95
+ praetorian_cli-2.2.3.dist-info/METADATA,sha256=PsQEkHd-xhwCPwmCWZWD3f3T5sEUgeLbrsjnosdmscI,7751
96
+ praetorian_cli-2.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
+ praetorian_cli-2.2.3.dist-info/entry_points.txt,sha256=uJbDvZdkYaLiCh2DMvXPUGKFm2p5ZfzJCizUK3-PUEE,56
98
+ praetorian_cli-2.2.3.dist-info/top_level.txt,sha256=QbUdRPGEj_TyHO-E7AD5BxFfR8ore37i273jP4Gn43c,15
99
+ praetorian_cli-2.2.3.dist-info/RECORD,,