generated from coulomb/repo-seed
Align naming with coulomb.social reuse-surface conventions
Some checks failed
ci / validate-registry (push) Has been cancelled
Some checks failed
ci / validate-registry (push) Has been cancelled
Use reuse.coulomb.social, REUSE_SURFACE_URL/TOKEN env vars, reuse-surface image and reuse-surface-env secret. Replace reuse-surface-hub entrypoint with reuse-surface serve; CLI uses --base-url.
This commit is contained in:
@@ -130,11 +130,11 @@ artifacts.
|
|||||||
.venv/bin/reuse-surface federation compose
|
.venv/bin/reuse-surface federation compose
|
||||||
.venv/bin/reuse-surface graph --check
|
.venv/bin/reuse-surface graph --check
|
||||||
|
|
||||||
# Federation hub service (local)
|
# Federation service (local)
|
||||||
# REUSE_SURFACE_HUB_TOKEN=dev-token reuse-surface-hub
|
# REUSE_SURFACE_TOKEN=dev-token reuse-surface serve
|
||||||
|
|
||||||
# Hub CLI (against deployed or local hub)
|
# Hub CLI (against deployed or local service)
|
||||||
# REUSE_SURFACE_HUB_URL=http://127.0.0.1:8000 reuse-surface hub status
|
# REUSE_SURFACE_URL=http://127.0.0.1:8000 reuse-surface hub status
|
||||||
|
|
||||||
# Automated tests
|
# Automated tests
|
||||||
.venv/bin/pytest -q
|
.venv/bin/pytest -q
|
||||||
|
|||||||
10
Dockerfile
10
Dockerfile
@@ -8,11 +8,11 @@ COPY schemas ./schemas
|
|||||||
|
|
||||||
RUN pip install --no-cache-dir .
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
ENV REUSE_SURFACE_HUB_HOST=0.0.0.0
|
ENV REUSE_SURFACE_HOST=0.0.0.0
|
||||||
ENV REUSE_SURFACE_HUB_PORT=8000
|
ENV REUSE_SURFACE_PORT=8000
|
||||||
ENV REUSE_SURFACE_HUB_DB=/data/hub.db
|
ENV REUSE_SURFACE_DB=/data/reuse.db
|
||||||
ENV REUSE_SURFACE_HUB_CACHE_DIR=/data/cache
|
ENV REUSE_SURFACE_CACHE_DIR=/data/cache
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD ["reuse-surface-hub"]
|
CMD ["reuse-surface", "serve"]
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Federation Hub — Kubernetes Deployment
|
|
||||||
|
|
||||||
Companion to **RAILIANCE-WP-0007** (`railiance-apps` Helm release).
|
|
||||||
|
|
||||||
## Image
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t gitea.coulomb.social/coulomb/reuse-surface-hub:<tag> .
|
|
||||||
docker push gitea.coulomb.social/coulomb/reuse-surface-hub:<tag>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Required environment
|
|
||||||
|
|
||||||
| Variable | Purpose |
|
|
||||||
|---|---|
|
|
||||||
| `REUSE_SURFACE_HUB_TOKEN` | Bearer token for write API |
|
|
||||||
| `REUSE_SURFACE_HUB_DB` | SQLite path (default `/data/hub.db`) |
|
|
||||||
| `REUSE_SURFACE_HUB_CACHE_DIR` | Remote index cache (default `/data/cache`) |
|
|
||||||
|
|
||||||
Mount a PVC at `/data` for persistence.
|
|
||||||
|
|
||||||
## Probes
|
|
||||||
|
|
||||||
- Liveness/readiness: `GET /health` on port `8000`
|
|
||||||
|
|
||||||
## Client configuration
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export REUSE_SURFACE_HUB_URL=https://reuse-hub.whywhynot.de
|
|
||||||
export REUSE_SURFACE_HUB_TOKEN=<write-token>
|
|
||||||
reuse-surface hub status
|
|
||||||
```
|
|
||||||
39
docs/deploy/reuse-kubernetes.md
Normal file
39
docs/deploy/reuse-kubernetes.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# reuse-surface Service — Kubernetes Deployment
|
||||||
|
|
||||||
|
Companion to **RAILIANCE-WP-0007** (`railiance-apps` Helm release).
|
||||||
|
|
||||||
|
## Image
|
||||||
|
|
||||||
|
Repository: `gitea.coulomb.social/coulomb/reuse-surface` (Gitea org `coulomb`, repo `reuse-surface`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t gitea.coulomb.social/coulomb/reuse-surface:<tag> .
|
||||||
|
docker push gitea.coulomb.social/coulomb/reuse-surface:<tag>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Required environment
|
||||||
|
|
||||||
|
| Variable | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `REUSE_SURFACE_TOKEN` | Bearer token for write API |
|
||||||
|
| `REUSE_SURFACE_DB` | SQLite path (default `/data/reuse.db`) |
|
||||||
|
| `REUSE_SURFACE_CACHE_DIR` | Remote index cache (default `/data/cache`) |
|
||||||
|
|
||||||
|
Mount a PVC at `/data` for persistence. Inject secrets via Kubernetes Secret
|
||||||
|
`reuse-surface-env`.
|
||||||
|
|
||||||
|
## Probes
|
||||||
|
|
||||||
|
- Liveness/readiness: `GET /health` on port `8000`
|
||||||
|
|
||||||
|
## Public URL
|
||||||
|
|
||||||
|
`https://reuse.coulomb.social`
|
||||||
|
|
||||||
|
## Client configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export REUSE_SURFACE_URL=https://reuse.coulomb.social
|
||||||
|
export REUSE_SURFACE_TOKEN=<write-token>
|
||||||
|
reuse-surface hub status
|
||||||
|
```
|
||||||
@@ -23,7 +23,6 @@ dev = [
|
|||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
reuse-surface = "reuse_surface.cli:main"
|
reuse-surface = "reuse_surface.cli:main"
|
||||||
reuse-surface-hub = "reuse_surface.hub.app:main"
|
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = ["."]
|
where = ["."]
|
||||||
|
|||||||
@@ -192,13 +192,20 @@ def cmd_catalog(args: argparse.Namespace) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _hub_url(args: argparse.Namespace) -> str | None:
|
def _service_url(args: argparse.Namespace) -> str | None:
|
||||||
return getattr(args, "hub_url", None)
|
return getattr(args, "base_url", None)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_serve(args: argparse.Namespace) -> int:
|
||||||
|
from reuse_surface.hub.app import main as serve_main
|
||||||
|
|
||||||
|
serve_main()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def cmd_hub_status(args: argparse.Namespace) -> int:
|
def cmd_hub_status(args: argparse.Namespace) -> int:
|
||||||
try:
|
try:
|
||||||
status, payload = hub_client.hub_status(_hub_url(args))
|
status, payload = hub_client.hub_status(_service_url(args))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
print(f"error: {exc}", file=sys.stderr)
|
print(f"error: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -211,7 +218,7 @@ def cmd_hub_status(args: argparse.Namespace) -> int:
|
|||||||
|
|
||||||
def cmd_hub_list(args: argparse.Namespace) -> int:
|
def cmd_hub_list(args: argparse.Namespace) -> int:
|
||||||
try:
|
try:
|
||||||
status, payload = hub_client.hub_list(_hub_url(args))
|
status, payload = hub_client.hub_list(_service_url(args))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
print(f"error: {exc}", file=sys.stderr)
|
print(f"error: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -227,7 +234,7 @@ def cmd_hub_list(args: argparse.Namespace) -> int:
|
|||||||
|
|
||||||
def cmd_hub_show(args: argparse.Namespace) -> int:
|
def cmd_hub_show(args: argparse.Namespace) -> int:
|
||||||
try:
|
try:
|
||||||
status, payload = hub_client.hub_show(args.repo, _hub_url(args))
|
status, payload = hub_client.hub_show(args.repo, _service_url(args))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
print(f"error: {exc}", file=sys.stderr)
|
print(f"error: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -249,7 +256,7 @@ def cmd_hub_register(args: argparse.Namespace) -> int:
|
|||||||
if args.description:
|
if args.description:
|
||||||
body["description"] = args.description
|
body["description"] = args.description
|
||||||
try:
|
try:
|
||||||
status, payload = hub_client.hub_register(body, _hub_url(args))
|
status, payload = hub_client.hub_register(body, _service_url(args))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
print(f"error: {exc}", file=sys.stderr)
|
print(f"error: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -276,7 +283,7 @@ def cmd_hub_update(args: argparse.Namespace) -> int:
|
|||||||
print("error: no fields to update", file=sys.stderr)
|
print("error: no fields to update", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
try:
|
try:
|
||||||
status, payload = hub_client.hub_update(args.repo, body, _hub_url(args))
|
status, payload = hub_client.hub_update(args.repo, body, _service_url(args))
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
print(f"error: {exc}", file=sys.stderr)
|
print(f"error: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -412,10 +419,13 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
)
|
)
|
||||||
graph.set_defaults(func=cmd_graph)
|
graph.set_defaults(func=cmd_graph)
|
||||||
|
|
||||||
hub = subparsers.add_parser("hub", help="federation hub client")
|
serve = subparsers.add_parser("serve", help="run federation service API")
|
||||||
|
serve.set_defaults(func=cmd_serve)
|
||||||
|
|
||||||
|
hub = subparsers.add_parser("hub", help="federation service client")
|
||||||
hub.add_argument(
|
hub.add_argument(
|
||||||
"--hub-url",
|
"--base-url",
|
||||||
help="hub base URL (or set REUSE_SURFACE_HUB_URL)",
|
help="service base URL (or set REUSE_SURFACE_URL)",
|
||||||
)
|
)
|
||||||
hub_sub = hub.add_subparsers(dest="hub_command", required=True)
|
hub_sub = hub.add_subparsers(dest="hub_command", required=True)
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ HUB_VERSION = "0.1.0"
|
|||||||
|
|
||||||
|
|
||||||
def _db_path() -> Path:
|
def _db_path() -> Path:
|
||||||
return Path(os.environ.get("REUSE_SURFACE_HUB_DB", "/data/hub.db"))
|
return Path(os.environ.get("REUSE_SURFACE_DB", "/data/reuse.db"))
|
||||||
|
|
||||||
|
|
||||||
def _cache_dir() -> Path:
|
def _cache_dir() -> Path:
|
||||||
return Path(os.environ.get("REUSE_SURFACE_HUB_CACHE_DIR", "/data/cache"))
|
return Path(os.environ.get("REUSE_SURFACE_CACHE_DIR", "/data/cache"))
|
||||||
|
|
||||||
|
|
||||||
def _write_token() -> str:
|
def _write_token() -> str:
|
||||||
return os.environ.get("REUSE_SURFACE_HUB_TOKEN", "")
|
return os.environ.get("REUSE_SURFACE_TOKEN", "")
|
||||||
|
|
||||||
|
|
||||||
def _store() -> HubStore:
|
def _store() -> HubStore:
|
||||||
@@ -41,7 +41,7 @@ def _require_auth(authorization: str | None = Header(default=None)) -> None:
|
|||||||
write_token = _write_token()
|
write_token = _write_token()
|
||||||
if not write_token:
|
if not write_token:
|
||||||
raise _http_error(
|
raise _http_error(
|
||||||
503, "misconfigured", "REUSE_SURFACE_HUB_TOKEN is not configured"
|
503, "misconfigured", "REUSE_SURFACE_TOKEN is not configured"
|
||||||
)
|
)
|
||||||
if not authorization or not authorization.startswith("Bearer "):
|
if not authorization or not authorization.startswith("Bearer "):
|
||||||
raise _http_error(401, "unauthorized", "Bearer token required")
|
raise _http_error(401, "unauthorized", "Bearer token required")
|
||||||
@@ -56,7 +56,7 @@ def create_app() -> FastAPI:
|
|||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
def health() -> dict[str, str]:
|
def health() -> dict[str, str]:
|
||||||
return {"status": "ok", "service": "reuse-surface-hub", "version": HUB_VERSION}
|
return {"status": "ok", "service": "reuse-surface", "version": HUB_VERSION}
|
||||||
|
|
||||||
@app.get("/v1/repos")
|
@app.get("/v1/repos")
|
||||||
def list_repos() -> dict[str, Any]:
|
def list_repos() -> dict[str, Any]:
|
||||||
@@ -138,6 +138,6 @@ def create_app() -> FastAPI:
|
|||||||
def main() -> None:
|
def main() -> None:
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
host = os.environ.get("REUSE_SURFACE_HUB_HOST", "0.0.0.0")
|
host = os.environ.get("REUSE_SURFACE_HOST", "0.0.0.0")
|
||||||
port = int(os.environ.get("REUSE_SURFACE_HUB_PORT", "8000"))
|
port = int(os.environ.get("REUSE_SURFACE_PORT", "8000"))
|
||||||
uvicorn.run(create_app(), host=host, port=port, reload=False)
|
uvicorn.run(create_app(), host=host, port=port, reload=False)
|
||||||
@@ -7,7 +7,7 @@ from typing import Any
|
|||||||
from reuse_surface.federation import compose_federated_index
|
from reuse_surface.federation import compose_federated_index
|
||||||
from reuse_surface.hub.store import HubStore
|
from reuse_surface.hub.store import HubStore
|
||||||
|
|
||||||
DEFAULT_DOMAIN = os.environ.get("REUSE_SURFACE_HUB_DOMAIN", "helix_forge")
|
DEFAULT_DOMAIN = os.environ.get("REUSE_SURFACE_DOMAIN", "helix_forge")
|
||||||
|
|
||||||
|
|
||||||
def registrations_to_manifest(
|
def registrations_to_manifest(
|
||||||
|
|||||||
@@ -7,17 +7,17 @@ import urllib.request
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def hub_base_url(explicit: str | None = None) -> str:
|
def service_base_url(explicit: str | None = None) -> str:
|
||||||
base = (explicit or os.environ.get("REUSE_SURFACE_HUB_URL", "")).rstrip("/")
|
base = (explicit or os.environ.get("REUSE_SURFACE_URL", "")).rstrip("/")
|
||||||
if not base:
|
if not base:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"hub URL not configured; set REUSE_SURFACE_HUB_URL or pass --hub-url"
|
"service URL not configured; set REUSE_SURFACE_URL or pass --base-url"
|
||||||
)
|
)
|
||||||
return base
|
return base
|
||||||
|
|
||||||
|
|
||||||
def hub_token() -> str | None:
|
def service_token() -> str | None:
|
||||||
return os.environ.get("REUSE_SURFACE_HUB_TOKEN")
|
return os.environ.get("REUSE_SURFACE_TOKEN")
|
||||||
|
|
||||||
|
|
||||||
def _request(
|
def _request(
|
||||||
@@ -49,24 +49,24 @@ def _request(
|
|||||||
|
|
||||||
|
|
||||||
def hub_status(base_url: str | None = None) -> tuple[int, Any]:
|
def hub_status(base_url: str | None = None) -> tuple[int, Any]:
|
||||||
return _request("GET", f"{hub_base_url(base_url)}/health")
|
return _request("GET", f"{service_base_url(base_url)}/health")
|
||||||
|
|
||||||
|
|
||||||
def hub_list(base_url: str | None = None) -> tuple[int, Any]:
|
def hub_list(base_url: str | None = None) -> tuple[int, Any]:
|
||||||
return _request("GET", f"{hub_base_url(base_url)}/v1/repos")
|
return _request("GET", f"{service_base_url(base_url)}/v1/repos")
|
||||||
|
|
||||||
|
|
||||||
def hub_show(repo: str, base_url: str | None = None) -> tuple[int, Any]:
|
def hub_show(repo: str, base_url: str | None = None) -> tuple[int, Any]:
|
||||||
return _request("GET", f"{hub_base_url(base_url)}/v1/repos/{repo}")
|
return _request("GET", f"{service_base_url(base_url)}/v1/repos/{repo}")
|
||||||
|
|
||||||
|
|
||||||
def hub_register(payload: dict[str, Any], base_url: str | None = None) -> tuple[int, Any]:
|
def hub_register(payload: dict[str, Any], base_url: str | None = None) -> tuple[int, Any]:
|
||||||
token = hub_token()
|
token = service_token()
|
||||||
if not token:
|
if not token:
|
||||||
raise ValueError("REUSE_SURFACE_HUB_TOKEN is required for register")
|
raise ValueError("REUSE_SURFACE_TOKEN is required for register")
|
||||||
return _request(
|
return _request(
|
||||||
"POST",
|
"POST",
|
||||||
f"{hub_base_url(base_url)}/v1/repos",
|
f"{service_base_url(base_url)}/v1/repos",
|
||||||
token=token,
|
token=token,
|
||||||
body=payload,
|
body=payload,
|
||||||
)
|
)
|
||||||
@@ -75,12 +75,12 @@ def hub_register(payload: dict[str, Any], base_url: str | None = None) -> tuple[
|
|||||||
def hub_update(
|
def hub_update(
|
||||||
repo: str, payload: dict[str, Any], base_url: str | None = None
|
repo: str, payload: dict[str, Any], base_url: str | None = None
|
||||||
) -> tuple[int, Any]:
|
) -> tuple[int, Any]:
|
||||||
token = hub_token()
|
token = service_token()
|
||||||
if not token:
|
if not token:
|
||||||
raise ValueError("REUSE_SURFACE_HUB_TOKEN is required for update")
|
raise ValueError("REUSE_SURFACE_TOKEN is required for update")
|
||||||
return _request(
|
return _request(
|
||||||
"PATCH",
|
"PATCH",
|
||||||
f"{hub_base_url(base_url)}/v1/repos/{repo}",
|
f"{service_base_url(base_url)}/v1/repos/{repo}",
|
||||||
token=token,
|
token=token,
|
||||||
body=payload,
|
body=payload,
|
||||||
)
|
)
|
||||||
@@ -21,7 +21,7 @@ Companion deployment workplan: `railiance-apps` **RAILIANCE-WP-0007**.
|
|||||||
|
|
||||||
| Item | Value |
|
| Item | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Default production URL | `https://reuse-hub.whywhynot.de` (confirm at deploy) |
|
| Default production URL | `https://reuse.coulomb.social` |
|
||||||
| API prefix | `/v1` |
|
| API prefix | `/v1` |
|
||||||
| Read formats | JSON (default), YAML via `Accept: application/yaml` or `?format=yaml` |
|
| Read formats | JSON (default), YAML via `Accept: application/yaml` or `?format=yaml` |
|
||||||
| Write content type | `application/json` |
|
| Write content type | `application/json` |
|
||||||
@@ -30,8 +30,8 @@ Environment variables for clients:
|
|||||||
|
|
||||||
| Variable | Purpose |
|
| Variable | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `REUSE_SURFACE_HUB_URL` | Hub base URL (no trailing slash) |
|
| `REUSE_SURFACE_URL` | Service base URL (no trailing slash) |
|
||||||
| `REUSE_SURFACE_HUB_TOKEN` | Bearer token for write operations |
|
| `REUSE_SURFACE_TOKEN` | Bearer token for write operations |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Environment variables for clients:
|
|||||||
Write requests must include:
|
Write requests must include:
|
||||||
|
|
||||||
```http
|
```http
|
||||||
Authorization: Bearer <REUSE_SURFACE_HUB_TOKEN>
|
Authorization: Bearer <REUSE_SURFACE_TOKEN>
|
||||||
```
|
```
|
||||||
|
|
||||||
Missing or invalid token → `401 Unauthorized`.
|
Missing or invalid token → `401 Unauthorized`.
|
||||||
@@ -88,7 +88,7 @@ Liveness/readiness probe.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"service": "reuse-surface-hub",
|
"service": "reuse-surface",
|
||||||
"version": "0.1.0"
|
"version": "0.1.0"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -232,10 +232,10 @@ Non-2xx responses use:
|
|||||||
|
|
||||||
| Env var | Required | Purpose |
|
| Env var | Required | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `REUSE_SURFACE_HUB_TOKEN` | yes | Write API bearer token |
|
| `REUSE_SURFACE_TOKEN` | yes | Write API bearer token |
|
||||||
| `REUSE_SURFACE_HUB_DB` | no | SQLite path (default `/data/hub.db`) |
|
| `REUSE_SURFACE_DB` | no | SQLite path (default `/data/reuse.db`) |
|
||||||
| `REUSE_SURFACE_HUB_CACHE_DIR` | no | Remote index cache (default `/data/cache`) |
|
| `REUSE_SURFACE_CACHE_DIR` | no | Remote index cache (default `/data/cache`) |
|
||||||
| `REUSE_SURFACE_HUB_DOMAIN` | no | Default federated `domain` (default `helix_forge`) |
|
| `REUSE_SURFACE_DOMAIN` | no | Default federated `domain` (default `helix_forge`) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -249,13 +249,16 @@ Non-2xx responses use:
|
|||||||
| `reuse-surface hub register ...` | `POST /v1/repos` |
|
| `reuse-surface hub register ...` | `POST /v1/repos` |
|
||||||
| `reuse-surface hub update ...` | `PATCH /v1/repos/{repo}` |
|
| `reuse-surface hub update ...` | `PATCH /v1/repos/{repo}` |
|
||||||
|
|
||||||
Global flags: `--hub-url`, env `REUSE_SURFACE_HUB_URL`, `REUSE_SURFACE_HUB_TOKEN`.
|
Run locally: `reuse-surface serve`. Global client flags: `--base-url`, env
|
||||||
|
`REUSE_SURFACE_URL`, `REUSE_SURFACE_TOKEN`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Deployment reference
|
## 9. Deployment reference
|
||||||
|
|
||||||
- Image: `gitea.coulomb.social/coulomb/reuse-surface-hub:<tag>`
|
- Image: `gitea.coulomb.social/coulomb/reuse-surface:<tag>`
|
||||||
|
- Public URL: `https://reuse.coulomb.social`
|
||||||
|
- Secret: `reuse-surface-env` with `REUSE_SURFACE_TOKEN`
|
||||||
- Probe path: `/health`
|
- Probe path: `/health`
|
||||||
- Persistence: PVC at `/data` (SQLite + fetch cache)
|
- Persistence: PVC at `/data` (SQLite + fetch cache)
|
||||||
- Helm release: `railiance-apps` RAILIANCE-WP-0007
|
- Helm release: `railiance-apps` RAILIANCE-WP-0007
|
||||||
@@ -32,9 +32,9 @@ capabilities:
|
|||||||
def hub_client(tmp_path, monkeypatch):
|
def hub_client(tmp_path, monkeypatch):
|
||||||
db_path = tmp_path / "hub.db"
|
db_path = tmp_path / "hub.db"
|
||||||
cache_dir = tmp_path / "cache"
|
cache_dir = tmp_path / "cache"
|
||||||
monkeypatch.setenv("REUSE_SURFACE_HUB_TOKEN", "test-token")
|
monkeypatch.setenv("REUSE_SURFACE_TOKEN", "test-token")
|
||||||
monkeypatch.setenv("REUSE_SURFACE_HUB_DB", str(db_path))
|
monkeypatch.setenv("REUSE_SURFACE_DB", str(db_path))
|
||||||
monkeypatch.setenv("REUSE_SURFACE_HUB_CACHE_DIR", str(cache_dir))
|
monkeypatch.setenv("REUSE_SURFACE_CACHE_DIR", str(cache_dir))
|
||||||
app = create_app()
|
app = create_app()
|
||||||
with TestClient(app) as client:
|
with TestClient(app) as client:
|
||||||
yield client
|
yield client
|
||||||
|
|||||||
@@ -92,15 +92,15 @@ Writes `docs/graph/capability-graph.mmd` and `docs/graph/index.html`.
|
|||||||
Client for the federation hub service (REUSE-WP-0011).
|
Client for the federation hub service (REUSE-WP-0011).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export REUSE_SURFACE_HUB_URL=https://reuse-hub.whywhynot.de
|
export REUSE_SURFACE_URL=https://reuse.coulomb.social
|
||||||
export REUSE_SURFACE_HUB_TOKEN=<write-token>
|
export REUSE_SURFACE_TOKEN=<write-token>
|
||||||
reuse-surface hub status
|
reuse-surface hub status
|
||||||
reuse-surface hub list
|
reuse-surface hub list
|
||||||
reuse-surface hub register --repo state-hub --url https://.../capabilities.yaml
|
reuse-surface hub register --repo state-hub --url https://.../capabilities.yaml
|
||||||
reuse-surface hub update --repo state-hub --enabled true
|
reuse-surface hub update --repo state-hub --enabled true
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the hub service locally: `reuse-surface-hub` (requires `REUSE_SURFACE_HUB_TOKEN`).
|
Run the service locally: `REUSE_SURFACE_TOKEN=dev-token reuse-surface serve`
|
||||||
|
|
||||||
## Export format
|
## Export format
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ for discovery without cloning every repo.
|
|||||||
| Operations | Container image, deployment manifests, TLS ingress, documented runbook |
|
| Operations | Container image, deployment manifests, TLS ingress, documented runbook |
|
||||||
| Dogfood | `reuse-surface` and at least one sibling repo registered via the hub |
|
| Dogfood | `reuse-surface` and at least one sibling repo registered via the hub |
|
||||||
|
|
||||||
**Proposed public URL (confirm in T05):** `https://reuse-hub.whywhynot.de`
|
**Public URL:** `https://reuse.coulomb.social`
|
||||||
|
|
||||||
## Design decisions (draft)
|
## Design decisions (draft)
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ for discovery without cloning every repo.
|
|||||||
`url` sources (reuse WP-0010 fetch/cache logic) and merges into
|
`url` sources (reuse WP-0010 fetch/cache logic) and merges into
|
||||||
`GET /v1/federated` output. Local-only `index` paths are **not** valid hub
|
`GET /v1/federated` output. Local-only `index` paths are **not** valid hub
|
||||||
registrations unless expressed as published raw URLs.
|
registrations unless expressed as published raw URLs.
|
||||||
- **Auth (MVP):** Token-based write access via `REUSE_SURFACE_HUB_TOKEN` /
|
- **Auth (MVP):** Token-based write access via `REUSE_SURFACE_TOKEN` /
|
||||||
`Authorization: Bearer`; read endpoints public for agent discovery.
|
`Authorization: Bearer`; read endpoints public for agent discovery.
|
||||||
- **Persistence (MVP):** SQLite on a PVC inside the hub container. Postgres
|
- **Persistence (MVP):** SQLite on a PVC inside the hub container. Postgres
|
||||||
via cnpg is a follow-up if multi-replica or backup requirements emerge.
|
via cnpg is a follow-up if multi-replica or backup requirements emerge.
|
||||||
@@ -100,7 +100,7 @@ plus hub metadata (`registered_at`, `updated_at`, `registered_by`).
|
|||||||
## CLI sketch (T03 refines)
|
## CLI sketch (T03 refines)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Configure hub endpoint (env REUSE_SURFACE_HUB_URL or --hub-url)
|
# Configure service URL (env REUSE_SURFACE_URL or --base-url)
|
||||||
reuse-surface hub status
|
reuse-surface hub status
|
||||||
reuse-surface hub list
|
reuse-surface hub list
|
||||||
reuse-surface hub register --repo state-hub \
|
reuse-surface hub register --repo state-hub \
|
||||||
@@ -167,8 +167,9 @@ state_hub_task_id: "38fec6ce-23c0-4157-8350-7d112b9e8264"
|
|||||||
Extend `reuse-surface` CLI with `hub` subcommands:
|
Extend `reuse-surface` CLI with `hub` subcommands:
|
||||||
|
|
||||||
- `register`, `update`, `show`, `list`, `status`
|
- `register`, `update`, `show`, `list`, `status`
|
||||||
- `--hub-url` flag and `REUSE_SURFACE_HUB_URL` env support
|
- `--base-url` flag and `REUSE_SURFACE_URL` env support
|
||||||
- `REUSE_SURFACE_HUB_TOKEN` for authenticated writes
|
- `REUSE_SURFACE_TOKEN` for authenticated writes
|
||||||
|
- `reuse-surface serve` to run the API locally or in container
|
||||||
- Document in `tools/README.md` and `AGENTS.md`
|
- Document in `tools/README.md` and `AGENTS.md`
|
||||||
|
|
||||||
## Containerize And Publish Deployment Artifacts
|
## Containerize And Publish Deployment Artifacts
|
||||||
@@ -183,8 +184,8 @@ state_hub_task_id: "24eec9ad-21fc-4f0b-8671-72d955b15e68"
|
|||||||
Provide:
|
Provide:
|
||||||
|
|
||||||
- `Dockerfile` for the hub service
|
- `Dockerfile` for the hub service
|
||||||
- Example k8s manifests or Helm values template under `deploy/` or `docs/deploy/`
|
- Example k8s manifests or Helm values template under `docs/deploy/`
|
||||||
- Image naming convention: `gitea.coulomb.social/coulomb/reuse-surface-hub:<tag>`
|
- Image: `gitea.coulomb.social/coulomb/reuse-surface:<tag>`
|
||||||
- CI job or documented build/push steps (coordinate with `railiance-forge`
|
- CI job or documented build/push steps (coordinate with `railiance-forge`
|
||||||
registry guidance)
|
registry guidance)
|
||||||
|
|
||||||
@@ -199,10 +200,10 @@ state_hub_task_id: "7f26a70f-7b7d-413d-8162-931c6dffef6a"
|
|||||||
|
|
||||||
Deploy the hub as a governed release on `railiance01`:
|
Deploy the hub as a governed release on `railiance01`:
|
||||||
|
|
||||||
- Confirm hostname (default `reuse-hub.whywhynot.de`) and DNS A record
|
- Confirm DNS for `reuse.coulomb.social` (coulomb.social zone)
|
||||||
- Traefik ingress + cert-manager TLS
|
- Traefik ingress + cert-manager TLS
|
||||||
- PVC for SQLite data
|
- PVC for SQLite data
|
||||||
- Inject hub write token via SOPS/sealed secret
|
- Inject `REUSE_SURFACE_TOKEN` via Secret `reuse-surface-env` (SOPS handoff)
|
||||||
- Verify `GET /health` and `GET /v1/federated` from workstation and from cluster
|
- Verify `GET /health` and `GET /v1/federated` from workstation and from cluster
|
||||||
|
|
||||||
**Blocked on:** DNS decision, operator secret provisioning, and
|
**Blocked on:** DNS decision, operator secret provisioning, and
|
||||||
|
|||||||
Reference in New Issue
Block a user