albus-cli 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {albus_cli-0.2.0 → albus_cli-0.3.0}/PKG-INFO +2 -2
- {albus_cli-0.2.0 → albus_cli-0.3.0}/pyproject.toml +2 -2
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/client.py +21 -17
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_auth.py +10 -14
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_health.py +3 -4
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_invites.py +2 -3
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_tokens.py +2 -3
- {albus_cli-0.2.0 → albus_cli-0.3.0}/uv.lock +5 -5
- {albus_cli-0.2.0 → albus_cli-0.3.0}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/.github/pull_request_template.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/.github/workflows/close-pull-requests.yml +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/.gitignore +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/AGENTS.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/CONTRIBUTING.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/LICENSE +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/Makefile +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/README.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/RELEASING.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/SECURITY.md +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/install.ps1 +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/install.sh +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/pyrightconfig.json +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/setup.sh +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/__init__.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/__main__.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/__init__.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/agents.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/auth.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/invites.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/secrets.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/sessions.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/status.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/commands/tokens.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/context.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/credentials.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/docs.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/main.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/oauth.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/src/albus_cli/output.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/__init__.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/conftest.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_cli.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_credentials.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_oauth.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tests/test_status.py +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tools/check +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tools/mirror-release +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tools/publish +0 -0
- {albus_cli-0.2.0 → albus_cli-0.3.0}/tools/release_state.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: albus-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Command-line client for the Albus REST API
|
|
5
5
|
Project-URL: Homepage, https://github.com/albusgroup/albus-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/albusgroup/albus-cli
|
|
@@ -9,7 +9,7 @@ Author: Albus
|
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Python: >=3.11
|
|
12
|
-
Requires-Dist: albus-sdk==0.
|
|
12
|
+
Requires-Dist: albus-sdk==0.8.0
|
|
13
13
|
Requires-Dist: typer<0.28,>=0.26.8
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "albus-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Command-line client for the Albus REST API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -13,7 +13,7 @@ authors = [{ name = "Albus" }]
|
|
|
13
13
|
dependencies = [
|
|
14
14
|
# Pinned, not floated: the published CLI states the one SDK version it was
|
|
15
15
|
# tested against, and bumping it is a reviewed edit made when releasing.
|
|
16
|
-
"albus-sdk==0.
|
|
16
|
+
"albus-sdk==0.8.0",
|
|
17
17
|
"typer>=0.26.8,<0.28",
|
|
18
18
|
]
|
|
19
19
|
|
|
@@ -10,7 +10,7 @@ import time
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
|
|
12
12
|
import httpx
|
|
13
|
-
from albus_sdk import Albus
|
|
13
|
+
from albus_sdk import Albus
|
|
14
14
|
from albus_sdk.sdkconfiguration import SERVERS
|
|
15
15
|
|
|
16
16
|
from albus_cli import credentials, oauth
|
|
@@ -59,9 +59,7 @@ def client(base_url: str, timeout: float | None) -> Albus:
|
|
|
59
59
|
if key:
|
|
60
60
|
# The environment wins over a stored session deliberately, so CI
|
|
61
61
|
# and agent harnesses inject a credential without touching disk.
|
|
62
|
-
return _client(
|
|
63
|
-
base_url, timeout, models.Security(api_key_auth=key), True
|
|
64
|
-
)
|
|
62
|
+
return _client(base_url, timeout, api_key=key)
|
|
65
63
|
|
|
66
64
|
stored = credentials.load(base_url)
|
|
67
65
|
if stored is None:
|
|
@@ -96,7 +94,7 @@ def public_client(base_url: str, timeout: float | None) -> Albus:
|
|
|
96
94
|
sign-in changes."""
|
|
97
95
|
global _used
|
|
98
96
|
_used = None
|
|
99
|
-
return _built(base_url, timeout
|
|
97
|
+
return _built(base_url, timeout)
|
|
100
98
|
|
|
101
99
|
|
|
102
100
|
def bearer_client(
|
|
@@ -104,12 +102,7 @@ def bearer_client(
|
|
|
104
102
|
) -> Albus:
|
|
105
103
|
"""A client on one credential, for `login` reading back the session
|
|
106
104
|
it just stored rather than whatever precedence would pick."""
|
|
107
|
-
return _client(
|
|
108
|
-
base_url,
|
|
109
|
-
timeout,
|
|
110
|
-
models.Security(bearer_auth=credential.access_token),
|
|
111
|
-
False,
|
|
112
|
-
)
|
|
105
|
+
return _client(base_url, timeout, access_token=credential.access_token)
|
|
113
106
|
|
|
114
107
|
|
|
115
108
|
def credential(tokens: oauth.Tokens, replacing: Credential | None) -> Credential:
|
|
@@ -213,19 +206,30 @@ def _shadowing(consequence: str) -> str | None:
|
|
|
213
206
|
def _client(
|
|
214
207
|
base_url: str,
|
|
215
208
|
timeout: float | None,
|
|
216
|
-
|
|
217
|
-
api_key:
|
|
209
|
+
*,
|
|
210
|
+
api_key: str | None = None,
|
|
211
|
+
access_token: str | None = None,
|
|
218
212
|
) -> Albus:
|
|
219
213
|
global _used
|
|
220
|
-
_used = _Used(base_url=base_url, api_key=api_key)
|
|
221
|
-
return _built(
|
|
214
|
+
_used = _Used(base_url=base_url, api_key=api_key is not None)
|
|
215
|
+
return _built(
|
|
216
|
+
base_url,
|
|
217
|
+
timeout,
|
|
218
|
+
api_key=api_key,
|
|
219
|
+
access_token=access_token,
|
|
220
|
+
)
|
|
222
221
|
|
|
223
222
|
|
|
224
223
|
def _built(
|
|
225
|
-
base_url: str,
|
|
224
|
+
base_url: str,
|
|
225
|
+
timeout: float | None,
|
|
226
|
+
*,
|
|
227
|
+
api_key: str | None = None,
|
|
228
|
+
access_token: str | None = None,
|
|
226
229
|
) -> Albus:
|
|
227
230
|
return Albus(
|
|
228
|
-
|
|
231
|
+
api_key=api_key,
|
|
232
|
+
access_token=access_token,
|
|
229
233
|
server_url=base_url,
|
|
230
234
|
client=httpx.Client(follow_redirects=True, timeout=timeout),
|
|
231
235
|
)
|
|
@@ -74,9 +74,8 @@ def test_api_key_wins_over_a_stored_session(
|
|
|
74
74
|
result = runner.invoke(app, ["sessions", "list"])
|
|
75
75
|
|
|
76
76
|
assert result.exit_code == 0, result.output
|
|
77
|
-
|
|
78
|
-
assert
|
|
79
|
-
assert security.bearer_auth is None
|
|
77
|
+
assert albus.init_kwargs[0]["api_key"] == "env-key"
|
|
78
|
+
assert albus.init_kwargs[0]["access_token"] is None
|
|
80
79
|
|
|
81
80
|
|
|
82
81
|
def test_stored_session_authenticates_with_a_bearer_token(
|
|
@@ -87,9 +86,8 @@ def test_stored_session_authenticates_with_a_bearer_token(
|
|
|
87
86
|
result = runner.invoke(app, ["sessions", "list"])
|
|
88
87
|
|
|
89
88
|
assert result.exit_code == 0, result.output
|
|
90
|
-
|
|
91
|
-
assert
|
|
92
|
-
assert security.api_key_auth is None
|
|
89
|
+
assert signed_out.init_kwargs[0]["access_token"] == "stored-access"
|
|
90
|
+
assert signed_out.init_kwargs[0]["api_key"] is None
|
|
93
91
|
|
|
94
92
|
|
|
95
93
|
def test_expired_session_is_refreshed_and_stored(
|
|
@@ -113,7 +111,7 @@ def test_expired_session_is_refreshed_and_stored(
|
|
|
113
111
|
|
|
114
112
|
assert result.exit_code == 0, result.output
|
|
115
113
|
assert grants == ["refresh"]
|
|
116
|
-
assert signed_out.init_kwargs[0]["
|
|
114
|
+
assert signed_out.init_kwargs[0]["access_token"] == "renewed-access"
|
|
117
115
|
saved = credentials.load(BASE_URL)
|
|
118
116
|
assert saved is not None
|
|
119
117
|
assert saved.access_token == "renewed-access"
|
|
@@ -159,8 +157,7 @@ def test_a_session_expiring_within_the_leeway_is_refreshed(
|
|
|
159
157
|
)
|
|
160
158
|
|
|
161
159
|
assert runner.invoke(app, ["sessions", "list"]).exit_code == 0
|
|
162
|
-
|
|
163
|
-
assert security.bearer_auth == "renewed-access"
|
|
160
|
+
assert signed_out.init_kwargs[0]["access_token"] == "renewed-access"
|
|
164
161
|
|
|
165
162
|
|
|
166
163
|
def test_rejected_refresh_reports_an_expired_session(
|
|
@@ -242,7 +239,7 @@ def test_login_stores_the_session_and_names_the_account(
|
|
|
242
239
|
# The account is resolved over the API with the new credential,
|
|
243
240
|
# never by reading the token.
|
|
244
241
|
assert signed_out.calls[-1].name == "whoami"
|
|
245
|
-
assert signed_out.init_kwargs[-1]["
|
|
242
|
+
assert signed_out.init_kwargs[-1]["access_token"] == "fresh-access"
|
|
246
243
|
|
|
247
244
|
|
|
248
245
|
def signs_in(
|
|
@@ -273,7 +270,7 @@ def test_login_names_the_account_it_just_signed_in_as(
|
|
|
273
270
|
|
|
274
271
|
assert result.exit_code == 0, result.output
|
|
275
272
|
assert "as carlo@albus.sh" in result.output
|
|
276
|
-
assert albus.init_kwargs[-1]["
|
|
273
|
+
assert albus.init_kwargs[-1]["access_token"] == "fresh-access"
|
|
277
274
|
|
|
278
275
|
|
|
279
276
|
def test_login_says_an_api_key_shadows_the_new_session(
|
|
@@ -441,9 +438,8 @@ def test_whoami_uses_the_session_over_an_api_key(
|
|
|
441
438
|
stored(expires_in=3600)
|
|
442
439
|
|
|
443
440
|
assert runner.invoke(app, ["whoami"]).exit_code == 0
|
|
444
|
-
|
|
445
|
-
assert
|
|
446
|
-
assert security.api_key_auth is None
|
|
441
|
+
assert albus.init_kwargs[0]["access_token"] == "stored-access"
|
|
442
|
+
assert albus.init_kwargs[0]["api_key"] is None
|
|
447
443
|
|
|
448
444
|
|
|
449
445
|
def test_whoami_with_only_an_api_key_asks_for_a_sign_in(
|
|
@@ -25,15 +25,14 @@ def test_health_needs_no_credential(
|
|
|
25
25
|
|
|
26
26
|
assert result.exit_code == 0, result.output
|
|
27
27
|
assert json.loads(result.stdout) == {"status": "ok"}
|
|
28
|
-
|
|
29
|
-
assert
|
|
30
|
-
assert security.api_key_auth is None
|
|
28
|
+
assert albus.init_kwargs[0]["access_token"] is None
|
|
29
|
+
assert albus.init_kwargs[0]["api_key"] is None
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
def test_health_sends_no_api_key_either(albus: FakeAlbus) -> None:
|
|
34
33
|
"""The `albus` fixture exports an API key, which `/health` ignores."""
|
|
35
34
|
assert runner.invoke(app, ["health"]).exit_code == 0
|
|
36
|
-
assert albus.init_kwargs[0]["
|
|
35
|
+
assert albus.init_kwargs[0]["api_key"] is None
|
|
37
36
|
|
|
38
37
|
|
|
39
38
|
def test_rejected_health_names_no_credential(albus: FakeAlbus) -> None:
|
|
@@ -58,6 +58,5 @@ def test_the_session_is_used_over_an_api_key(
|
|
|
58
58
|
result = runner.invoke(app, ["invites", "create", "new@example.com"])
|
|
59
59
|
|
|
60
60
|
assert result.exit_code == 0, result.output
|
|
61
|
-
|
|
62
|
-
assert
|
|
63
|
-
assert security.api_key_auth is None
|
|
61
|
+
assert signed_in.init_kwargs[0]["access_token"] == "stored-access"
|
|
62
|
+
assert signed_in.init_kwargs[0]["api_key"] is None
|
|
@@ -85,9 +85,8 @@ def test_the_session_is_used_over_an_api_key(
|
|
|
85
85
|
monkeypatch.setenv(client.API_KEY_ENV, "env-key")
|
|
86
86
|
|
|
87
87
|
assert runner.invoke(app, ["tokens", "list"]).exit_code == 0
|
|
88
|
-
|
|
89
|
-
assert
|
|
90
|
-
assert security.api_key_auth is None
|
|
88
|
+
assert signed_in.init_kwargs[0]["access_token"] == "stored-access"
|
|
89
|
+
assert signed_in.init_kwargs[0]["api_key"] is None
|
|
91
90
|
|
|
92
91
|
|
|
93
92
|
def test_only_an_api_key_asks_for_a_sign_in(
|
|
@@ -8,7 +8,7 @@ resolution-markers = [
|
|
|
8
8
|
|
|
9
9
|
[[package]]
|
|
10
10
|
name = "albus-cli"
|
|
11
|
-
version = "0.
|
|
11
|
+
version = "0.3.0"
|
|
12
12
|
source = { editable = "." }
|
|
13
13
|
dependencies = [
|
|
14
14
|
{ name = "albus-sdk" },
|
|
@@ -24,7 +24,7 @@ dev = [
|
|
|
24
24
|
|
|
25
25
|
[package.metadata]
|
|
26
26
|
requires-dist = [
|
|
27
|
-
{ name = "albus-sdk", specifier = "==0.
|
|
27
|
+
{ name = "albus-sdk", specifier = "==0.8.0" },
|
|
28
28
|
{ name = "typer", specifier = ">=0.26.8,<0.28" },
|
|
29
29
|
]
|
|
30
30
|
|
|
@@ -37,16 +37,16 @@ dev = [
|
|
|
37
37
|
|
|
38
38
|
[[package]]
|
|
39
39
|
name = "albus-sdk"
|
|
40
|
-
version = "0.
|
|
40
|
+
version = "0.8.0"
|
|
41
41
|
source = { registry = "https://pypi.org/simple" }
|
|
42
42
|
dependencies = [
|
|
43
43
|
{ name = "httpcore" },
|
|
44
44
|
{ name = "httpx" },
|
|
45
45
|
{ name = "pydantic" },
|
|
46
46
|
]
|
|
47
|
-
sdist = { url = "https://files.pythonhosted.org/packages/86/
|
|
47
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ca/86/c891c6fdd1ad4c34e4f49af973af09c23058288ae36e4ed89f58542cd3d3/albus_sdk-0.8.0.tar.gz", hash = "sha256:18609e42cbdbbd80fa27bd78e951cfff6da208f61b31b54a3c3efc8ae8a37856", size = 66873, upload-time = "2026-08-12T22:08:58.186Z" }
|
|
48
48
|
wheels = [
|
|
49
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
49
|
+
{ url = "https://files.pythonhosted.org/packages/43/5a/4392771345d808c5f44a78cffef7532d486fa976bc00072df6b6b3b69365/albus_sdk-0.8.0-py3-none-any.whl", hash = "sha256:1226da9d23f3530e060a0081ce5e1d7de1f023e2b9e2056b66784757996a028c", size = 95910, upload-time = "2026-08-12T22:08:57.18Z" },
|
|
50
50
|
]
|
|
51
51
|
|
|
52
52
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|