raise 404 in case if repository is unknown

This commit is contained in:
Evgenii Alekseev 2023-10-16 15:13:13 +03:00
parent c5bd862ae9
commit 2b207e1a89
18 changed files with 43 additions and 16 deletions

View File

@ -202,6 +202,7 @@ Again, the most checks can be performed by `make check` command, though some add
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, # exception raised by this method 400: {"description": "Bad data is supplied", "schema": ErrorSchema}, # exception raised by this method
401: {"description": "Authorization required", "schema": ErrorSchema}, # should be always presented 401: {"description": "Authorization required", "schema": ErrorSchema}, # should be always presented
403: {"description": "Access is forbidden", "schema": ErrorSchema}, # should be always presented 403: {"description": "Access is forbidden", "schema": ErrorSchema}, # should be always presented
404: {"description": "Repository is unknown", "schema": ErrorSchema}, # include if BaseView.service() method is called
500: {"description": "Internal server error", "schema": ErrorSchema}, # should be always presented 500: {"description": "Internal server error", "schema": ErrorSchema}, # should be always presented
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -70,9 +70,8 @@ class Lock(LazyLogging):
repository_id(RepositoryId): repository unique identifier repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
""" """
lock_suffix = f"{repository_id.name}_{repository_id.architecture}"
self.path: Path | None = \ self.path: Path | None = \
args.lock.with_stem(f"{args.lock.stem}_{lock_suffix}") if args.lock is not None else None args.lock.with_stem(f"{args.lock.stem}_{repository_id.id}") if args.lock is not None else None
self.force: bool = args.force self.force: bool = args.force
self.unsafe: bool = args.unsafe self.unsafe: bool = args.unsafe

View File

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from aiohttp_cors import CorsViewMixin # type: ignore[import-untyped] from aiohttp_cors import CorsViewMixin # type: ignore[import-untyped]
from aiohttp.web import HTTPBadRequest, Request, StreamResponse, View from aiohttp.web import HTTPBadRequest, HTTPNotFound, Request, StreamResponse, View
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from typing import Any, TypeVar from typing import Any, TypeVar
@ -245,10 +245,16 @@ class BaseView(View, CorsViewMixin):
Returns: Returns:
Watcher: build status watcher instance. If no repository provided, it will return the first one Watcher: build status watcher instance. If no repository provided, it will return the first one
Raises:
HTTPNotFound: if no repository found
""" """
if repository_id is None: if repository_id is None:
repository_id = self.repository_id() repository_id = self.repository_id()
return self.services[repository_id] try:
return self.services[repository_id]
except KeyError:
raise HTTPNotFound(reason=f"Repository {repository_id.id} is unknown")
async def username(self) -> str | None: async def username(self) -> str | None:
""" """

View File

@ -46,6 +46,7 @@ class AddView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -48,7 +48,7 @@ class PGPView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema}, 404: {"description": "PGP key is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -75,7 +75,7 @@ class PGPView(BaseView):
try: try:
key = self.sign.key_download(server, key) key = self.sign.key_download(server, key)
except Exception: except Exception:
raise HTTPNotFound raise HTTPNotFound(reason=f"Key {key} is unknown")
return json_response({"key": key}) return json_response({"key": key})

View File

@ -45,7 +45,7 @@ class ProcessView(BaseView):
200: {"description": "Success response", "schema": ProcessSchema}, 200: {"description": "Success response", "schema": ProcessSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Not found", "schema": ErrorSchema}, 404: {"description": "Process is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],

View File

@ -46,6 +46,7 @@ class RebuildView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -46,6 +46,7 @@ class RemoveView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -46,6 +46,7 @@ class RequestView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -46,6 +46,7 @@ class UpdateView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -101,7 +101,7 @@ class UploadView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Not found", "schema": ErrorSchema}, 404: {"description": "Repository is unknown or endpoint is disabled", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -51,6 +51,7 @@ class LogsView(BaseView):
204: {"description": "Success response"}, 204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [DELETE_PERMISSION]}], security=[{"token": [DELETE_PERMISSION]}],
@ -78,7 +79,7 @@ class LogsView(BaseView):
200: {"description": "Success response", "schema": LogsSchema}, 200: {"description": "Success response", "schema": LogsSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema}, 404: {"description": "Package base and/or repository are unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -101,7 +102,7 @@ class LogsView(BaseView):
try: try:
_, status = self.service().package_get(package_base) _, status = self.service().package_get(package_base)
except UnknownPackageError: except UnknownPackageError:
raise HTTPNotFound raise HTTPNotFound(reason=f"Package {package_base} is unknown")
logs = self.service().logs_get(package_base) logs = self.service().logs_get(package_base)
response = { response = {
@ -120,6 +121,7 @@ class LogsView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -52,6 +52,7 @@ class PackageView(BaseView):
204: {"description": "Success response"}, 204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [DELETE_PERMISSION]}], security=[{"token": [DELETE_PERMISSION]}],
@ -79,7 +80,7 @@ class PackageView(BaseView):
200: {"description": "Success response", "schema": PackageStatusSchema(many=True)}, 200: {"description": "Success response", "schema": PackageStatusSchema(many=True)},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema}, 404: {"description": "Package base and/or repository are unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -103,7 +104,7 @@ class PackageView(BaseView):
try: try:
package, status = self.service(repository_id).package_get(package_base) package, status = self.service(repository_id).package_get(package_base)
except UnknownPackageError: except UnknownPackageError:
raise HTTPNotFound raise HTTPNotFound(reason=f"Package {package_base} is unknown")
response = [ response = [
{ {
@ -123,6 +124,7 @@ class PackageView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -52,6 +52,7 @@ class PackagesView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -90,6 +91,7 @@ class PackagesView(BaseView):
204: {"description": "Success response"}, 204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -51,6 +51,7 @@ class StatusView(BaseView):
200: {"description": "Success response", "schema": InternalStatusSchema}, 200: {"description": "Success response", "schema": InternalStatusSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -84,6 +85,7 @@ class StatusView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Repository is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [POST_PERMISSION]}], security=[{"token": [POST_PERMISSION]}],

View File

@ -47,7 +47,7 @@ class LogsView(BaseView):
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, 400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema}, 401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema}, 403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema}, 404: {"description": "Package base and/or repository are unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema}, 500: {"description": "Internal server error", "schema": ErrorSchema},
}, },
security=[{"token": [GET_PERMISSION]}], security=[{"token": [GET_PERMISSION]}],
@ -71,7 +71,7 @@ class LogsView(BaseView):
try: try:
_, status = self.service().package_get(package_base) _, status = self.service().package_get(package_base)
except UnknownPackageError: except UnknownPackageError:
raise HTTPNotFound raise HTTPNotFound(reason=f"Package {package_base} is unknown")
logs = self.service().logs_get(package_base, limit, offset) logs = self.service().logs_get(package_base, limit, offset)
response = { response = {

View File

@ -23,7 +23,7 @@ def test_path(args: argparse.Namespace, configuration: Configuration) -> None:
assert Lock(args, repository_id, configuration).path is None assert Lock(args, repository_id, configuration).path is None
args.lock = Path("/run/ahriman.lock") args.lock = Path("/run/ahriman.lock")
assert Lock(args, repository_id, configuration).path == Path("/run/ahriman_aur-clone_x86_64.lock") assert Lock(args, repository_id, configuration).path == Path("/run/ahriman_x86_64-aur-clone.lock")
with pytest.raises(ValueError): with pytest.raises(ValueError):
args.lock = Path("/") args.lock = Path("/")

View File

@ -2,7 +2,7 @@ import pytest
from multidict import MultiDict from multidict import MultiDict
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
from aiohttp.web import HTTPBadRequest from aiohttp.web import HTTPBadRequest, HTTPNotFound
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
@ -240,6 +240,14 @@ def test_service_auto(base: BaseView, repository_id: RepositoryId, mocker: Mocke
assert base.service() == base.services[repository_id] assert base.service() == base.services[repository_id]
def test_service_not_found(base: BaseView) -> None:
"""
must raise HTTPNotFound if no repository found
"""
with pytest.raises(HTTPNotFound):
base.service(RepositoryId("", ""))
async def test_username(base: BaseView, mocker: MockerFixture) -> None: async def test_username(base: BaseView, mocker: MockerFixture) -> None:
""" """
must return identity of logged-in user must return identity of logged-in user