Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,17 @@ Docker:

---

## 8. CryptoLabs Public Sites Are Not Routed Here

This repository is the fleet proxy product for customer datacenters. It never
routes CryptoLabs' own public sites (`*.cryptolabs.co.za` on wk01). Those are
served by the common proxy in `cryptolabs-ai-platform`:
https://github.com/cryptolabsza/cryptolabs-ai-platform/tree/dev/services/nginx-configs
— change public-site routing by a PR there. `tests/test_edge_ownership.py`
keeps wk01 routes out of the shipped nginx config and templates.

---

## Summary

| Policy | One-Liner |
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ Unified reverse proxy and fleet management landing page for CryptoLabs products.
| Grafana | `/grafana/` | Metrics visualization |
| Prometheus | `/prometheus/` | Metrics collection (with auth) |

### CryptoLabs' own public sites

This product is the fleet proxy for customer datacenters. It does **not** route
CryptoLabs' own public sites under `cryptolabs.co.za`. Those are served by the
common proxy owned by `cryptolabs-ai-platform`
([services/nginx-configs](https://github.com/cryptolabsza/cryptolabs-ai-platform/tree/dev/services/nginx-configs),
deployed by its Synchronized Platform Deployment).
Add or change public-site routing there, not here.

## Quick Start

The easiest way to deploy is through **DC Overview** or **IPMI Monitor** quickstart, which automatically sets up cryptolabs-proxy:
Expand Down
61 changes: 5 additions & 56 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -497,61 +497,10 @@ http {
}

# =====================================================
# Subdomain Services - Proxy to GPU Worker (wk01)
# These services run on 192.168.1.101 behind their own
# nginx with SSL (Let's Encrypt) and service-specific config.
# CryptoLabs' own public sites (kb, api.ai, webui.ai, ipmi-ai, ...) are
# NOT routed by this product. They are served by the common proxy owned by
# cryptolabs-ai-platform (services/nginx-configs), which is the only place
# that ships public-site routing. See that repo before adding any
# *.cryptolabs.co.za server block here.
# =====================================================

server {
listen 80;
server_name kb.cryptolabs.co.za
ipmi-ai.cryptolabs.co.za
webui.ai.cryptolabs.co.za
api.ai.cryptolabs.co.za
tts.cryptolabs.co.za
wpbm.ai.cryptolabs.co.za
framepack.ai.cryptolabs.co.za;

location / {
proxy_pass http://192.168.1.101:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

server {
listen 443 ssl;
http2 on;
server_name kb.cryptolabs.co.za
ipmi-ai.cryptolabs.co.za
webui.ai.cryptolabs.co.za
api.ai.cryptolabs.co.za
tts.cryptolabs.co.za
wpbm.ai.cryptolabs.co.za
framepack.ai.cryptolabs.co.za;

# Use proxy's own certs (wk01 nginx handles real SSL termination)
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols TLSv1.2 TLSv1.3;

location / {
proxy_pass https://192.168.1.101;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffering off;
client_max_body_size 100M;
}
}
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "cryptolabs-proxy"
version = "1.1.9"
version = "1.1.10"
description = "Unified reverse proxy and fleet management landing page for CryptoLabs products"
readme = "README.md"
license = {text = "MIT"}
Expand Down
2 changes: 1 addition & 1 deletion src/cryptolabs_proxy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""CryptoLabs Proxy - Unified reverse proxy for CryptoLabs products."""

__version__ = "1.1.9"
__version__ = "1.1.10"

# Export programmatic setup API
from .setup import (
Expand Down
87 changes: 87 additions & 0 deletions tests/test_edge_ownership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""CryptoLabs' own public wk01 sites are served by the common proxy in
cryptolabs-ai-platform (services/nginx-configs), not by this customer fleet
proxy product. These tests keep wk01 routing out of the shipped nginx config
and templates."""

import re
from pathlib import Path

import pytest

REPOSITORY = Path(__file__).resolve().parents[1]
WK01_ADDRESS = "192.168.1.101"
SERVER_NAME = re.compile(r"^\s*server_name\s+([^;]*);", re.MULTILINE)


def _nginx_files():
files = [REPOSITORY / "nginx" / "nginx.conf"]
files += sorted((REPOSITORY / "src" / "cryptolabs_proxy" / "templates").glob("*.j2"))
return files


def _server_names(text):
names = []
for match in SERVER_NAME.finditer(text):
names.extend(match.group(1).split())
return names


def _rendered_templates(tmp_path):
from cryptolabs_proxy.config import generate_nginx_config
from cryptolabs_proxy.services import DEFAULT_SERVICES

generate_nginx_config(tmp_path, "fleet.example.test", services=dict(DEFAULT_SERVICES))
plain = (tmp_path / "nginx.conf").read_text()
generate_nginx_config(tmp_path, "fleet.example.test", letsencrypt=True, services=dict(DEFAULT_SERVICES))
return [plain, (tmp_path / "nginx.conf").read_text()]


def test_scanned_files_exist():
names = [path.name for path in _nginx_files()]
assert "nginx.conf" in names and "nginx.conf.j2" in names


@pytest.mark.parametrize("path", _nginx_files(), ids=lambda path: path.name)
def test_shipped_nginx_files_do_not_route_to_wk01(path):
assert WK01_ADDRESS not in path.read_text()


@pytest.mark.parametrize("path", _nginx_files(), ids=lambda path: path.name)
def test_shipped_nginx_files_do_not_serve_cryptolabs_co_za_hosts(path):
offenders = [n for n in _server_names(path.read_text()) if n.rstrip(".").endswith(".cryptolabs.co.za")]
assert offenders == []


def test_rendered_template_does_not_route_to_wk01_or_serve_cryptolabs_co_za(tmp_path):
for config in _rendered_templates(tmp_path):
assert "server {" in config
assert WK01_ADDRESS not in config
offenders = [n for n in _server_names(config) if n.rstrip(".").endswith(".cryptolabs.co.za")]
assert offenders == []


def test_nginx_conf_points_to_the_common_proxy():
text = (REPOSITORY / "nginx" / "nginx.conf").read_text()
assert "cryptolabs-ai-platform" in text
assert "services/nginx-configs" in text


def test_readme_points_to_the_common_proxy():
text = (REPOSITORY / "README.md").read_text()
assert "cryptolabs-ai-platform" in text
assert "services/nginx-configs" in text


COMMON_PROXY_LINK = "https://github.com/cryptolabsza/cryptolabs-ai-platform/tree/dev/services/nginx-configs"


def test_readme_links_to_the_common_proxy_and_names_no_hosts():
text = (REPOSITORY / "README.md").read_text()
assert COMMON_PROXY_LINK in text
assert "framepack" not in text


def test_agents_md_forbids_routing_cryptolabs_sites():
text = (REPOSITORY / "AGENTS.md").read_text()
assert "common proxy" in text
assert COMMON_PROXY_LINK in text
13 changes: 13 additions & 0 deletions tests/test_version_consistency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""The package version must be the same in pyproject.toml and __init__.py."""
import re
from pathlib import Path

import cryptolabs_proxy

ROOT = Path(__file__).resolve().parents[1]


def test_pyproject_and_dunder_version_match():
text = (ROOT / "pyproject.toml").read_text()
pyproject = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE).group(1)
assert pyproject == cryptolabs_proxy.__version__
Loading