insightfactory-cli 1.0.0.dev1__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,265 @@
1
+ Metadata-Version: 2.5
2
+ Name: insightfactory-cli
3
+ Version: 1.0.0.dev1
4
+ Summary: Profile-based authentication CLI for the InsightFactory Interfaces API
5
+ Project-URL: Homepage, https://github.com/insightfactory-ai/insightfactory-cli
6
+ Project-URL: Repository, https://github.com/insightfactory-ai/insightfactory-cli
7
+ Author-email: "insightfactory.ai Support" <support@insightfactory.ai>
8
+ Keywords: cli,insightfactory,oauth,pkce
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+
17
+ # insightfactory-cli
18
+
19
+ Profile-based authentication CLI for the InsightFactory Interfaces API. It
20
+ installs the `if-cli` command: browser OAuth login (authorization-code + PKCE),
21
+ token refresh, and authenticated API calls, with profiles stored in
22
+ `~/.insightfactory` in the same layout as the Node `@insightfactory-ai/if-cli`
23
+ so the two implementations can share a config directory.
24
+
25
+ This is the production Python CLI, published to public PyPI. Python 3.10 or
26
+ newer is required.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ uv tool install insightfactory-cli # persistent install, on PATH
32
+ uvx insightfactory-cli profiles # or zero-install, run-once
33
+ uv tool upgrade insightfactory-cli # updates
34
+ ```
35
+
36
+ `uv` fetches a managed Python automatically if the machine lacks one. Fallbacks:
37
+
38
+ ```bash
39
+ pipx install insightfactory-cli
40
+ pip install insightfactory-cli
41
+ ```
42
+
43
+ Develop-branch builds are published as PEP 440 `.devN` pre-releases. Install the
44
+ bleeding edge with:
45
+
46
+ ```bash
47
+ pip install --pre insightfactory-cli
48
+ uv tool install --prerelease allow insightfactory-cli
49
+ ```
50
+
51
+ PEP 440 orders `1.0.0.devN` *before* `1.0.0`, so a dependency spec of
52
+ `insightfactory-cli>=1.0.0` does **not** match a develop-channel dev build.
53
+ An in-process consumer that wants those builds must use a pre-release-bearing
54
+ spec such as `insightfactory-cli>=1.0.0.dev0`, which matches both `.devN`
55
+ builds and the final `1.0.0` release.
56
+
57
+ ## Usage
58
+
59
+ ```bash
60
+ # Create a profile and authenticate through the browser.
61
+ if-cli login -p example-dev --host https://factory.example
62
+
63
+ # Inspect profiles and cached-token status. Statuses are colour-coded on a TTY
64
+ # (green valid, yellow refreshable-but-expired, red missing or broken); set
65
+ # NO_COLOR=1 to disable or FORCE_COLOR=1 to keep colour when piping.
66
+ if-cli profiles
67
+ if-cli profiles --json
68
+
69
+ # Read a single non-secret profile value for scripting.
70
+ if-cli config get host -p example-dev
71
+
72
+ # Print a valid token, refreshing it when a refresh token is available.
73
+ if-cli token -p example-dev
74
+ if-cli token -p example-dev --env
75
+ if-cli token -p example-dev --env-name INSIGHTFACTORY_ACCESS_TOKEN_DEV
76
+
77
+ # Make an authenticated API request.
78
+ if-cli api -p example-dev /api/agent-projects
79
+ if-cli api -p example-dev -X POST -d '{"name":"example"}' /api/example
80
+
81
+ # Discover API routes from the factory's OpenAPI document.
82
+ if-cli api routes -p example-dev
83
+ if-cli api routes -p example-dev agent-projects
84
+ if-cli api describe -p example-dev GET /api/agent-projects/{id}
85
+
86
+ # Remove the cached credential for a profile.
87
+ if-cli logout -p example-dev
88
+
89
+ # Fallback for factories where browser OAuth is not available.
90
+ if-cli set-token -p example-dev
91
+
92
+ if-cli --version
93
+ ```
94
+
95
+ Profile selection uses `-p`, then `INSIGHTFACTORY_CONFIG_PROFILE`, then
96
+ `[DEFAULT]`. Route discovery reads `{host}/swagger/v1/swagger.json` and does
97
+ not require a login. Authenticated API requests are restricted to the selected
98
+ factory origin so a profile token cannot be forwarded to another host. Profile
99
+ hosts must be bare origins rather than URLs containing application path
100
+ prefixes.
101
+
102
+ Override the config directory with `INSIGHTFACTORY_CONFIG_DIR` (useful in tests
103
+ and CI). The default is `~/.insightfactory`.
104
+
105
+ On Git Bash (MSYS2) on Windows, path conversion rewrites a leading-slash
106
+ argument such as `/api/agent-projects` into a Windows path. Prefix the command
107
+ with `MSYS_NO_PATHCONV=1`:
108
+
109
+ ```bash
110
+ MSYS_NO_PATHCONV=1 if-cli api -p example-dev /api/agent-projects
111
+ ```
112
+
113
+ ### Scripting against profiles
114
+
115
+ `profiles --json` and `config get` are the supported machine-readable
116
+ interfaces; the padded `profiles` columns are for humans and are not a
117
+ contract, and neither is the layout of `~/.insightfactory/config`.
118
+
119
+ `if-cli profiles --json` prints an array — one entry per configured profile, in
120
+ file order — of `name`, `host`, and `token`:
121
+
122
+ ```json
123
+ [
124
+ {
125
+ "name": "example-dev",
126
+ "host": "https://factory.example",
127
+ "token": { "status": "valid", "expires_at": 1785918336, "refreshable": true }
128
+ },
129
+ { "name": "other", "host": "https://other.factory.example", "token": { "status": "none" } }
130
+ ]
131
+ ```
132
+
133
+ `token.status` is `valid`, `expired`, `none`, or `unknown`; `expires_at` and
134
+ `refreshable` are present only when a cached token exists. `valid` means
135
+ `if-cli token` will hand back the cached token as-is, so a token inside the
136
+ 60-second slack window that command refreshes within is reported as `expired` —
137
+ use the raw `expires_at` if you need the literal expiry instant instead. A
138
+ profile that cannot be resolved has a `host` of `null` (or its raw configured
139
+ value) and a top-level `error` describing the problem, and does not stop the
140
+ other profiles from being listed; `token.error` is set only when the token
141
+ cache itself could not be read.
142
+
143
+ `if-cli config get <key> -p <profile>` prints one newline-terminated value and
144
+ exits non-zero if the profile cannot be resolved, or the key is not configured
145
+ within it. A profile with no host cannot be resolved at all, so every key on it
146
+ fails, not just `host`. A key present but empty (`client_id =`) counts as not
147
+ configured:
148
+
149
+ ```bash
150
+ curl -H "Authorization: Bearer $(if-cli token -p example-dev)" \
151
+ "$(if-cli config get host -p example-dev)/api/agent-projects"
152
+ ```
153
+
154
+ The readable keys are `host`, `audience`, `callback_port`, `client_id`, and
155
+ `organization` — all non-secret, and resolved the same way the CLI itself
156
+ resolves them, so `audience` and `callback_port` return their defaults when the
157
+ profile omits them. Tokens are deliberately not readable this way; use
158
+ `if-cli token`.
159
+
160
+ ## Programmatic API
161
+
162
+ `insightfactory-cli` may be imported in-process as a library to resolve a
163
+ profile to a factory host and a fresh access token. These four symbols are a
164
+ supported programmatic surface for in-process consumers:
165
+
166
+ - `if_cli.config.load_config`
167
+ - `if_cli.config.get_profile`
168
+ - `if_cli.oauth.get_valid_token`
169
+ - `if_cli.runtime.CliError`
170
+
171
+ They raise `CliError` on failure (never `SystemExit` or `sys.exit`), never
172
+ write to stdout, never launch a browser or block on interactive input, and use
173
+ only bounded waits. Changing or removing any of them is a breaking change and
174
+ requires a major version bump.
175
+
176
+ ## How authentication works
177
+
178
+ - Profiles are stored in `~/.insightfactory/config`, one per customer/environment.
179
+ - The profile file is managed by the CLI and is regenerated on updates; comments
180
+ and empty sections are not preserved.
181
+ - Tokens are cached by host in `~/.insightfactory/token-cache.json` with file
182
+ mode `0600`.
183
+ - The configuration directory is `0700`; configuration and cache updates are
184
+ atomic.
185
+ - Remote factory, authorization, and token endpoints must use HTTPS. HTTP is
186
+ accepted only for loopback development.
187
+ - Login discovers OAuth metadata from
188
+ `{host}/.well-known/oauth-authorization-server`.
189
+ - Authorization uses PKCE through the factory `/authorize` proxy with a
190
+ loopback-only (`127.0.0.1`) callback. The CLI is a public OAuth client: the
191
+ client ID is read from the factory's discovery document at runtime (no client
192
+ secret).
193
+
194
+ ## Development
195
+
196
+ ```bash
197
+ uv sync
198
+ uv run pytest
199
+ uv run ruff check .
200
+ uv run ty check
201
+ ```
202
+
203
+ Smoke-test against a throwaway config directory, never `~/.insightfactory`:
204
+
205
+ ```bash
206
+ uv run if-cli --help
207
+ uv run if-cli --version
208
+ INSIGHTFACTORY_CONFIG_DIR=$(mktemp -d) uv run if-cli profiles
209
+ ```
210
+
211
+ Python 3.10 or newer is required. Runtime code is stdlib-only.
212
+
213
+ ## Release
214
+
215
+ Publishing is automatic from GitHub Actions on merge. Verify and build live in
216
+ the reusable workflow
217
+ [`if_s_insightfactory_cli.yml`](https://github.com/insightfactory-ai/if_sre_github_actions/blob/main/.github/workflows/if_s_insightfactory_cli.yml)
218
+ in `insightfactory-ai/if_sre_github_actions`
219
+ ([PR #300](https://github.com/insightfactory-ai/if_sre_github_actions/pull/300)
220
+ must merge before these stubs go green). This repository's
221
+ `.github/workflows/release.yml` keeps only the OIDC publish job, because PyPI
222
+ Trusted Publishing is registered for **this** repo, workflow `release.yml`, and
223
+ environment `pypi` — a reusable workflow cannot be registered.
224
+
225
+ A one-time trusted-publisher registration is required on the PyPI project for
226
+ that triple. The publish job downloads the `dist-release` artifact staged by
227
+ the reusable workflow and uploads it with `pypa/gh-action-pypi-publish`.
228
+
229
+ | Trigger | Published version | PyPI role |
230
+ |---|---|---|
231
+ | Push / merge to `develop` | `1.0.0.dev{N}` | pre-release (`pip install --pre`) |
232
+ | Push / merge to `main` | `1.0.0` (the version in `pyproject.toml`) | latest |
233
+ | Push of a `v*` tag | same as `main` | retry / explicit cut of that version |
234
+
235
+ `N` is `github.run_number` of the reusable workflow: a per-workflow integer
236
+ that goes up on every run and stays the same across re-runs of that run (so a
237
+ failed publish can be retried under the same version). It does not depend on
238
+ git history or clone depth. After a successful `main` publish, bump `version`
239
+ in `pyproject.toml` on `develop` so later `.devN` builds sort *after* what just
240
+ landed; PEP 440 puts `1.0.0.devN` before `1.0.0`. Because of that ordering, a
241
+ dependency spec of `insightfactory-cli>=1.0.0` does not match develop-channel
242
+ `.devN` builds; an in-process consumer that wants them must specify a
243
+ pre-release-bearing spec such as `insightfactory-cli>=1.0.0.dev0` (which also
244
+ matches the final `1.0.0` release).
245
+
246
+ A version that is already on PyPI is skipped rather than failing, so a second
247
+ push to `main` (or a `v*` tag for the same version) is a no-op. A `v*` tag
248
+ whose name does not match `pyproject.toml` fails before publishing.
249
+
250
+ ## Differences from the Node CLI
251
+
252
+ Behaviour matches `@insightfactory-ai/if-cli` except where the platforms
253
+ genuinely diverge:
254
+
255
+ - **Unknown-option wording** is aligned (`Unknown option '--flag'`). Other
256
+ argparse messages (for example a missing option value) still differ from
257
+ Node's `util.parseArgs`.
258
+ - **Expiry timestamps** in human-readable output use the C-locale `%c` format
259
+ rather than JavaScript `Date#toLocaleString()`.
260
+ - **`--version`** reads the installed package metadata (`1.0.0` and later)
261
+ rather than an npm `package.json`.
262
+
263
+ On-disk profile and token-cache paths, JSON shapes, and file permissions stay
264
+ compatible with the Node CLI, so you can switch implementations without
265
+ re-authenticating.
@@ -0,0 +1,23 @@
1
+ if_cli/__init__.py,sha256=YYcz-hEiXXUjdBFGipOrVHynsyH4ZLqQOCDobvCAu8Y,26
2
+ if_cli/__main__.py,sha256=2hLFIiT-gocMb0VJVzVYtGVIoHrxyMChucRgexbXLSQ,68
3
+ if_cli/cache.py,sha256=UfvHs3GQIVg0sVfKYWw4UGlq8d-8BEXuZIDfC1hwwjA,6587
4
+ if_cli/cli.py,sha256=kBblhYrKEHFcWhI14imvEykxFYvagRTVrnc_hHEHzLY,2573
5
+ if_cli/colour.py,sha256=2hbaM4ubTHGja6YZRD886eqnB7T2IaZyW5rvfOjxe4M,682
6
+ if_cli/config.py,sha256=IZhuo0cMsP-L9rLIKYVB87YRhCF-tcuyBTWp0-um4vM,6338
7
+ if_cli/constants.py,sha256=7pY68ZXSspE3dDVFnSQ461CnKNSDu2ibMbPT3WfYWFA,209
8
+ if_cli/http.py,sha256=85NsHK84TMExELCIpBK-RhnjQ_B06dJ9iUKYHyZwu18,5142
9
+ if_cli/main.py,sha256=0bZZDNoT1NGHeZhH6sD2ZNBTtpYGGTfPTnRIJiGr2vA,2537
10
+ if_cli/oauth.py,sha256=MUvG1aNGpknFfbtblq2Eg86rQv3VM9NrGl4oDgIr5oM,15596
11
+ if_cli/runtime.py,sha256=Pz2iVclqy-uu1UMQWK2P_Hx7O4zAF30UpSFqQvGN0NY,2663
12
+ if_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ if_cli/commands/api.py,sha256=f0hpf6ZzgoX3UNERXVeZi6RsQbAfJnMXQj9EQCVbz70,7499
14
+ if_cli/commands/config.py,sha256=1KAxjme897NIbXTGBw1rNJlXnFvhbEUf5MAli8A93ns,1724
15
+ if_cli/commands/login.py,sha256=vxsYcRZWsaNEzekyN1zy4ROJO-OCGUpjaVUBhtbK1LY,3255
16
+ if_cli/commands/logout.py,sha256=TW0P4_tXcTtiHHR73xVPHyhlbOWD1jBnkZsMImCiCBw,668
17
+ if_cli/commands/profiles.py,sha256=JNBrYWdHQ9MHauwZxH33IAOYgRYRniX7bwd7KBT6Vyk,3869
18
+ if_cli/commands/set_token.py,sha256=BVyv_QmByvllr04pE2sz8JFEscHbIgOC-7ZPg61PRoc,1886
19
+ if_cli/commands/token.py,sha256=CyiXkyH7vxgH91-n-XJzeHnLI6mZJwO9Js5AHvfHaeM,1120
20
+ insightfactory_cli-1.0.0.dev1.dist-info/METADATA,sha256=m4q9y44Zw6yLllpCVHnK4z5RYQcv9TR3uY24W17c2H8,10880
21
+ insightfactory_cli-1.0.0.dev1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
22
+ insightfactory_cli-1.0.0.dev1.dist-info/entry_points.txt,sha256=UlX854D7f-7dBj5F0wGdakVy6vopvP9hA1BN-gv739w,44
23
+ insightfactory_cli-1.0.0.dev1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ if-cli = if_cli.main:main