A wheel whose top-level module is `app` collides with anything else in a user's venv, so the package that is about to be published takes the name it is published under. Only the Python package moves; the repo, the Docker WORKDIR and the compose project keep theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
"""A session the server will not accept must say so as an auth failure.
|
|
|
|
The client clears the stored token and returns to the login screen on 401. Any
|
|
other status leaves the browser holding a token that can never work, stuck on a
|
|
page that will not load.
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import timedelta
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from fluksio.core import security
|
|
from fluksio.core.config import settings
|
|
|
|
PROTECTED = [
|
|
f"{settings.API_V1_STR}/users/me",
|
|
f"{settings.API_V1_STR}/flows/",
|
|
]
|
|
|
|
|
|
def token_for(subject: str) -> str:
|
|
return security.create_access_token(subject, timedelta(days=1))
|
|
|
|
|
|
def test_no_token_is_unauthorised(client: TestClient) -> None:
|
|
for path in PROTECTED:
|
|
assert client.get(path).status_code == 401
|
|
|
|
|
|
def test_a_token_we_did_not_sign_is_unauthorised(client: TestClient) -> None:
|
|
headers = {"Authorization": "Bearer not.a.real.token"}
|
|
for path in PROTECTED:
|
|
assert client.get(path, headers=headers).status_code == 401
|
|
|
|
|
|
def test_a_token_for_a_user_who_is_gone_is_unauthorised(
|
|
client: TestClient,
|
|
) -> None:
|
|
# Properly signed, but the user it names no longer exists — which is what a
|
|
# browser holds after the database is reset.
|
|
headers = {"Authorization": f"Bearer {token_for(str(uuid.uuid4()))}"}
|
|
for path in PROTECTED:
|
|
response = client.get(path, headers=headers)
|
|
assert response.status_code == 401, path
|