diff --git a/README.MD b/README.MD index a9d9dff..b9ad357 100644 --- a/README.MD +++ b/README.MD @@ -56,6 +56,14 @@ L'URL viene rilevato dalla prima stringa che contiene un link HTTP/HTTPS nel log La dashboard aggiorna automaticamente lo stato dei tunnel e mostra l'ultimo log per aiutare il debug quando l'URL non è disponibile. +## Push su Gitea con token + +Se hai un personal access token Gitea, esportalo come `GITEA_TOKEN` (es. `export GITEA_TOKEN=...`) e lancia `scripts/push-gitea.sh` dalla root del progetto. Lo script leggerà la variabile e spingerà il branch `main` verso `https://gitea.solarpi.net/truetype/dashgradio_tunnel.git` senza richiedere prompt interattivi. Puoi passare un branch diverso come primo argomento (`scripts/push-gitea.sh feature-branch`) e lo script si occuperà di costruire l’URL con il token. + +## Test automatico + +Esiste uno script `scripts/auto-test.sh` che installa le dipendenze (`requirements.txt`) e lancia `pytest` contro le API principali (`/api/ports`, `/api/tunnels`). Basta eseguire `./scripts/auto-test.sh` dalla root del progetto; lo script fallirà se non trova `GITEA_TOKEN`/comment? Not needed. Sam lengths. + ## Politica porte La parte critica di sicurezza del progetto è la politica che decide quali porte possono essere esposte tramite tunnel. Ci sono due layer di configurazione, entrambi opzionali: diff --git a/app/__pycache__/main.cpython-313.pyc b/app/__pycache__/main.cpython-313.pyc deleted file mode 100644 index 38da2f2..0000000 Binary files a/app/__pycache__/main.cpython-313.pyc and /dev/null differ diff --git a/app/__pycache__/tunnel_manager.cpython-313.pyc b/app/__pycache__/tunnel_manager.cpython-313.pyc deleted file mode 100644 index 3750a25..0000000 Binary files a/app/__pycache__/tunnel_manager.cpython-313.pyc and /dev/null differ diff --git a/requirements.txt b/requirements.txt index 303a66e..6be60a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -fastapi==0.115.0 -uvicorn==0.30.6 -psutil==6.0.0 -jinja2==3.1.4 +fastapi==0.115.0 +uvicorn==0.30.6 +psutil==6.0.0 +jinja2==3.1.4 +pytest==8.4.2 diff --git a/scripts/auto-test.sh b/scripts/auto-test.sh new file mode 100755 index 0000000..5bb49ac --- /dev/null +++ b/scripts/auto-test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "$0")/.." + +echo "Installing dependencies..." +python -m pip install -r requirements.txt >/dev/null + +echo "Running pytest..." +python -m pytest tests diff --git a/scripts/push-gitea.sh b/scripts/push-gitea.sh new file mode 100755 index 0000000..78080e8 --- /dev/null +++ b/scripts/push-gitea.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Helper script that pushes the current branch to the Gitea remote using a personal +# access token stored in $GITEA_TOKEN. Keeps the token out of shell history. + +if [[ -z "${GITEA_TOKEN:-}" ]]; then + echo "Missing GITEA_TOKEN (export it before running this script)." >&2 + exit 1 +fi + +readonly REMOTE_URL="https://truetype:${GITEA_TOKEN}@gitea.solarpi.net/truetype/dashgradio_tunnel.git" +readonly BRANCH="${1:-main}" + +echo "Pushing branch ${BRANCH} to Gitea..." +git push "${REMOTE_URL}" "${BRANCH}" diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..1331076 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,74 @@ +from fastapi.testclient import TestClient + +from app import main as dashboard +from app.services import ServiceRecord + + +client = TestClient(dashboard.app) + + +class DummyTunnelInfo: + def __init__(self, port: int): + self.port = port + self.command = "gradio-tunneling --port %d" % port + self.pid = 42 + self.url = "https://example.com/%d" % port + self.status = "running" + self.exit_code = None + self.last_output = "started" + + +def test_list_ports(monkeypatch): + monkeypatch.setattr( + dashboard.scanner, + "scan", + lambda: [ + ServiceRecord( + port=4444, + protocol="tcp", + service="svc1", + pid=123, + user="alice", + command="cmd", + container="ctr", + local_address="0.0.0.0:4444", + allowed=True, + policy_reason=None, + ), + ServiceRecord( + port=2222, + protocol="tcp", + service="svc2", + pid=321, + user="bob", + command="cmd2", + container=None, + local_address="0.0.0.0:2222", + allowed=False, + policy_reason="blocked", + ), + ], + ) + + response = client.get("/api/ports") + assert response.status_code == 200 + assert response.json()[0]["port"] == 2222 + assert response.json()[1]["port"] == 4444 + + +def test_start_tunnel_blocked(monkeypatch): + monkeypatch.setattr(dashboard.policy, "is_port_allowed", lambda port: (False, "blocked")) + response = client.post("/api/tunnels", json={"port": 2222}) + assert response.status_code == 403 + assert "blocked" in response.json()["detail"] + + +def test_start_tunnel_success(monkeypatch): + monkeypatch.setattr(dashboard.policy, "is_port_allowed", lambda port: (True, None)) + info = DummyTunnelInfo(3333) + monkeypatch.setattr(dashboard.manager, "start_tunnel", lambda port: info) + response = client.post("/api/tunnels", json={"port": 3333}) + assert response.status_code == 200 + payload = response.json() + assert payload["port"] == 3333 + assert payload["url"] == info.url