sofe-server 0.1.0__tar.gz → 0.2.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.
- sofe_server-0.2.0/PKG-INFO +202 -0
- sofe_server-0.2.0/README.md +184 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/pyproject.toml +11 -2
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server/__init__.py +1 -1
- sofe_server-0.2.0/sofe_server/app.py +638 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server/main.py +2 -2
- sofe_server-0.2.0/sofe_server.egg-info/PKG-INFO +202 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server.egg-info/SOURCES.txt +2 -1
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server.egg-info/requires.txt +5 -1
- sofe_server-0.2.0/tests/test_evaluate_role.py +229 -0
- sofe_server-0.1.0/PKG-INFO +0 -124
- sofe_server-0.1.0/README.md +0 -109
- sofe_server-0.1.0/sofe_server/app.py +0 -221
- sofe_server-0.1.0/sofe_server.egg-info/PKG-INFO +0 -124
- {sofe_server-0.1.0 → sofe_server-0.2.0}/LICENSE +0 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/setup.cfg +0 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server.egg-info/dependency_links.txt +0 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server.egg-info/entry_points.txt +0 -0
- {sofe_server-0.1.0 → sofe_server-0.2.0}/sofe_server.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sofe-server
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: SOFE API Server — FinOps Policies as Code REST API
|
|
5
|
+
Author-email: Carlos Cortez <carlos@cortez.cloud>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: sofe>=0.5.0
|
|
11
|
+
Requires-Dist: fastapi>=0.111.0
|
|
12
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
13
|
+
Requires-Dist: pydantic>=2.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
16
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img alt="SOFE Server" src="https://img.shields.io/badge/🟢-SOFE_Server-22C55E?style=for-the-badge" height="50">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<b>REST API for the SOFE FinOps Engine</b><br>
|
|
25
|
+
Multi-tenant evaluation platform with catalog, history, and alerts.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="#quick-start">Quick Start</a>
|
|
30
|
+
·
|
|
31
|
+
<a href="#endpoints">Endpoints</a>
|
|
32
|
+
·
|
|
33
|
+
<a href="#usage">Usage</a>
|
|
34
|
+
·
|
|
35
|
+
<a href="#ecosystem">Ecosystem</a>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="https://img.shields.io/pypi/v/sofe-server?style=flat-square&logo=pypi&color=22C55E" alt="PyPI">
|
|
40
|
+
<img src="https://img.shields.io/badge/python-3.11%2B-blue?style=flat-square&logo=python" alt="Python">
|
|
41
|
+
<img src="https://img.shields.io/badge/license-Apache_2.0-22C55E?style=flat-square" alt="License">
|
|
42
|
+
<img src="https://img.shields.io/badge/FastAPI-0.115-009688?style=flat-square&logo=fastapi" alt="FastAPI">
|
|
43
|
+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square" alt="PRs">
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
Wraps the [SOFE](https://github.com/breakingthecloud/sofe) Python engine in a FastAPI application, enabling HTTP-based evaluations.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install sofe sofe-server
|
|
52
|
+
sofe-server
|
|
53
|
+
# → http://localhost:8080
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Install
|
|
60
|
+
pip install sofe sofe-server
|
|
61
|
+
|
|
62
|
+
# Start server
|
|
63
|
+
sofe-server
|
|
64
|
+
|
|
65
|
+
# Evaluate your AWS account
|
|
66
|
+
curl -X POST http://localhost:8080/evaluate \
|
|
67
|
+
-H "Content-Type: application/json" \
|
|
68
|
+
-d '{"profile": "default"}'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or use the Go CLI:
|
|
72
|
+
```bash
|
|
73
|
+
sofe serve # starts sofe-server in background
|
|
74
|
+
sofe evaluate # calls localhost:8080/evaluate
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Endpoints
|
|
78
|
+
|
|
79
|
+
| Method | Path | Description |
|
|
80
|
+
|--------|------|-------------|
|
|
81
|
+
| GET | `/health` | Health check |
|
|
82
|
+
| POST | `/evaluate` | Evaluate AWS account against policies |
|
|
83
|
+
| POST | `/validate` | Validate an Architecture Graph (BYaML v0.4 JSON) |
|
|
84
|
+
| GET | `/policies` | List all loaded policies |
|
|
85
|
+
| GET | `/collectors` | List available collectors |
|
|
86
|
+
| GET | `/metrics` | List metrics per collector |
|
|
87
|
+
| POST | `/connect/test` | Test STS AssumeRole connection |
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
### Evaluate a different AWS account (cross-account role)
|
|
92
|
+
|
|
93
|
+
Pass the role to assume and its ExternalId. The server calls `sts:AssumeRole` and runs
|
|
94
|
+
**every** collector with those temporary credentials, so the account behind the role is
|
|
95
|
+
the one that gets evaluated:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
curl -X POST http://localhost:8080/evaluate \
|
|
99
|
+
-H "Content-Type: application/json" \
|
|
100
|
+
-d '{
|
|
101
|
+
"role_arn": "arn:aws:iam::123456789012:role/sofe-read-only",
|
|
102
|
+
"external_id": "your-external-id"
|
|
103
|
+
}'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Field | Notes |
|
|
107
|
+
|-------|-------|
|
|
108
|
+
| `role_arn` | IAM role ARN to assume. Takes precedence over `profile`. |
|
|
109
|
+
| `external_id` | Required with `role_arn` (2-1224 chars: letters, digits, `+=,.@:/-`). |
|
|
110
|
+
|
|
111
|
+
The response says what was actually read: `account_id`, `evaluated_via`
|
|
112
|
+
(`assumed_role` \| `profile` \| `default_credentials`) and `evaluated_role_arn`.
|
|
113
|
+
|
|
114
|
+
| Status | Meaning |
|
|
115
|
+
|--------|---------|
|
|
116
|
+
| `400` | Missing/invalid `role_arn` or `external_id`, or a role is required (see below). No AWS call is made. |
|
|
117
|
+
| `403` | STS denied the assume: the role does not exist in that account or its trust policy ExternalId does not match. |
|
|
118
|
+
| `502` | STS failed for another reason. |
|
|
119
|
+
| `501` | The installed `sofe` engine is too old for role-based evaluation (upgrade `sofe`). |
|
|
120
|
+
|
|
121
|
+
The ExternalId is never echoed in responses or logs.
|
|
122
|
+
|
|
123
|
+
### Hosted deployments: require a role
|
|
124
|
+
|
|
125
|
+
By default, a request without `role_arn` evaluates the account of the server's own
|
|
126
|
+
credentials (or `profile`) — the right behavior for self-hosted use. A **hosted** server
|
|
127
|
+
that evaluates *other people's* accounts must never do that. Set:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
SOFE_REQUIRE_ROLE=true
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
and any `/evaluate` request that does not name a role is rejected with `400` before any
|
|
134
|
+
AWS API is called.
|
|
135
|
+
|
|
136
|
+
### List policies
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
curl http://localhost:8080/policies
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Docker
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
docker run -p 8080:8080 -v ~/.aws:/root/.aws:ro \
|
|
146
|
+
ghcr.io/breakingthecloud/sofe-community:latest
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Architecture
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
sofe-server (this repo)
|
|
153
|
+
│
|
|
154
|
+
│ imports
|
|
155
|
+
▼
|
|
156
|
+
sofe/ (engine — pip install sofe)
|
|
157
|
+
│
|
|
158
|
+
│ boto3
|
|
159
|
+
▼
|
|
160
|
+
Your AWS Account (read-only)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
sofe-server is a **thin wrapper** — all policy evaluation logic lives in the [sofe engine](https://github.com/breakingthecloud/sofe).
|
|
164
|
+
|
|
165
|
+
## Requirements
|
|
166
|
+
|
|
167
|
+
- Python 3.11+
|
|
168
|
+
- `sofe` >= 0.2.0 (engine)
|
|
169
|
+
- AWS credentials (profile or role)
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git clone https://github.com/breakingthecloud/sofe-server.git
|
|
175
|
+
cd sofe-server
|
|
176
|
+
uv venv && source .venv/bin/activate
|
|
177
|
+
uv pip install -e ".[dev]" -e ../sofe/
|
|
178
|
+
uvicorn sofe_server.app:app --reload --port 8080
|
|
179
|
+
|
|
180
|
+
# Tests (no AWS needed: STS and the engine are faked)
|
|
181
|
+
pytest
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Ecosystem
|
|
185
|
+
|
|
186
|
+
| Project | Description |
|
|
187
|
+
|---------|-------------|
|
|
188
|
+
| [sofe](https://github.com/breakingthecloud/sofe) | Python engine (collectors + policies) |
|
|
189
|
+
| [sofe-cli](https://github.com/breakingthecloud/sofe-cli) | Go CLI (19 commands, TUI) |
|
|
190
|
+
| [sofe-action](https://github.com/breakingthecloud/sofe-action) | GitHub Action for CI/CD |
|
|
191
|
+
| [platform.sofe.dev](https://platform.sofe.dev) | SaaS dashboard (free tier) |
|
|
192
|
+
| [sofe.dev/docs](https://sofe.dev/docs) | Documentation (26 pages) |
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
<p align="center">
|
|
201
|
+
<a href="https://sofe.dev">sofe.dev</a> · <a href="https://github.com/breakingthecloud/sofe">Engine</a> · <a href="https://finoptix.dev">finoptix.dev</a>
|
|
202
|
+
</p>
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="SOFE Server" src="https://img.shields.io/badge/🟢-SOFE_Server-22C55E?style=for-the-badge" height="50">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<b>REST API for the SOFE FinOps Engine</b><br>
|
|
7
|
+
Multi-tenant evaluation platform with catalog, history, and alerts.
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="#quick-start">Quick Start</a>
|
|
12
|
+
·
|
|
13
|
+
<a href="#endpoints">Endpoints</a>
|
|
14
|
+
·
|
|
15
|
+
<a href="#usage">Usage</a>
|
|
16
|
+
·
|
|
17
|
+
<a href="#ecosystem">Ecosystem</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<img src="https://img.shields.io/pypi/v/sofe-server?style=flat-square&logo=pypi&color=22C55E" alt="PyPI">
|
|
22
|
+
<img src="https://img.shields.io/badge/python-3.11%2B-blue?style=flat-square&logo=python" alt="Python">
|
|
23
|
+
<img src="https://img.shields.io/badge/license-Apache_2.0-22C55E?style=flat-square" alt="License">
|
|
24
|
+
<img src="https://img.shields.io/badge/FastAPI-0.115-009688?style=flat-square&logo=fastapi" alt="FastAPI">
|
|
25
|
+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square" alt="PRs">
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
Wraps the [SOFE](https://github.com/breakingthecloud/sofe) Python engine in a FastAPI application, enabling HTTP-based evaluations.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install sofe sofe-server
|
|
34
|
+
sofe-server
|
|
35
|
+
# → http://localhost:8080
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Install
|
|
42
|
+
pip install sofe sofe-server
|
|
43
|
+
|
|
44
|
+
# Start server
|
|
45
|
+
sofe-server
|
|
46
|
+
|
|
47
|
+
# Evaluate your AWS account
|
|
48
|
+
curl -X POST http://localhost:8080/evaluate \
|
|
49
|
+
-H "Content-Type: application/json" \
|
|
50
|
+
-d '{"profile": "default"}'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or use the Go CLI:
|
|
54
|
+
```bash
|
|
55
|
+
sofe serve # starts sofe-server in background
|
|
56
|
+
sofe evaluate # calls localhost:8080/evaluate
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Endpoints
|
|
60
|
+
|
|
61
|
+
| Method | Path | Description |
|
|
62
|
+
|--------|------|-------------|
|
|
63
|
+
| GET | `/health` | Health check |
|
|
64
|
+
| POST | `/evaluate` | Evaluate AWS account against policies |
|
|
65
|
+
| POST | `/validate` | Validate an Architecture Graph (BYaML v0.4 JSON) |
|
|
66
|
+
| GET | `/policies` | List all loaded policies |
|
|
67
|
+
| GET | `/collectors` | List available collectors |
|
|
68
|
+
| GET | `/metrics` | List metrics per collector |
|
|
69
|
+
| POST | `/connect/test` | Test STS AssumeRole connection |
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
### Evaluate a different AWS account (cross-account role)
|
|
74
|
+
|
|
75
|
+
Pass the role to assume and its ExternalId. The server calls `sts:AssumeRole` and runs
|
|
76
|
+
**every** collector with those temporary credentials, so the account behind the role is
|
|
77
|
+
the one that gets evaluated:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -X POST http://localhost:8080/evaluate \
|
|
81
|
+
-H "Content-Type: application/json" \
|
|
82
|
+
-d '{
|
|
83
|
+
"role_arn": "arn:aws:iam::123456789012:role/sofe-read-only",
|
|
84
|
+
"external_id": "your-external-id"
|
|
85
|
+
}'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Field | Notes |
|
|
89
|
+
|-------|-------|
|
|
90
|
+
| `role_arn` | IAM role ARN to assume. Takes precedence over `profile`. |
|
|
91
|
+
| `external_id` | Required with `role_arn` (2-1224 chars: letters, digits, `+=,.@:/-`). |
|
|
92
|
+
|
|
93
|
+
The response says what was actually read: `account_id`, `evaluated_via`
|
|
94
|
+
(`assumed_role` \| `profile` \| `default_credentials`) and `evaluated_role_arn`.
|
|
95
|
+
|
|
96
|
+
| Status | Meaning |
|
|
97
|
+
|--------|---------|
|
|
98
|
+
| `400` | Missing/invalid `role_arn` or `external_id`, or a role is required (see below). No AWS call is made. |
|
|
99
|
+
| `403` | STS denied the assume: the role does not exist in that account or its trust policy ExternalId does not match. |
|
|
100
|
+
| `502` | STS failed for another reason. |
|
|
101
|
+
| `501` | The installed `sofe` engine is too old for role-based evaluation (upgrade `sofe`). |
|
|
102
|
+
|
|
103
|
+
The ExternalId is never echoed in responses or logs.
|
|
104
|
+
|
|
105
|
+
### Hosted deployments: require a role
|
|
106
|
+
|
|
107
|
+
By default, a request without `role_arn` evaluates the account of the server's own
|
|
108
|
+
credentials (or `profile`) — the right behavior for self-hosted use. A **hosted** server
|
|
109
|
+
that evaluates *other people's* accounts must never do that. Set:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
SOFE_REQUIRE_ROLE=true
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
and any `/evaluate` request that does not name a role is rejected with `400` before any
|
|
116
|
+
AWS API is called.
|
|
117
|
+
|
|
118
|
+
### List policies
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
curl http://localhost:8080/policies
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Docker
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
docker run -p 8080:8080 -v ~/.aws:/root/.aws:ro \
|
|
128
|
+
ghcr.io/breakingthecloud/sofe-community:latest
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Architecture
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
sofe-server (this repo)
|
|
135
|
+
│
|
|
136
|
+
│ imports
|
|
137
|
+
▼
|
|
138
|
+
sofe/ (engine — pip install sofe)
|
|
139
|
+
│
|
|
140
|
+
│ boto3
|
|
141
|
+
▼
|
|
142
|
+
Your AWS Account (read-only)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
sofe-server is a **thin wrapper** — all policy evaluation logic lives in the [sofe engine](https://github.com/breakingthecloud/sofe).
|
|
146
|
+
|
|
147
|
+
## Requirements
|
|
148
|
+
|
|
149
|
+
- Python 3.11+
|
|
150
|
+
- `sofe` >= 0.2.0 (engine)
|
|
151
|
+
- AWS credentials (profile or role)
|
|
152
|
+
|
|
153
|
+
## Development
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
git clone https://github.com/breakingthecloud/sofe-server.git
|
|
157
|
+
cd sofe-server
|
|
158
|
+
uv venv && source .venv/bin/activate
|
|
159
|
+
uv pip install -e ".[dev]" -e ../sofe/
|
|
160
|
+
uvicorn sofe_server.app:app --reload --port 8080
|
|
161
|
+
|
|
162
|
+
# Tests (no AWS needed: STS and the engine are faked)
|
|
163
|
+
pytest
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Ecosystem
|
|
167
|
+
|
|
168
|
+
| Project | Description |
|
|
169
|
+
|---------|-------------|
|
|
170
|
+
| [sofe](https://github.com/breakingthecloud/sofe) | Python engine (collectors + policies) |
|
|
171
|
+
| [sofe-cli](https://github.com/breakingthecloud/sofe-cli) | Go CLI (19 commands, TUI) |
|
|
172
|
+
| [sofe-action](https://github.com/breakingthecloud/sofe-action) | GitHub Action for CI/CD |
|
|
173
|
+
| [platform.sofe.dev](https://platform.sofe.dev) | SaaS dashboard (free tier) |
|
|
174
|
+
| [sofe.dev/docs](https://sofe.dev/docs) | Documentation (26 pages) |
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
<p align="center">
|
|
183
|
+
<a href="https://sofe.dev">sofe.dev</a> · <a href="https://github.com/breakingthecloud/sofe">Engine</a> · <a href="https://finoptix.dev">finoptix.dev</a>
|
|
184
|
+
</p>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sofe-server"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "SOFE API Server — FinOps Policies as Code REST API"
|
|
5
5
|
requires-python = ">=3.11"
|
|
6
6
|
license = {text = "Apache-2.0"}
|
|
7
7
|
authors = [{name = "Carlos Cortez", email = "carlos@cortez.cloud"}]
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"sofe>=0.
|
|
10
|
+
"sofe>=0.5.0",
|
|
11
11
|
"fastapi>=0.111.0",
|
|
12
12
|
"uvicorn>=0.30.0",
|
|
13
13
|
"pydantic>=2.0",
|
|
@@ -16,6 +16,15 @@ dependencies = [
|
|
|
16
16
|
[project.scripts]
|
|
17
17
|
sofe-server = "sofe_server.main:run"
|
|
18
18
|
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest>=8.0",
|
|
22
|
+
"httpx>=0.27",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[tool.pytest.ini_options]
|
|
26
|
+
testpaths = ["tests"]
|
|
27
|
+
|
|
19
28
|
[build-system]
|
|
20
29
|
requires = ["setuptools>=68"]
|
|
21
30
|
build-backend = "setuptools.build_meta"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""SOFE Server — FinOps Policies as Code API."""
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.2.0"
|