agilicus 1.244.3__py3-none-any.whl → 1.246.0__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.
agilicus/__init__.py CHANGED
@@ -38,6 +38,7 @@ def create_or_update(
38
38
  create_method: Callable,
39
39
  update_method: Callable = None,
40
40
  to_dict=True,
41
+ guid_finder=find_guid,
41
42
  ) -> [dict, str]:
42
43
  """A helper method that handles duplicate (409)
43
44
  creation of objects. On 409, if the update_method is provided,
@@ -70,7 +71,7 @@ def create_or_update(
70
71
  raise
71
72
  result = json.loads(body)
72
73
  if update_method:
73
- guid = find_guid(result)
74
+ guid = guid_finder(result)
74
75
  if to_dict:
75
76
  return update_method(guid, obj).to_dict(), 200
76
77
  else:
@@ -2364,6 +2364,7 @@ class RulesApi(object):
2364
2364
  org_id (str): Organisation Unique identifier. [optional]
2365
2365
  label (str): Filters based on whether or not the items in the collection have the given label. . [optional]
2366
2366
  get_rulesets (bool): When querying a bundle, return all rulesets associated with bundle . [optional]
2367
+ standalone_ruleset_bundles_etag (str): The entity tag (etag) for a list of bundles. If the returned etag matches the requested etag, then no data is returned, along with status code 304. . [optional]
2367
2368
  _return_http_data_only (bool): response data without head status
2368
2369
  code and headers. Default is True.
2369
2370
  _preload_content (bool): if False, the urllib3.HTTPResponse object
@@ -2430,6 +2431,7 @@ class RulesApi(object):
2430
2431
  'org_id',
2431
2432
  'label',
2432
2433
  'get_rulesets',
2434
+ 'standalone_ruleset_bundles_etag',
2433
2435
  ],
2434
2436
  'required': [],
2435
2437
  'nullable': [
@@ -2463,6 +2465,8 @@ class RulesApi(object):
2463
2465
  (str,),
2464
2466
  'get_rulesets':
2465
2467
  (bool,),
2468
+ 'standalone_ruleset_bundles_etag':
2469
+ (str,),
2466
2470
  },
2467
2471
  'attribute_map': {
2468
2472
  'limit': 'limit',
@@ -2471,6 +2475,7 @@ class RulesApi(object):
2471
2475
  'org_id': 'org_id',
2472
2476
  'label': 'label',
2473
2477
  'get_rulesets': 'get_rulesets',
2478
+ 'standalone_ruleset_bundles_etag': 'standalone_ruleset_bundles_etag',
2474
2479
  },
2475
2480
  'location_map': {
2476
2481
  'limit': 'query',
@@ -2479,6 +2484,7 @@ class RulesApi(object):
2479
2484
  'org_id': 'query',
2480
2485
  'label': 'query',
2481
2486
  'get_rulesets': 'query',
2487
+ 'standalone_ruleset_bundles_etag': 'query',
2482
2488
  },
2483
2489
  'collection_format_map': {
2484
2490
  }
@@ -77,7 +77,7 @@ class ApiClient(object):
77
77
  self.default_headers[header_name] = header_value
78
78
  self.cookie = cookie
79
79
  # Set default User-Agent.
80
- self.user_agent = 'OpenAPI-Generator/1.244.3/python'
80
+ self.user_agent = 'OpenAPI-Generator/1.246.0/python'
81
81
 
82
82
  def __enter__(self):
83
83
  return self
@@ -387,7 +387,7 @@ class Configuration(object):
387
387
  "OS: {env}\n"\
388
388
  "Python Version: {pyversion}\n"\
389
389
  "Version of the API: 2024.03.19\n"\
390
- "SDK Package Version: 1.244.3".\
390
+ "SDK Package Version: 1.246.0".\
391
391
  format(env=sys.platform, pyversion=sys.version)
392
392
 
393
393
  def get_host_settings(self):
@@ -7,6 +7,8 @@ Name | Type | Description | Notes
7
7
  ------------ | ------------- | ------------- | -------------
8
8
  **standalone_ruleset_bundles** | [**[StandaloneRulesetBundle]**](StandaloneRulesetBundle.md) | List of StandaloneRulesetBundle |
9
9
  **limit** | **int** | Limit on the number of rows in the response |
10
+ **page_at_id** | **str** | The id to request in the pagination query to get the next page. | [optional]
11
+ **standalone_ruleset_bundles_etag** | **str** | The entity tag (etag) associated with standalone_ruleset_bundles. | [optional]
10
12
  **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
11
13
 
12
14
  [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
@@ -2101,12 +2101,13 @@ with agilicus_api.ApiClient(configuration) as api_client:
2101
2101
  org_id = "1234" # str | Organisation Unique identifier (optional)
2102
2102
  label = "label-1" # str | Filters based on whether or not the items in the collection have the given label. (optional)
2103
2103
  get_rulesets = True # bool | When querying a bundle, return all rulesets associated with bundle (optional)
2104
+ standalone_ruleset_bundles_etag = "asdflkjasf" # str | The entity tag (etag) for a list of bundles. If the returned etag matches the requested etag, then no data is returned, along with status code 304. (optional)
2104
2105
 
2105
2106
  # example passing only required values which don't have defaults set
2106
2107
  # and optional values
2107
2108
  try:
2108
2109
  # List all standalone ruleset bundles
2109
- api_response = api_instance.list_standalone_ruleset_bundles(limit=limit, name=name, page_at_id=page_at_id, org_id=org_id, label=label, get_rulesets=get_rulesets)
2110
+ api_response = api_instance.list_standalone_ruleset_bundles(limit=limit, name=name, page_at_id=page_at_id, org_id=org_id, label=label, get_rulesets=get_rulesets, standalone_ruleset_bundles_etag=standalone_ruleset_bundles_etag)
2110
2111
  pprint(api_response)
2111
2112
  except agilicus_api.ApiException as e:
2112
2113
  print("Exception when calling RulesApi->list_standalone_ruleset_bundles: %s\n" % e)
@@ -2123,6 +2124,7 @@ Name | Type | Description | Notes
2123
2124
  **org_id** | **str**| Organisation Unique identifier | [optional]
2124
2125
  **label** | **str**| Filters based on whether or not the items in the collection have the given label. | [optional]
2125
2126
  **get_rulesets** | **bool**| When querying a bundle, return all rulesets associated with bundle | [optional]
2127
+ **standalone_ruleset_bundles_etag** | **str**| The entity tag (etag) for a list of bundles. If the returned etag matches the requested etag, then no data is returned, along with status code 304. | [optional]
2126
2128
 
2127
2129
  ### Return type
2128
2130
 
@@ -2142,6 +2144,7 @@ Name | Type | Description | Notes
2142
2144
  | Status code | Description | Response headers |
2143
2145
  |-------------|-------------|------------------|
2144
2146
  **200** | Query succeeded | - |
2147
+ **304** | Response not modified | - |
2145
2148
 
2146
2149
  [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
2147
2150
 
@@ -81,6 +81,22 @@ class ListStandaloneRulesetBundlesResponse(ModelNormal):
81
81
  def limit(self, new_value):
82
82
  self.limit = new_value
83
83
 
84
+ @property
85
+ def page_at_id(self):
86
+ return self.get("page_at_id")
87
+
88
+ @page_at_id.setter
89
+ def page_at_id(self, new_value):
90
+ self.page_at_id = new_value
91
+
92
+ @property
93
+ def standalone_ruleset_bundles_etag(self):
94
+ return self.get("standalone_ruleset_bundles_etag")
95
+
96
+ @standalone_ruleset_bundles_etag.setter
97
+ def standalone_ruleset_bundles_etag(self, new_value):
98
+ self.standalone_ruleset_bundles_etag = new_value
99
+
84
100
  @cached_property
85
101
  def additional_properties_type():
86
102
  """
@@ -106,6 +122,8 @@ class ListStandaloneRulesetBundlesResponse(ModelNormal):
106
122
  return {
107
123
  'standalone_ruleset_bundles': ([StandaloneRulesetBundle],), # noqa: E501
108
124
  'limit': (int,), # noqa: E501
125
+ 'page_at_id': (str,), # noqa: E501
126
+ 'standalone_ruleset_bundles_etag': (str,), # noqa: E501
109
127
  }
110
128
 
111
129
  @cached_property
@@ -117,6 +135,8 @@ class ListStandaloneRulesetBundlesResponse(ModelNormal):
117
135
  attribute_map = {
118
136
  'standalone_ruleset_bundles': 'standalone_ruleset_bundles', # noqa: E501
119
137
  'limit': 'limit', # noqa: E501
138
+ 'page_at_id': 'page_at_id', # noqa: E501
139
+ 'standalone_ruleset_bundles_etag': 'standalone_ruleset_bundles_etag', # noqa: E501
120
140
  }
121
141
 
122
142
  read_only_vars = {
@@ -164,6 +184,8 @@ class ListStandaloneRulesetBundlesResponse(ModelNormal):
164
184
  Animal class but this time we won't travel
165
185
  through its discriminator because we passed in
166
186
  _visited_composed_classes = (Animal,)
187
+ page_at_id (str): The id to request in the pagination query to get the next page.. [optional] # noqa: E501
188
+ standalone_ruleset_bundles_etag (str): The entity tag (etag) associated with standalone_ruleset_bundles.. [optional] # noqa: E501
167
189
  """
168
190
 
169
191
  _check_type = kwargs.pop('_check_type', True)
@@ -254,6 +276,8 @@ class ListStandaloneRulesetBundlesResponse(ModelNormal):
254
276
  Animal class but this time we won't travel
255
277
  through its discriminator because we passed in
256
278
  _visited_composed_classes = (Animal,)
279
+ page_at_id (str): The id to request in the pagination query to get the next page.. [optional] # noqa: E501
280
+ standalone_ruleset_bundles_etag (str): The entity tag (etag) associated with standalone_ruleset_bundles.. [optional] # noqa: E501
257
281
  """
258
282
 
259
283
  _check_type = kwargs.pop('_check_type', True)
@@ -4,7 +4,7 @@ Agilicus is API-first. Modern software is controlled by other software, is open,
4
4
  The `agilicus_api` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
5
5
 
6
6
  - API version: 2024.03.19
7
- - Package version: 1.244.3
7
+ - Package version: 1.246.0
8
8
  - Build package: org.openapitools.codegen.languages.PythonClientCodegen
9
9
  For more information, please visit [https://www.agilicus.com/api](https://www.agilicus.com/api)
10
10
 
agilicus/main.py CHANGED
@@ -75,6 +75,7 @@ from .labels import labels_main
75
75
  from .rules import rules_main
76
76
  from .products import products_main
77
77
  from .features import features_main
78
+ from .policy import policy_main
78
79
  from .features.features import format_features
79
80
  from .credentials_commands import credentials_main
80
81
  from .files_pkg import files_main
@@ -7939,6 +7940,7 @@ def main():
7939
7940
  hosts_main.add_commands(cli)
7940
7941
  labels_main.add_commands(cli)
7941
7942
  rules_main.add_commands(cli)
7943
+ policy_main.add_commands(cli)
7942
7944
  products_main.add_commands(cli)
7943
7945
  credentials_main.add_commands(cli)
7944
7946
  features_main.add_commands(cli)
@@ -0,0 +1,97 @@
1
+ from ..input_helpers import (
2
+ get_org_from_input_or_ctx,
3
+ )
4
+
5
+ from .. import context
6
+ from ..rules.rules import (
7
+ add_list_resources_sdk,
8
+ list_rules,
9
+ list_rule_trees,
10
+ list_rulesets,
11
+ RuleAddInfo,
12
+ RulesetAddInfo,
13
+ RuleTreeAddInfo,
14
+ )
15
+
16
+ from ..output.table import (
17
+ format_table,
18
+ column,
19
+ )
20
+
21
+ from .templates import MultifactorTemplate, MFA_LABEL
22
+
23
+
24
+ class LabelAddInfo:
25
+ def __init__(self, apiclient):
26
+ super().__init__()
27
+ self.create_fn = lambda obj: apiclient.rules_api.create_ruleset_label(obj)
28
+ # Can't replace. Just return the object
29
+ self.replace_fn = lambda guid, obj: obj
30
+ self.name_getter = lambda obj: obj.spec.name
31
+ self.guid_finder = lambda obj_as_dict: obj_as_dict["spec"]["name"]
32
+
33
+
34
+ def set_multifactor_policy(ctx, name, duration, label=None, **kwargs):
35
+ org_id = get_org_from_input_or_ctx(ctx, **kwargs)
36
+ tmpl = MultifactorTemplate(name, duration, org_id=org_id, labels=label)
37
+
38
+ token = context.get_token(ctx)
39
+ apiclient = context.get_apiclient(ctx, token)
40
+ add_list_resources_sdk(
41
+ ctx,
42
+ tmpl.get_rules(),
43
+ RuleAddInfo(apiclient),
44
+ handle_failure=False,
45
+ )
46
+ add_list_resources_sdk(
47
+ ctx, tmpl.get_trees(), RuleTreeAddInfo(apiclient), handle_failure=False
48
+ )
49
+ add_list_resources_sdk(
50
+ ctx, tmpl.get_labels(), LabelAddInfo(apiclient), handle_failure=False
51
+ )
52
+
53
+ add_list_resources_sdk(
54
+ ctx, tmpl.get_sets(), RulesetAddInfo(apiclient), handle_failure=False
55
+ )
56
+
57
+ return tmpl
58
+
59
+
60
+ def ruleset_labelled(ruleset, label):
61
+ for ruleset_label in ruleset.spec.labels or []:
62
+ if str(ruleset_label) == label:
63
+ return True
64
+ return False
65
+
66
+
67
+ def list_multifactor_policies(ctx, **kwargs):
68
+ org_id = get_org_from_input_or_ctx(ctx, **kwargs)
69
+ rules = list_rules(ctx, org_id=org_id)
70
+ trees = list_rule_trees(ctx, org_id=org_id)
71
+ sets = list_rulesets(ctx, org_id=org_id)
72
+
73
+ names = []
74
+ for ruleset in sets:
75
+ if ruleset_labelled(ruleset, MFA_LABEL):
76
+ names.append(str(ruleset.spec.name))
77
+
78
+ templates = []
79
+ for name in names:
80
+ tmpl = MultifactorTemplate.from_api(
81
+ name=name, rules=rules, trees=trees, sets=sets, org_id=org_id
82
+ )
83
+ if tmpl:
84
+ templates.append(tmpl)
85
+
86
+ return templates
87
+
88
+
89
+ def format_multifactor_policies(ctx, templates):
90
+ columns = [
91
+ column("name"),
92
+ column("org_id"),
93
+ column("duration"),
94
+ column("labels"),
95
+ ]
96
+
97
+ return format_table(ctx, templates, columns)
@@ -0,0 +1,31 @@
1
+ import click
2
+
3
+ from . import policies
4
+ from ..output.table import output_entry
5
+
6
+
7
+ @click.command(name="set-multifactor-policy")
8
+ @click.option("--name", required=True)
9
+ @click.option("--label", multiple=True, type=str)
10
+ @click.option("--duration", required=True, type=int)
11
+ @click.option("--org-id", default=None)
12
+ @click.pass_context
13
+ def cli_command_set_multifactor_policy(ctx, **kwargs):
14
+ output_entry(ctx, policies.set_multifactor_policy(ctx, **kwargs).to_dict())
15
+
16
+
17
+ @click.command(name="list-multifactor-policies")
18
+ @click.option("--org-id", default=None)
19
+ @click.pass_context
20
+ def cli_command_list_multifactor_policies(ctx, **kwargs):
21
+ results = policies.list_multifactor_policies(ctx, **kwargs)
22
+ print(policies.format_multifactor_policies(ctx, results))
23
+
24
+
25
+ all_funcs = [func for func in dir() if "cli_command_" in func]
26
+
27
+
28
+ def add_commands(cli):
29
+ glob = globals()
30
+ for func in all_funcs:
31
+ cli.add_command(glob[func])
@@ -0,0 +1,194 @@
1
+ import regex
2
+
3
+ from abc import abstractmethod
4
+ from typing import Optional
5
+
6
+ from agilicus import (
7
+ RuleAction,
8
+ RuleCondition,
9
+ RuleConfig,
10
+ MaxMFAProofRuleCondition,
11
+ StandaloneObjectConditions,
12
+ StandaloneRule,
13
+ StandaloneRuleName,
14
+ StandaloneRuleScope,
15
+ StandaloneRuleSpec,
16
+ StandaloneRuleTree,
17
+ StandaloneRuleTreeSpec,
18
+ StandaloneRuleTreeRef,
19
+ StandaloneRuleTreeRuleRef,
20
+ StandaloneRuleTreeNode,
21
+ StandaloneRuleset,
22
+ StandaloneRulesetLabelName,
23
+ StandaloneRulesetLabelSpec,
24
+ StandaloneRulesetLabel,
25
+ StandaloneRulesetSpec,
26
+ )
27
+
28
+
29
+ class PolicyTemplate:
30
+ @abstractmethod
31
+ def get_rules(self) -> list[StandaloneRule]:
32
+ pass
33
+
34
+ @abstractmethod
35
+ def get_trees(self) -> list[StandaloneRuleTree]:
36
+ pass
37
+
38
+ @abstractmethod
39
+ def get_sets(self) -> list[StandaloneRuleset]:
40
+ pass
41
+
42
+ @abstractmethod
43
+ def get_labels(self) -> list[StandaloneRulesetLabel]:
44
+ pass
45
+
46
+
47
+ def mfa_cond(max_seconds):
48
+ return MaxMFAProofRuleCondition(
49
+ condition_type="mfa_rule_condition", max_seconds=max_seconds
50
+ )
51
+
52
+
53
+ MFA_LABEL = "global-multifactor"
54
+ LABEL_REGEX = regex.compile(r"urn:agilicus:label:(?P<label>[a-zA-Z0-9\-\._:]+)")
55
+
56
+
57
+ def parse_label(scope):
58
+ match = LABEL_REGEX.match(str(scope))
59
+ if not match:
60
+ return None
61
+ return match.group("label")
62
+
63
+
64
+ def parse_labels(scopes):
65
+ result = []
66
+ for scope in scopes:
67
+ label = parse_label(scope)
68
+ if not label:
69
+ continue
70
+ result.append(label)
71
+ return result
72
+
73
+
74
+ class MultifactorTemplate(PolicyTemplate):
75
+ name_regex = regex.compile(r"agilicus-mfa-tmpl-(?P<name>[a-zA-Z0-9\-\._]+)")
76
+
77
+ def __init__(self, name, duration, org_id, labels: Optional[list[str]] = None):
78
+ self.name = name
79
+ self.duration = duration
80
+ self.labels = labels or []
81
+ self.org_id = org_id
82
+
83
+ def to_dict(self):
84
+ return {
85
+ "name": self.name,
86
+ "duration": self.duration,
87
+ "labels": self.labels,
88
+ "org_id": self.org_id,
89
+ }
90
+
91
+ @classmethod
92
+ def build_name(cls, name):
93
+ return f"agilicus-mfa-tmpl-{name}"
94
+
95
+ def get_name(self):
96
+ return self.build_name(self.name)
97
+
98
+ @classmethod
99
+ def parse_name(cls, name):
100
+ match = cls.name_regex.match(name)
101
+ if not match:
102
+ return None
103
+ return match.group("name")
104
+
105
+ def get_rules(self) -> list[StandaloneRule]:
106
+ cond = mfa_cond(self.duration)
107
+ action = RuleAction(action="mfa")
108
+ extended_condition = RuleCondition(negated=True, condition=cond)
109
+ spec = StandaloneRuleSpec(
110
+ rule=RuleConfig(
111
+ name=self.get_name(),
112
+ extended_condition=extended_condition,
113
+ actions=[action],
114
+ ),
115
+ org_id=self.org_id,
116
+ )
117
+
118
+ rule = StandaloneRule(spec=spec)
119
+ return [rule]
120
+
121
+ def get_trees(self) -> list[StandaloneRuleTree]:
122
+ spec = StandaloneRuleTreeSpec(
123
+ tree=StandaloneRuleTreeNode(
124
+ rules=[
125
+ StandaloneRuleTreeRuleRef(
126
+ rule_name=StandaloneRuleName(self.get_name()),
127
+ )
128
+ ],
129
+ children=[],
130
+ ),
131
+ name=StandaloneRuleName(self.get_name()),
132
+ org_id=self.org_id,
133
+ object_conditions=StandaloneObjectConditions(),
134
+ # object_conditions=StandaloneObjectConditions(
135
+ # scopes=[StandaloneRuleScope("urn:agilicus:scope:any_resource_user")]
136
+ # )
137
+ )
138
+
139
+ return [StandaloneRuleTree(spec=spec)]
140
+
141
+ def get_sets(self) -> list[StandaloneRuleset]:
142
+ spec = StandaloneRulesetSpec(
143
+ rule_trees=[
144
+ StandaloneRuleTreeRef(
145
+ rule_tree_name=StandaloneRuleName(self.get_name()),
146
+ priority=0,
147
+ )
148
+ ],
149
+ labels=[StandaloneRulesetLabelName(MFA_LABEL)],
150
+ name=StandaloneRuleName(self.get_name()),
151
+ org_id=self.org_id,
152
+ )
153
+ scopes = [
154
+ StandaloneRuleScope(f"urn:agilicus:label:{label}") for label in self.labels
155
+ ]
156
+ if scopes:
157
+ object_conditions = StandaloneObjectConditions(scopes=scopes)
158
+ spec.object_conditions = object_conditions
159
+
160
+ return [StandaloneRuleset(spec=spec)]
161
+
162
+ def get_labels(self) -> list[StandaloneRulesetLabel]:
163
+ spec = StandaloneRulesetLabelSpec(
164
+ name=StandaloneRulesetLabelName(MFA_LABEL),
165
+ org_id=self.org_id,
166
+ )
167
+
168
+ return [
169
+ StandaloneRulesetLabel(spec=spec),
170
+ ]
171
+
172
+ @classmethod
173
+ def from_api(cls, name, rules, org_id, trees, sets):
174
+ found_sets = list(filter(lambda s: str(s.spec.name) == name, sets))
175
+ found_trees = list(filter(lambda s: str(s.spec.name) == name, trees))
176
+ found_rules = list(filter(lambda s: str(s.spec.rule.name) == name, rules))
177
+
178
+ if len(found_sets) == 0 or len(found_rules) == 0 or len(found_trees) == 0:
179
+ return None
180
+
181
+ # There should be only one, given that names are unique.
182
+ ruleset = found_sets[0]
183
+ labels = []
184
+ if ruleset.spec.object_conditions:
185
+ labels = parse_labels(ruleset.spec.object_conditions.scopes)
186
+ rule = found_rules[0]
187
+ try:
188
+ duration = rule.spec.rule.extended_condition.condition.max_seconds
189
+ except Exception:
190
+ return None
191
+
192
+ return MultifactorTemplate(
193
+ name=cls.parse_name(name), duration=duration, labels=labels, org_id=org_id
194
+ )
agilicus/rules/rules.py CHANGED
@@ -18,7 +18,7 @@ from ..output.table import (
18
18
  column,
19
19
  )
20
20
 
21
- from agilicus import create_or_update
21
+ from agilicus import create_or_update, find_guid
22
22
 
23
23
  ACTIONS = ["allow", "deny", "redirect", "log", "none", "revocation_check", "mfa"]
24
24
 
@@ -116,29 +116,80 @@ def _obj_from_dict(klass, obj_dict, org_id):
116
116
  return model_from_dict(klass, obj_dict)
117
117
 
118
118
 
119
+ class AddInfo:
120
+ def __init__(self):
121
+ super().__init__()
122
+ self.name_getter = name_in_spec
123
+ self.guid_finder = find_guid
124
+
125
+
119
126
  def name_in_spec(obj):
120
127
  return obj.spec.name
121
128
 
122
129
 
123
- def add_list_of_resouces(
124
- ctx, as_dicts, klass, create_fn, replace_fn, name_getter=name_in_spec, **kwargs
125
- ):
130
+ class RuleAddInfo(AddInfo):
131
+ def __init__(self, apiclient):
132
+ super().__init__()
133
+ self.create_fn = lambda obj: apiclient.rules_api.create_standalone_rule(obj)
134
+ self.replace_fn = lambda guid, obj: apiclient.rules_api.replace_standalone_rule(
135
+ guid, standalone_rule=obj
136
+ )
137
+ self.name_getter = lambda obj: obj.spec.rule.name
138
+
139
+
140
+ class RuleTreeAddInfo(AddInfo):
141
+ def __init__(self, apiclient):
142
+ super().__init__()
143
+ self.create_fn = lambda obj: apiclient.rules_api.create_standalone_rule_tree(obj)
144
+ self.replace_fn = (
145
+ lambda guid, obj: apiclient.rules_api.replace_standalone_rule_tree(
146
+ guid, standalone_rule_tree=obj
147
+ )
148
+ )
149
+
150
+
151
+ class RulesetAddInfo(AddInfo):
152
+ def __init__(self, apiclient):
153
+ super().__init__()
154
+ self.create_fn = lambda obj: apiclient.rules_api.create_standalone_ruleset(obj)
155
+ self.replace_fn = (
156
+ lambda guid, obj: apiclient.rules_api.replace_standalone_ruleset(
157
+ guid, standalone_ruleset=obj
158
+ )
159
+ )
160
+
161
+
162
+ def add_list_of_resouces(ctx, as_dicts, klass, add_info, **kwargs):
126
163
  org_id = get_org_from_input_or_ctx(ctx, **kwargs)
127
164
  objs = [_obj_from_dict(klass, obj, org_id) for obj in as_dicts]
165
+
166
+ return add_list_resources_sdk(ctx, objs, add_info)
167
+
168
+
169
+ def add_list_resources_sdk(ctx, objs, add_info, handle_failure=True):
128
170
  results = []
129
171
  for obj in objs:
130
172
  try:
131
- result, _ = create_or_update(obj, create_fn, replace_fn, to_dict=False)
173
+ result, _ = create_or_update(
174
+ obj,
175
+ add_info.create_fn,
176
+ add_info.replace_fn,
177
+ to_dict=False,
178
+ guid_finder=add_info.guid_finder,
179
+ )
132
180
  results.append(
133
181
  AddResult(
134
- result_name=name_getter(result),
135
- result_id=result.metadata.id,
182
+ result_name=add_info.name_getter(result),
183
+ result_id=add_info.guid_finder(result),
136
184
  )
137
185
  )
138
186
  except Exception as exc:
187
+ if not handle_failure:
188
+ raise
189
+
139
190
  results.append(
140
191
  AddResult(
141
- result_name=name_getter(obj),
192
+ result_name=add_info.name_getter(obj),
142
193
  exc=str(exc),
143
194
  )
144
195
  )
@@ -155,11 +206,7 @@ def add_rules(ctx, rules, **kwargs):
155
206
  ctx,
156
207
  rules,
157
208
  agilicus.StandaloneRule,
158
- lambda obj: apiclient.rules_api.create_standalone_rule(obj),
159
- lambda guid, obj: apiclient.rules_api.replace_standalone_rule(
160
- guid, standalone_rule=obj
161
- ),
162
- name_getter=lambda obj: obj.spec.rule.name,
209
+ RuleAddInfo(apiclient),
163
210
  )
164
211
 
165
212
 
@@ -296,10 +343,7 @@ def add_trees(ctx, trees, **kwargs):
296
343
  ctx,
297
344
  trees,
298
345
  agilicus.StandaloneRuleTree,
299
- lambda obj: apiclient.rules_api.create_standalone_rule_tree(obj),
300
- lambda guid, obj: apiclient.rules_api.replace_standalone_rule_tree(
301
- guid, standalone_rule_tree=obj
302
- ),
346
+ RuleTreeAddInfo(apiclient),
303
347
  )
304
348
 
305
349
 
@@ -426,10 +470,7 @@ def add_rulesets(ctx, rulesets, **kwargs):
426
470
  ctx,
427
471
  rulesets,
428
472
  agilicus.StandaloneRuleset,
429
- lambda obj: apiclient.rules_api.create_standalone_ruleset(obj),
430
- lambda guid, obj: apiclient.rules_api.replace_standalone_ruleset(
431
- guid, standalone_ruleset=obj
432
- ),
473
+ RulesetAddInfo(apiclient),
433
474
  )
434
475
 
435
476
 
@@ -630,7 +671,7 @@ def list_bundles(ctx, **kwargs):
630
671
  kwargs = strip_none(kwargs)
631
672
  return apiclient.rules_api.list_standalone_ruleset_bundles(
632
673
  **kwargs,
633
- ).standalone_ruleset_bundles
674
+ )
634
675
 
635
676
 
636
677
  def get_bundle(ctx, bundle_id, **kwargs):
@@ -1,6 +1,7 @@
1
1
  import click
2
2
  import click_extension
3
3
 
4
+ from .. import context
4
5
  from . import rules
5
6
  from ..output.table import output_entry
6
7
 
@@ -268,10 +269,17 @@ def cli_command_delete_rulesets_bundle(ctx, bundle_id, **kwargs):
268
269
 
269
270
  @click.command(name="list-standalone-ruleset-bundles")
270
271
  @click.option("--org-id", default=None)
272
+ @click.option("--page-at-id", default=None)
273
+ @click.option("--get-rulesets", is_flag=True, default=None)
274
+ @click.option("--standalone-ruleset-bundles-etag", default=None)
275
+ @click.option("--limit", default=None, type=int)
271
276
  @click.pass_context
272
277
  def cli_command_list_rulesets_bundle(ctx, **kwargs):
273
278
  results = rules.list_bundles(ctx, **kwargs)
274
- print(rules.format_bundles(ctx, results))
279
+ if context.output_console(ctx):
280
+ print(rules.format_bundles(ctx, results.standalone_ruleset_bundles))
281
+ return
282
+ output_entry(ctx, results.to_dict())
275
283
 
276
284
 
277
285
  @click.command(name="get-standalone-ruleset-bundle")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: agilicus
3
- Version: 1.244.3
3
+ Version: 1.246.0
4
4
  Summary: Agilicus SDK
5
5
  Home-page: https://www.agilicus.com/
6
6
  License: MIT
@@ -2,7 +2,7 @@ agilicus/.gitignore,sha256=TyHq6BCuVrFiqgUb1QAayLxWcBseKwEOoKJTQb_-iW8,5
2
2
  agilicus/.openapi-generator/FILES,sha256=K8BDgVDJIh7xUpYphJsmb-ZM2ny3_oJKBn1oEEe70Qk,107380
3
3
  agilicus/.openapi-generator/VERSION,sha256=LXsIFraL1muXBEww1sZWaewc9ji87Ih3gIa04Z37RYM,14
4
4
  agilicus/.openapi-generator-ignore,sha256=pu2PTide7pJtJ-DFLzDy0cTYQJRlrB-8RRH3zGLeUds,1040
5
- agilicus/__init__.py,sha256=_H58rxzMyqBJq8B0TpwzyVIYDlPaLOqGTcwp-GDaDSM,4949
5
+ agilicus/__init__.py,sha256=S2_3WLG9tTuRxTPcP_0eNzBALnu9MMiZnFUEbv-dAqE,4978
6
6
  agilicus/access.py,sha256=UEHHhE3cCaCjxXQDjhKxQAoUEMWandygN0d-yEIIf8A,5457
7
7
  agilicus/admin.py,sha256=Gd4HfM7vQktFOuYOoOV_5uAZXEKWOgL_79Ndnlvxhyw,9340
8
8
  agilicus/agilicus_api/__init__.py,sha256=jmFa7Pr4rMPhCT_QFsO408OQ2RrZZFgrrzWKyABULPI,60973
@@ -57,7 +57,7 @@ agilicus/agilicus_api/api/regions_api.py,sha256=4R1gOgDBn0V7hMJj5MygnZ-yRx7rm_gw
57
57
  agilicus/agilicus_api/api/regions_api_mock.py,sha256=cBnoAURuccE36TePbYeOVgJzfJmoFu7EWpxvr6alryg,1596
58
58
  agilicus/agilicus_api/api/resources_api.py,sha256=hfIe0qmk8pAIuU-in6U7MnHoQqEjRSppplGnU5KlWOA,44716
59
59
  agilicus/agilicus_api/api/resources_api_mock.py,sha256=06pIiRJdLjnDWKVQrTnIamp5pF1X-G4VPz_PzdUG5N0,2070
60
- agilicus/agilicus_api/api/rules_api.py,sha256=PkeY-wt6XHJGCsCG2wdkROXrjJPdrCPNDF3R0yl-ifY,130378
60
+ agilicus/agilicus_api/api/rules_api.py,sha256=QZTsG-y2Y6dVnJ4aTO54wAuXWZ08CR3O16BcXJzXXtM,130910
61
61
  agilicus/agilicus_api/api/rules_api_mock.py,sha256=BJcQzQC4A6ZcWh4lq3KqcTGvNO9X6qerWEH0z2i0vMs,7475
62
62
  agilicus/agilicus_api/api/tokens_api.py,sha256=151rL7BLBz5mmdNIIAjiMCivDhpSLrN8Qp8oBhh0waw,173574
63
63
  agilicus/agilicus_api/api/tokens_api_mock.py,sha256=S7kDLZpQ8wCVM0OMlFn8OGk4GcQxrDHThaT3DkUfY-4,9714
@@ -67,9 +67,9 @@ agilicus/agilicus_api/api/users_api.py,sha256=zLwPF_gsWfKZeSmDL3dnJOcp66DlQolvwq
67
67
  agilicus/agilicus_api/api/users_api_mock.py,sha256=wA_xiqL3Pz3KjljKlsmf5NveLZS1FpbaKJHBp7QvarY,15411
68
68
  agilicus/agilicus_api/api/whoami_api.py,sha256=Xnn2HjfIbO7FoNQZ_q3UbOTuC6YoPNw1IiSLqYDPu2g,7941
69
69
  agilicus/agilicus_api/api/whoami_api_mock.py,sha256=rlvZoWnMCqORMZBg7SOv6d3xp52kELdh6wXcCaIZ93w,346
70
- agilicus/agilicus_api/api_client.py,sha256=7E-MzDg8kFezht9AQ_Np_rDXtgYI9vM4T7tB3lGu7K4,38845
70
+ agilicus/agilicus_api/api_client.py,sha256=ZhXs4O8uzqMg8bANYTiZIPy1IV4BYzDNupEYGLoB4NQ,38845
71
71
  agilicus/agilicus_api/apis/__init__.py,sha256=m_hg6OJsEsMp6mZ1mn9OlaTflLjrU3Jc-jvYD9gi_PA,2092
72
- agilicus/agilicus_api/configuration.py,sha256=m5aQybYAl17CVB9rIJMvrmb4xV-gaSHaoqVvqDju_Jg,18447
72
+ agilicus/agilicus_api/configuration.py,sha256=kbAOkGmULb3zsdgXMW0JVeQo0VQOX9ZIR_EL7xwLrFk,18447
73
73
  agilicus/agilicus_api/docs/APIKey.md,sha256=4cKuz4_l9HcEDnUrLwYbEnn9C2WoDayrjfrY1Ixgaf4,1747
74
74
  agilicus/agilicus_api/docs/APIKeyIntrospect.md,sha256=nJ-zkuFm3JMbWFDYYN_vYyQk1snGBtBvIxtCQxamhAU,1019
75
75
  agilicus/agilicus_api/docs/APIKeyIntrospectAuthorizationInfo.md,sha256=7RApOOLjvWQs5sw2jb25g7i3Kta1BiEY-s8VRXfppH8,725
@@ -487,7 +487,7 @@ agilicus/agilicus_api/docs/ListServiceForwardersResponse.md,sha256=uGIZRJcW1WZAo
487
487
  agilicus/agilicus_api/docs/ListSessionsResponse.md,sha256=lW7z2xBTrcWDg0se_DVGxEznjRaZZm76gL2GeQtJRDk,1433
488
488
  agilicus/agilicus_api/docs/ListStandaloneRuleTreesResponse.md,sha256=GipviHaK1UZWwHG47yK6sadh0ekpa2sPK0Z2gF-MeLg,839
489
489
  agilicus/agilicus_api/docs/ListStandaloneRulesResponse.md,sha256=aXZ1t1x8GfYbuBbo32fyyLvshtLt6rT7JBHzeX4Vfls,814
490
- agilicus/agilicus_api/docs/ListStandaloneRulesetBundlesResponse.md,sha256=3x-Cj_Rq2NPHDsr_1suhODYyWecdXeAMkamLapWjmNM,732
490
+ agilicus/agilicus_api/docs/ListStandaloneRulesetBundlesResponse.md,sha256=3mUkELKJf7QRpOD7KUlISrVcBchF_XcL2KvRyZUZcmo,965
491
491
  agilicus/agilicus_api/docs/ListStandaloneRulesetLabelsResponse.md,sha256=lRg1-qPUUp4S27iPd6BYcDg2fElg6lWjAk2hIlkackM,726
492
492
  agilicus/agilicus_api/docs/ListStandaloneRulesetsResponse.md,sha256=1qC7omQdlz4v6wyrQvzS0ti-nm64_HEUaRBiT0haCZg,836
493
493
  agilicus/agilicus_api/docs/ListTOTPEnrollmentResponse.md,sha256=gCMl-Wti-OhTn5lLyzMt6xoRx0I5TVryKEZ8-iIbZek,681
@@ -694,7 +694,7 @@ agilicus/agilicus_api/docs/RuleSetComponent.md,sha256=xk2mA069dsggG4uRSKRAYpv45-
694
694
  agilicus/agilicus_api/docs/RuleSetNode.md,sha256=rEktF4HJeKwH52-TkKMwgkOAH1GsyLuRL-gcnfIrc3o,883
695
695
  agilicus/agilicus_api/docs/RuleSpec.md,sha256=cmKB_ksUIuW6okLMS5g3tdGiJwrMtM4-8sxfJXgoOLM,968
696
696
  agilicus/agilicus_api/docs/RuleV2.md,sha256=WKcttrVbzFUtZqqIrS0olNtVPMwytfk6ZxJkP-93cY8,943
697
- agilicus/agilicus_api/docs/RulesApi.md,sha256=OTngB76WjeB2D6mZD6SQ3Txx_tBtqwPvgyuwmQPDbzA,135577
697
+ agilicus/agilicus_api/docs/RulesApi.md,sha256=75PZo5R9JHEarjVes_WzZmRgsJA4b1-EjKEYLDSUVM4,136111
698
698
  agilicus/agilicus_api/docs/RulesConfig.md,sha256=1InJwa3YSCzYVwLBObH-27ysP0I2J0qgeU86cPvv6W4,1952
699
699
  agilicus/agilicus_api/docs/RuntimeStatus.md,sha256=TEypz-SIg1oy2YZcuYyMjzTW10OJi87-BBTyBQMuxyw,3687
700
700
  agilicus/agilicus_api/docs/SSHResource.md,sha256=ZFTmdXWOfrXr71MEbS8_uoXql3vMr8qrEp6jS-OPXxI,990
@@ -1256,7 +1256,7 @@ agilicus/agilicus_api/model/list_sessions_response.py,sha256=5VAFqQYH9zmEWaMBpG7
1256
1256
  agilicus/agilicus_api/model/list_ssh_resources_response.py,sha256=Xtb3u-yXDUA57O7QsRiJ67K_lKt8BnXbJcqTEhsXtGg,14637
1257
1257
  agilicus/agilicus_api/model/list_standalone_rule_trees_response.py,sha256=xe6kiMhi6Z5SH8amrp9zsqwn7fmxBNOCDxVFR1-Lqxk,14912
1258
1258
  agilicus/agilicus_api/model/list_standalone_rules_response.py,sha256=S_SPj7Gec-HZeC8o8dK3eRf85vfaTWDGqhJ5Ss8aUw4,14783
1259
- agilicus/agilicus_api/model/list_standalone_ruleset_bundles_response.py,sha256=1xjHONPhsvQKMNXEsk-DTla9uz6JyXRBfol2Ipusz3c,14500
1259
+ agilicus/agilicus_api/model/list_standalone_ruleset_bundles_response.py,sha256=0dCc1YMxPXRYKA0vw24JD2uY08-118vJvafOTE1jKIE,15738
1260
1260
  agilicus/agilicus_api/model/list_standalone_ruleset_labels_response.py,sha256=z--SLdBXFPvMXZJfe0rMP3ZVoLB7Ti4TudrQLbtM-wU,14472
1261
1261
  agilicus/agilicus_api/model/list_standalone_rulesets_response.py,sha256=IGcC4dpoEpCfpoSRf1L116VIguowbcAkfkvsBDiNSeo,14867
1262
1262
  agilicus/agilicus_api/model/list_tokens_response.py,sha256=Q80Srg2aA5Pab8W7PZPkE84W4DR5pQUcLzuuHKpufi4,13918
@@ -2398,7 +2398,7 @@ agilicus/agilicus_api/test/test_x509_root_certificate.py,sha256=AqH9tZ825V2RHtNc
2398
2398
  agilicus/agilicus_api/test/test_x509_root_certificate_spec.py,sha256=8PCPuXVkHrLCXqnaOJm64WGuSnpqIL0zj1AVQSBgf9U,2832
2399
2399
  agilicus/agilicus_api/test/test_x509_root_certificate_status.py,sha256=s8Ups8bxho__nuXR86gwXAtBlAjrmZqA1-YkJwmmCEg,2846
2400
2400
  agilicus/agilicus_api/test/test_xss_settings.py,sha256=kj4qWEH4k8kQWZ4Zb-S6mEvK1e18dN7kPowJ5uyqFE4,2746
2401
- agilicus/agilicus_api_README.md,sha256=t8CeEepwUB1S0al4VJjjpY4DUTLa8b9R9ZVWmy2DK60,154557
2401
+ agilicus/agilicus_api_README.md,sha256=JLOX2uGzj0NMTZqeVI8iegBhWTZuoa7mtjUxv8MdED8,154557
2402
2402
  agilicus/aliases.ini,sha256=MxqiVo2f2xdUDVF1YDkNW36AIqN8hrYjlTVfraEUZXY,455
2403
2403
  agilicus/amq.py,sha256=yxi-YTbJPVl10s78Hlr1dmrQR63iaSIoROGVILzFPmE,1775
2404
2404
  agilicus/apps.py,sha256=8k_tGraPUVKJURksZwKR8eNGW-4CSPv54FYcApQ3Ly8,50857
@@ -2447,7 +2447,7 @@ agilicus/labels/labels_main.py,sha256=i3HA1ZuMG6N28mwmlhAMt4N95RNpm4eDS3EVRChjRu
2447
2447
  agilicus/launchers.py,sha256=XRW8cO_S7HHs-Cc6_baol9AOOsuGlMto7bLcsKYk6qA,11199
2448
2448
  agilicus/logs.py,sha256=tS8c_sdre1Dncrl59GVGQ0L3d2jtwlVjvIMl3SHJraY,766
2449
2449
  agilicus/lookups.py,sha256=MNmNsKpP7Fq_poLAnL9xo_iptFilKM9ziGLyIe8VKaw,669
2450
- agilicus/main.py,sha256=ZvTEn8D5Bl5pU-wybGWBnyZD51cD_VJdQRxIEkVH4RQ,263647
2450
+ agilicus/main.py,sha256=WbKlV5agX3-aJnOHgOVaRGKenCDtIteYk02HWJv7ddA,263713
2451
2451
  agilicus/messages.py,sha256=Ydm-VhAsK23UnYdstv_HsOybBODfui5ubKc7F8R_dsw,5187
2452
2452
  agilicus/metrics.py,sha256=v4rwpvqDzeNG5GKNoZ7t34X5qUgly5IW2s-kXlS2vQM,2315
2453
2453
  agilicus/orgs.py,sha256=rwTuumHWz0_QPqWNdDPPdAJRGTTNUxVw7bBkxU5a8n8,12874
@@ -2461,6 +2461,9 @@ agilicus/output/tests/column_builder_test.py,sha256=fKP4V5sqXtmEIr-Q0gWVSFdBqCUt
2461
2461
  agilicus/pagination/pagination.py,sha256=hC7eLHxXKe4Iv7LdOZK3Dh8R_fKQIr9PPiWKJVyP4Nk,1672
2462
2462
  agilicus/patches.py,sha256=qTqLOgCAcFZPcPOkgfqMnK9bnqTXMvj_0ERsjRFcZug,1384
2463
2463
  agilicus/permissions.py,sha256=uB65yuDFICp1N10m0cdUjgizx9MQzAbLbAsBSTw1Rcc,2117
2464
+ agilicus/policy/policies.py,sha256=-Sf7I4Qs2jGk6qxLuuKrR5a7hnTJ8I8kuTM4Z7guKZ0,2570
2465
+ agilicus/policy/policy_main.py,sha256=eY0mc445ct5Nv4Jinee4oWersIpj2TncS1TG-b5ZjRo,931
2466
+ agilicus/policy/templates.py,sha256=EUvAhOhSjDuLAe2UKIFEzBp5pNpOT5y1r7uyV_GG6uI,5638
2464
2467
  agilicus/products/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2465
2468
  agilicus/products/products.py,sha256=he27jN3MUyXBdTdV2HRyvUYb0zD3W1TGsuC7NHLKngQ,5365
2466
2469
  agilicus/products/products_main.py,sha256=saa2-e5oeHW6D5AWPcld99KwgQ9nBY3hoW8Jz_5nfMQ,3421
@@ -2468,8 +2471,8 @@ agilicus/regions.py,sha256=21SzUJ9_hC8DiWLSLJ-vtSb1tWLhlcPXH9JhmXD_ypU,3343
2468
2471
  agilicus/resource_helpers.py,sha256=fyfqAxjfnIth1KlHNALlLtYYXIZzlWEJmSZNLdj2JV0,380
2469
2472
  agilicus/resources.py,sha256=nlH4cezzfaiq4M7BK7iwXFUYF3kG9_Su6sFEEXX6I2M,10163
2470
2473
  agilicus/response.py,sha256=tI2-dAJwhBuuDplSsouuMmCmKHSwR_Mx71af8tgsuYo,468
2471
- agilicus/rules/rules.py,sha256=6axCkTlOa9_5e9rQNjo99VScKjUZwbrhbHQwbuhmMks,20019
2472
- agilicus/rules/rules_main.py,sha256=bfad7Nm4L9YFG071ZwjHhGyXCULFBGNPtu0_islAGDc,10386
2474
+ agilicus/rules/rules.py,sha256=ALHJr_tX2iGDKGKUMTteAp0iUQExqNGAhz3hcypxaF0,21019
2475
+ agilicus/rules/rules_main.py,sha256=hHyeY0WzFT2l1AQlA1C1PJQLuaEAgRhSbIUALHIyaa8,10750
2473
2476
  agilicus/scopes.py,sha256=OgPUksJSOSaJ3XcHPP8WJQ3e_p8B9wVmRXr-oZDfZP0,1344
2474
2477
  agilicus/service_configuration.py,sha256=WlsvTKA_bkle1PthJK0S96lpPK7GNr-BWWp8a_-MgtM,490
2475
2478
  agilicus/service_token.py,sha256=YDVFeBe9Yv0qYvfUenwnpGHuj2x1J06YUe5A_C8L6L4,7162
@@ -2484,8 +2487,8 @@ agilicus/trusted_certs/trusted_certs_main.py,sha256=6dHHWXvNIcUa_nA9ptigL4Vibe4n
2484
2487
  agilicus/users.py,sha256=cBqZwqNz_9lcEJuFL5YTUFpbN56kL0-maBlM29KWWrQ,38728
2485
2488
  agilicus/version.py,sha256=G9OFdL1v_4dLDfk6I6taDNypM5bbO-JHAwilsu9LYgg,23
2486
2489
  agilicus/whoami.py,sha256=kqghtWMgZOd2rhKmfguDwCTm6A3gNS8Kj-S2IBxBtl0,206
2487
- agilicus-1.244.3.dist-info/LICENSE.txt,sha256=Zq4tqiCroC2CVrBB_PWjapRdvpae23nljdiaSkOzUho,1061
2488
- agilicus-1.244.3.dist-info/METADATA,sha256=z55fzhbI-5AjMGQ2hV8d36FYbHqWsyQME6kr9j6nyUk,3822
2489
- agilicus-1.244.3.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
2490
- agilicus-1.244.3.dist-info/entry_points.txt,sha256=a66hGozzLkHu0IewFzIMbSAhMTNTddUaA2T3_16Gb_s,51
2491
- agilicus-1.244.3.dist-info/RECORD,,
2490
+ agilicus-1.246.0.dist-info/LICENSE.txt,sha256=Zq4tqiCroC2CVrBB_PWjapRdvpae23nljdiaSkOzUho,1061
2491
+ agilicus-1.246.0.dist-info/METADATA,sha256=tTBFD6BkRJPQ23J8nAiRnf_bQAP2mVOBgtv9eYBS9PA,3822
2492
+ agilicus-1.246.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
2493
+ agilicus-1.246.0.dist-info/entry_points.txt,sha256=a66hGozzLkHu0IewFzIMbSAhMTNTddUaA2T3_16Gb_s,51
2494
+ agilicus-1.246.0.dist-info/RECORD,,