agilicus 1.244.3__py3-none-any.whl → 1.246.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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,,