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.
@@ -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.1.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.2.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.1.0"
2
+ __version__ = "0.2.0"