- shared/ = portable Android-origin sources vendored from deferred/desktop-server (app/build.gradle.kts srcDir repointed; PlaybackController.kt excluded as Android-only) - backend/ = bundled-lite engine (SQLite + inline queue); .venv symlinked from the old checkout, PYTHONPATH pins THIS backend's code over any editable install - repoRoot() resolves this project dir (env SHONAR_REPO still wins); desktop-dev.sh watches shared/ + backend/ - Verified: :app:compileKotlin + :app:test green (23 tests); engine boots on :8010, self-migrates, /healthz ok
35 lines
1.3 KiB
Python
35 lines
1.3 KiB
Python
"""provider-info handshake tests (P2/P3 client probing depends on this)."""
|
|
|
|
|
|
async def test_provider_info_identifies_shonar(client):
|
|
r = await client.get("/api/v1/provider-info")
|
|
assert r.status_code == 200
|
|
body = r.json()
|
|
assert body["kind"] == "shonar"
|
|
assert body["api_version"] == "v1"
|
|
caps = body["capabilities"]
|
|
assert caps["chunked_upload"] is True
|
|
assert caps["account_deletion"] is True
|
|
# test env configures no AI providers -> flags must be false
|
|
assert caps["server_transcription"] is False
|
|
assert caps["server_summary"] is False
|
|
assert body["storage_backend"] in ("local", "s3")
|
|
|
|
|
|
async def test_provider_info_leaks_no_paths_or_secrets(client):
|
|
r = await client.get("/api/v1/provider-info")
|
|
body = r.json()
|
|
# every string value must be a bare identifier, never a filesystem path
|
|
def walk(v):
|
|
if isinstance(v, str):
|
|
assert not v.startswith("/"), f"path-like value in handshake: {v!r}"
|
|
low = v.lower()
|
|
for banned in ("secret", "token", "password", "key"):
|
|
assert banned not in low
|
|
elif isinstance(v, dict):
|
|
for x in v.values():
|
|
walk(x)
|
|
elif isinstance(v, list):
|
|
for x in v:
|
|
walk(x)
|
|
walk(body)
|