insightfactory-cli 1.0.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.
- insightfactory_cli-1.0.0/.github/workflows/ci.yml +17 -0
- insightfactory_cli-1.0.0/.github/workflows/claude.yml +76 -0
- insightfactory_cli-1.0.0/.github/workflows/release.yml +43 -0
- insightfactory_cli-1.0.0/.gitignore +11 -0
- insightfactory_cli-1.0.0/.python-version +1 -0
- insightfactory_cli-1.0.0/AGENTS.md +1 -0
- insightfactory_cli-1.0.0/CLAUDE.md +28 -0
- insightfactory_cli-1.0.0/PKG-INFO +265 -0
- insightfactory_cli-1.0.0/README.md +249 -0
- insightfactory_cli-1.0.0/pyproject.toml +43 -0
- insightfactory_cli-1.0.0/src/if_cli/__init__.py +1 -0
- insightfactory_cli-1.0.0/src/if_cli/__main__.py +4 -0
- insightfactory_cli-1.0.0/src/if_cli/cache.py +206 -0
- insightfactory_cli-1.0.0/src/if_cli/cli.py +163 -0
- insightfactory_cli-1.0.0/src/if_cli/colour.py +24 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/__init__.py +0 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/api.py +177 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/config.py +45 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/login.py +75 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/logout.py +20 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/profiles.py +119 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/set_token.py +62 -0
- insightfactory_cli-1.0.0/src/if_cli/commands/token.py +32 -0
- insightfactory_cli-1.0.0/src/if_cli/config.py +188 -0
- insightfactory_cli-1.0.0/src/if_cli/constants.py +5 -0
- insightfactory_cli-1.0.0/src/if_cli/http.py +153 -0
- insightfactory_cli-1.0.0/src/if_cli/main.py +76 -0
- insightfactory_cli-1.0.0/src/if_cli/oauth.py +389 -0
- insightfactory_cli-1.0.0/src/if_cli/runtime.py +94 -0
- insightfactory_cli-1.0.0/tests/__init__.py +0 -0
- insightfactory_cli-1.0.0/tests/cache_writer.py +14 -0
- insightfactory_cli-1.0.0/tests/conftest.py +11 -0
- insightfactory_cli-1.0.0/tests/helpers.py +210 -0
- insightfactory_cli-1.0.0/tests/servers.py +99 -0
- insightfactory_cli-1.0.0/tests/test_api.py +120 -0
- insightfactory_cli-1.0.0/tests/test_api_command.py +324 -0
- insightfactory_cli-1.0.0/tests/test_cache.py +146 -0
- insightfactory_cli-1.0.0/tests/test_cli.py +444 -0
- insightfactory_cli-1.0.0/tests/test_config.py +163 -0
- insightfactory_cli-1.0.0/tests/test_config_command.py +115 -0
- insightfactory_cli-1.0.0/tests/test_login.py +240 -0
- insightfactory_cli-1.0.0/tests/test_oauth.py +74 -0
- insightfactory_cli-1.0.0/tests/test_oauth_flow.py +535 -0
- insightfactory_cli-1.0.0/tests/test_profiles.py +259 -0
- insightfactory_cli-1.0.0/tests/test_programmatic_api.py +43 -0
- insightfactory_cli-1.0.0/tests/test_runtime.py +78 -0
- insightfactory_cli-1.0.0/tests/test_set_token.py +114 -0
- insightfactory_cli-1.0.0/tests/test_token.py +44 -0
- insightfactory_cli-1.0.0/uv.lock +212 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: ci-${{ github.event.pull_request.number || github.ref }}
|
|
9
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
ci:
|
|
16
|
+
uses: insightfactory-ai/if_sre_github_actions/.github/workflows/if_s_insightfactory_cli.yml@main
|
|
17
|
+
secrets: inherit
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# =======================================================
|
|
2
|
+
# GitHub Actions Workflow: Claude Code Assistant
|
|
3
|
+
#
|
|
4
|
+
# Purpose: AI-powered code review and assistance, on demand only.
|
|
5
|
+
# Triggered by mentioning @claude in a PR comment, an issue
|
|
6
|
+
# comment, or an inline PR review comment (e.g. `@claude review`).
|
|
7
|
+
# There is no automatic review on PR open.
|
|
8
|
+
#
|
|
9
|
+
# =======================================================
|
|
10
|
+
|
|
11
|
+
name: Claude Workflow
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
issue_comment:
|
|
15
|
+
types: [created]
|
|
16
|
+
pull_request_review_comment:
|
|
17
|
+
types: [created]
|
|
18
|
+
|
|
19
|
+
# Least privilege at the workflow level; the reusable workflow requests what it
|
|
20
|
+
# needs for its own jobs.
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
claude:
|
|
26
|
+
# Author gating. The comment body is attacker-controlled and the call below
|
|
27
|
+
# inherits every secret, so restrict the trigger to people with write-ish
|
|
28
|
+
# access rather than anyone who can leave a comment.
|
|
29
|
+
if: |
|
|
30
|
+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) &&
|
|
31
|
+
contains(github.event.comment.body, '@claude')
|
|
32
|
+
uses: insightfactory-ai/if_sre_github_actions/.github/workflows/if_s_claude_review.yml@main
|
|
33
|
+
secrets: inherit
|
|
34
|
+
with:
|
|
35
|
+
# CONSTRAINT: the value below is interpolated inside a double-quoted CLI argument with no
|
|
36
|
+
# escaping. Do NOT include ASCII double-quote characters. Use single quotes or backticks
|
|
37
|
+
# if you need to quote something. Newlines are fine.
|
|
38
|
+
append_system_prompt: |
|
|
39
|
+
This repository (insightfactory-cli) is the production Python `if-cli`, published to public
|
|
40
|
+
PyPI. Read CLAUDE.md and README.md before reviewing; the rules below are the ones that get
|
|
41
|
+
violated most often.
|
|
42
|
+
|
|
43
|
+
Runtime and layout:
|
|
44
|
+
- Runtime code is stdlib-only. Flag any new runtime dependency in pyproject.toml or any
|
|
45
|
+
import outside the standard library.
|
|
46
|
+
- Keep one module per CLI command under `src/if_cli/commands/`.
|
|
47
|
+
- Do not suggest third-party HTTP, OAuth, or CLI frameworks; the codebase uses urllib and
|
|
48
|
+
argparse deliberately.
|
|
49
|
+
|
|
50
|
+
Security and auth:
|
|
51
|
+
- A profile's bearer token must never be sent outside that profile's factory origin. Flag
|
|
52
|
+
any code path that could forward a token to another host.
|
|
53
|
+
- OAuth uses authorization-code flow with PKCE and a loopback-only (`127.0.0.1`) callback.
|
|
54
|
+
The CLI is a public client with no client secret.
|
|
55
|
+
- Do not commit credentials, access tokens, refresh tokens, or client secrets in code,
|
|
56
|
+
tests, or fixtures. Fixtures must use neutral hostnames such as `factory.example`.
|
|
57
|
+
|
|
58
|
+
On-disk compatibility:
|
|
59
|
+
- Profiles and tokens must be written only through the atomic private-file helpers
|
|
60
|
+
(`write_private_file` in config.py): `0o600` files, `0o700` directories, atomic replace
|
|
61
|
+
via temp file.
|
|
62
|
+
- On-disk profile and token-cache paths, JSON shapes, and file permissions must stay
|
|
63
|
+
byte-compatible with the Node `@insightfactory-ai/if-cli` so users can switch
|
|
64
|
+
implementations without re-authenticating.
|
|
65
|
+
|
|
66
|
+
Programmatic API (breaking-change surface):
|
|
67
|
+
- These four symbols are a supported in-process surface documented in README.md:
|
|
68
|
+
`if_cli.config.load_config`, `if_cli.config.get_profile`, `if_cli.oauth.get_valid_token`,
|
|
69
|
+
`if_cli.runtime.CliError`.
|
|
70
|
+
- They must raise `CliError` on failure (never `SystemExit`), never write to stdout, never
|
|
71
|
+
launch a browser or block on interactive input, and use only bounded waits.
|
|
72
|
+
- Changing signatures, behaviour, or removing any of them requires a major version bump.
|
|
73
|
+
|
|
74
|
+
Tests:
|
|
75
|
+
- `tests/` uses isolated config dirs via `INSIGHTFACTORY_CONFIG_DIR`; never smoke-test
|
|
76
|
+
against `~/.insightfactory`.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# CD: merge to develop/main (or a v* tag) publishes to public PyPI.
|
|
4
|
+
# Verify + build live in insightfactory-ai/if_sre_github_actions
|
|
5
|
+
# (if_s_insightfactory_cli.yml). The publish job stays here because PyPI
|
|
6
|
+
# Trusted Publishing is registered for this repository, workflow `release.yml`,
|
|
7
|
+
# and environment `pypi` — a reusable workflow cannot be registered.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [develop, main]
|
|
11
|
+
tags:
|
|
12
|
+
- "v*"
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: release-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
ci:
|
|
23
|
+
uses: insightfactory-ai/if_sre_github_actions/.github/workflows/if_s_insightfactory_cli.yml@main
|
|
24
|
+
secrets: inherit
|
|
25
|
+
|
|
26
|
+
publish:
|
|
27
|
+
name: Publish to PyPI
|
|
28
|
+
needs: ci
|
|
29
|
+
if: needs.ci.outputs.should_publish == 'true'
|
|
30
|
+
runs-on: ${{ vars.RUN_LINUX }}
|
|
31
|
+
timeout-minutes: 10
|
|
32
|
+
environment:
|
|
33
|
+
name: pypi
|
|
34
|
+
url: https://pypi.org/p/insightfactory-cli
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/download-artifact@v6
|
|
39
|
+
with:
|
|
40
|
+
name: dist-release
|
|
41
|
+
path: dist/
|
|
42
|
+
|
|
43
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CLAUDE.md
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# InsightFactory CLI contributor guide
|
|
2
|
+
|
|
3
|
+
This repository publishes `insightfactory-cli` to public PyPI, which installs
|
|
4
|
+
the `if-cli` executable. It uses Python 3.10+, uv, pytest, ruff, and ty.
|
|
5
|
+
|
|
6
|
+
## Commands
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
uv sync
|
|
10
|
+
uv run pytest
|
|
11
|
+
uv run ruff check .
|
|
12
|
+
uv run ty check
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Conventions
|
|
16
|
+
|
|
17
|
+
- Keep one module per CLI command under `src/if_cli/commands/`.
|
|
18
|
+
- Never send a profile bearer token outside that profile's factory origin.
|
|
19
|
+
- OAuth uses authorization-code flow with PKCE and a loopback-only callback.
|
|
20
|
+
- Store profiles and tokens through the atomic private-file helpers.
|
|
21
|
+
- On-disk profile/token-store paths and JSON shapes stay compatible with the
|
|
22
|
+
Node CLI (`~/.insightfactory`, `INSIGHTFACTORY_CONFIG_DIR` override).
|
|
23
|
+
- Do not commit credentials, access tokens, refresh tokens, or client secrets.
|
|
24
|
+
- Test fixtures use only neutral hostnames (`factory.example`).
|
|
25
|
+
- Do not publish to PyPI or create release tags from a developer machine;
|
|
26
|
+
merges to `develop` / `main` (and optional `v*` tags) publish via the
|
|
27
|
+
reusable workflow in `if_sre_github_actions` plus the OIDC job in
|
|
28
|
+
`.github/workflows/release.yml`.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: insightfactory-cli
|
|
3
|
+
Version: 1.0.0
|
|
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.
|