forktex-cloud 0.2.3__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.
Files changed (30) hide show
  1. forktex_cloud-0.2.3/LICENSE +45 -0
  2. forktex_cloud-0.2.3/NOTICE +23 -0
  3. forktex_cloud-0.2.3/PKG-INFO +226 -0
  4. forktex_cloud-0.2.3/README.md +189 -0
  5. forktex_cloud-0.2.3/pyproject.toml +107 -0
  6. forktex_cloud-0.2.3/src/forktex_cloud/__init__.py +92 -0
  7. forktex_cloud-0.2.3/src/forktex_cloud/bridge/__init__.py +24 -0
  8. forktex_cloud-0.2.3/src/forktex_cloud/bridge/local_compose.py +295 -0
  9. forktex_cloud-0.2.3/src/forktex_cloud/bridge/log_formatter.py +62 -0
  10. forktex_cloud-0.2.3/src/forktex_cloud/bridge/loki.py +109 -0
  11. forktex_cloud-0.2.3/src/forktex_cloud/bridge/persistence_defaults.py +120 -0
  12. forktex_cloud-0.2.3/src/forktex_cloud/client/__init__.py +83 -0
  13. forktex_cloud-0.2.3/src/forktex_cloud/client/client.py +599 -0
  14. forktex_cloud-0.2.3/src/forktex_cloud/client/generated/__init__.py +1057 -0
  15. forktex_cloud-0.2.3/src/forktex_cloud/config.py +63 -0
  16. forktex_cloud-0.2.3/src/forktex_cloud/manifest/__init__.py +58 -0
  17. forktex_cloud-0.2.3/src/forktex_cloud/manifest/errors.py +34 -0
  18. forktex_cloud-0.2.3/src/forktex_cloud/manifest/loader.py +296 -0
  19. forktex_cloud-0.2.3/src/forktex_cloud/manifest/merge.py +52 -0
  20. forktex_cloud-0.2.3/src/forktex_cloud/manifest/schema.py +88 -0
  21. forktex_cloud-0.2.3/src/forktex_cloud/paths.py +297 -0
  22. forktex_cloud-0.2.3/src/forktex_cloud/scaffold/__init__.py +24 -0
  23. forktex_cloud-0.2.3/src/forktex_cloud/scaffold/templates.py +143 -0
  24. forktex_cloud-0.2.3/src/forktex_cloud/secrets/__init__.py +24 -0
  25. forktex_cloud-0.2.3/src/forktex_cloud/secrets/base.py +52 -0
  26. forktex_cloud-0.2.3/src/forktex_cloud/secrets/factory.py +57 -0
  27. forktex_cloud-0.2.3/src/forktex_cloud/secrets/fernet.py +96 -0
  28. forktex_cloud-0.2.3/src/forktex_cloud/secrets/resolver.py +59 -0
  29. forktex_cloud-0.2.3/src/forktex_cloud/templates/observability/loki.yml +55 -0
  30. forktex_cloud-0.2.3/src/forktex_cloud/templates/observability/promtail.yml +46 -0
@@ -0,0 +1,45 @@
1
+ forktex-cloud -- Dual License
2
+
3
+ Copyright (C) 2026 FORKTEX S.R.L.
4
+
5
+ This software is licensed under a dual-license model:
6
+
7
+ ============================================================================
8
+
9
+ 1. OPEN-SOURCE LICENSE -- GNU Affero General Public License v3.0 (AGPL-3.0)
10
+
11
+ You may use, modify, and redistribute this software under the terms of the
12
+ GNU Affero General Public License v3.0 or later, as published by the Free
13
+ Software Foundation. The full license text is available at:
14
+ https://www.gnu.org/licenses/agpl-3.0.html
15
+
16
+ Key obligations under AGPL-3.0:
17
+ - Any modified version MUST be released under the same AGPL-3.0 license.
18
+ - If you run a modified version on a server and let users interact with it
19
+ over a network, you MUST make the complete source code available to those
20
+ users under AGPL-3.0.
21
+ - You MUST preserve all copyright notices and attribution to FORKTEX S.R.L.
22
+
23
+ ============================================================================
24
+
25
+ 2. COMMERCIAL LICENSE
26
+
27
+ If you wish to use this software without the obligations of AGPL-3.0 --
28
+ for example, to keep your modifications proprietary, to embed this software
29
+ in a closed-source product, or to operate it as part of a commercial service
30
+ without releasing your source code -- you MUST obtain a commercial license
31
+ from FORKTEX S.R.L.
32
+
33
+ Commercial licensing includes, but is not limited to:
34
+ - SaaS / hosted deployments generating revenue
35
+ - Embedding in proprietary products or platforms
36
+ - Redistribution in closed-source form
37
+ - Use by organizations exceeding the AGPL-3.0 compliance scope
38
+
39
+ For commercial licensing inquiries, contact:
40
+ info@forktex.com
41
+
42
+ ============================================================================
43
+
44
+ Unless you have obtained a separate commercial license from FORKTEX S.R.L.,
45
+ your use of this software is governed exclusively by the AGPL-3.0 license.
@@ -0,0 +1,23 @@
1
+ forktex-cloud
2
+ Copyright (C) 2026 FORKTEX S.R.L.
3
+
4
+ forktex-cloud is the standalone Python SDK for the ForkTex Cloud platform.
5
+ It provides the typed httpx-based client and Pydantic models for provisioning
6
+ servers, deploying projects, managing static sites, single-container apps and
7
+ native builds, vault secrets, blue-green rollouts, and the declarative
8
+ forktex.json cloud manifest.
9
+
10
+ This program is free software: you can redistribute it and/or modify
11
+ it under the terms of the GNU Affero General Public License as published by
12
+ the Free Software Foundation, either version 3 of the License, or
13
+ (at your option) any later version.
14
+
15
+ This program is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ GNU Affero General Public License for more details.
19
+
20
+ You should have received a copy of the GNU Affero General Public License
21
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
22
+
23
+ For commercial licensing inquiries, contact: info@forktex.com
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: forktex-cloud
3
+ Version: 0.2.3
4
+ Summary: Typed Python SDK for the ForkTex Cloud platform — provision, deploy, and manage VPS-backed apps via a declarative manifest.
5
+ License-Expression: AGPL-3.0-only
6
+ License-File: LICENSE
7
+ License-File: NOTICE
8
+ Keywords: forktex,cloud,deployment,vps,hetzner,ansible,blue-green,iac,infrastructure-as-code,sdk
9
+ Author: FORKTEX
10
+ Author-email: info@forktex.com
11
+ Requires-Python: >=3.12
12
+ Classifier: Development Status :: 5 - Production/Stable
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 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: System :: Distributed Computing
23
+ Classifier: Topic :: System :: Installation/Setup
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Typing :: Typed
26
+ Requires-Dist: cryptography (>=42.0)
27
+ Requires-Dist: httpx (>=0.27.0,<1.0.0)
28
+ Requires-Dist: pydantic[email] (>=2.11.10,<3.0.0)
29
+ Requires-Dist: pyyaml (>=6.0)
30
+ Project-URL: Changelog, https://github.com/forktex/cloud/blob/master/sdk-py/CHANGELOG.md
31
+ Project-URL: Documentation, https://github.com/forktex/cloud/tree/master/docs
32
+ Project-URL: Homepage, https://forktex.com
33
+ Project-URL: Issues, https://github.com/forktex/cloud/issues
34
+ Project-URL: Repository, https://github.com/forktex/cloud
35
+ Description-Content-Type: text/markdown
36
+
37
+ # forktex-cloud
38
+
39
+ [![PyPI](https://img.shields.io/pypi/v/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
40
+ [![Python](https://img.shields.io/pypi/pyversions/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
41
+ [![License](https://img.shields.io/pypi/l/forktex-cloud.svg)](https://github.com/forktex/cloud/blob/master/sdk-py/LICENSE)
42
+
43
+ Standalone Python SDK for the [ForkTex Cloud](https://cloud.forktex.com) platform.
44
+
45
+ `forktex-cloud` is the typed `httpx` client + manifest plumbing that the `forktex` CLI uses to talk to the ForkTex Cloud control plane: project provisioning, server management, deployments, vault, manifest validation, and the docker-compose / Hetzner / Ansible bridge.
46
+
47
+ You can use it directly from any Python application — no `forktex` CLI required.
48
+
49
+ ## Install
50
+
51
+ ```bash
52
+ pip install forktex-cloud
53
+ ```
54
+
55
+ **Requires Python 3.12+.** Tested on 3.12, 3.13, 3.14.
56
+
57
+ ## Quick Start
58
+
59
+ ### Authenticated client
60
+
61
+ ```python
62
+ from forktex_cloud import ForktexCloudClient, CloudContext
63
+
64
+ ctx = CloudContext(controller="https://cloud.forktex.com", account_key="ftx-...")
65
+ with ForktexCloudClient.from_context(ctx) as client:
66
+ projects = client.list_projects()
67
+ servers = client.list_servers()
68
+ health = client.health()
69
+ ```
70
+
71
+ ### Direct auth
72
+
73
+ ```python
74
+ from forktex_cloud import ForktexCloudClient
75
+
76
+ # JWT bearer (user login)
77
+ with ForktexCloudClient("https://cloud.forktex.com", access_token="eyJ...") as client:
78
+ me = client.me()
79
+
80
+ # Org-scoped API key (CI/CD)
81
+ with ForktexCloudClient(
82
+ "https://cloud.forktex.com",
83
+ account_key="ftx-...",
84
+ org_id="00000000-0000-0000-0000-000000000001",
85
+ ) as client:
86
+ events = client.list_events(project_id="...")
87
+ status = client.server_status("server-uuid")
88
+ ```
89
+
90
+ ### Local dev (point at your `make local` stack)
91
+
92
+ ```python
93
+ client = ForktexCloudClient(
94
+ base_url="http://localhost:8000",
95
+ account_key="ftx-dev-key-2026",
96
+ org_id="<your-org-uuid>",
97
+ )
98
+ ```
99
+
100
+ ### Trigger a deploy pipeline
101
+
102
+ ```python
103
+ # Full up (provision + bootstrap + deploy + DNS + SSL)
104
+ job = client.up(project_dir=Path("./my-project")) # reads forktex.json
105
+ print(job.job_id, job.deployment_id, job.status)
106
+
107
+ # Code push to an existing server (no re-provision)
108
+ job = client.deploy(server_id="...", service="api") # Ansible deploy tag
109
+
110
+ # Tear down
111
+ job = client.down(keep_dns=True) # preserves DNS record
112
+ ```
113
+
114
+ ### Manifest loading + validation
115
+
116
+ ```python
117
+ from forktex_cloud import Manifest, ManifestError
118
+
119
+ # Validates eagerly against the canonical Pydantic schema at construction
120
+ try:
121
+ m = Manifest.load("forktex.json", env="production")
122
+ except ManifestError as e:
123
+ print(f"Invalid manifest: {e}")
124
+ raise
125
+
126
+ # Typed access to the cloud block (discriminated union over all 4 kinds)
127
+ print(m.cloud.kind) # "ProjectDeployment" | "StaticSite" | ...
128
+ print(m.cloud.metadata.name)
129
+ for svc in m.services_for_env(env="production"):
130
+ print(svc.id, svc.type, svc.image)
131
+
132
+ # Wire format round-trips cleanly (model_dump → parse_cloud_block)
133
+ as_dict = m.cloud.model_dump(by_alias=True, exclude_none=True)
134
+ ```
135
+
136
+ ### Secrets vault (server-side, org-scoped)
137
+
138
+ ```python
139
+ client.vault_set("POSTGRES_PASSWORD", "hunter2")
140
+ secret = client.vault_get("POSTGRES_PASSWORD") # -> VaultGetResponse
141
+ keys = client.vault_list() # -> list[str]
142
+ client.vault_delete("POSTGRES_PASSWORD")
143
+ ```
144
+
145
+ ## What's in the package
146
+
147
+ | Module | Purpose |
148
+ |---|---|
149
+ | `forktex_cloud.client` | Typed sync httpx client (`ForktexCloudClient`) + all OpenAPI-codegenned Pydantic models (`ServerRead`, `ProjectRead`, `EventRead`, `VaultGetResponse`, ...) |
150
+ | `forktex_cloud.manifest` | `Manifest` loader, discriminated-union schema (v1beta2), deep-merge for env overlays, `ManifestError` |
151
+ | `forktex_cloud.config` | `CloudContext` — controller URL, JWT / account-key, current org + project keys |
152
+ | `forktex_cloud.scaffold` | `forktex cloud init` template generator (ProjectDeployment / StaticSite / SingleContainer / NativeBuild) |
153
+ | `forktex_cloud.bridge` | docker-compose generator (local mode), Loki config, log formatters used by `forktex cloud up --env local` |
154
+ | `forktex_cloud.secrets` | Fernet vault + `${vault:KEY}` resolver for compile-time secret injection |
155
+ | `forktex_cloud.paths` | Cross-platform `.forktex/` + `~/.forktex/` filesystem spec (V1). See [docs/forktex-directory-spec.md](https://github.com/forktex/cloud/blob/master/docs/forktex-directory-spec.md) |
156
+
157
+ All response models come from the OpenAPI codegen pipeline — **one source of truth** shared between the server and every consumer. No hand-written model drift.
158
+
159
+ ## Top-level re-exports
160
+
161
+ ```python
162
+ from forktex_cloud import (
163
+ # Client
164
+ ForktexCloudClient, CloudAPIError,
165
+ # Config
166
+ CloudContext,
167
+ # Manifest
168
+ Manifest, ManifestError,
169
+ # Response models (from OpenAPI codegen)
170
+ ApiKeyCreated, ApiKeyRead,
171
+ EnvironmentRead, EventRead,
172
+ HealthRead, JobResponse, MeResponse,
173
+ OrgRead, ProjectRead, ServerRead, UserRead,
174
+ StatusResponse, TokenResponse, VaultGetResponse,
175
+ WorkspaceRead,
176
+ )
177
+ ```
178
+
179
+ ## Versioning
180
+
181
+ The SDK follows [SemVer](https://semver.org/). The client's response models are generated from the server's OpenAPI spec at a fixed `SPEC_VERSION` + `SPEC_HASH` (inspectable at runtime via `forktex_cloud.client.generated.SPEC_VERSION`). When the server OpenAPI changes, the SDK is regenerated and released with a bumped version.
182
+
183
+ ## Repository
184
+
185
+ This SDK lives inside the [`forktex/cloud`](https://github.com/forktex/cloud) monorepo alongside the API server (`api/`) and React Native client (`client/`). The SDK package is independently versioned and published to PyPI.
186
+
187
+ - Docs: [https://github.com/forktex/cloud/tree/master/docs](https://github.com/forktex/cloud/tree/master/docs)
188
+ - Production runbook: [production-runbook.md](https://github.com/forktex/cloud/blob/master/docs/production-runbook.md)
189
+ - Issues: [https://github.com/forktex/cloud/issues](https://github.com/forktex/cloud/issues)
190
+
191
+ ## Development
192
+
193
+ The [`Makefile`](Makefile) is generated by `forktex fsd makefile sync` from [`forktex.json`](forktex.json) — do not hand-edit.
194
+
195
+ ```bash
196
+ make help # list every available target
197
+ make deps # editable install with the dev group
198
+ make format # ruff format
199
+ make lint # ruff check
200
+ make test # pytest tests/
201
+ make codegen-check # verify the generated client imports cleanly
202
+ make build # python3 -m build → dist/
203
+ make ci # format-check + lint + license-check + audit + test + build
204
+ make clean # remove caches and dist/
205
+ ```
206
+
207
+ `make ci` is the single command that gates a publish: format-check, lint, dual-license header check, dependency CVE audit, full test suite, and `python -m build` + `twine check`.
208
+
209
+ ### License headers
210
+
211
+ Every source file carries the AGPL-3.0 + Commercial dual-license SPDX header, applied idempotently via:
212
+
213
+ ```bash
214
+ make license-check # CI gate — fails if any source file is missing the header
215
+ make license-fix # add or refresh headers across src/, tests/, scripts/
216
+ make license-strip # remove headers (used before license-model changes)
217
+ ```
218
+
219
+ ## License
220
+
221
+ Dual-licensed — **AGPL-3.0-or-later** for open-source use, **commercial** for everything else (proprietary products, SaaS without source release, redistribution in closed-source form). See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE) for the full terms.
222
+
223
+ Commercial licensing inquiries: info@forktex.com.
224
+
225
+ The 1.0.x releases on PyPI remain under MIT; from **0.2.3** onwards the package ships AGPL-3.0+Commercial.
226
+
@@ -0,0 +1,189 @@
1
+ # forktex-cloud
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
5
+ [![License](https://img.shields.io/pypi/l/forktex-cloud.svg)](https://github.com/forktex/cloud/blob/master/sdk-py/LICENSE)
6
+
7
+ Standalone Python SDK for the [ForkTex Cloud](https://cloud.forktex.com) platform.
8
+
9
+ `forktex-cloud` is the typed `httpx` client + manifest plumbing that the `forktex` CLI uses to talk to the ForkTex Cloud control plane: project provisioning, server management, deployments, vault, manifest validation, and the docker-compose / Hetzner / Ansible bridge.
10
+
11
+ You can use it directly from any Python application — no `forktex` CLI required.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install forktex-cloud
17
+ ```
18
+
19
+ **Requires Python 3.12+.** Tested on 3.12, 3.13, 3.14.
20
+
21
+ ## Quick Start
22
+
23
+ ### Authenticated client
24
+
25
+ ```python
26
+ from forktex_cloud import ForktexCloudClient, CloudContext
27
+
28
+ ctx = CloudContext(controller="https://cloud.forktex.com", account_key="ftx-...")
29
+ with ForktexCloudClient.from_context(ctx) as client:
30
+ projects = client.list_projects()
31
+ servers = client.list_servers()
32
+ health = client.health()
33
+ ```
34
+
35
+ ### Direct auth
36
+
37
+ ```python
38
+ from forktex_cloud import ForktexCloudClient
39
+
40
+ # JWT bearer (user login)
41
+ with ForktexCloudClient("https://cloud.forktex.com", access_token="eyJ...") as client:
42
+ me = client.me()
43
+
44
+ # Org-scoped API key (CI/CD)
45
+ with ForktexCloudClient(
46
+ "https://cloud.forktex.com",
47
+ account_key="ftx-...",
48
+ org_id="00000000-0000-0000-0000-000000000001",
49
+ ) as client:
50
+ events = client.list_events(project_id="...")
51
+ status = client.server_status("server-uuid")
52
+ ```
53
+
54
+ ### Local dev (point at your `make local` stack)
55
+
56
+ ```python
57
+ client = ForktexCloudClient(
58
+ base_url="http://localhost:8000",
59
+ account_key="ftx-dev-key-2026",
60
+ org_id="<your-org-uuid>",
61
+ )
62
+ ```
63
+
64
+ ### Trigger a deploy pipeline
65
+
66
+ ```python
67
+ # Full up (provision + bootstrap + deploy + DNS + SSL)
68
+ job = client.up(project_dir=Path("./my-project")) # reads forktex.json
69
+ print(job.job_id, job.deployment_id, job.status)
70
+
71
+ # Code push to an existing server (no re-provision)
72
+ job = client.deploy(server_id="...", service="api") # Ansible deploy tag
73
+
74
+ # Tear down
75
+ job = client.down(keep_dns=True) # preserves DNS record
76
+ ```
77
+
78
+ ### Manifest loading + validation
79
+
80
+ ```python
81
+ from forktex_cloud import Manifest, ManifestError
82
+
83
+ # Validates eagerly against the canonical Pydantic schema at construction
84
+ try:
85
+ m = Manifest.load("forktex.json", env="production")
86
+ except ManifestError as e:
87
+ print(f"Invalid manifest: {e}")
88
+ raise
89
+
90
+ # Typed access to the cloud block (discriminated union over all 4 kinds)
91
+ print(m.cloud.kind) # "ProjectDeployment" | "StaticSite" | ...
92
+ print(m.cloud.metadata.name)
93
+ for svc in m.services_for_env(env="production"):
94
+ print(svc.id, svc.type, svc.image)
95
+
96
+ # Wire format round-trips cleanly (model_dump → parse_cloud_block)
97
+ as_dict = m.cloud.model_dump(by_alias=True, exclude_none=True)
98
+ ```
99
+
100
+ ### Secrets vault (server-side, org-scoped)
101
+
102
+ ```python
103
+ client.vault_set("POSTGRES_PASSWORD", "hunter2")
104
+ secret = client.vault_get("POSTGRES_PASSWORD") # -> VaultGetResponse
105
+ keys = client.vault_list() # -> list[str]
106
+ client.vault_delete("POSTGRES_PASSWORD")
107
+ ```
108
+
109
+ ## What's in the package
110
+
111
+ | Module | Purpose |
112
+ |---|---|
113
+ | `forktex_cloud.client` | Typed sync httpx client (`ForktexCloudClient`) + all OpenAPI-codegenned Pydantic models (`ServerRead`, `ProjectRead`, `EventRead`, `VaultGetResponse`, ...) |
114
+ | `forktex_cloud.manifest` | `Manifest` loader, discriminated-union schema (v1beta2), deep-merge for env overlays, `ManifestError` |
115
+ | `forktex_cloud.config` | `CloudContext` — controller URL, JWT / account-key, current org + project keys |
116
+ | `forktex_cloud.scaffold` | `forktex cloud init` template generator (ProjectDeployment / StaticSite / SingleContainer / NativeBuild) |
117
+ | `forktex_cloud.bridge` | docker-compose generator (local mode), Loki config, log formatters used by `forktex cloud up --env local` |
118
+ | `forktex_cloud.secrets` | Fernet vault + `${vault:KEY}` resolver for compile-time secret injection |
119
+ | `forktex_cloud.paths` | Cross-platform `.forktex/` + `~/.forktex/` filesystem spec (V1). See [docs/forktex-directory-spec.md](https://github.com/forktex/cloud/blob/master/docs/forktex-directory-spec.md) |
120
+
121
+ All response models come from the OpenAPI codegen pipeline — **one source of truth** shared between the server and every consumer. No hand-written model drift.
122
+
123
+ ## Top-level re-exports
124
+
125
+ ```python
126
+ from forktex_cloud import (
127
+ # Client
128
+ ForktexCloudClient, CloudAPIError,
129
+ # Config
130
+ CloudContext,
131
+ # Manifest
132
+ Manifest, ManifestError,
133
+ # Response models (from OpenAPI codegen)
134
+ ApiKeyCreated, ApiKeyRead,
135
+ EnvironmentRead, EventRead,
136
+ HealthRead, JobResponse, MeResponse,
137
+ OrgRead, ProjectRead, ServerRead, UserRead,
138
+ StatusResponse, TokenResponse, VaultGetResponse,
139
+ WorkspaceRead,
140
+ )
141
+ ```
142
+
143
+ ## Versioning
144
+
145
+ The SDK follows [SemVer](https://semver.org/). The client's response models are generated from the server's OpenAPI spec at a fixed `SPEC_VERSION` + `SPEC_HASH` (inspectable at runtime via `forktex_cloud.client.generated.SPEC_VERSION`). When the server OpenAPI changes, the SDK is regenerated and released with a bumped version.
146
+
147
+ ## Repository
148
+
149
+ This SDK lives inside the [`forktex/cloud`](https://github.com/forktex/cloud) monorepo alongside the API server (`api/`) and React Native client (`client/`). The SDK package is independently versioned and published to PyPI.
150
+
151
+ - Docs: [https://github.com/forktex/cloud/tree/master/docs](https://github.com/forktex/cloud/tree/master/docs)
152
+ - Production runbook: [production-runbook.md](https://github.com/forktex/cloud/blob/master/docs/production-runbook.md)
153
+ - Issues: [https://github.com/forktex/cloud/issues](https://github.com/forktex/cloud/issues)
154
+
155
+ ## Development
156
+
157
+ The [`Makefile`](Makefile) is generated by `forktex fsd makefile sync` from [`forktex.json`](forktex.json) — do not hand-edit.
158
+
159
+ ```bash
160
+ make help # list every available target
161
+ make deps # editable install with the dev group
162
+ make format # ruff format
163
+ make lint # ruff check
164
+ make test # pytest tests/
165
+ make codegen-check # verify the generated client imports cleanly
166
+ make build # python3 -m build → dist/
167
+ make ci # format-check + lint + license-check + audit + test + build
168
+ make clean # remove caches and dist/
169
+ ```
170
+
171
+ `make ci` is the single command that gates a publish: format-check, lint, dual-license header check, dependency CVE audit, full test suite, and `python -m build` + `twine check`.
172
+
173
+ ### License headers
174
+
175
+ Every source file carries the AGPL-3.0 + Commercial dual-license SPDX header, applied idempotently via:
176
+
177
+ ```bash
178
+ make license-check # CI gate — fails if any source file is missing the header
179
+ make license-fix # add or refresh headers across src/, tests/, scripts/
180
+ make license-strip # remove headers (used before license-model changes)
181
+ ```
182
+
183
+ ## License
184
+
185
+ Dual-licensed — **AGPL-3.0-or-later** for open-source use, **commercial** for everything else (proprietary products, SaaS without source release, redistribution in closed-source form). See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE) for the full terms.
186
+
187
+ Commercial licensing inquiries: info@forktex.com.
188
+
189
+ The 1.0.x releases on PyPI remain under MIT; from **0.2.3** onwards the package ships AGPL-3.0+Commercial.
@@ -0,0 +1,107 @@
1
+ # Copyright (C) 2026 FORKTEX S.R.L.
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-ForkTex-Commercial
4
+ #
5
+ # This file is part of forktex-cloud.
6
+ #
7
+ # For commercial licensing -- including use in proprietary products, SaaS
8
+ # deployments, or any context where AGPL obligations cannot be met -- you
9
+ # MUST obtain a commercial license from FORKTEX S.R.L. (info@forktex.com).
10
+ #
11
+ # This program is free software: you can redistribute it and/or modify
12
+ # it under the terms of the GNU Affero General Public License as published by
13
+ # the Free Software Foundation, either version 3 of the License, or
14
+ # (at your option) any later version.
15
+ #
16
+ # This program is distributed in the hope that it will be useful,
17
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ # GNU Affero General Public License for more details.
20
+ #
21
+ # You should have received a copy of the GNU Affero General Public License
22
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
23
+
24
+ [project]
25
+ name = "forktex-cloud"
26
+ version = "0.2.3"
27
+ description = "Typed Python SDK for the ForkTex Cloud platform — provision, deploy, and manage VPS-backed apps via a declarative manifest."
28
+ authors = [
29
+ {name = "FORKTEX", email = "info@forktex.com"}
30
+ ]
31
+ readme = "README.md"
32
+ license = "AGPL-3.0-only"
33
+ license-files = ["LICENSE", "NOTICE"]
34
+ requires-python = ">=3.12"
35
+ keywords = [
36
+ "forktex",
37
+ "cloud",
38
+ "deployment",
39
+ "vps",
40
+ "hetzner",
41
+ "ansible",
42
+ "blue-green",
43
+ "iac",
44
+ "infrastructure-as-code",
45
+ "sdk",
46
+ ]
47
+ classifiers = [
48
+ "Development Status :: 5 - Production/Stable",
49
+ "Intended Audience :: Developers",
50
+ "Intended Audience :: System Administrators",
51
+ "Operating System :: OS Independent",
52
+ "Programming Language :: Python :: 3",
53
+ "Programming Language :: Python :: 3 :: Only",
54
+ "Programming Language :: Python :: 3.12",
55
+ "Programming Language :: Python :: 3.13",
56
+ "Programming Language :: Python :: 3.14",
57
+ "Topic :: Software Development :: Libraries :: Python Modules",
58
+ "Topic :: System :: Distributed Computing",
59
+ "Topic :: System :: Installation/Setup",
60
+ "Topic :: System :: Systems Administration",
61
+ "Typing :: Typed",
62
+ ]
63
+ dependencies = [
64
+ "pydantic[email] (>=2.11.10,<3.0.0)",
65
+ "httpx (>=0.27.0,<1.0.0)",
66
+ "pyyaml>=6.0",
67
+ "cryptography>=42.0",
68
+ ]
69
+
70
+ [project.urls]
71
+ "Homepage" = "https://forktex.com"
72
+ "Documentation" = "https://github.com/forktex/cloud/tree/master/docs"
73
+ "Repository" = "https://github.com/forktex/cloud"
74
+ "Issues" = "https://github.com/forktex/cloud/issues"
75
+ "Changelog" = "https://github.com/forktex/cloud/blob/master/sdk-py/CHANGELOG.md"
76
+
77
+ [build-system]
78
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
79
+ build-backend = "poetry.core.masonry.api"
80
+
81
+ [dependency-groups]
82
+ dev = [
83
+ "pytest (>=8.4.2,<9.0.0)",
84
+ "pytest-asyncio (>=1.2.0,<2.0.0)",
85
+ "ruff (>=0.8.0)",
86
+ "pyright>=1.1.350",
87
+ "pip-audit>=2.7.0",
88
+ "build>=1.2.0",
89
+ "twine>=5.0.0",
90
+ ]
91
+
92
+ [tool.ruff]
93
+ target-version = "py312"
94
+ line-length = 100
95
+ extend-exclude = [
96
+ # Auto-generated by OpenAPI codegen. Canonical import shape comes from
97
+ # datamodel-code-generator + our custom header (SPEC_VERSION / SPEC_HASH
98
+ # before the imports). Linting this file would churn every regen.
99
+ "src/forktex_cloud/client/generated/**",
100
+ ]
101
+
102
+ [tool.ruff.lint]
103
+ select = ["E", "F", "I", "W"]
104
+
105
+ [tool.pytest.ini_options]
106
+ asyncio_mode = "auto"
107
+ testpaths = ["tests"]
@@ -0,0 +1,92 @@
1
+ # Copyright (C) 2026 FORKTEX S.R.L.
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-ForkTex-Commercial
4
+ #
5
+ # This file is part of forktex-cloud.
6
+ #
7
+ # For commercial licensing -- including use in proprietary products, SaaS
8
+ # deployments, or any context where AGPL obligations cannot be met -- you
9
+ # MUST obtain a commercial license from FORKTEX S.R.L. (info@forktex.com).
10
+ #
11
+ # This program is free software: you can redistribute it and/or modify
12
+ # it under the terms of the GNU Affero General Public License as published by
13
+ # the Free Software Foundation, either version 3 of the License, or
14
+ # (at your option) any later version.
15
+ #
16
+ # This program is distributed in the hope that it will be useful,
17
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ # GNU Affero General Public License for more details.
20
+ #
21
+ # You should have received a copy of the GNU Affero General Public License
22
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
23
+
24
+ """forktex_cloud — Standalone Python SDK for the ForkTex Cloud platform.
25
+
26
+ Usage::
27
+
28
+ from forktex_cloud import ForktexCloudClient, CloudContext
29
+
30
+ ctx = CloudContext(controller="https://cloud.forktex.com", account_key="ftx-...")
31
+ with ForktexCloudClient.from_context(ctx) as client:
32
+ projects = client.list_projects()
33
+ servers = client.list_servers()
34
+ """
35
+
36
+ __version__ = "0.2.3"
37
+
38
+ from forktex_cloud import paths
39
+ from forktex_cloud.client.client import CloudAPIError, ForktexCloudClient
40
+ from forktex_cloud.client.generated import (
41
+ SPEC_HASH,
42
+ SPEC_VERSION,
43
+ ApiKeyCreated,
44
+ ApiKeyRead,
45
+ EnvironmentRead,
46
+ EventRead,
47
+ HealthRead,
48
+ JobResponse,
49
+ MeResponse,
50
+ OrgRead,
51
+ ProjectRead,
52
+ ServerRead,
53
+ StatusResponse,
54
+ TokenResponse,
55
+ UserRead,
56
+ VaultGetResponse,
57
+ WorkspaceRead,
58
+ )
59
+ from forktex_cloud.config import CloudContext
60
+ from forktex_cloud.manifest.loader import Manifest, ManifestError
61
+
62
+ __all__ = [
63
+ # Filesystem layout spec (V1)
64
+ "paths",
65
+ # Codegen contract (wire-compatibility markers)
66
+ "SPEC_VERSION",
67
+ "SPEC_HASH",
68
+ # Client
69
+ "ForktexCloudClient",
70
+ "CloudAPIError",
71
+ # Config
72
+ "CloudContext",
73
+ # Manifest
74
+ "Manifest",
75
+ "ManifestError",
76
+ # Models (from OpenAPI codegen — the single source of truth)
77
+ "ApiKeyCreated",
78
+ "ApiKeyRead",
79
+ "EnvironmentRead",
80
+ "EventRead",
81
+ "HealthRead",
82
+ "JobResponse",
83
+ "MeResponse",
84
+ "OrgRead",
85
+ "ProjectRead",
86
+ "ServerRead",
87
+ "StatusResponse",
88
+ "TokenResponse",
89
+ "UserRead",
90
+ "VaultGetResponse",
91
+ "WorkspaceRead",
92
+ ]