superwise-sentinel-cli 0.1.4__tar.gz → 0.2.1__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.
- superwise_sentinel_cli-0.2.1/CHANGELOG.md +6 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/CLAUDE.md +3 -3
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/PKG-INFO +2 -1
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/README.md +10 -1
- superwise_sentinel_cli-0.2.1/build.env +1 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/poetry.lock +184 -3
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/pyproject.toml +10 -1
- superwise_sentinel_cli-0.2.1/src/superwise_sentinel_cli/auth.py +166 -0
- superwise_sentinel_cli-0.2.1/src/superwise_sentinel_cli/cli.py +399 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/src/superwise_sentinel_cli/config.py +59 -6
- superwise_sentinel_cli-0.2.1/src/superwise_sentinel_cli/controller.py +141 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/src/superwise_sentinel_cli/docker_manager.py +33 -22
- superwise_sentinel_cli-0.2.1/src/superwise_sentinel_cli/exceptions.py +21 -0
- superwise_sentinel_cli-0.2.1/tests/__init__.py +0 -0
- superwise_sentinel_cli-0.2.1/tests/test_auth.py +518 -0
- superwise_sentinel_cli-0.2.1/tests/test_controller.py +299 -0
- superwise_sentinel_cli-0.2.1/tests/test_docker_manager.py +259 -0
- superwise_sentinel_cli-0.2.1/tests/test_shell_profile.py +186 -0
- superwise_sentinel_cli-0.1.4/build.env +0 -1
- superwise_sentinel_cli-0.1.4/src/superwise_sentinel_cli/auth.py +0 -29
- superwise_sentinel_cli-0.1.4/src/superwise_sentinel_cli/cli.py +0 -235
- superwise_sentinel_cli-0.1.4/src/superwise_sentinel_cli/runner.py +0 -52
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/.gitignore +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/.gitlab-ci.yml +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/.pre-commit-config.yaml +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/.releaserc.json +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/poetry.toml +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/scripts/semantic-release-cli-publish.sh +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/src/superwise_sentinel_cli/__init__.py +0 -0
- {superwise_sentinel_cli-0.1.4 → superwise_sentinel_cli-0.2.1}/src/superwise_sentinel_cli/shell_profile.py +0 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## [0.1.4](https://gitlab.com/askboss/product/superwise/platform/sentinel-cli/compare/0.1.3...0.1.4) (2026-07-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### <!-- 2. -->:bug: Bug Fixes
|
|
5
|
+
|
|
6
|
+
* update provider config ([b9d249a](https://gitlab.com/askboss/product/superwise/platform/sentinel-cli/commit/b9d249a28302f8fdd295fcd07d86da2ca989777e))
|
|
@@ -40,11 +40,11 @@ Run manually: `pre-commit run --all-files`
|
|
|
40
40
|
|
|
41
41
|
All source lives under `src/superwise_sentinel_cli/`:
|
|
42
42
|
|
|
43
|
-
- **`cli.py`** — Click command tree: root group `main`, with subgroups `gateway` (start/stop) and `proxy` (on/off), plus top-level commands `auth` and `config`. Imports from `auth`, `
|
|
43
|
+
- **`cli.py`** — Click command tree: root group `main`, with subgroups `gateway` (start/stop/update) and `proxy` (on/off), plus top-level commands `auth` and `config`. Imports from `auth`, `controller`, `shell_profile`, and `config`.
|
|
44
44
|
- **`config.py`** — `AppConfig` (pydantic-settings). Settings priority: env vars (`SENTINEL_*`) > `~/.config/sentinel/config.json` > field defaults. Also owns `_PROVIDER_CONFIG` (provider → env var + URL path mapping) and `VALID_PROVIDERS`. `AppConfig.load()` / `.save()` are the only intended access points.
|
|
45
45
|
- **`auth.py`** — `authenticate()` hits the Superwise auth API and caches the token at `~/.config/sentinel/token`. Skips the network call on subsequent invocations unless `force=True`.
|
|
46
|
-
- **`
|
|
47
|
-
- **`docker_manager.py`** — Manages the `sentinel-local` Docker container (image
|
|
46
|
+
- **`controller.py`** — Business logic layer between `cli.py` and `docker_manager.py`/`shell_profile.py`. `get_or_create_local_endpoint()` starts the Docker container and returns its base URL. `resolve_env_vars()` maps provider names to `(env_var, full_url)` pairs using `_PROVIDER_CONFIG` from `config.py`. `update_gateway_image` is an alias for `docker_manager.pull_latest_image` — it only refreshes the local image, it does not touch a running container.
|
|
47
|
+
- **`docker_manager.py`** — Manages the `sentinel-local` Docker container (image from `AppConfig.CONTAINER_IMAGE`). `ensure_container_running()` pulls (if not cached), starts, and returns a `ContainerEndpoint`; `stop_container()` stops and removes it; `pull_latest_image()` force-pulls the image regardless of local cache, for use by `gateway update`. Falls back to `linux/amd64` when native platform image is unavailable.
|
|
48
48
|
- **`shell_profile.py`** — `ShellContext` abstraction with `_UnixShellContext` (bash/zsh, auto-detected) and `_WindowsShellContext` (PowerShell). `ensure_shell_integration()` / `remove_shell_integration()` patch the shell profile. `write_env_vars()` / `remove_env_vars()` manage `~/.config/sentinel/protected_vars.json` and a sourced env file. On macOS, also calls `launchctl setenv/unsetenv` for GUI app visibility. The module-level `SHELL` constant holds the current platform context.
|
|
49
49
|
|
|
50
50
|
## Config & state files
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: superwise-sentinel-cli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Sentinel is an LLM proxy that intercepts traffic, enabling you to monitor, secure, and optimize your AI usage. This CLI tool helps you quickly set up traffic interception on this machine
|
|
5
5
|
Requires-Python: <4.0,>=3.11
|
|
6
6
|
Requires-Dist: click>=8.1
|
|
7
7
|
Requires-Dist: docker>=7.0
|
|
8
8
|
Requires-Dist: pydantic-settings>=2.3
|
|
9
9
|
Requires-Dist: pydantic>=2.0
|
|
10
|
+
Requires-Dist: requests>=2.28
|
|
@@ -28,13 +28,22 @@ Authenticate with Superwise (prompts for Client ID and Client Secret). Pass `--a
|
|
|
28
28
|
|---|---|
|
|
29
29
|
| `sentinel gateway start` | Pull and start the local Docker gateway container |
|
|
30
30
|
| `sentinel gateway stop` | Stop and remove the container |
|
|
31
|
+
| `sentinel gateway update` | Pull the latest gateway image, without touching the running container |
|
|
31
32
|
|
|
32
|
-
Pass `--sentinel-id <uuid>` to `start` to use an existing sentinel rather than creating a new one.
|
|
33
|
+
Pass `--sentinel-id <uuid>` to `start` to use an existing sentinel rather than creating a new one. After `gateway update`, run `sentinel gateway start --force` to switch the running gateway over to the newly pulled image.
|
|
33
34
|
|
|
34
35
|
### `sentinel config`
|
|
35
36
|
|
|
36
37
|
Configure the gateway URL and which LLM providers to intercept. Valid providers: `anthropic`, `openai`, `google`. Use `all` to select every provider.
|
|
37
38
|
|
|
39
|
+
Run interactively via `sentinel config url` / `sentinel config providers`, or set both non-interactively in one line:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
sentinel config --url "https://gateway.example.com" --providers "openai anthropic"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each subcommand also accepts `--set` for setting just that one value non-interactively, e.g. `sentinel config url --set "https://gateway.example.com"` or `sentinel config providers --set all`.
|
|
46
|
+
|
|
38
47
|
### `sentinel proxy`
|
|
39
48
|
|
|
40
49
|
| Command | Description |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
RELEASED_VERSION=0.2.1
|
|
@@ -184,12 +184,116 @@ version = "0.4.6"
|
|
|
184
184
|
description = "Cross-platform colored terminal text."
|
|
185
185
|
optional = false
|
|
186
186
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
187
|
-
groups = ["main"]
|
|
188
|
-
markers = "platform_system == \"Windows\""
|
|
187
|
+
groups = ["main", "test"]
|
|
189
188
|
files = [
|
|
190
189
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
191
190
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
192
191
|
]
|
|
192
|
+
markers = {main = "platform_system == \"Windows\"", test = "sys_platform == \"win32\""}
|
|
193
|
+
|
|
194
|
+
[[package]]
|
|
195
|
+
name = "coverage"
|
|
196
|
+
version = "7.15.0"
|
|
197
|
+
description = "Code coverage measurement for Python"
|
|
198
|
+
optional = false
|
|
199
|
+
python-versions = ">=3.10"
|
|
200
|
+
groups = ["test"]
|
|
201
|
+
files = [
|
|
202
|
+
{file = "coverage-7.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50913d4bf5ddafa6ca3693da5e4dd833dd1b772e0283c99ca7f7d287db67331a"},
|
|
203
|
+
{file = "coverage-7.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:359e141ccd33893ce3f1ad5525f8b96083003677c82182e5907d62d4ea5799fc"},
|
|
204
|
+
{file = "coverage-7.15.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3200b6204935f928c64b2ca1f923ab8c1acb7c9de45ec61569711b34d25cccaf"},
|
|
205
|
+
{file = "coverage-7.15.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:be616bf61346883b2cfdc5178669647e03531d81ab761a7e378558b7e8bcb628"},
|
|
206
|
+
{file = "coverage-7.15.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc7bafc3fe1059463a8fdd97ca79972d6e2bf819d775c7d54991b5b1971201d6"},
|
|
207
|
+
{file = "coverage-7.15.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b713aa7fcf325a01d4184d848acb46fd84f78fdb0978470c636b23a06a753d91"},
|
|
208
|
+
{file = "coverage-7.15.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e38e6fba2d56652fdfaf0231f8f78aeb805234a912de25dc291ee5cce5b8faa4"},
|
|
209
|
+
{file = "coverage-7.15.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:884499f42e382675be80770391983b90e0c0c774d87dbeeebf5f991cf6612b20"},
|
|
210
|
+
{file = "coverage-7.15.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:840481b12e083dbcbafab14794a8781a958edf327c8d3d70b4eee42f9b8253aa"},
|
|
211
|
+
{file = "coverage-7.15.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:276646e9481703d09f854f3b2f018f24e19fd7049ae670a92570043eb97203b1"},
|
|
212
|
+
{file = "coverage-7.15.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4de4b4d3f5545aa6c60dc4efd9c63b5b5dcc3bf00fe83146b2bdfffb8f6613bd"},
|
|
213
|
+
{file = "coverage-7.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5c504097b2a89b1e85bc6070d920df77daec701337e3aeef2c17775a5dd0ca90"},
|
|
214
|
+
{file = "coverage-7.15.0-cp310-cp310-win32.whl", hash = "sha256:f6e80ed91f98316e86b9c137206b04b2bcfbffccbdff49bd2eb09dddb1cf14e0"},
|
|
215
|
+
{file = "coverage-7.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:b3b3e22030f3f6f5e01a5ce69936552a5c0f6992b7698777377b99041961031f"},
|
|
216
|
+
{file = "coverage-7.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:003fff99412ea848c0aaebcc78ed2b6ce7d8a1227ed17e68470672770b78a02a"},
|
|
217
|
+
{file = "coverage-7.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5cbd804bf2784ce7b45114516050f346ecd50f960c4bb630a7ee9e1d78fa2118"},
|
|
218
|
+
{file = "coverage-7.15.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8773e15c23305b58882a4611fb9b2755977eae0dc2e515366a1b6c98866cc4c2"},
|
|
219
|
+
{file = "coverage-7.15.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f50e40081494c1dc4239ebb202014cbcc3306ea96fb6302a34c8cc0967fc5ae8"},
|
|
220
|
+
{file = "coverage-7.15.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daf96f37f5fc3a7b6c6da862eb4aee61c426bd63da236ed4a73ef0e503b4bca5"},
|
|
221
|
+
{file = "coverage-7.15.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:51aa20f6ae2788fd197747766edf4cd8234fd9423309b934257fa6b21a592723"},
|
|
222
|
+
{file = "coverage-7.15.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03d1f922757662eb7af586e77834792274cff776bc7b1d1a0b66a49ea9d84735"},
|
|
223
|
+
{file = "coverage-7.15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a6d6acc9a7666245e6133dd15144ca038a85a9cd5026bb06d6bbae9e77440dc9"},
|
|
224
|
+
{file = "coverage-7.15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1ac2c4c27c7df851dc9a017c2d7de00b69147e84ba3d96f37a530b0b6fb51035"},
|
|
225
|
+
{file = "coverage-7.15.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b761a1d504fd4bd1f20f418753964dca9f5862a511fc854dac58296b3b223671"},
|
|
226
|
+
{file = "coverage-7.15.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e43b045e11c16e897895758ae90e4a90cf99e93d58549e2f90c0e2272e155695"},
|
|
227
|
+
{file = "coverage-7.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:589b54513e901739f4b4582c705ce96b80c96f57641b1464607e2367a270e540"},
|
|
228
|
+
{file = "coverage-7.15.0-cp311-cp311-win32.whl", hash = "sha256:106781b8482749162d0b47056937ba0933508e5d9447f65a5e7d5c422f0d6bb4"},
|
|
229
|
+
{file = "coverage-7.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:821e92b3631d762a339695824cadbbc73020354eba2a23a551a99ad34938fbe6"},
|
|
230
|
+
{file = "coverage-7.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:309990eb5fb8014b9f67cb211f7fd41876ec8a88a88d3ae76de0ed1d611e3640"},
|
|
231
|
+
{file = "coverage-7.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b75ee5e8cb7575636ac598719b4307ac529ec8fcd79608a35c3cd4d4dada812d"},
|
|
232
|
+
{file = "coverage-7.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffb31267816b93b075302248cc1737506081b4f163df4401e9df1a6424aafabe"},
|
|
233
|
+
{file = "coverage-7.15.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e4d0bb73455bf97ab243a8f12c37c686ccf1c13bb614b7b85f1d062f06f42b2c"},
|
|
234
|
+
{file = "coverage-7.15.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:20d9ccc4ebd0edc434d86dfd2a1dd2a8efa6b6b3073d0485a394fee86459ebb4"},
|
|
235
|
+
{file = "coverage-7.15.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20c8a976c365c8cb12f0cbd099508772ea41fb5fa80657a8506df0e11bd278c5"},
|
|
236
|
+
{file = "coverage-7.15.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f948fd5ba1b9cbca91f0ae08b4c1ce2b139509149a435e2585d056d57d70bf01"},
|
|
237
|
+
{file = "coverage-7.15.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f58185f06edf6ad68ec9fb155d63ef650c82f3fbd7e1770e2867751fb13158f4"},
|
|
238
|
+
{file = "coverage-7.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02adc79a920c73c647c5d117f55747df7f2de94571884758ce8bc58e04f0a796"},
|
|
239
|
+
{file = "coverage-7.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6eb7c300fbed667fd6e3588eba71c1904cdb06110ca6fdf908c26bdd88b8e382"},
|
|
240
|
+
{file = "coverage-7.15.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b5fb23fa2de9dce1f5c36c09066d8fcda16cd96e8e26686caa2d7cb9b567d65c"},
|
|
241
|
+
{file = "coverage-7.15.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cec79341dbe6281484024979976d0c7f22beae08b4a254655decd25d42cbe766"},
|
|
242
|
+
{file = "coverage-7.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c664c5444b1d970b1b2a450e21fb19ee5c9cfdf151ded2dda37260031cca0da"},
|
|
243
|
+
{file = "coverage-7.15.0-cp312-cp312-win32.whl", hash = "sha256:5f764a3fa339bde6b3aa97657f5a6a3a9451e4a5b4ea98a2892c773a43525f77"},
|
|
244
|
+
{file = "coverage-7.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:52f9a4d2c4c56c8848bc2f524916698354b0211488b38c49ad9ae54f6cafbff6"},
|
|
245
|
+
{file = "coverage-7.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:31e5c3e70c85307ea35a12964e2e40f56ca2ee4b1c8c721ccf4609d17071080b"},
|
|
246
|
+
{file = "coverage-7.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5be4caf3b28836f078abe700f8944dac4a65d78f16d6c600c89cb624e5535782"},
|
|
247
|
+
{file = "coverage-7.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dd58ad1404704303ca8d4f4b8a1095e7cbc7040ef17a66df1e6619aa10176430"},
|
|
248
|
+
{file = "coverage-7.15.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bbcbb317c2e5ded5b21104af81c29f391be2af98d065693ffbe8d23949b948e5"},
|
|
249
|
+
{file = "coverage-7.15.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:27f31ecb458da3f859aab3f15ada871eb7a7768807d88df4a9f186bb17737970"},
|
|
250
|
+
{file = "coverage-7.15.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fb759be317fdc62e0f56bffdf61cfcb45c7761ad6b71e3e583e71a67ae753c"},
|
|
251
|
+
{file = "coverage-7.15.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5cf007add5ab4bb8fa9f4c77e3732127c9e6cad501d7db43355fbfafca0be84"},
|
|
252
|
+
{file = "coverage-7.15.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc78d9843bd576fbe2118248258d485e968dc535f95ed504a7b0867ba9b51389"},
|
|
253
|
+
{file = "coverage-7.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a263060f1de0b4b74b4e089c2a70b8003b3781c733329a9c8fd54995328f9950"},
|
|
254
|
+
{file = "coverage-7.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c48decf16e0dfd5b049c7d5e82200c23c08126719142998d4f172444e3d0529e"},
|
|
255
|
+
{file = "coverage-7.15.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:08fb028000ed0aaa0a4cbdfbb98be7cb42f370db973fbbb469733505ab20e13e"},
|
|
256
|
+
{file = "coverage-7.15.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb7dc0c3b7d8a1077abea0b8546ebc5e26d6ef6ecefc2f0f5ad2b8a53bdad837"},
|
|
257
|
+
{file = "coverage-7.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cb3602054ccbe9f0d8c2dc04bbeba90d5719236e2cd06e042ddd6d3fc7b6e37"},
|
|
258
|
+
{file = "coverage-7.15.0-cp313-cp313-win32.whl", hash = "sha256:0bf781da64326b677be344df505171435b6f58716108606621d5d27d964fff8b"},
|
|
259
|
+
{file = "coverage-7.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:2c57a275078ee3fa185f83e400f765bc764a549de66d99b47881645cbd4ea629"},
|
|
260
|
+
{file = "coverage-7.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:3812c61afc6685c7999b39320779ab8f43b7a3081fdb0def39976e56fbdb9a21"},
|
|
261
|
+
{file = "coverage-7.15.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:41cb79af843222e11da87127ad0ecbfa878abadd0f770a4a99391a27d3887324"},
|
|
262
|
+
{file = "coverage-7.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7d2008989ef8fe54188d3f3bfa2e3099b025af11e90a6a1b9e7dc433d04263d8"},
|
|
263
|
+
{file = "coverage-7.15.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:769e8ece11a596315ebf5aa7ec383aeeed016c091d2bf6363ffb996d41529092"},
|
|
264
|
+
{file = "coverage-7.15.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:65a6b6164ee5c39e2f3803f314292d6c61a607ba7fee253d1e03c42dc3903502"},
|
|
265
|
+
{file = "coverage-7.15.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75128817f95a5c45bb01d65fd2d8b9cb54bbe03d81608fb70e3e14b437ad56c2"},
|
|
266
|
+
{file = "coverage-7.15.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9887bb428fe2d4cd4bee89bac1a6c9932f484afd5b36fbd4ff6ea5f825bb1f5e"},
|
|
267
|
+
{file = "coverage-7.15.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0bfc0be1f702042207a93a00523b1065ee1fe951e96edf311581c0bbc2e34888"},
|
|
268
|
+
{file = "coverage-7.15.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f64627d55def5a43282d70e08396672692f77e4da610a5bb8bb4060b432b6859"},
|
|
269
|
+
{file = "coverage-7.15.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2c6f0fa473003905c6d5bac328ee4eba9fbea654f15bc24b8a3274b23363fa99"},
|
|
270
|
+
{file = "coverage-7.15.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2bcf9afaf064172c6ec3c58a325a9957ad1178c05dd934e25f253321776e0676"},
|
|
271
|
+
{file = "coverage-7.15.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:baf06bc987115d6fb938d403f7eab684a057766c490367999a2b71a6883110c6"},
|
|
272
|
+
{file = "coverage-7.15.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f0405f2ff97b1c4c0e782cb32e02f32369bcf2e6b618b591d67e1ea754575dfe"},
|
|
273
|
+
{file = "coverage-7.15.0-cp314-cp314-win32.whl", hash = "sha256:ab282853ed5fbd64bbb162f19cb8fcb7087187508a6374b4f9c34ec1577c4e8f"},
|
|
274
|
+
{file = "coverage-7.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:3bb3040e9f4bbe26fcb0cd7cc85ac63e630d3f3a9c74f027abf4caa27e706663"},
|
|
275
|
+
{file = "coverage-7.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:346771144d34f7fa84ec28386f78e0f31653f33cf35e19d253d5b35f9e8201da"},
|
|
276
|
+
{file = "coverage-7.15.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d34a010905fb6401324ba016b5da03d574967f7b21ce48ea41e66f0f1f95f641"},
|
|
277
|
+
{file = "coverage-7.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bb25d825d885ca8036795dacfc3924d33091fc76d71ebc99420c6b79e77d96fa"},
|
|
278
|
+
{file = "coverage-7.15.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:94c9686bfe8a9a6810297aecbd99beaa3445f9e8dc2f80b1382cca0d86b64461"},
|
|
279
|
+
{file = "coverage-7.15.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9bd671c25f9d85f09d7ec481d0e43d5139f486c06a37139847a7ce569788af72"},
|
|
280
|
+
{file = "coverage-7.15.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:110cbdf8d2e216577312cf06ccf85539c0e5a5420ef747e4a4719b5e483c88cd"},
|
|
281
|
+
{file = "coverage-7.15.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2c5d4619214f1d9993e7b00a8600d14614b7e9d84e89507460b126aa5e6559e5"},
|
|
282
|
+
{file = "coverage-7.15.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:781a704516e2d8346fbbd5be6c6f3412dd824785146528b3a01816f26c081007"},
|
|
283
|
+
{file = "coverage-7.15.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd4a1b44bcb65ee29e947ac92bbee04956df3a6bfc6143641bb6cae7ede00fc9"},
|
|
284
|
+
{file = "coverage-7.15.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0e4950c9d6d3e39c64c991814ff315e2d0b9cb8152363594212c9e55208c0a8f"},
|
|
285
|
+
{file = "coverage-7.15.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:fe9c87ff42e5472d80d21704972e1f96e104a0a599d77c5e35db5a3c562e2571"},
|
|
286
|
+
{file = "coverage-7.15.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f00d5ae1dd2fe13fb8186e3e7d37bcbd8b25c0d764ff7d1b32cef9be058510a8"},
|
|
287
|
+
{file = "coverage-7.15.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:363ab38cc78b615f11c9cac3cf1d7eef950c18b9fdedfb9066f59461dcf84d68"},
|
|
288
|
+
{file = "coverage-7.15.0-cp314-cp314t-win32.whl", hash = "sha256:54fd9c53a5fafff509195f1b6a3f9be615d8e8362a3629ff1de23d270c03c86b"},
|
|
289
|
+
{file = "coverage-7.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:87b47553097ba185ed964866078e7e63adea9f5f51b5f39691c34f30afd21080"},
|
|
290
|
+
{file = "coverage-7.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aeefb2dd178fe7eee79f0ad25d75855cb35ee9ed472db2c5ea06f5b4fd00cec5"},
|
|
291
|
+
{file = "coverage-7.15.0-py3-none-any.whl", hash = "sha256:56da6a4cbe8f7e9e80bd072ca9cefe67d7106a440a7ec06519ec6507ac94ad19"},
|
|
292
|
+
{file = "coverage-7.15.0.tar.gz", hash = "sha256:9ac3fe7a1435986463eaa8ee253ae2f2a268709ba4ae5c7dd1f52a05391ad78f"},
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
[package.extras]
|
|
296
|
+
toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
|
|
193
297
|
|
|
194
298
|
[[package]]
|
|
195
299
|
name = "docker"
|
|
@@ -229,6 +333,46 @@ files = [
|
|
|
229
333
|
[package.extras]
|
|
230
334
|
all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
|
231
335
|
|
|
336
|
+
[[package]]
|
|
337
|
+
name = "iniconfig"
|
|
338
|
+
version = "2.3.0"
|
|
339
|
+
description = "brain-dead simple config-ini parsing"
|
|
340
|
+
optional = false
|
|
341
|
+
python-versions = ">=3.10"
|
|
342
|
+
groups = ["test"]
|
|
343
|
+
files = [
|
|
344
|
+
{file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
|
|
345
|
+
{file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
|
|
346
|
+
]
|
|
347
|
+
|
|
348
|
+
[[package]]
|
|
349
|
+
name = "packaging"
|
|
350
|
+
version = "26.2"
|
|
351
|
+
description = "Core utilities for Python packages"
|
|
352
|
+
optional = false
|
|
353
|
+
python-versions = ">=3.8"
|
|
354
|
+
groups = ["test"]
|
|
355
|
+
files = [
|
|
356
|
+
{file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"},
|
|
357
|
+
{file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"},
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
[[package]]
|
|
361
|
+
name = "pluggy"
|
|
362
|
+
version = "1.6.0"
|
|
363
|
+
description = "plugin and hook calling mechanisms for python"
|
|
364
|
+
optional = false
|
|
365
|
+
python-versions = ">=3.9"
|
|
366
|
+
groups = ["test"]
|
|
367
|
+
files = [
|
|
368
|
+
{file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
|
|
369
|
+
{file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
|
|
370
|
+
]
|
|
371
|
+
|
|
372
|
+
[package.extras]
|
|
373
|
+
dev = ["pre-commit", "tox"]
|
|
374
|
+
testing = ["coverage", "pytest", "pytest-benchmark"]
|
|
375
|
+
|
|
232
376
|
[[package]]
|
|
233
377
|
name = "pydantic"
|
|
234
378
|
version = "2.13.4"
|
|
@@ -408,6 +552,43 @@ gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"]
|
|
|
408
552
|
toml = ["tomli (>=2.0.1)"]
|
|
409
553
|
yaml = ["pyyaml (>=6.0.1)"]
|
|
410
554
|
|
|
555
|
+
[[package]]
|
|
556
|
+
name = "pygments"
|
|
557
|
+
version = "2.20.0"
|
|
558
|
+
description = "Pygments is a syntax highlighting package written in Python."
|
|
559
|
+
optional = false
|
|
560
|
+
python-versions = ">=3.9"
|
|
561
|
+
groups = ["test"]
|
|
562
|
+
files = [
|
|
563
|
+
{file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"},
|
|
564
|
+
{file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"},
|
|
565
|
+
]
|
|
566
|
+
|
|
567
|
+
[package.extras]
|
|
568
|
+
windows-terminal = ["colorama (>=0.4.6)"]
|
|
569
|
+
|
|
570
|
+
[[package]]
|
|
571
|
+
name = "pytest"
|
|
572
|
+
version = "9.1.1"
|
|
573
|
+
description = "pytest: simple powerful testing with Python"
|
|
574
|
+
optional = false
|
|
575
|
+
python-versions = ">=3.10"
|
|
576
|
+
groups = ["test"]
|
|
577
|
+
files = [
|
|
578
|
+
{file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"},
|
|
579
|
+
{file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"},
|
|
580
|
+
]
|
|
581
|
+
|
|
582
|
+
[package.dependencies]
|
|
583
|
+
colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
|
|
584
|
+
iniconfig = ">=1.0.1"
|
|
585
|
+
packaging = ">=22"
|
|
586
|
+
pluggy = ">=1.5,<2"
|
|
587
|
+
pygments = ">=2.7.2"
|
|
588
|
+
|
|
589
|
+
[package.extras]
|
|
590
|
+
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
|
|
591
|
+
|
|
411
592
|
[[package]]
|
|
412
593
|
name = "python-dotenv"
|
|
413
594
|
version = "1.2.2"
|
|
@@ -525,4 +706,4 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""]
|
|
|
525
706
|
[metadata]
|
|
526
707
|
lock-version = "2.1"
|
|
527
708
|
python-versions = ">=3.11, <4.0"
|
|
528
|
-
content-hash = "
|
|
709
|
+
content-hash = "b2291011b34a3b81b2f9f32bc8d7fcc77aeeff74dc5ffd66b6bc16161dc97663"
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "superwise-sentinel-cli"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Sentinel is an LLM proxy that intercepts traffic, enabling you to monitor, secure, and optimize your AI usage. This CLI tool helps you quickly set up traffic interception on this machine"
|
|
9
9
|
requires-python = ">=3.11, <4.0"
|
|
10
10
|
dependencies = [
|
|
@@ -12,6 +12,7 @@ dependencies = [
|
|
|
12
12
|
"docker>=7.0",
|
|
13
13
|
"pydantic>=2.0",
|
|
14
14
|
"pydantic-settings>=2.3",
|
|
15
|
+
"requests>=2.28",
|
|
15
16
|
]
|
|
16
17
|
|
|
17
18
|
[project.scripts]
|
|
@@ -19,3 +20,11 @@ sentinel = "superwise_sentinel_cli.cli:main"
|
|
|
19
20
|
|
|
20
21
|
[tool.hatch.build.targets.wheel]
|
|
21
22
|
packages = ["src/superwise_sentinel_cli"]
|
|
23
|
+
|
|
24
|
+
[tool.poetry.group.test.dependencies]
|
|
25
|
+
pytest = "^9.1.1"
|
|
26
|
+
coverage = "^7.15.0"
|
|
27
|
+
|
|
28
|
+
[tool.pytest.ini_options]
|
|
29
|
+
testpaths = ["tests"]
|
|
30
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from superwise_sentinel_cli.config import AppConfig
|
|
7
|
+
from superwise_sentinel_cli.config import CONFIG_DIR
|
|
8
|
+
from superwise_sentinel_cli.exceptions import AuthenticationError
|
|
9
|
+
from superwise_sentinel_cli.exceptions import BaseCLIException
|
|
10
|
+
|
|
11
|
+
_TOKEN_FILE = CONFIG_DIR / "token"
|
|
12
|
+
_REFRESH_TOKEN_FILE = CONFIG_DIR / "refresh_token"
|
|
13
|
+
|
|
14
|
+
_TERMINAL_DEVICE_ERRORS = {"access_denied", "expired_token", "invalid_grant"}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _save_tokens(access_token: str, refresh_token: str | None = None) -> None:
|
|
18
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
_TOKEN_FILE.write_text(access_token)
|
|
20
|
+
if refresh_token is not None:
|
|
21
|
+
_REFRESH_TOKEN_FILE.write_text(refresh_token)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def device_authorize() -> dict:
|
|
25
|
+
cfg = AppConfig.load()
|
|
26
|
+
client_id = cfg.FRONTEGG_APP_CLIENT_ID
|
|
27
|
+
auth_host = cfg.sw_auth_host
|
|
28
|
+
response = requests.post(
|
|
29
|
+
auth_host + "/oauth/device/authorize",
|
|
30
|
+
headers={"content-type": "application/json"},
|
|
31
|
+
json={"client_id": client_id},
|
|
32
|
+
timeout=10,
|
|
33
|
+
)
|
|
34
|
+
response.raise_for_status()
|
|
35
|
+
return response.json()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def device_poll(device_code: str, poll_interval: int = 5, expires_in: int = 900) -> str:
|
|
39
|
+
cfg = AppConfig.load()
|
|
40
|
+
client_id = cfg.FRONTEGG_APP_CLIENT_ID
|
|
41
|
+
auth_host = cfg.sw_auth_host
|
|
42
|
+
url = auth_host + "/oauth/token"
|
|
43
|
+
body = {
|
|
44
|
+
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
|
|
45
|
+
"device_code": device_code,
|
|
46
|
+
"client_id": client_id,
|
|
47
|
+
}
|
|
48
|
+
deadline = time.monotonic() + expires_in
|
|
49
|
+
|
|
50
|
+
while time.monotonic() < deadline:
|
|
51
|
+
time.sleep(poll_interval)
|
|
52
|
+
response = requests.post(
|
|
53
|
+
url,
|
|
54
|
+
headers={"content-type": "application/json"},
|
|
55
|
+
json=body,
|
|
56
|
+
timeout=10,
|
|
57
|
+
)
|
|
58
|
+
if response.status_code == 200:
|
|
59
|
+
data = response.json()
|
|
60
|
+
_save_tokens(data["access_token"], data["refresh_token"])
|
|
61
|
+
return data["access_token"]
|
|
62
|
+
|
|
63
|
+
if response.status_code == 400:
|
|
64
|
+
error = response.json().get("error", "")
|
|
65
|
+
if error == "authorization_pending":
|
|
66
|
+
continue
|
|
67
|
+
elif error == "slow_down":
|
|
68
|
+
poll_interval += 5
|
|
69
|
+
continue
|
|
70
|
+
elif error in _TERMINAL_DEVICE_ERRORS:
|
|
71
|
+
raise BaseCLIException(f"Device authorization failed: {error}")
|
|
72
|
+
try:
|
|
73
|
+
response.raise_for_status()
|
|
74
|
+
except Exception:
|
|
75
|
+
raise BaseCLIException("Device authorization failed. Please try again later.")
|
|
76
|
+
|
|
77
|
+
raise BaseCLIException("Device authorization timed out. Run 'sentinel auth' again.")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def refresh_access_token(auth_host: str) -> str:
|
|
81
|
+
stored = _REFRESH_TOKEN_FILE.read_text().strip()
|
|
82
|
+
if not stored:
|
|
83
|
+
raise RuntimeError("Cached refresh token is empty.")
|
|
84
|
+
response = requests.post(
|
|
85
|
+
auth_host + "/oauth/token",
|
|
86
|
+
headers={"content-type": "application/json"},
|
|
87
|
+
json={
|
|
88
|
+
"grant_type": "refresh_token",
|
|
89
|
+
"refresh_token": stored,
|
|
90
|
+
"client_id": AppConfig.load().FRONTEGG_APP_CLIENT_ID,
|
|
91
|
+
},
|
|
92
|
+
timeout=10,
|
|
93
|
+
)
|
|
94
|
+
response.raise_for_status()
|
|
95
|
+
data = response.json()
|
|
96
|
+
new_access = data["access_token"]
|
|
97
|
+
_save_tokens(new_access, data.get("refresh_token", stored))
|
|
98
|
+
return new_access
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def authenticate_machine_credentials(
|
|
102
|
+
client_id: str | None = None,
|
|
103
|
+
client_secret: str | None = None,
|
|
104
|
+
auth_host: str | None = None,
|
|
105
|
+
force: bool = False,
|
|
106
|
+
) -> str:
|
|
107
|
+
if not force and _TOKEN_FILE.exists():
|
|
108
|
+
return _TOKEN_FILE.read_text()
|
|
109
|
+
|
|
110
|
+
cfg = AppConfig.load()
|
|
111
|
+
url = (auth_host or cfg.sw_auth_host) + "/identity/resources/auth/v1/api-token"
|
|
112
|
+
headers = {"accept": "application/json", "content-type": "application/json"}
|
|
113
|
+
body = {"clientId": client_id or cfg.superwise_client_id, "secret": client_secret or cfg.superwise_client_secret}
|
|
114
|
+
response = requests.post(url, headers=headers, json=body, timeout=10)
|
|
115
|
+
if response.status_code == 401:
|
|
116
|
+
raise AuthenticationError("Invalid credentials.")
|
|
117
|
+
else:
|
|
118
|
+
response.raise_for_status()
|
|
119
|
+
token = response.json()["accessToken"]
|
|
120
|
+
_save_tokens(token)
|
|
121
|
+
return token
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def authenticate(
|
|
125
|
+
client_id: str | None = None,
|
|
126
|
+
client_secret: str | None = None,
|
|
127
|
+
force: bool = False,
|
|
128
|
+
) -> str:
|
|
129
|
+
cfg = AppConfig.load()
|
|
130
|
+
resolved_host = cfg.sw_auth_host
|
|
131
|
+
|
|
132
|
+
if not force and _TOKEN_FILE.exists():
|
|
133
|
+
return _TOKEN_FILE.read_text()
|
|
134
|
+
|
|
135
|
+
if not (client_id or client_secret) and _REFRESH_TOKEN_FILE.exists():
|
|
136
|
+
try:
|
|
137
|
+
return refresh_access_token(resolved_host)
|
|
138
|
+
except Exception:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
effective_id = client_id or cfg.superwise_client_id
|
|
142
|
+
effective_secret = client_secret or cfg.superwise_client_secret
|
|
143
|
+
if effective_id and effective_secret:
|
|
144
|
+
return authenticate_machine_credentials(
|
|
145
|
+
client_id=effective_id,
|
|
146
|
+
client_secret=effective_secret,
|
|
147
|
+
auth_host=resolved_host,
|
|
148
|
+
force=True,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
raise AuthenticationError("Not authenticated. Run 'sentinel auth' to log in.")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def create_api_token(access_token: str) -> None:
|
|
155
|
+
cfg = AppConfig.load()
|
|
156
|
+
response = requests.post(
|
|
157
|
+
cfg.sw_auth_host + "/identity/resources/users/api-tokens/v1",
|
|
158
|
+
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
159
|
+
json={"description": "cli-token"},
|
|
160
|
+
timeout=10,
|
|
161
|
+
)
|
|
162
|
+
response.raise_for_status()
|
|
163
|
+
data = response.json()
|
|
164
|
+
cfg.superwise_client_id = data["clientId"]
|
|
165
|
+
cfg.superwise_client_secret = data["secret"]
|
|
166
|
+
cfg.save()
|