34 lines
1.1 KiB
Python
34 lines
1.1 KiB
Python
"""SDK security surface for heavy plugins: vault + multi-method guarded HTTP."""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from app.accounts.ssrf import SsrfError, guarded_request
|
||
|
|
from app.plugins.sdk import sdk
|
||
|
|
|
||
|
|
|
||
|
|
def test_vault_round_trips_secrets() -> None:
|
||
|
|
vault = sdk("calendar").vault
|
||
|
|
secret = b"caldav-app-password-123"
|
||
|
|
blob = vault.encrypt(secret)
|
||
|
|
assert blob != secret # encrypted at rest
|
||
|
|
assert vault.decrypt(blob) == secret
|
||
|
|
|
||
|
|
|
||
|
|
async def test_guarded_request_rejects_non_https() -> None:
|
||
|
|
with pytest.raises(SsrfError, match="https"):
|
||
|
|
await guarded_request("PROPFIND", "http://dav.example/cal/")
|
||
|
|
|
||
|
|
|
||
|
|
async def test_guarded_request_rejects_private_host() -> None:
|
||
|
|
# Resolves to a loopback/private address -> blocked before any connection.
|
||
|
|
with pytest.raises(SsrfError, match="non-public|resolve"):
|
||
|
|
await guarded_request("GET", "https://localhost/")
|
||
|
|
|
||
|
|
|
||
|
|
def test_http_facade_exposes_dav_verbs() -> None:
|
||
|
|
http = sdk("calendar").http
|
||
|
|
for verb in ("request", "get", "put", "delete", "propfind", "report"):
|
||
|
|
assert callable(getattr(http, verb))
|