Add WebDAV backup, statistics, progress and dashboard
- WebDAV uploader: concurrency, request and bandwidth limits, retry with backoff, offline catch-up, encrypted manifests, durability tracking - Automatic unique remote directory claimed with a conditional PUT - AES-256-GCM client-side encryption with keyed blob names - /stats, /progress, /progress/stream and a /dashboard page - Own ctypes inotify binding with a compact watch tree (263 MB -> 76 MB RSS) - Directory-path ignore patterns and a forget command - Indexed range queries instead of LIKE for path prefixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ddf09bea88
commit
7e05e3d26c
@@ -174,3 +174,15 @@ def test_restore_refuses_unsafe_paths(env):
|
||||
os.symlink("/etc", project / "escape")
|
||||
r = client.post(f"/api/v1/versions/{vid}/restore", json={"target_path": str(project / "escape" / "x")})
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
def test_forget(env):
|
||||
client, project = env
|
||||
root = client.post("/api/v1/roots", json={"path": str(project)}).json()
|
||||
wait_for(lambda: client.get(f"/api/v1/roots/{root['id']}").json()["baseline_state"] == "done")
|
||||
dry = client.post("/api/v1/forget", json={"path": str(project / "src")}).json()
|
||||
assert dry["dry_run"] and dry["files"] == 1 and dry["versions"] == 1
|
||||
done = client.post("/api/v1/forget", json={"path": str(project / "src"), "dry_run": False}).json()
|
||||
assert done["files_removed"] == 1 and done["blobs_removed"] == 1
|
||||
assert history(client, project / "src" / "app.py") == []
|
||||
assert history(client, project / "pyproject.toml") # outside the forgotten tree
|
||||
|
||||
Reference in New Issue
Block a user