xenfra-sdk 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
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.
- xenfra_sdk/__init__.py +61 -21
- xenfra_sdk/cli/main.py +226 -226
- xenfra_sdk/client.py +90 -90
- xenfra_sdk/config.py +26 -26
- xenfra_sdk/db/models.py +24 -24
- xenfra_sdk/db/session.py +30 -30
- xenfra_sdk/dependencies.py +39 -39
- xenfra_sdk/detection.py +396 -0
- xenfra_sdk/dockerizer.py +195 -194
- xenfra_sdk/engine.py +741 -619
- xenfra_sdk/exceptions.py +19 -19
- xenfra_sdk/manifest.py +212 -0
- xenfra_sdk/mcp_client.py +154 -154
- xenfra_sdk/models.py +184 -184
- xenfra_sdk/orchestrator.py +666 -0
- xenfra_sdk/patterns.json +13 -13
- xenfra_sdk/privacy.py +153 -153
- xenfra_sdk/recipes.py +26 -26
- xenfra_sdk/resources/base.py +3 -3
- xenfra_sdk/resources/deployments.py +278 -248
- xenfra_sdk/resources/files.py +101 -101
- xenfra_sdk/resources/intelligence.py +102 -95
- xenfra_sdk/security.py +41 -41
- xenfra_sdk/security_scanner.py +431 -0
- xenfra_sdk/templates/Caddyfile.j2 +14 -0
- xenfra_sdk/templates/Dockerfile.j2 +41 -38
- xenfra_sdk/templates/cloud-init.sh.j2 +90 -90
- xenfra_sdk/templates/docker-compose-multi.yml.j2 +29 -0
- xenfra_sdk/templates/docker-compose.yml.j2 +30 -30
- xenfra_sdk-0.2.4.dist-info/METADATA +116 -0
- xenfra_sdk-0.2.4.dist-info/RECORD +38 -0
- xenfra_sdk-0.2.2.dist-info/METADATA +0 -118
- xenfra_sdk-0.2.2.dist-info/RECORD +0 -32
- {xenfra_sdk-0.2.2.dist-info → xenfra_sdk-0.2.4.dist-info}/WHEEL +0 -0
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
export DEBIAN_FRONTEND=noninteractive
|
|
3
|
-
LOG="/root/setup.log"
|
|
4
|
-
touch $LOG
|
|
5
|
-
|
|
6
|
-
echo "--------------------------------" >> $LOG
|
|
7
|
-
echo "🧘 XENFRA: Context-Aware Boot" >> $LOG
|
|
8
|
-
echo "--------------------------------" >> $LOG
|
|
9
|
-
|
|
10
|
-
# Create App Directory
|
|
11
|
-
mkdir -p /root/app
|
|
12
|
-
cd /root/app
|
|
13
|
-
|
|
14
|
-
# --- MERCILESS FIX: TERMINATE BACKGROUND PROCESSES ---
|
|
15
|
-
echo "⚔️ [0/6] Mercilessly Terminating Background Processes..." >> $LOG
|
|
16
|
-
|
|
17
|
-
kill_apt_processes() {
|
|
18
|
-
echo "🎯 Killing processes holding apt/dpkg locks..." >> $LOG
|
|
19
|
-
fuser -k /var/lib/dpkg/lock >/dev/null 2>&1
|
|
20
|
-
fuser -k /var/lib/apt/lists/lock >/dev/null 2>&1
|
|
21
|
-
fuser -k /var/lib/dpkg/lock-frontends >/dev/null 2>&1
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# Explicitly stop and disable services that cause locks
|
|
25
|
-
systemctl stop unattended-upgrades.service || true
|
|
26
|
-
systemctl disable unattended-upgrades.service || true
|
|
27
|
-
systemctl stop apt-daily.service || true
|
|
28
|
-
systemctl disable apt-daily.service || true
|
|
29
|
-
systemctl stop apt-daily-upgrade.service || true
|
|
30
|
-
systemctl disable apt-daily-upgrade.service || true
|
|
31
|
-
|
|
32
|
-
# Forcefully kill any remaining lock holders
|
|
33
|
-
kill_apt_processes
|
|
34
|
-
|
|
35
|
-
# Force remove locks if they still exist (The Nuclear Option)
|
|
36
|
-
rm -f /var/lib/dpkg/lock*
|
|
37
|
-
rm -f /var/lib/apt/lists/lock*
|
|
38
|
-
rm -f /var/cache/apt/archives/lock
|
|
39
|
-
dpkg --configure -a || true
|
|
40
|
-
# -----------------------------------------------
|
|
41
|
-
|
|
42
|
-
# 1. System Updates
|
|
43
|
-
echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
|
|
44
|
-
apt-get update
|
|
45
|
-
apt-get install -y python3-pip git curl
|
|
46
|
-
|
|
47
|
-
# 2. Setup Environment
|
|
48
|
-
{% if is_dockerized %}
|
|
49
|
-
echo "🐳 [2/5] Installing Docker..." >> $LOG
|
|
50
|
-
apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
|
|
51
|
-
echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
|
|
52
|
-
apt-get install -y docker-compose-v2
|
|
53
|
-
{% else %}
|
|
54
|
-
echo "🐍 [2/5] Setting up host-based Python environment..." >> $LOG
|
|
55
|
-
apt-get install -y python3-venv python3-dev build-essential
|
|
56
|
-
{% endif %}
|
|
57
|
-
|
|
58
|
-
# 3. Setup Reverse Proxy
|
|
59
|
-
{% if is_dockerized %}
|
|
60
|
-
echo "📦 [3/5] Installing Caddy..." >> $LOG
|
|
61
|
-
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
|
|
62
|
-
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
63
|
-
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
|
|
64
|
-
apt-get update
|
|
65
|
-
apt-get install -y caddy
|
|
66
|
-
{% else %}
|
|
67
|
-
echo "🛡️ [3/5] Skipping Caddy for host deployment (setup manual reverse proxy if needed)." >> $LOG
|
|
68
|
-
{% endif %}
|
|
69
|
-
|
|
70
|
-
{% if domain %}
|
|
71
|
-
# Dynamically generate Caddyfile content
|
|
72
|
-
echo "🔒 Writing Caddyfile for {{ domain }}..." >> $LOG
|
|
73
|
-
cat << EOF > /etc/caddy/Caddyfile
|
|
74
|
-
{{ domain }}:80, {{ domain }}:443 {
|
|
75
|
-
reverse_proxy localhost:{{ port | default(8000) }}
|
|
76
|
-
tls {{ email }}
|
|
77
|
-
}
|
|
78
|
-
EOF
|
|
79
|
-
{% endif %}
|
|
80
|
-
|
|
81
|
-
{% if domain %}
|
|
82
|
-
echo "🚀 [5/5] Starting Caddy..." >> $LOG
|
|
83
|
-
systemctl restart caddy
|
|
84
|
-
{% else %}
|
|
85
|
-
echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
|
|
86
|
-
{% endif %}
|
|
87
|
-
|
|
88
|
-
# Finish
|
|
89
|
-
echo "✅ SETUP SCRIPT COMPLETE" >> $LOG
|
|
90
|
-
touch /root/setup_complete
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
export DEBIAN_FRONTEND=noninteractive
|
|
3
|
+
LOG="/root/setup.log"
|
|
4
|
+
touch $LOG
|
|
5
|
+
|
|
6
|
+
echo "--------------------------------" >> $LOG
|
|
7
|
+
echo "🧘 XENFRA: Context-Aware Boot" >> $LOG
|
|
8
|
+
echo "--------------------------------" >> $LOG
|
|
9
|
+
|
|
10
|
+
# Create App Directory
|
|
11
|
+
mkdir -p /root/app
|
|
12
|
+
cd /root/app
|
|
13
|
+
|
|
14
|
+
# --- MERCILESS FIX: TERMINATE BACKGROUND PROCESSES ---
|
|
15
|
+
echo "⚔️ [0/6] Mercilessly Terminating Background Processes..." >> $LOG
|
|
16
|
+
|
|
17
|
+
kill_apt_processes() {
|
|
18
|
+
echo "🎯 Killing processes holding apt/dpkg locks..." >> $LOG
|
|
19
|
+
fuser -k /var/lib/dpkg/lock >/dev/null 2>&1
|
|
20
|
+
fuser -k /var/lib/apt/lists/lock >/dev/null 2>&1
|
|
21
|
+
fuser -k /var/lib/dpkg/lock-frontends >/dev/null 2>&1
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Explicitly stop and disable services that cause locks
|
|
25
|
+
systemctl stop unattended-upgrades.service || true
|
|
26
|
+
systemctl disable unattended-upgrades.service || true
|
|
27
|
+
systemctl stop apt-daily.service || true
|
|
28
|
+
systemctl disable apt-daily.service || true
|
|
29
|
+
systemctl stop apt-daily-upgrade.service || true
|
|
30
|
+
systemctl disable apt-daily-upgrade.service || true
|
|
31
|
+
|
|
32
|
+
# Forcefully kill any remaining lock holders
|
|
33
|
+
kill_apt_processes
|
|
34
|
+
|
|
35
|
+
# Force remove locks if they still exist (The Nuclear Option)
|
|
36
|
+
rm -f /var/lib/dpkg/lock*
|
|
37
|
+
rm -f /var/lib/apt/lists/lock*
|
|
38
|
+
rm -f /var/cache/apt/archives/lock
|
|
39
|
+
dpkg --configure -a || true
|
|
40
|
+
# -----------------------------------------------
|
|
41
|
+
|
|
42
|
+
# 1. System Updates
|
|
43
|
+
echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
|
|
44
|
+
apt-get update
|
|
45
|
+
apt-get install -y python3-pip git curl
|
|
46
|
+
|
|
47
|
+
# 2. Setup Environment
|
|
48
|
+
{% if is_dockerized %}
|
|
49
|
+
echo "🐳 [2/5] Installing Docker..." >> $LOG
|
|
50
|
+
apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
|
|
51
|
+
echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
|
|
52
|
+
apt-get install -y docker-compose-v2
|
|
53
|
+
{% else %}
|
|
54
|
+
echo "🐍 [2/5] Setting up host-based Python environment..." >> $LOG
|
|
55
|
+
apt-get install -y python3-venv python3-dev build-essential
|
|
56
|
+
{% endif %}
|
|
57
|
+
|
|
58
|
+
# 3. Setup Reverse Proxy
|
|
59
|
+
{% if is_dockerized or install_caddy %}
|
|
60
|
+
echo "📦 [3/5] Installing Caddy..." >> $LOG
|
|
61
|
+
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
|
|
62
|
+
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
63
|
+
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
|
|
64
|
+
apt-get update
|
|
65
|
+
apt-get install -y caddy
|
|
66
|
+
{% else %}
|
|
67
|
+
echo "🛡️ [3/5] Skipping Caddy for host deployment (setup manual reverse proxy if needed)." >> $LOG
|
|
68
|
+
{% endif %}
|
|
69
|
+
|
|
70
|
+
{% if domain %}
|
|
71
|
+
# Dynamically generate Caddyfile content
|
|
72
|
+
echo "🔒 Writing Caddyfile for {{ domain }}..." >> $LOG
|
|
73
|
+
cat << EOF > /etc/caddy/Caddyfile
|
|
74
|
+
{{ domain }}:80, {{ domain }}:443 {
|
|
75
|
+
reverse_proxy localhost:{{ port | default(8000) }}
|
|
76
|
+
tls {{ email }}
|
|
77
|
+
}
|
|
78
|
+
EOF
|
|
79
|
+
{% endif %}
|
|
80
|
+
|
|
81
|
+
{% if domain %}
|
|
82
|
+
echo "🚀 [5/5] Starting Caddy..." >> $LOG
|
|
83
|
+
systemctl restart caddy
|
|
84
|
+
{% else %}
|
|
85
|
+
echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
|
|
86
|
+
{% endif %}
|
|
87
|
+
|
|
88
|
+
# Finish
|
|
89
|
+
echo "✅ SETUP SCRIPT COMPLETE" >> $LOG
|
|
90
|
+
touch /root/setup_complete
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# docker-compose.yml template for multi-service deployments
|
|
2
|
+
# Generated by Xenfra for microservices
|
|
3
|
+
|
|
4
|
+
services:
|
|
5
|
+
{% for service in services %}
|
|
6
|
+
{{ service.name }}:
|
|
7
|
+
build: {{ service.path }}
|
|
8
|
+
ports:
|
|
9
|
+
- "{{ service.port }}:{{ service.port }}"
|
|
10
|
+
{% if service.command %}
|
|
11
|
+
command: {{ service.command }}
|
|
12
|
+
{% elif service.entrypoint %}
|
|
13
|
+
{% if service.framework == 'fastapi' %}
|
|
14
|
+
command: uvicorn {{ service.entrypoint }} --host 0.0.0.0 --port {{ service.port }}
|
|
15
|
+
{% elif service.framework == 'flask' %}
|
|
16
|
+
command: gunicorn {{ service.entrypoint }} -b 0.0.0.0:{{ service.port }}
|
|
17
|
+
{% elif service.framework == 'django' %}
|
|
18
|
+
command: gunicorn {{ service.entrypoint }} --bind 0.0.0.0:{{ service.port }}
|
|
19
|
+
{% endif %}
|
|
20
|
+
{% endif %}
|
|
21
|
+
{% if service.env %}
|
|
22
|
+
environment:
|
|
23
|
+
{% for key, value in service.env.items() %}
|
|
24
|
+
- {{ key }}={{ value }}
|
|
25
|
+
{% endfor %}
|
|
26
|
+
{% endif %}
|
|
27
|
+
restart: unless-stopped
|
|
28
|
+
|
|
29
|
+
{% endfor %}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# docker-compose.yml template
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
app:
|
|
5
|
-
build: .
|
|
6
|
-
ports:
|
|
7
|
-
- "{{ port | default(8000) }}:{{ port | default(8000) }}"
|
|
8
|
-
{% if command and command != 'None' %}
|
|
9
|
-
command: {{ command }}
|
|
10
|
-
{% else %}
|
|
11
|
-
command: ["uvicorn", "{{ entrypoint | default('src.main:app') }}", "--host", "0.0.0.0", "--port", "{{ port | default(8000) }}"]
|
|
12
|
-
{% endif %}
|
|
13
|
-
{% if database == 'postgres' or database == 'postgresql' %}
|
|
14
|
-
depends_on:
|
|
15
|
-
- db
|
|
16
|
-
environment:
|
|
17
|
-
- DATABASE_URL=postgresql://{{ db_user | default('user') }}:{{ db_password | default('password') }}@db:5432/{{ db_name | default('appdb') }}
|
|
18
|
-
|
|
19
|
-
db:
|
|
20
|
-
image: postgres:15-alpine
|
|
21
|
-
volumes:
|
|
22
|
-
- postgres_data:/var/lib/postgresql/data/
|
|
23
|
-
environment:
|
|
24
|
-
- POSTGRES_USER={{ db_user | default('user') }}
|
|
25
|
-
- POSTGRES_PASSWORD={{ db_password | default('password') }}
|
|
26
|
-
- POSTGRES_DB={{ db_name | default('appdb') }}
|
|
27
|
-
|
|
28
|
-
volumes:
|
|
29
|
-
postgres_data:
|
|
30
|
-
{% endif %}
|
|
1
|
+
# docker-compose.yml template
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
app:
|
|
5
|
+
build: .
|
|
6
|
+
ports:
|
|
7
|
+
- "{{ port | default(8000) }}:{{ port | default(8000) }}"
|
|
8
|
+
{% if command and command != 'None' %}
|
|
9
|
+
command: {{ command }}
|
|
10
|
+
{% else %}
|
|
11
|
+
command: ["uvicorn", "{{ entrypoint | default('src.main:app') }}", "--host", "0.0.0.0", "--port", "{{ port | default(8000) }}"]
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% if database == 'postgres' or database == 'postgresql' %}
|
|
14
|
+
depends_on:
|
|
15
|
+
- db
|
|
16
|
+
environment:
|
|
17
|
+
- DATABASE_URL=postgresql://{{ db_user | default('user') }}:{{ db_password | default('password') }}@db:5432/{{ db_name | default('appdb') }}
|
|
18
|
+
|
|
19
|
+
db:
|
|
20
|
+
image: postgres:15-alpine
|
|
21
|
+
volumes:
|
|
22
|
+
- postgres_data:/var/lib/postgresql/data/
|
|
23
|
+
environment:
|
|
24
|
+
- POSTGRES_USER={{ db_user | default('user') }}
|
|
25
|
+
- POSTGRES_PASSWORD={{ db_password | default('password') }}
|
|
26
|
+
- POSTGRES_DB={{ db_name | default('appdb') }}
|
|
27
|
+
|
|
28
|
+
volumes:
|
|
29
|
+
postgres_data:
|
|
30
|
+
{% endif %}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: xenfra-sdk
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: Xenfra SDK: Core engine and utilities for the Xenfra platform.
|
|
5
|
+
Author: xenfra-cloud
|
|
6
|
+
Author-email: xenfra-cloud <xenfracloud@gmail.com>
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: Topic :: System :: Systems Administration
|
|
14
|
+
Requires-Dist: fabric>=3.2.2
|
|
15
|
+
Requires-Dist: python-digitalocean>=1.17.0
|
|
16
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
17
|
+
Requires-Dist: rich>=14.2.0
|
|
18
|
+
Requires-Dist: sqlmodel>=0.0.16
|
|
19
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Requires-Dist: jinja2>=3.1.3
|
|
22
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
23
|
+
Requires-Dist: passlib>=1.7.4
|
|
24
|
+
Requires-Dist: cryptography>=41.0.0
|
|
25
|
+
Requires-Dist: pytest>=8.0.0 ; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-mock>=3.12.0 ; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-cov>=4.0.0 ; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.21.0 ; extra == 'dev'
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Project-URL: Homepage, https://github.com/xenfra-cloud/xenfra-sdk
|
|
31
|
+
Project-URL: Issues, https://github.com/xenfra-cloud/xenfra-sdk/issues
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Xenfra SDK (The Engine) 📦
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/xenfra-sdk/)
|
|
38
|
+
[](https://opensource.org/licenses/MIT)
|
|
39
|
+
[](https://pypi.org/project/xenfra-sdk/)
|
|
40
|
+
|
|
41
|
+
The core infrastructure automation engine behind **Xenfra** (The Sovereign Cloud OS). This SDK provides the primitives for deploying, managing, and diagnosing applications on DigitalOcean with "Zen Mode" auto-healing.
|
|
42
|
+
|
|
43
|
+
## 🚀 Features
|
|
44
|
+
|
|
45
|
+
- **InfraEngine**: A robust 9-phase deployment pipeline (Setup -> Asset Gen -> Droplet -> Code -> Build -> Health).
|
|
46
|
+
- **Dockerizer**: Deterministic Dockerfile and Compose generation using Jinja2 templates.
|
|
47
|
+
- **Zen Mode**: Utilities to automatically heal common failures (e.g., locked dpkg, exhausted ports).
|
|
48
|
+
- **Privacy-First**: Built-in PII scrubbing for logs before they touch any AI services.
|
|
49
|
+
- **Security**: Fernet encryption for tokens and RS256 JWT validation helpers.
|
|
50
|
+
|
|
51
|
+
## 📦 Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install xenfra-sdk
|
|
55
|
+
# or with uv
|
|
56
|
+
uv add xenfra-sdk
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 🛠️ Usage
|
|
60
|
+
|
|
61
|
+
### 1. Initialize the Engine
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from xenfra_sdk import XenfraClient, InfraEngine
|
|
65
|
+
|
|
66
|
+
# Authenticate (Token usually comes from the CLI)
|
|
67
|
+
client = XenfraClient(token="xenfra_...")
|
|
68
|
+
engine = InfraEngine(client)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Deploy a Project
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
project_path = "/path/to/my-fastapi-app"
|
|
75
|
+
|
|
76
|
+
# The engine handles detection (Python/Node), dockerization, and provisioning
|
|
77
|
+
deployment = await engine.deploy(
|
|
78
|
+
path=project_path,
|
|
79
|
+
project_id="proj_123",
|
|
80
|
+
env_vars={"DATABASE_URL": "..."}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
print(f"🚀 Deployed successfully to: http://{deployment.ip_address}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. Diagnose a Failure
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from xenfra_sdk.intelligence import diagnose_failure
|
|
90
|
+
|
|
91
|
+
logs = client.deployments.get_logs(deployment.id)
|
|
92
|
+
analysis = await diagnose_failure(logs)
|
|
93
|
+
|
|
94
|
+
print(f"Diagnosis: {analysis.root_cause}")
|
|
95
|
+
print(f"Suggested Fix: {analysis.suggestion}")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 🔗 The Xenfra Ecosystem
|
|
99
|
+
|
|
100
|
+
This SDK is the "Body" of the Xenfra Open Core architecture:
|
|
101
|
+
|
|
102
|
+
- **[xenfra-cli](https://github.com/xenfracloud/xenfra-cli)**: The Terminal Interface (Uses this SDK).
|
|
103
|
+
- **[xenfra-mcp](https://github.com/xenfracloud/xenfra-mcp)**: The AI Agent Interface (Uses this SDK).
|
|
104
|
+
- **xenfra-platform**: The Private SaaS Backend (Uses this SDK).
|
|
105
|
+
|
|
106
|
+
## 🤝 Contributing
|
|
107
|
+
|
|
108
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
109
|
+
|
|
110
|
+
1. Clone: `git clone https://github.com/xenfracloud/xenfra-sdk`
|
|
111
|
+
2. Install: `uv sync`
|
|
112
|
+
3. Test: `pytest`
|
|
113
|
+
|
|
114
|
+
## 📄 License
|
|
115
|
+
|
|
116
|
+
MIT © [Xenfra Cloud](https://xenfra.tech)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
xenfra_sdk/__init__.py,sha256=ZPdW5mFBa9UbmJXRjyBeodbIHWCQsOvmJ2MmUn0aApY,1420
|
|
2
|
+
xenfra_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
xenfra_sdk/cli/main.py,sha256=541nlIUYFFeu4h1sCXivaHMC7SqpskazI0YocM8ylh4,7958
|
|
4
|
+
xenfra_sdk/client.py,sha256=88M-ram8wDVfVEPpa3q1z4hXToBg4kSOgsIBOLXxsBo,3597
|
|
5
|
+
xenfra_sdk/client_with_hooks.py,sha256=iN-xTGdeSPizktM6UG-aZEsuwQc5OgosNYUf1_Tq4Dc,10046
|
|
6
|
+
xenfra_sdk/config.py,sha256=gaT4k5iJgW9guNVmlnYkCFGDSU1_er4LRZA2CgfKmJ0,588
|
|
7
|
+
xenfra_sdk/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
xenfra_sdk/db/models.py,sha256=ysAvkbVuLdOjhD2iA-oJ1xggPrNBsUNLY3Cfm-FFJ_Q,682
|
|
9
|
+
xenfra_sdk/db/session.py,sha256=0MA0404QU9eUabDgTqi-wNIUP0DpIKKG-OvB4Jzf7rc,885
|
|
10
|
+
xenfra_sdk/dependencies.py,sha256=WHGfIrEYkss5yuBd_uOFrB6lPBWM2X0mEuG26ILAjXI,1211
|
|
11
|
+
xenfra_sdk/detection.py,sha256=t8FA_AaNphvv-G0dGL6hLYqOdC9an6-QnVrtFoiTd7M,13993
|
|
12
|
+
xenfra_sdk/dockerizer.py,sha256=KuVGcS5RacR91fGo_6pPlQ4wvJYqnenz0C6x9JoLPWU,7291
|
|
13
|
+
xenfra_sdk/engine.py,sha256=1APOo3DWQBeZscYs9Ay6BdYrp0VzialZiz06L3X4gng,35710
|
|
14
|
+
xenfra_sdk/exceptions.py,sha256=aMVtDVlzG7-FT2G_b-pJSuuey22B4YvC-b-L37GaImM,477
|
|
15
|
+
xenfra_sdk/manifest.py,sha256=49wfCr0VK9AJBCF8HGOJ_K0ru8iUbjRDczH3MPzPJBc,6613
|
|
16
|
+
xenfra_sdk/mcp_client.py,sha256=NZtQz_qK_8i504rVPXlE1vPdzt75hg8Lkp4d8BA8dk0,5777
|
|
17
|
+
xenfra_sdk/models.py,sha256=qSUvtsBMaiTKCHxOcdgY9ghJc-rwwZEOHMp1qiTuvMI,7198
|
|
18
|
+
xenfra_sdk/orchestrator.py,sha256=vRRBC9dl8A8HwQ7gHGwzC31MeZ7aXvyqhfjK4t4Yvno,27211
|
|
19
|
+
xenfra_sdk/patterns.json,sha256=xHxbc0ogHDwysMczi30_hW1Ylfdsf-nsQdAom7RZ4KI,446
|
|
20
|
+
xenfra_sdk/privacy.py,sha256=Bscv7bopCQTeJhvU8Z2jxdBfc5tCZDY5kuODonTcgSk,5509
|
|
21
|
+
xenfra_sdk/recipes.py,sha256=-LLMz1ye6sqHb9zg3YGhOXzYO6-S9I13xTEKhca7C5U,947
|
|
22
|
+
xenfra_sdk/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
xenfra_sdk/resources/base.py,sha256=5n-HTKAnIX2lTgXwio0xtwoaBn-nksjdm8qRTpe3iDk,81
|
|
24
|
+
xenfra_sdk/resources/deployments.py,sha256=kqSxxAwJx_3TveNH-075RQH9IbQ9w-qJ9uM29CETuJU,11941
|
|
25
|
+
xenfra_sdk/resources/files.py,sha256=opdxZt6GWMU-qu5ltfWfv2hm8TscdaK-r9o4k743Irs,3087
|
|
26
|
+
xenfra_sdk/resources/intelligence.py,sha256=_jCIqny-gTV5cBjC6RF5CAs86xzXUKuoqNSAtkNnIYY,3560
|
|
27
|
+
xenfra_sdk/resources/projects.py,sha256=EsCVXmqkhWl_Guz_8WDQDi3kAm1Wyg1rjXcyAigPD6E,3712
|
|
28
|
+
xenfra_sdk/security.py,sha256=6vMZpbglhkRGBVVj4RCTu45-MCnQ15wt94-996zmaT8,1199
|
|
29
|
+
xenfra_sdk/security_scanner.py,sha256=US9QdMjHdTUkqObrGPHvDPxMP0QXCxmwK5e28d8KT2E,12957
|
|
30
|
+
xenfra_sdk/templates/Caddyfile.j2,sha256=PVXffF6dQN06xZ5KyiaSBTK31742v3GN4ISSwiJAXC4,320
|
|
31
|
+
xenfra_sdk/templates/Dockerfile.j2,sha256=qEMnFo2kfYNWaeTpyjh6qeKciHv0dBBNxSVRmnmAIQQ,1176
|
|
32
|
+
xenfra_sdk/templates/cloud-init.sh.j2,sha256=xOwf-VERYXnL8vNMU13SnrmRX0H-hEh3l1A4zSmLG0c,2999
|
|
33
|
+
xenfra_sdk/templates/docker-compose-multi.yml.j2,sha256=PWSPdWsGb-sWJ-XCutMdHiz-uhChIwEN6QMaZ0_Spxs,911
|
|
34
|
+
xenfra_sdk/templates/docker-compose.yml.j2,sha256=TQ__p3-TYAUbU0RNeZCxTjJ9gt81-Rry1B1QnuPzBzc,935
|
|
35
|
+
xenfra_sdk/utils.py,sha256=d8eCjjV32QwqoJa759CEcETnnsjG5qVKDLQ84yYtlus,3898
|
|
36
|
+
xenfra_sdk-0.2.4.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
37
|
+
xenfra_sdk-0.2.4.dist-info/METADATA,sha256=-YUayzDL4AnUeQI4lXbfjx_l5_P4Psd62qfeglVCxr4,3982
|
|
38
|
+
xenfra_sdk-0.2.4.dist-info/RECORD,,
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: xenfra-sdk
|
|
3
|
-
Version: 0.2.2
|
|
4
|
-
Summary: Xenfra SDK: Core engine and utilities for the Xenfra platform.
|
|
5
|
-
Author: xenfra-cloud
|
|
6
|
-
Author-email: xenfra-cloud <xenfracloud@gmail.com>
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
-
Classifier: Topic :: System :: Systems Administration
|
|
14
|
-
Requires-Dist: fabric>=3.2.2
|
|
15
|
-
Requires-Dist: python-digitalocean>=1.17.0
|
|
16
|
-
Requires-Dist: python-dotenv>=1.2.1
|
|
17
|
-
Requires-Dist: rich>=14.2.0
|
|
18
|
-
Requires-Dist: sqlmodel>=0.0.16
|
|
19
|
-
Requires-Dist: pyyaml>=6.0.1
|
|
20
|
-
Requires-Dist: httpx>=0.27.0
|
|
21
|
-
Requires-Dist: jinja2>=3.1.3
|
|
22
|
-
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
23
|
-
Requires-Dist: passlib>=1.7.4
|
|
24
|
-
Requires-Dist: cryptography>=41.0.0
|
|
25
|
-
Requires-Python: >=3.13
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
|
|
28
|
-
# Xenfra Python SDK
|
|
29
|
-
|
|
30
|
-
The official, open-source Python SDK for interacting with the Xenfra API.
|
|
31
|
-
|
|
32
|
-
This SDK provides a simple and Pythonic interface for developers and AI Agents to programmatically manage infrastructure, deployments, and other platform resources.
|
|
33
|
-
|
|
34
|
-
## Installation
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pip install xenfra-sdk
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Basic Usage
|
|
41
|
-
|
|
42
|
-
Initialize the client with your API token (or ensure the `XENFRA_TOKEN` environment variable is set).
|
|
43
|
-
|
|
44
|
-
```python
|
|
45
|
-
import os
|
|
46
|
-
from xenfra_sdk import XenfraClient
|
|
47
|
-
from xenfra_sdk.exceptions import XenfraAPIError
|
|
48
|
-
|
|
49
|
-
client = XenfraClient(token=os.getenv("XENFRA_TOKEN"))
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
projects = client.projects.list()
|
|
53
|
-
for p in projects:
|
|
54
|
-
print(f"Found project: {p.name} (Status: {p.status})")
|
|
55
|
-
except XenfraAPIError as e:
|
|
56
|
-
print(f"API Error: {e.detail}")
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Usage for Agentic Workflows
|
|
60
|
-
|
|
61
|
-
The Xenfra SDK is designed to be used as a "tool" by AI Agents (e.g., OpenAI Assistants). The Pydantic models are compatible with function-calling schemas, allowing an agent to easily call these methods.
|
|
62
|
-
|
|
63
|
-
Here is a conceptual example of how an agent might use the SDK to fulfill a user's request.
|
|
64
|
-
|
|
65
|
-
```python
|
|
66
|
-
# This is a conceptual representation of an agent's internal logic.
|
|
67
|
-
# The agent would be configured with functions that call these SDK methods.
|
|
68
|
-
|
|
69
|
-
def list_all_projects():
|
|
70
|
-
"""Lists all available projects in the Xenfra account."""
|
|
71
|
-
return client.projects.list()
|
|
72
|
-
|
|
73
|
-
def create_new_deployment(project_name: str, git_repo: str, branch: str = "main"):
|
|
74
|
-
"""
|
|
75
|
-
Creates a new deployment for a project.
|
|
76
|
-
|
|
77
|
-
Args:
|
|
78
|
-
project_name: The name for the new deployment.
|
|
79
|
-
git_repo: The URL of the git repository to deploy.
|
|
80
|
-
branch: The branch to deploy (defaults to 'main').
|
|
81
|
-
"""
|
|
82
|
-
return client.deployments.create(
|
|
83
|
-
project_name=project_name,
|
|
84
|
-
git_repo=git_repo,
|
|
85
|
-
branch=branch,
|
|
86
|
-
framework="fastapi" # Framework detection would be part of a more complex agent
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
# --- Agent Execution Flow ---
|
|
90
|
-
|
|
91
|
-
# User prompt: "Deploy my new app from github.com/user/my-app"
|
|
92
|
-
|
|
93
|
-
# 1. Agent decides which tool to use: `create_new_deployment`
|
|
94
|
-
# 2. Agent extracts parameters:
|
|
95
|
-
# - project_name = "my-app" (inferred)
|
|
96
|
-
# - git_repo = "https://github.com/user/my-app"
|
|
97
|
-
# 3. Agent calls the tool:
|
|
98
|
-
# create_new_deployment(
|
|
99
|
-
# project_name="my-app",
|
|
100
|
-
# git_repo="https://github.com/user/my-app"
|
|
101
|
-
# )
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Error Handling
|
|
105
|
-
|
|
106
|
-
The SDK uses custom exceptions for clear error handling. All API-related errors will raise a `XenfraAPIError`, which contains the `status_code` and a `detail` message from the API response.
|
|
107
|
-
|
|
108
|
-
```python
|
|
109
|
-
from xenfra_sdk.exceptions import XenfraAPIError, AuthenticationError
|
|
110
|
-
|
|
111
|
-
try:
|
|
112
|
-
# Make an API call
|
|
113
|
-
...
|
|
114
|
-
except AuthenticationError as e:
|
|
115
|
-
print("Authentication failed. Please check your token.")
|
|
116
|
-
except XenfraAPIError as e:
|
|
117
|
-
print(f"An API error occurred with status {e.status_code}: {e.detail}")
|
|
118
|
-
```
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
xenfra_sdk/__init__.py,sha256=ILBGPKNWJjEwvLWxYD2ulOYLD43nf3-Xu71FwcraH5c,488
|
|
2
|
-
xenfra_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
xenfra_sdk/cli/main.py,sha256=9uQja07LxLfBCHeCRlDCStK1X248h9kMRPep6iFShyk,8184
|
|
4
|
-
xenfra_sdk/client.py,sha256=QrielXkhYw4CBw3Qr7VA91279BMsS0SLUAMGRecpTa8,3687
|
|
5
|
-
xenfra_sdk/client_with_hooks.py,sha256=iN-xTGdeSPizktM6UG-aZEsuwQc5OgosNYUf1_Tq4Dc,10046
|
|
6
|
-
xenfra_sdk/config.py,sha256=omb3SQMAk5NXOuCrLZe4bp_bX7F0SXA1ERJ5PdDaxMU,614
|
|
7
|
-
xenfra_sdk/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
xenfra_sdk/db/models.py,sha256=oNT9UhYzr_SgzDJdPu5fF6IiiztWjm2tHZzpIAYVJ4Y,706
|
|
9
|
-
xenfra_sdk/db/session.py,sha256=ul6tFBBDKU8UErJsZ-g7b8cryLr9-yA6jGY3d8fD15Q,853
|
|
10
|
-
xenfra_sdk/dependencies.py,sha256=k7tiy_5dayr_iQx_i2klGeNjGWhxfivGVC38SpvQvzE,1250
|
|
11
|
-
xenfra_sdk/dockerizer.py,sha256=E-8oqmaS-Cb06B8lRj3iZpby43ObqhUMQU_5msAdYRM,7428
|
|
12
|
-
xenfra_sdk/engine.py,sha256=gFiARsp9FcUuCULfmnbA9jkIL3u3sLVn_dWA0zt4hSc,30096
|
|
13
|
-
xenfra_sdk/exceptions.py,sha256=FaKctVJNMFIw09G8Lm2yd_DHhSngGcyh2j_BTgXMM60,496
|
|
14
|
-
xenfra_sdk/mcp_client.py,sha256=GPsVJtWT87G7k_GxePATLfCqFkYFFNIbpW5AsZi4Bhk,5931
|
|
15
|
-
xenfra_sdk/models.py,sha256=2Zrvi7EWAzpw1ArcYa8HmF3WjuRhzYCYpK8XyMh2XE4,7382
|
|
16
|
-
xenfra_sdk/patterns.json,sha256=RBuQdU59UEXF5pxUvcWq_ZegsK0iUfh4wusWaY77qxo,459
|
|
17
|
-
xenfra_sdk/privacy.py,sha256=ksGf5L9PVtRP-xZS3T-Gj7MKfexTqIMgbFLoYkIESOE,5662
|
|
18
|
-
xenfra_sdk/recipes.py,sha256=jSFlPLIze3rKpBaeFKNVkWESQzBXWGkoSwSH1jwx0Vs,973
|
|
19
|
-
xenfra_sdk/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
xenfra_sdk/resources/base.py,sha256=C6BuZfhR-oU5ecHSfkGG6ZLU6MHGXUyCWoy1F-yTIf8,84
|
|
21
|
-
xenfra_sdk/resources/deployments.py,sha256=AUNixKvyW4imq4W2iKeXcbxQUW82SrUeY8ZG4rr6HLI,10549
|
|
22
|
-
xenfra_sdk/resources/files.py,sha256=t6jVvzN71J_soPj7MphzRaYxGeJ0X9H98nTY8euEfR8,3188
|
|
23
|
-
xenfra_sdk/resources/intelligence.py,sha256=Y11K6_iXfm2QKTbH1vUmt45MifLoVtZtlHEkqbzmTzs,3418
|
|
24
|
-
xenfra_sdk/resources/projects.py,sha256=EsCVXmqkhWl_Guz_8WDQDi3kAm1Wyg1rjXcyAigPD6E,3712
|
|
25
|
-
xenfra_sdk/security.py,sha256=Px887RRb1BUDXaPUrxmQITJ1mHyOyupCJqEDZ78F7Tk,1240
|
|
26
|
-
xenfra_sdk/templates/Dockerfile.j2,sha256=XDZv_93Yzk_qn9QF6g-uo2TaFphiwoj9JbANvBSZ0BE,1178
|
|
27
|
-
xenfra_sdk/templates/cloud-init.sh.j2,sha256=fxQP2GVAAVVvDAqlOVH3eNmeKSTFQ2soErQQRD5RX3U,3072
|
|
28
|
-
xenfra_sdk/templates/docker-compose.yml.j2,sha256=rJ6Z2UwHwu-FN137WrY29mbOK1yYBtTXq89xRolB_zw,965
|
|
29
|
-
xenfra_sdk/utils.py,sha256=d8eCjjV32QwqoJa759CEcETnnsjG5qVKDLQ84yYtlus,3898
|
|
30
|
-
xenfra_sdk-0.2.2.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
31
|
-
xenfra_sdk-0.2.2.dist-info/METADATA,sha256=BqHTZBO_b9zPMXLrb4brk_kcSFI91EOzNgmMlx2xrnw,3980
|
|
32
|
-
xenfra_sdk-0.2.2.dist-info/RECORD,,
|
|
File without changes
|