kx-auth-cli 0.5.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.
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.5
2
+ Name: kx-auth-cli
3
+ Version: 0.5.0
4
+ Summary: kx auth and kx rbac — client-side OAuth/identity assertion plus atomic policy administration for the kx.auth and kx.rbac q modules (no fastmcp).
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: <3.14,>=3.10
7
+ Requires-Dist: httpx
8
+ Requires-Dist: kx-auth-core<0.6,>=0.5.0b1
9
+ Provides-Extra: qipc
10
+ Requires-Dist: pykx>=4.0.0.b4; extra == 'qipc'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # kx-auth-cli — the `kx auth` CLI
14
+
15
+ The client-side auth CLI for kdb+ identity assertion, and the OAuth-aware half of the
16
+ [`kx.auth`](../../modules/kx/auth/) story. The q module does no token parsing and no crypto, on purpose,
17
+ so acquiring a bearer, exchanging it for a backend-scoped one, and projecting it into a principal all
18
+ happen out here. `assert` binds the result onto a kdb+ process over qIPC.
19
+
20
+ It ships the `kx` console script with `auth` and `rbac` command groups.
21
+
22
+ | Command | What it does | Needs |
23
+ |---|---|---|
24
+ | `auth login` | Acquire a bearer: RFC 9728 discovery, then RFC 8628 device code. | a resource server |
25
+ | `auth exchange` | Swap any subject token for a backend-scoped one (RFC 8693). | a token endpoint |
26
+ | `auth assert` | Project a principal; with `--connect`, run the live `.kx.auth.bind` handshake. | a q host running `kx.auth` |
27
+ | `auth introspect` | Validate a bearer: issuer, audience, signature, expiry, scopes. | a JWKS URI or public key |
28
+ | `rbac …` | Inspect, test and atomically administer policy. | a q host running `kx.rbac` |
29
+
30
+ **Full command reference: [KX_AUTH_CLI.md](../../docs/KX_AUTH_CLI.md).** Flags, output envelopes,
31
+ credential precedence, the gateway route table and the environment variables all live there.
32
+
33
+ It runs where the client runs, not where kdb+ runs, so it depends on the lean `kx-auth-core` plus
34
+ `httpx` and never on `fastmcp`.
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ uv tool install kx-auth-cli # or: pipx install kx-auth-cli
40
+ kx auth --help
41
+ ```
42
+
43
+ Add the `qipc` extra for the live `assert --connect` handshake, which needs PyKX:
44
+
45
+ ```bash
46
+ uv tool install 'kx-auth-cli[qipc]'
47
+ ```
48
+
49
+ ### Run without installing (`uvx`)
50
+
51
+ The `kx` console script is the whole entry point, and `uvx` runs it from the published wheel in an
52
+ ephemeral environment:
53
+
54
+ ```bash
55
+ uvx --from kx-auth-cli kx auth --help
56
+ ```
57
+
58
+ `--from kx-auth-cli` names the package that owns the `kx` command, since `uvx` can't infer it from the
59
+ executable name. Add the `qipc` extra the same way: `--from 'kx-auth-cli[qipc]'`. To pin a version, use
60
+ `--from kx-auth-cli==<X.Y.Z>`. The CLI shares its version number with the q modules' releases.
61
+
62
+ ## Exit codes
63
+
64
+ Stable across every subcommand. Branch on the code, not the text.
65
+
66
+ | Code | Meaning |
67
+ |---|---|
68
+ | `0` | ok, allowed |
69
+ | `1` | error |
70
+ | `2` | usage |
71
+ | `3` | auth-required |
72
+ | `4` | denied |
73
+
74
+ Every subcommand supports `--json`, which emits exactly one envelope: `{"status": …, "result": …}` on
75
+ success, `{"status": …, "reason": …}` on failure — and a `denied` decision or a tripped `--fail-on`
76
+ carries `result` too. Every command's payload lives under `result`; all five share one emitter
77
+ (`kx_auth_cli/envelope.py`), so none can drift from the shape or the exit table.
78
+
79
+ Which input earns which code is documented per command in
80
+ [`docs/KX_AUTH_CLI.md`](../../docs/KX_AUTH_CLI.md) — as a rule of thumb, a malformed *document* (a
81
+ `--principal` file, a server's response) is an error (`1`), while a malformed *flag value* (`--ctx`, an
82
+ unknown `--strategy`) is usage (`2`).
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ uv pip install -e '.[qipc]' --group dev
88
+ pytest
89
+ ```
90
+
91
+ The suite is hermetic: no live IdP, no Keycloak, no kdb+. `login`'s tests stand up an in-process mock
92
+ authorization server, and `assert --connect`'s inject a fake `pykx`. Tokens are minted with PyJWT while
93
+ `kx-auth-core` verifies with joserfc, which is deliberate cross-library coverage.
94
+
95
+ Because it fakes `pykx`, **no test here proves the qIPC handshake works against real kdb+.** That is
96
+ [`demos/local-assertion/cli-check.sh`](../../demos/local-assertion/cli-check.sh), which drives a live
97
+ demo host with this CLI. Install the `[qipc]` extra and `bash demos/local-assertion/run.sh` picks it up.
98
+ Run both when you touch `assert`.
99
+
100
+ ### The fastmcp-free invariant
101
+
102
+ This CLI ships light: `kx-auth-core` and `httpx` only, and it must never import `fastmcp`. Three things
103
+ hold the line.
104
+
105
+ - `introspect`'s verifier is the shared `kx_auth_core.verify_token`, so bearer validation has one
106
+ implementation rather than a client-side copy to drift.
107
+ - `login`'s discovery, device-code and cache machinery is CLI-local rather than in `kx-auth-core`. A
108
+ server never logs in, and the cache is a client concern.
109
+ - PyKX is imported lazily, only on the `--connect` path, and ships in the `qipc` extra.
110
+
111
+ Pinned by `test_assert_cmd_import_is_fastmcp_free`, which fails if importing the command pulls
112
+ `fastmcp` into the process.
113
+
114
+ `--json` stdout is exactly one envelope, including on the PyKX path. PyKX's Community banner is
115
+ suppressed during the lazy import, so consumers should treat any surrounding output as a contract
116
+ violation.
@@ -0,0 +1,16 @@
1
+ kx_auth_cli/__init__.py,sha256=BMgpl-G7qD9t1S9flZUf-WSDaGJJRCFgPZOROd2kfC4,752
2
+ kx_auth_cli/assert_cmd.py,sha256=lqDy4SsPOhCMbQthg7_TTq0Xd8niRSOmhlNk1XWZEfI,13607
3
+ kx_auth_cli/atomic.py,sha256=gKuqfCHoNhUjfUqZNQJrF5UTkAjQUE7hAZ5sD6v2s7g,2435
4
+ kx_auth_cli/cache.py,sha256=SAYDizo3IRTJekumPknV1YNU65ASak0q5060YoL1pfw,2777
5
+ kx_auth_cli/cli.py,sha256=TwVfEjudSu5j-90mzTK-Hw6qAfDfNeYoPzEcAgppfBI,4041
6
+ kx_auth_cli/discovery.py,sha256=BAuPpKvNs6NkzvZRptrLEgVlz_OHPht4ahbBAsABXAk,11171
7
+ kx_auth_cli/envelope.py,sha256=rB2k18SGWzgZDcJVv8ejNpb7EFpID5Q4gvlfW0afvew,5684
8
+ kx_auth_cli/exchange.py,sha256=3-dFpbDpzwaonljkK4di5kyxBCvwwAs7iin_6jzi3-0,10389
9
+ kx_auth_cli/introspect.py,sha256=7kW5GfTcSfAyBN1rFz97zDRJmqfMoa9nuM47L-P3HYA,7364
10
+ kx_auth_cli/login.py,sha256=w0RV6Npo-EHcqblKUaT6qAlbwNjubUWdsllGwSbJMfM,6745
11
+ kx_auth_cli/qbridge.py,sha256=W-x6xKItaMgOmx3pxReVGU5XQVoOSFZtjx4pkeU5INM,1923
12
+ kx_auth_cli/rbac.py,sha256=R05bhd2Kp7u_HAcytvHuWJzkpCG_VIa1v9TyCMqzPz0,34802
13
+ kx_auth_cli-0.5.0.dist-info/METADATA,sha256=m7Fvhfw-sGiVGhYVhTxGDxPO_hq-tuEbZinKo9gkd-s,5082
14
+ kx_auth_cli-0.5.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
15
+ kx_auth_cli-0.5.0.dist-info/entry_points.txt,sha256=8Ypxn3t-7iYbDMh6TFppWMyxwVK4Yl5ANGtf2U4pMRQ,44
16
+ kx_auth_cli-0.5.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ kx = kx_auth_cli.cli:main