ophix-client-core 2026.10.4.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.
- ophix_client_core-2026.10.4.1/PKG-INFO +148 -0
- ophix_client_core-2026.10.4.1/README.md +116 -0
- ophix_client_core-2026.10.4.1/pyproject.toml +49 -0
- ophix_client_core-2026.10.4.1/setup.cfg +4 -0
- ophix_client_core-2026.10.4.1/src/client_core/__init__.py +5 -0
- ophix_client_core-2026.10.4.1/src/client_core/_version.py +2 -0
- ophix_client_core-2026.10.4.1/src/client_core/commands.py +552 -0
- ophix_client_core-2026.10.4.1/src/client_core/config.py +20 -0
- ophix_client_core-2026.10.4.1/src/client_core/core.py +372 -0
- ophix_client_core-2026.10.4.1/src/client_core/parser.py +61 -0
- ophix_client_core-2026.10.4.1/src/ophix_client_core.egg-info/PKG-INFO +148 -0
- ophix_client_core-2026.10.4.1/src/ophix_client_core.egg-info/SOURCES.txt +13 -0
- ophix_client_core-2026.10.4.1/src/ophix_client_core.egg-info/dependency_links.txt +1 -0
- ophix_client_core-2026.10.4.1/src/ophix_client_core.egg-info/requires.txt +3 -0
- ophix_client_core-2026.10.4.1/src/ophix_client_core.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ophix-client-core
|
|
3
|
+
Version: 2026.10.4.1
|
|
4
|
+
Summary: Shared base library for Ophix Tier 1 clients
|
|
5
|
+
Author: Ophix Project
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://ophix.io
|
|
8
|
+
Project-URL: Documentation, https://github.com/ophixproject/ophix-client-core#readme
|
|
9
|
+
Project-URL: Source, https://github.com/ophixproject/ophix-client-core
|
|
10
|
+
Keywords: ophix,cli,client,fleet management
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Topic :: System :: Systems Administration
|
|
27
|
+
Requires-Python: >=3.7
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
Requires-Dist: requests>=2.28
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0
|
|
31
|
+
Requires-Dist: distro>=1.8
|
|
32
|
+
|
|
33
|
+
# ophix-client-core
|
|
34
|
+
|
|
35
|
+
**The shared foundation every [Ophix](https://ophix.io) client is built on.**
|
|
36
|
+
|
|
37
|
+
Every fleet client — whichever domain it's fetching credentials, configs, certificates, or tasks for — needs the same underlying plumbing: registration, token rotation with post-rotation validation, HTTP handling, a consistent CLI. `ophix-client-core` is that shared foundation, so each Tier 1 client (`ophix-cred-client`, `ophix-task-client`, etc.) only has to implement the handful of API calls specific to its own domain.
|
|
38
|
+
|
|
39
|
+
This package is automatically included with every Ophix client, no need to separately install it.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## For domain client authors
|
|
44
|
+
|
|
45
|
+
Add `ophix-client-core` as a dependency in your `pyproject.toml`, then follow the pattern below.
|
|
46
|
+
|
|
47
|
+
### `_config.py` — declare your ClientConfig
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from client_core.config import ClientConfig
|
|
51
|
+
from my_client._version import __version__
|
|
52
|
+
|
|
53
|
+
CLIENT_CONFIG = ClientConfig(
|
|
54
|
+
prog="my-client",
|
|
55
|
+
description="Ophix My Domain client.",
|
|
56
|
+
env_file=".my.env",
|
|
57
|
+
server_url_key="MYSERVER_URL",
|
|
58
|
+
api_token_key="MYSERVER_API_TOKEN",
|
|
59
|
+
ca_cert_key="MYSERVER_CA_CERT",
|
|
60
|
+
client_name="my", # drives X-My-* request headers and .my/ cert directory
|
|
61
|
+
version=__version__,
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `cli.py` — extend the base command registry
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from client_core.commands import build_commands
|
|
69
|
+
from client_core.parser import make_main
|
|
70
|
+
from my_client._config import CLIENT_CONFIG
|
|
71
|
+
from my_client.core import get_things
|
|
72
|
+
|
|
73
|
+
def cmd_fetch(args):
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
COMMANDS = build_commands(CLIENT_CONFIG)
|
|
77
|
+
COMMANDS["fetch"] = {
|
|
78
|
+
"help": "Fetch things from the server.",
|
|
79
|
+
"arguments": [],
|
|
80
|
+
"handler": cmd_fetch,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
main = make_main(CLIENT_CONFIG, COMMANDS)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`build_commands(config)` returns the full set of base commands pre-bound to your config. Extend the dict with domain-specific entries and pass it to `make_main`.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## What's included
|
|
91
|
+
|
|
92
|
+
### Base CLI commands
|
|
93
|
+
|
|
94
|
+
All commands are registered automatically by `build_commands(config)`.
|
|
95
|
+
|
|
96
|
+
| Command | Description |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `quickstart <server_url> <client_name>` | Set server URL, download CA cert, and register in one step |
|
|
99
|
+
| `set server\|ca-cert\|token <value>` | Write a configuration value to the env file |
|
|
100
|
+
| `download ca-cert` | Download and save the server CA certificate |
|
|
101
|
+
| `register <name>` | Register this client with the server |
|
|
102
|
+
| `rotate-token` | Generate a new token, send to server, update env file |
|
|
103
|
+
| `info` | Show client identity from the server |
|
|
104
|
+
| `update` | Update venv info on the server |
|
|
105
|
+
| `doctor` | Diagnose local configuration and server connectivity |
|
|
106
|
+
|
|
107
|
+
### `client_core.config` — `ClientConfig`
|
|
108
|
+
|
|
109
|
+
Dataclass holding all domain-specific identifiers. Passed to every shared function so no global state is required.
|
|
110
|
+
|
|
111
|
+
### `client_core.core`
|
|
112
|
+
|
|
113
|
+
Shared utilities:
|
|
114
|
+
|
|
115
|
+
- `resolve_server_config(config, ...)` — load env file, resolve URL/token/CA cert, validate
|
|
116
|
+
- `build_client_headers(config, api_token=None)` — standard `X-{Name}-*` request headers
|
|
117
|
+
- `ensure_env_file(config)` — find or create the domain env file with 600 permissions
|
|
118
|
+
- `find_project_root()` — walk up from cwd to find project root
|
|
119
|
+
- `in_venv()` — return `Path(sys.prefix)` if inside a venv, else `None`
|
|
120
|
+
- `detect_os_flavour()` — human-readable OS description
|
|
121
|
+
- `detect_invocation()` — best-effort invocation string from `sys.argv`
|
|
122
|
+
|
|
123
|
+
### `client_core.parser`
|
|
124
|
+
|
|
125
|
+
- `build_parser(config, commands)` — build an `ArgumentParser` from a `ClientConfig` and `COMMANDS` dict
|
|
126
|
+
- `make_main(config, commands)` — return a `main()` callable suitable for use as a `pyproject.toml` entry point
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Environment file
|
|
131
|
+
|
|
132
|
+
Each domain client uses its own env file (e.g. `.task.env`, `.cred.env`). `ClientConfig.env_file` sets the filename. Three keys are always present:
|
|
133
|
+
|
|
134
|
+
| Key | Description |
|
|
135
|
+
| --- | --- |
|
|
136
|
+
| `{NAME}SERVER_URL` | Server base URL |
|
|
137
|
+
| `{NAME}SERVER_API_TOKEN` | 64-character hex client token |
|
|
138
|
+
| `{NAME}SERVER_CA_CERT` | Path to CA certificate PEM (optional) |
|
|
139
|
+
|
|
140
|
+
The CA certificate is saved to `.<client_name>/ca-cert.pem` relative to the project root.
|
|
141
|
+
|
|
142
|
+
If the server has no custom CA configured (e.g. it uses a publicly trusted certificate such as Let's Encrypt), `/api/server/ca-cert/` returns 404. Both `download ca-cert` and `quickstart` treat this as expected — they print an informational message and continue rather than failing, since the system trust store already covers a publicly signed certificate and no local CA file is needed.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# ophix-client-core
|
|
2
|
+
|
|
3
|
+
**The shared foundation every [Ophix](https://ophix.io) client is built on.**
|
|
4
|
+
|
|
5
|
+
Every fleet client — whichever domain it's fetching credentials, configs, certificates, or tasks for — needs the same underlying plumbing: registration, token rotation with post-rotation validation, HTTP handling, a consistent CLI. `ophix-client-core` is that shared foundation, so each Tier 1 client (`ophix-cred-client`, `ophix-task-client`, etc.) only has to implement the handful of API calls specific to its own domain.
|
|
6
|
+
|
|
7
|
+
This package is automatically included with every Ophix client, no need to separately install it.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## For domain client authors
|
|
12
|
+
|
|
13
|
+
Add `ophix-client-core` as a dependency in your `pyproject.toml`, then follow the pattern below.
|
|
14
|
+
|
|
15
|
+
### `_config.py` — declare your ClientConfig
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from client_core.config import ClientConfig
|
|
19
|
+
from my_client._version import __version__
|
|
20
|
+
|
|
21
|
+
CLIENT_CONFIG = ClientConfig(
|
|
22
|
+
prog="my-client",
|
|
23
|
+
description="Ophix My Domain client.",
|
|
24
|
+
env_file=".my.env",
|
|
25
|
+
server_url_key="MYSERVER_URL",
|
|
26
|
+
api_token_key="MYSERVER_API_TOKEN",
|
|
27
|
+
ca_cert_key="MYSERVER_CA_CERT",
|
|
28
|
+
client_name="my", # drives X-My-* request headers and .my/ cert directory
|
|
29
|
+
version=__version__,
|
|
30
|
+
)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `cli.py` — extend the base command registry
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from client_core.commands import build_commands
|
|
37
|
+
from client_core.parser import make_main
|
|
38
|
+
from my_client._config import CLIENT_CONFIG
|
|
39
|
+
from my_client.core import get_things
|
|
40
|
+
|
|
41
|
+
def cmd_fetch(args):
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
COMMANDS = build_commands(CLIENT_CONFIG)
|
|
45
|
+
COMMANDS["fetch"] = {
|
|
46
|
+
"help": "Fetch things from the server.",
|
|
47
|
+
"arguments": [],
|
|
48
|
+
"handler": cmd_fetch,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
main = make_main(CLIENT_CONFIG, COMMANDS)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`build_commands(config)` returns the full set of base commands pre-bound to your config. Extend the dict with domain-specific entries and pass it to `make_main`.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## What's included
|
|
59
|
+
|
|
60
|
+
### Base CLI commands
|
|
61
|
+
|
|
62
|
+
All commands are registered automatically by `build_commands(config)`.
|
|
63
|
+
|
|
64
|
+
| Command | Description |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `quickstart <server_url> <client_name>` | Set server URL, download CA cert, and register in one step |
|
|
67
|
+
| `set server\|ca-cert\|token <value>` | Write a configuration value to the env file |
|
|
68
|
+
| `download ca-cert` | Download and save the server CA certificate |
|
|
69
|
+
| `register <name>` | Register this client with the server |
|
|
70
|
+
| `rotate-token` | Generate a new token, send to server, update env file |
|
|
71
|
+
| `info` | Show client identity from the server |
|
|
72
|
+
| `update` | Update venv info on the server |
|
|
73
|
+
| `doctor` | Diagnose local configuration and server connectivity |
|
|
74
|
+
|
|
75
|
+
### `client_core.config` — `ClientConfig`
|
|
76
|
+
|
|
77
|
+
Dataclass holding all domain-specific identifiers. Passed to every shared function so no global state is required.
|
|
78
|
+
|
|
79
|
+
### `client_core.core`
|
|
80
|
+
|
|
81
|
+
Shared utilities:
|
|
82
|
+
|
|
83
|
+
- `resolve_server_config(config, ...)` — load env file, resolve URL/token/CA cert, validate
|
|
84
|
+
- `build_client_headers(config, api_token=None)` — standard `X-{Name}-*` request headers
|
|
85
|
+
- `ensure_env_file(config)` — find or create the domain env file with 600 permissions
|
|
86
|
+
- `find_project_root()` — walk up from cwd to find project root
|
|
87
|
+
- `in_venv()` — return `Path(sys.prefix)` if inside a venv, else `None`
|
|
88
|
+
- `detect_os_flavour()` — human-readable OS description
|
|
89
|
+
- `detect_invocation()` — best-effort invocation string from `sys.argv`
|
|
90
|
+
|
|
91
|
+
### `client_core.parser`
|
|
92
|
+
|
|
93
|
+
- `build_parser(config, commands)` — build an `ArgumentParser` from a `ClientConfig` and `COMMANDS` dict
|
|
94
|
+
- `make_main(config, commands)` — return a `main()` callable suitable for use as a `pyproject.toml` entry point
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Environment file
|
|
99
|
+
|
|
100
|
+
Each domain client uses its own env file (e.g. `.task.env`, `.cred.env`). `ClientConfig.env_file` sets the filename. Three keys are always present:
|
|
101
|
+
|
|
102
|
+
| Key | Description |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `{NAME}SERVER_URL` | Server base URL |
|
|
105
|
+
| `{NAME}SERVER_API_TOKEN` | 64-character hex client token |
|
|
106
|
+
| `{NAME}SERVER_CA_CERT` | Path to CA certificate PEM (optional) |
|
|
107
|
+
|
|
108
|
+
The CA certificate is saved to `.<client_name>/ca-cert.pem` relative to the project root.
|
|
109
|
+
|
|
110
|
+
If the server has no custom CA configured (e.g. it uses a publicly trusted certificate such as Let's Encrypt), `/api/server/ca-cert/` returns 404. Both `download ca-cert` and `quickstart` treat this as expected — they print an informational message and continue rather than failing, since the system trust store already covers a publicly signed certificate and no local CA file is needed.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ophix-client-core"
|
|
7
|
+
version = "2026.10.04.01"
|
|
8
|
+
description = "Shared base library for Ophix Tier 1 clients"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.7"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Ophix Project" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["ophix", "cli", "client", "fleet management"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Intended Audience :: System Administrators",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.7",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Programming Language :: Python :: 3.14",
|
|
31
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
32
|
+
"Topic :: System :: Systems Administration",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"requests>=2.28",
|
|
36
|
+
"python-dotenv>=1.0",
|
|
37
|
+
"distro>=1.8",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://ophix.io"
|
|
42
|
+
Documentation = "https://github.com/ophixproject/ophix-client-core#readme"
|
|
43
|
+
Source = "https://github.com/ophixproject/ophix-client-core"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
package-dir = { "" = "src" }
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
where = ["src"]
|