diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a73ab..0b8b303 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ # Changes - Ensure that curated path and incoming path definitions do not point - outside of the storage-root tree. + outside the storage-root tree. + +- Ensure that default tokens cannot be deleted. # 6.3.2 (2026-07-07) diff --git a/dump_things_service/tests/test_token_endpoints.py b/dump_things_service/tests/test_token_endpoints.py index 0af5019..fd66941 100644 --- a/dump_things_service/tests/test_token_endpoints.py +++ b/dump_things_service/tests/test_token_endpoints.py @@ -1,4 +1,4 @@ -from starlette.status import HTTP_409_CONFLICT +from starlette.status import HTTP_406_NOT_ACCEPTABLE, HTTP_409_CONFLICT from dump_things_service import HTTP_201_CREATED @@ -40,3 +40,14 @@ def test_token_creation(fastapi_client_simple): json=json_record, ) assert response.status_code == HTTP_409_CONFLICT + + +def test_default_token_removal(fastapi_client_simple): + test_client, _, admin_token = fastapi_client_simple + + # Create a token with name 'a' + response = test_client.delete( + '/tokens/test_default_token', + headers={'x-dumpthings-token': admin_token}, + ) + assert response.status_code == HTTP_406_NOT_ACCEPTABLE diff --git a/dump_things_service/token_endpoints.py b/dump_things_service/token_endpoints.py index 8f8d5d8..8cea286 100644 --- a/dump_things_service/token_endpoints.py +++ b/dump_things_service/token_endpoints.py @@ -266,7 +266,20 @@ async def delete_token_with_name( detail = f"token with name '{token_name}' does not exist." raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail=detail) - # Store the new token in the configuration + # Check that the token is not a default token of a collection + default_tokens = { + collection_info.default_token: collection_name + for collection_name, collection_info in abstract_config.collections.items() + } + if token_name in default_tokens: + detail = ( + f"token with name '{token_name}' cannot be deleted because" + 'it is the default token for collection ' + f"'{default_tokens[token_name]}'." + ) + raise HTTPException(status_code=HTTP_406_NOT_ACCEPTABLE, detail=detail) + + # Delete the token from the configuration del abstract_config.tokens[token_name] # Manifest the new configuration