develop #87

Merged
TheFurya merged 3 commits from develop into main 2026-03-22 11:54:27 +01:00
7 changed files with 97 additions and 7 deletions

View File

@@ -5,7 +5,7 @@ status: completed
type: bug
priority: high
created_at: 2026-03-22T09:41:57Z
updated_at: 2026-03-22T09:45:28Z
updated_at: 2026-03-22T09:45:38Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-2fp1

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-95g1
title: 'Crash: Hide edit controls for non-owners in frontend'
status: completed
type: bug
priority: high
created_at: 2026-03-22T09:41:57Z
updated_at: 2026-03-22T09:46:59Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-i2va
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-i2va
Title: Hide edit controls for non-owners in frontend
## Reasons for Scrapping
This crash bean is a false positive. The original task (nuzlocke-tracker-i2va) was already completed and merged to `develop` before this crash bean was created:
- Commit `3bd24fc`: fix: hide edit controls for non-owners in frontend
- Commit `118dbca`: chore: mark bean nuzlocke-tracker-i2va as completed
No additional work required.

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-9rm8
title: 'Crash: Optional TOTP MFA for email/password accounts'
status: scrapped
status: completed
type: bug
priority: high
created_at: 2026-03-22T09:41:57Z
updated_at: 2026-03-22T09:46:14Z
updated_at: 2026-03-22T09:46:30Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-f2hs

View File

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-snft
title: Support ES256 (ECC P-256) JWT keys in backend auth
status: completed
type: bug
priority: normal
created_at: 2026-03-22T10:51:30Z
updated_at: 2026-03-22T10:52:46Z
---
Backend JWKS verification only accepts RS256 algorithm, but Supabase JWT key was switched to ECC P-256 (ES256). This causes 401 errors on all authenticated requests. Fix: accept both RS256 and ES256 in the algorithms list, and update tests accordingly.
## Summary of Changes\n\nAdded ES256 to the accepted JWT algorithms in `_verify_jwt()` so ECC P-256 keys from Supabase are verified correctly alongside RSA keys. Added corresponding test with EC key fixtures.

View File

@@ -5,7 +5,7 @@ status: completed
type: bug
priority: high
created_at: 2026-03-21T21:50:48Z
updated_at: 2026-03-22T09:01:42Z
updated_at: 2026-03-22T09:44:54Z
---
## Problem

View File

@@ -60,7 +60,7 @@ def _verify_jwt_hs256(token: str) -> dict | None:
def _verify_jwt(token: str) -> dict | None:
"""Verify JWT using JWKS (RS256), falling back to HS256 shared secret."""
"""Verify JWT using JWKS (RS256/ES256), falling back to HS256 shared secret."""
client = _get_jwks_client()
if client:
try:
@@ -68,7 +68,7 @@ def _verify_jwt(token: str) -> dict | None:
return jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
algorithms=["RS256", "ES256"],
audience="authenticated",
)
except jwt.InvalidTokenError:

View File

@@ -4,7 +4,7 @@ from uuid import UUID
import jwt
import pytest
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric import ec, rsa
from httpx import ASGITransport, AsyncClient
from app.core.auth import AuthUser, get_current_user, require_admin, require_auth
@@ -73,6 +73,55 @@ def mock_jwks_client(rsa_key_pair):
return mock_client
@pytest.fixture(scope="module")
def ec_key_pair():
"""Generate EC P-256 key pair for testing."""
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
return private_key, public_key
@pytest.fixture
def valid_es256_token(ec_key_pair):
"""Generate a valid ES256 JWT token."""
private_key, _ = ec_key_pair
payload = {
"sub": "user-456",
"email": "ec-user@example.com",
"role": "authenticated",
"aud": "authenticated",
"exp": int(time.time()) + 3600,
}
return jwt.encode(payload, private_key, algorithm="ES256")
@pytest.fixture
def mock_jwks_client_ec(ec_key_pair):
"""Create a mock JWKS client that returns our test EC public key."""
_, public_key = ec_key_pair
mock_client = MagicMock()
mock_signing_key = MagicMock()
mock_signing_key.key = public_key
mock_client.get_signing_key_from_jwt.return_value = mock_signing_key
return mock_client
async def test_get_current_user_valid_es256_token(
valid_es256_token, mock_jwks_client_ec
):
"""Test get_current_user works with ES256 (ECC P-256) tokens."""
with patch("app.core.auth._get_jwks_client", return_value=mock_jwks_client_ec):
class MockRequest:
headers = {"Authorization": f"Bearer {valid_es256_token}"}
user = get_current_user(MockRequest())
assert user is not None
assert user.id == "user-456"
assert user.email == "ec-user@example.com"
assert user.role == "authenticated"
async def test_get_current_user_valid_token(valid_token, mock_jwks_client):
"""Test get_current_user returns user for valid token."""
with patch("app.core.auth._get_jwks_client", return_value=mock_jwks_client):