All checks were successful
CI / Windows build (push) Successful in 7m47s
Redesign the optional FastAPI companion around vault files (manifest / PUT/GET/DELETE + OCR jobs) instead of legacy strokes_json notes. Wire a client Server settings panel for health/login. Polish shell UX: l10n for settings/home/board, sticky-board empty state, and a narrow-screen diagnostics FAB. Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
"""Tests for v1 vault API (async, uses shared conftest)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
|
|
async def _token(client) -> str:
|
|
r = await client.post(
|
|
"/api/v1/auth/register",
|
|
json={"username": "vault_user", "password": "password123"},
|
|
)
|
|
if r.status_code == 409:
|
|
r = await client.post(
|
|
"/api/v1/auth/login",
|
|
json={"username": "vault_user", "password": "password123"},
|
|
)
|
|
assert r.status_code in (200, 201), r.text
|
|
return r.json()["token"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_health(client):
|
|
r = await client.get("/api/v1/health")
|
|
assert r.status_code == 200
|
|
body = r.json()
|
|
assert body["api"] == "v1"
|
|
assert "vault" in body["features"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_vault_roundtrip(client, tmp_path, monkeypatch):
|
|
from badnote_server.config import settings
|
|
|
|
monkeypatch.setattr(settings, "vault_path", str(tmp_path / "vaults"))
|
|
|
|
token = await _token(client)
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
|
|
files = {"upload": ("hello.txt", b"hello vault", "text/plain")}
|
|
r = await client.put(
|
|
"/api/v1/vault/files/NotebookA/hello.txt",
|
|
headers=headers,
|
|
files=files,
|
|
)
|
|
assert r.status_code == 200, r.text
|
|
assert r.json()["path"] == "NotebookA/hello.txt"
|
|
assert r.json()["size"] == 11
|
|
|
|
r = await client.get("/api/v1/vault/manifest", headers=headers)
|
|
assert r.status_code == 200
|
|
paths = [f["path"] for f in r.json()["files"]]
|
|
assert "NotebookA/hello.txt" in paths
|
|
|
|
r = await client.get(
|
|
"/api/v1/vault/files/NotebookA/hello.txt",
|
|
headers=headers,
|
|
)
|
|
assert r.status_code == 200
|
|
assert r.content == b"hello vault"
|
|
|
|
r = await client.delete(
|
|
"/api/v1/vault/files/NotebookA/hello.txt",
|
|
headers=headers,
|
|
)
|
|
assert r.status_code == 200
|
|
r = await client.get(
|
|
"/api/v1/vault/files/NotebookA/hello.txt",
|
|
headers=headers,
|
|
)
|
|
assert r.status_code == 404
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_path_escape_rejected(client, tmp_path, monkeypatch):
|
|
from badnote_server.config import settings
|
|
|
|
monkeypatch.setattr(settings, "vault_path", str(tmp_path / "vaults"))
|
|
|
|
token = await _token(client)
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
files = {"upload": ("x", b"nope", "application/octet-stream")}
|
|
r = await client.put(
|
|
"/api/v1/vault/files/../../etc/passwd",
|
|
headers=headers,
|
|
files=files,
|
|
)
|
|
assert r.status_code in (400, 404)
|