agilicus 1.286.5__py3-none-any.whl → 1.287.1__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.
@@ -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.286.5/python'
80
+ self.user_agent = 'OpenAPI-Generator/1.287.1/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: 2025.04.17\n"\
390
- "SDK Package Version: 1.286.5".\
390
+ "SDK Package Version: 1.287.1".\
391
391
  format(env=sys.platform, pyversion=sys.version)
392
392
 
393
393
  def get_host_settings(self):
@@ -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: 2025.04.17
7
- - Package version: 1.286.5
7
+ - Package version: 1.287.1
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
@@ -5222,6 +5222,23 @@ def list_api_keys(ctx, scope, **kwargs):
5222
5222
  output_entry(ctx, page_details)
5223
5223
 
5224
5224
 
5225
+ @cli.command(name="clean-api-keys")
5226
+ @click.option("--user-id", type=str, default=None)
5227
+ @click.option("--org-id", type=str, default=None)
5228
+ @click.option("--expires-at", type=custom_types.DateTime(), default=None)
5229
+ @click.option("--no-expiry", is_flag=True, default=None)
5230
+ @click.option("--older-than", type=custom_types.DateTime(), default=None)
5231
+ @click.pass_context
5232
+ def clear_api_keys(ctx, **kwargs):
5233
+ api_keys = tokens.clean_api_keys(ctx, **kwargs)
5234
+ if context.output_json(ctx):
5235
+ output_formatted(ctx, api_keys)
5236
+ return
5237
+
5238
+ table = tokens.format_api_keys_as_text(ctx, api_keys)
5239
+ print(table)
5240
+
5241
+
5225
5242
  @cli.command(name="show-api-key-introspection")
5226
5243
  @click.argument("email")
5227
5244
  @click.argument("api_key")
File without changes
@@ -1,3 +1,5 @@
1
+ import inspect
2
+
1
3
  from typing import Callable
2
4
 
3
5
 
@@ -7,6 +9,7 @@ def get_many_entries(
7
9
  page_size=100,
8
10
  maximum=None,
9
11
  page_callback=None,
12
+ page_key="page_at_id",
10
13
  **kwargs,
11
14
  ):
12
15
  """Implements the generic pagination strategy
@@ -20,25 +23,39 @@ def get_many_entries(
20
23
  if "limit" in kwargs:
21
24
  del kwargs["limit"]
22
25
  kwargs["limit"] = page_size
23
- if "page_at_id" not in kwargs:
24
- kwargs["page_at_id"] = ""
26
+ if page_key not in kwargs:
27
+ kwargs[page_key] = ""
28
+
29
+ retval = []
30
+
31
+ def apply_page(page):
32
+ retval.extend(page)
33
+ if not page_callback:
34
+ return
35
+ if len(inspect.getfullargspec(page_callback).args) > 0:
36
+ page_callback(page=page)
37
+ return
38
+
39
+ page_callback()
25
40
 
26
41
  list_resp = api_func(**kwargs)
27
- retval = list_resp.get(response_list_key) or []
42
+ page_items = list_resp.get(response_list_key) or []
43
+ apply_page(page_items)
44
+
28
45
  # loop quits when the list is < the page_size
29
46
  while len(list_resp.get(response_list_key, [])) >= page_size and _list_at_max_size(
30
47
  len(retval), maximum
31
48
  ):
32
- page_at_id = list_resp.get("page_at_id", None)
49
+ page_at_id = list_resp.get(page_key, None)
33
50
  if page_at_id is None:
34
51
  raise Exception(
35
- "page_at_id cannot be None for pagination to continue processing"
52
+ f"{page_key} cannot be None for pagination to continue processing"
36
53
  )
37
- kwargs["page_at_id"] = list_resp.get("page_at_id", None)
54
+ kwargs[page_key] = list_resp.get(page_key, None)
38
55
  list_resp = api_func(**kwargs)
39
- retval.extend(list_resp.get(response_list_key, []))
40
- if page_callback:
41
- page_callback()
56
+ page_items = list_resp.get(response_list_key, [])
57
+ apply_page(page_items)
58
+
42
59
  return _get_max_retval(retval, maximum)
43
60
 
44
61
 
@@ -0,0 +1,93 @@
1
+ from .pagination import get_many_entries
2
+
3
+
4
+ class fakeAPI:
5
+ def __init__(self, item_key, page_key, start_page=""):
6
+ self.item_key = item_key
7
+ self.page_key = page_key
8
+ self.pages = {}
9
+ self.next_page = start_page
10
+
11
+ def _make_page(self, items, next_page):
12
+ return {
13
+ "limit": len(items),
14
+ self.item_key: items,
15
+ self.page_key: next_page,
16
+ }
17
+
18
+ def add_page(self, items, next_page):
19
+ self.pages[self.next_page] = self._make_page(items, next_page)
20
+
21
+ self.next_page = next_page
22
+
23
+ def do_list(self, **kwargs):
24
+ page = kwargs[self.page_key]
25
+ result = self.pages.get(page)
26
+ if not result:
27
+ return self._make_page([], page)
28
+ return result
29
+
30
+
31
+ def make_test_page(items, item_key, page_key, next_page):
32
+ return {
33
+ "limit": len(items),
34
+ item_key: items,
35
+ page_key: next_page,
36
+ }
37
+
38
+
39
+ def test_get_many_entries_gets_all():
40
+ api = fakeAPI("items", "page_at_id")
41
+ api.add_page([10, 8, 6], 6)
42
+ api.add_page([4, 3, 2], 2)
43
+ api.add_page([1, 0], 0)
44
+
45
+ result = get_many_entries(api.do_list, api.item_key, page_size=3)
46
+ assert [10, 8, 6, 4, 3, 2, 1, 0] == result
47
+
48
+
49
+ def test_get_many_entries_limits_to_max():
50
+ api = fakeAPI("items", "page_at_id")
51
+ api.add_page([10, 8, 6], 6)
52
+ api.add_page([4, 3, 2], 2)
53
+ api.add_page([1, 0], 0)
54
+
55
+ result = get_many_entries(api.do_list, api.item_key, page_size=3, maximum=4)
56
+ assert [10, 8, 6, 4] == result
57
+
58
+
59
+ def test_get_many_entries_invokes_callback():
60
+ api = fakeAPI("items", "page_at_id")
61
+ api.add_page([10, 8, 6], 6)
62
+ api.add_page([4, 3, 2], 2)
63
+ api.add_page([1, 0], 0)
64
+
65
+ calls = []
66
+
67
+ def callback():
68
+ calls.append(None)
69
+
70
+ result = get_many_entries(
71
+ api.do_list, api.item_key, page_size=3, page_callback=callback
72
+ )
73
+ assert [10, 8, 6, 4, 3, 2, 1, 0] == result
74
+ assert len(calls) == 3
75
+
76
+
77
+ def test_get_many_entries_invokes_callback_with_page():
78
+ api = fakeAPI("items", "page_at_id")
79
+ api.add_page([10, 8, 6], 6)
80
+ api.add_page([4, 3, 2], 2)
81
+ api.add_page([1, 0], 0)
82
+
83
+ calls = []
84
+
85
+ def callback(page):
86
+ calls.append(page)
87
+
88
+ result = get_many_entries(
89
+ api.do_list, api.item_key, page_size=3, page_callback=callback
90
+ )
91
+ assert [10, 8, 6, 4, 3, 2, 1, 0] == result
92
+
93
+ assert [[10, 8, 6], [4, 3, 2], [1, 0]] == calls
agilicus/tokens.py CHANGED
@@ -3,6 +3,7 @@ import json
3
3
  import urllib.parse
4
4
  import datetime
5
5
  import jwt
6
+ import sys
6
7
 
7
8
  import requests
8
9
  import agilicus
@@ -13,6 +14,7 @@ from .input_helpers import get_user_id_from_input_or_ctx
13
14
  from .input_helpers import build_updated_model
14
15
  from .input_helpers import strip_none
15
16
  from .input_helpers import update_if_present
17
+ from .pagination import pagination
16
18
 
17
19
  from .output import output_if_console
18
20
 
@@ -595,3 +597,59 @@ def update_session_challenge(ctx, token=None):
595
597
  apiclient = context.get_apiclient_from_ctx(ctx, token=token)
596
598
  body = agilicus.SessionChallenge()
597
599
  return apiclient.tokens_api.update_session_challenge(body)
600
+
601
+
602
+ def clean_api_keys(
603
+ ctx, expires_at=None, no_expiry=False, older_than=None, max_failures=5, **kwargs
604
+ ):
605
+ apiclient = context.get_apiclient_from_ctx(ctx)
606
+ update_org_from_input_or_ctx(kwargs, ctx, **kwargs)
607
+ kwargs["user_id"] = get_user_id_from_input_or_ctx(ctx, **kwargs)
608
+ kwargs = strip_none(kwargs)
609
+ to_delete = []
610
+
611
+ def should_delete(api_key):
612
+ if older_than is not None and api_key.metadata.created >= older_than:
613
+ return False
614
+
615
+ if api_key.spec.expiry is None:
616
+ return no_expiry
617
+
618
+ if expires_at is not None:
619
+ return api_key.spec.expiry < expires_at
620
+
621
+ return False
622
+
623
+ def deleter(page: list):
624
+ for api_key in page:
625
+ if should_delete(api_key):
626
+ to_delete.append(api_key)
627
+
628
+ pagination.get_many_entries(
629
+ apiclient.tokens_api.list_api_keys,
630
+ "api_keys",
631
+ 100,
632
+ None,
633
+ page_callback=deleter,
634
+ page_key="page_at_created_date",
635
+ page_at_created_date=None,
636
+ sort_order="descending",
637
+ search_direction="forwards",
638
+ **kwargs,
639
+ )
640
+ failures = 0
641
+ deleted = []
642
+ for key in to_delete:
643
+ token_id = key.metadata.id
644
+ org_id = key.spec.org_id
645
+ try:
646
+ apiclient.tokens_api.delete_api_key(token_id, org_id=org_id)
647
+ except Exception as exc:
648
+ print(f"failed deleting {token_id}: {exc}", file=sys.stderr)
649
+ failures += 1
650
+ if failures >= max_failures:
651
+ print("too many failures. Exiting early", file=sys.stderr)
652
+ return
653
+ deleted.append(key)
654
+
655
+ return deleted
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: agilicus
3
- Version: 1.286.5
3
+ Version: 1.287.1
4
4
  Summary: Agilicus SDK
5
5
  Home-page: https://www.agilicus.com/
6
6
  License: MIT
@@ -71,9 +71,9 @@ agilicus/agilicus_api/api/users_api.py,sha256=vc1a6U7o4Pg_2A_FjPVIpiyRTIREZ58jpt
71
71
  agilicus/agilicus_api/api/users_api_mock.py,sha256=aMSUc12JQAo1O9rp2YnyQldANFGlfi57fMnQyCIrJuE,17209
72
72
  agilicus/agilicus_api/api/whoami_api.py,sha256=RNGWCYPit1iT7qrxDdOzyIKJkIdMuDryyKVmoxeg0qI,7941
73
73
  agilicus/agilicus_api/api/whoami_api_mock.py,sha256=rlvZoWnMCqORMZBg7SOv6d3xp52kELdh6wXcCaIZ93w,346
74
- agilicus/agilicus_api/api_client.py,sha256=T5vili8FQNaoOxChKKHk4Gap80buY93CAvMM_7RlqiE,38845
74
+ agilicus/agilicus_api/api_client.py,sha256=WZ4wYE6o-RY7hhg_bhPGA2qPI_k-qvyuuTaI5Vjqejs,38845
75
75
  agilicus/agilicus_api/apis/__init__.py,sha256=aJZD7x-umdSni6ZBr4XxzpH8pwtU9hA5LlCDxcqa1Q8,2224
76
- agilicus/agilicus_api/configuration.py,sha256=EuN3HdkIbSc_7_Ny14AqVCSTvtv5g5qs-K97tKrzRU8,18447
76
+ agilicus/agilicus_api/configuration.py,sha256=6gnetAAoozBXZHwaunB0P2fotR1u0uKZ2rX39-Oh6zU,18447
77
77
  agilicus/agilicus_api/docs/APIKey.md,sha256=4cKuz4_l9HcEDnUrLwYbEnn9C2WoDayrjfrY1Ixgaf4,1747
78
78
  agilicus/agilicus_api/docs/APIKeyIntrospect.md,sha256=nJ-zkuFm3JMbWFDYYN_vYyQk1snGBtBvIxtCQxamhAU,1019
79
79
  agilicus/agilicus_api/docs/APIKeyIntrospectAuthorizationInfo.md,sha256=7RApOOLjvWQs5sw2jb25g7i3Kta1BiEY-s8VRXfppH8,725
@@ -2667,7 +2667,7 @@ agilicus/agilicus_api/test/test_x509_root_certificate.py,sha256=LV5_rQa2jhob7DzH
2667
2667
  agilicus/agilicus_api/test/test_x509_root_certificate_spec.py,sha256=_csieI3dVbNe1oyoXCMPytlRUkatdg3rqVHNUASODf0,2832
2668
2668
  agilicus/agilicus_api/test/test_x509_root_certificate_status.py,sha256=0vDt4PephnpGCV7pw8JSOcvJ9ifukwyE5zYlFFF-Z7c,2846
2669
2669
  agilicus/agilicus_api/test/test_xss_settings.py,sha256=naM6PzbbiE5gF030lL5Ci5zfFcT-CVJzYZdMS9UNM8A,2746
2670
- agilicus/agilicus_api_README.md,sha256=rDP9fdfxkx5Hzpzu_asZeEWctuJTsEZkoW4q4CtY2Ww,171736
2670
+ agilicus/agilicus_api_README.md,sha256=-Z5nxFclI4EfIcyfDgZNGDTuuWhpFN2yX2abQipR11M,171736
2671
2671
  agilicus/aliases.ini,sha256=MxqiVo2f2xdUDVF1YDkNW36AIqN8hrYjlTVfraEUZXY,455
2672
2672
  agilicus/amq.py,sha256=yxi-YTbJPVl10s78Hlr1dmrQR63iaSIoROGVILzFPmE,1775
2673
2673
  agilicus/apps.py,sha256=Mdc_pRXyfa-IvIFH7gNbx0Ob64gUHggZyeSyLUDpjMs,54048
@@ -2722,7 +2722,7 @@ agilicus/labels/labels_main.py,sha256=l2z_41X3sMJoSM483LmAzJE6bKKHVAEvrPjfz7QvFg
2722
2722
  agilicus/launchers.py,sha256=r4nctnVtfP-Ho_HXEfAiMaMqJI0u7pbieHSS3Vd0QBE,11361
2723
2723
  agilicus/logs.py,sha256=Y4XVcLctY-2O-Q_CXbJs9sAqu0NknHKSsqilKiDM_A0,804
2724
2724
  agilicus/lookups.py,sha256=MNmNsKpP7Fq_poLAnL9xo_iptFilKM9ziGLyIe8VKaw,669
2725
- agilicus/main.py,sha256=vBoTqK9_r6TvwmeayEjIBgJtGHqdE59HT553v6W3NwU,289375
2725
+ agilicus/main.py,sha256=PvQ_Hmmy4qI83q0_7PeGECHm01Xhbq5qo8nKHQyV8rs,289990
2726
2726
  agilicus/messages/__init__.py,sha256=cVqfaKUndO-AYfppkdFICM5WvYFFB1hRjXihFWmiGPQ,174
2727
2727
  agilicus/messages/messages.py,sha256=b2eO6BaWI9UZTLETcdy1NotyuNlKIJf6CS_TUzehuk4,9175
2728
2728
  agilicus/messages/messages_main.py,sha256=A0xucYwwUZFIuUc0bAyAqVwofErakmyawq5bwhZKcOU,1598
@@ -2735,7 +2735,9 @@ agilicus/output/json.py,sha256=-5bX7ud1hIxux4l3P-K2gJXrE2gdZ0Ua1hfUOCX9MUM,899
2735
2735
  agilicus/output/table.py,sha256=o5kYgAtIAhei4ex7YZrTK9tDVarJQHzF2Yj42TXt21g,8744
2736
2736
  agilicus/output/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2737
2737
  agilicus/output/tests/column_builder_test.py,sha256=fKP4V5sqXtmEIr-Q0gWVSFdBqCUtugZkP6G5gML_T7I,2130
2738
- agilicus/pagination/pagination.py,sha256=hC7eLHxXKe4Iv7LdOZK3Dh8R_fKQIr9PPiWKJVyP4Nk,1672
2738
+ agilicus/pagination/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2739
+ agilicus/pagination/pagination.py,sha256=4OcBy0kC7J4r3ofEBrYX4ZvCoDpUXTSxHHpsuVwPTJs,1970
2740
+ agilicus/pagination/pagination_test.py,sha256=f28x57SoBz9xGp8Go1k-77Fvzbz9c2HPVeNlxkNcsK8,2409
2739
2741
  agilicus/patches.py,sha256=qTqLOgCAcFZPcPOkgfqMnK9bnqTXMvj_0ERsjRFcZug,1384
2740
2742
  agilicus/permissions.py,sha256=uB65yuDFICp1N10m0cdUjgizx9MQzAbLbAsBSTw1Rcc,2117
2741
2743
  agilicus/policy/policies.py,sha256=eAy1iRlYKvkuc-10ssw_iuchY-I24LvtHiruvyzo5Pg,11440
@@ -2760,15 +2762,15 @@ agilicus/ssh.py,sha256=mVqMlDM2zAcUphehyz9djXjrRPSIxR1qJr2Ehvl3Rvw,2925
2760
2762
  agilicus/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2761
2763
  agilicus/tests/keyring_test.py,sha256=Uwp2VS2_NffYBgHAS9bXuXnIxRoK0_VOWaaYCZKv0lg,1452
2762
2764
  agilicus/tests/test_pop_utils.py,sha256=gdSMOmE0pNSDA0UgUWdbLKpFzUGwfBwkFSrk1p1JdSo,1083
2763
- agilicus/tokens.py,sha256=H3_hSNUmyDeidCndQ_rlxqAaliAFIpNDJ1vW-fynwhs,18828
2765
+ agilicus/tokens.py,sha256=0zckgaZxYF8PFNBhUnV6yrrmVGru3dmh1qSH6YZQhsE,20515
2764
2766
  agilicus/transfers.py,sha256=PYr_fW7dyXNUXzi5Wp5mUjZOvU7MbRzoN-D8Omo-YSQ,1523
2765
2767
  agilicus/trusted_certs/trusted_certs.py,sha256=HCAvYxOA3ooaee2_KbYJd6Yt_dxDEn8hjhy1upVJUYE,7951
2766
2768
  agilicus/trusted_certs/trusted_certs_main.py,sha256=6dHHWXvNIcUa_nA9ptigL4Vibe4nB2wnWFTTJ8AOgXo,5155
2767
2769
  agilicus/users.py,sha256=bUFtVlTjUeEoQlzsQcfS8ChN0X9mbHs8v0xbkK-cldQ,41772
2768
2770
  agilicus/version.py,sha256=G9OFdL1v_4dLDfk6I6taDNypM5bbO-JHAwilsu9LYgg,23
2769
2771
  agilicus/whoami.py,sha256=kqghtWMgZOd2rhKmfguDwCTm6A3gNS8Kj-S2IBxBtl0,206
2770
- agilicus-1.286.5.dist-info/LICENSE.txt,sha256=Zq4tqiCroC2CVrBB_PWjapRdvpae23nljdiaSkOzUho,1061
2771
- agilicus-1.286.5.dist-info/METADATA,sha256=VN1cwLZeUoswkCJXSGlw6pKjPuLg4lQIApZN4uNaxy4,3878
2772
- agilicus-1.286.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2773
- agilicus-1.286.5.dist-info/entry_points.txt,sha256=a66hGozzLkHu0IewFzIMbSAhMTNTddUaA2T3_16Gb_s,51
2774
- agilicus-1.286.5.dist-info/RECORD,,
2772
+ agilicus-1.287.1.dist-info/LICENSE.txt,sha256=Zq4tqiCroC2CVrBB_PWjapRdvpae23nljdiaSkOzUho,1061
2773
+ agilicus-1.287.1.dist-info/METADATA,sha256=PWk0MyfBdFFkjNo85KaMnBDwOc8YrmDPkfeJCjGTINw,3878
2774
+ agilicus-1.287.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2775
+ agilicus-1.287.1.dist-info/entry_points.txt,sha256=a66hGozzLkHu0IewFzIMbSAhMTNTddUaA2T3_16Gb_s,51
2776
+ agilicus-1.287.1.dist-info/RECORD,,