mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
fix: fix some security issues
This commit is contained in:
parent
62dd77317d
commit
e03fcbfab5
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
_shtab_ahriman_subparsers=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
|
_shtab_ahriman_subparsers=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
|
||||||
|
|
||||||
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '--wait-timeout' '-V' '--version')
|
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout')
|
||||||
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||||
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||||
_shtab_ahriman_help_commands_unsafe_option_strings=('-h' '--help')
|
_shtab_ahriman_help_commands_unsafe_option_strings=('-h' '--help')
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
.TH AHRIMAN "1" "2023\-11\-06" "ahriman" "Generated Python Manual"
|
.TH AHRIMAN "1" "2023\-11\-12" "ahriman" "Generated Python Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ahriman
|
.B ahriman
|
||||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [--wait-timeout WAIT_TIMEOUT] [-V] {aur-search,search,help-commands-unsafe,help,help-updates,help-version,version,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-repositories,service-run,run,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ...
|
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {aur-search,search,help-commands-unsafe,help,help-updates,help-version,version,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-repositories,service-run,run,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
ArcH linux ReposItory MANager
|
ArcH linux ReposItory MANager
|
||||||
|
|
||||||
@ -44,15 +44,15 @@ filter by target repository
|
|||||||
\fB\-\-unsafe\fR
|
\fB\-\-unsafe\fR
|
||||||
allow to run ahriman as non\-ahriman user. Some actions might be unavailable
|
allow to run ahriman as non\-ahriman user. Some actions might be unavailable
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-V\fR, \fB\-\-version\fR
|
||||||
|
show program's version number and exit
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-wait\-timeout\fR \fI\,WAIT_TIMEOUT\/\fR
|
\fB\-\-wait\-timeout\fR \fI\,WAIT_TIMEOUT\/\fR
|
||||||
wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of
|
wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of
|
||||||
zero value, the application will wait infinitely
|
zero value, the application will wait infinitely
|
||||||
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR, \fB\-\-version\fR
|
|
||||||
show program's version number and exit
|
|
||||||
|
|
||||||
.SH
|
.SH
|
||||||
COMMAND
|
COMMAND
|
||||||
.TP
|
.TP
|
||||||
@ -208,22 +208,22 @@ sort field by this field. In case if two packages have the same value of the spe
|
|||||||
by name
|
by name
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
||||||
usage: ahriman help\-commands\-unsafe [\-h] [command ...]
|
usage: ahriman help\-commands\-unsafe [\-h] [subcommand ...]
|
||||||
|
|
||||||
list unsafe commands as defined in default args
|
list unsafe commands as defined in default args
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBcommand\fR
|
\fBsubcommand\fR
|
||||||
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
||||||
otherwise
|
otherwise
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help'\/\fR
|
.SH COMMAND \fI\,'ahriman help'\/\fR
|
||||||
usage: ahriman help [\-h] [command]
|
usage: ahriman help [\-h] [subcommand]
|
||||||
|
|
||||||
show help message for application or command and exit
|
show help message for application or command and exit
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBcommand\fR
|
\fBsubcommand\fR
|
||||||
show help message for specific command
|
show help message for specific command
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help\-updates'\/\fR
|
.SH COMMAND \fI\,'ahriman help\-updates'\/\fR
|
||||||
|
@ -90,8 +90,8 @@ _shtab_ahriman_options=(
|
|||||||
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
||||||
{-r,--repository}"[filter by target repository (default\: None)]:repository:"
|
{-r,--repository}"[filter by target repository (default\: None)]:repository:"
|
||||||
"--unsafe[allow to run ahriman as non-ahriman user. Some actions might be unavailable (default\: False)]"
|
"--unsafe[allow to run ahriman as non-ahriman user. Some actions might be unavailable (default\: False)]"
|
||||||
"--wait-timeout[wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of zero value, the application will wait infinitely (default\: -1)]:wait_timeout:"
|
|
||||||
"(- : *)"{-V,--version}"[show program\'s version number and exit]"
|
"(- : *)"{-V,--version}"[show program\'s version number and exit]"
|
||||||
|
"--wait-timeout[wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of zero value, the application will wait infinitely (default\: -1)]:wait_timeout:"
|
||||||
)
|
)
|
||||||
|
|
||||||
_shtab_ahriman_add_options=(
|
_shtab_ahriman_add_options=(
|
||||||
|
@ -87,11 +87,11 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("--repository-id", help=argparse.SUPPRESS)
|
parser.add_argument("--repository-id", help=argparse.SUPPRESS)
|
||||||
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
||||||
action="store_true")
|
action="store_true")
|
||||||
|
parser.add_argument("-V", "--version", action="version", version=__version__)
|
||||||
parser.add_argument("--wait-timeout", help="wait for lock to be free. Negative value will lead to "
|
parser.add_argument("--wait-timeout", help="wait for lock to be free. Negative value will lead to "
|
||||||
"immediate application run even if there is lock file. "
|
"immediate application run even if there is lock file. "
|
||||||
"In case of zero value, the application will wait infinitely",
|
"In case of zero value, the application will wait infinitely",
|
||||||
type=int, default=-1)
|
type=int, default=-1)
|
||||||
parser.add_argument("-V", "--version", action="version", version=__version__)
|
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command")
|
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command")
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument
|
|||||||
"""
|
"""
|
||||||
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
||||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||||
parser.add_argument("command", help="instead of showing commands, just test command line for unsafe subcommand "
|
parser.add_argument("subcommand", help="instead of showing commands, just test command line for unsafe subcommand "
|
||||||
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
|
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
|
||||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture="", lock=None, quiet=True, report=False,
|
parser.set_defaults(handler=handlers.UnsafeCommands, architecture="", lock=None, quiet=True, report=False,
|
||||||
repository="", unsafe=True, parser=_parser)
|
repository="", unsafe=True, parser=_parser)
|
||||||
@ -198,7 +198,7 @@ def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser = root.add_parser("help", help="show help message",
|
parser = root.add_parser("help", help="show help message",
|
||||||
description="show help message for application or command and exit",
|
description="show help message for application or command and exit",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("command", help="show help message for specific command", nargs="?")
|
parser.add_argument("subcommand", help="show help message for specific command", nargs="?")
|
||||||
parser.set_defaults(handler=handlers.Help, architecture="", lock=None, quiet=True, report=False, repository="",
|
parser.set_defaults(handler=handlers.Help, architecture="", lock=None, quiet=True, report=False, repository="",
|
||||||
unsafe=True, parser=_parser)
|
unsafe=True, parser=_parser)
|
||||||
return parser
|
return parser
|
||||||
|
@ -44,7 +44,7 @@ class Help(Handler):
|
|||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
parser: argparse.ArgumentParser = args.parser()
|
parser: argparse.ArgumentParser = args.parser()
|
||||||
if args.command is None:
|
if args.subcommand is None:
|
||||||
parser.parse_args(["--help"])
|
parser.parse_args(["--help"])
|
||||||
else:
|
else:
|
||||||
parser.parse_args([args.command, "--help"])
|
parser.parse_args([args.subcommand, "--help"])
|
||||||
|
@ -46,8 +46,8 @@ class UnsafeCommands(Handler):
|
|||||||
"""
|
"""
|
||||||
parser = args.parser()
|
parser = args.parser()
|
||||||
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
||||||
if args.command:
|
if args.subcommand:
|
||||||
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
|
UnsafeCommands.check_unsafe(args.subcommand, unsafe_commands, parser)
|
||||||
else:
|
else:
|
||||||
for command in unsafe_commands:
|
for command in unsafe_commands:
|
||||||
StringPrinter(command)(verbose=True)
|
StringPrinter(command)(verbose=True)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# 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.web import HTTPFound
|
from aiohttp.web import HTTPFound, HTTPNotFound
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
from ahriman.web.views.base import BaseView
|
from ahriman.web.views.base import BaseView
|
||||||
@ -40,5 +40,8 @@ class StaticView(BaseView):
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
HTTPFound: on success response
|
HTTPFound: on success response
|
||||||
|
HTTPNotFound: if path is invalid or unknown
|
||||||
"""
|
"""
|
||||||
|
if self.request.path in self.ROUTES: # explicit validation
|
||||||
raise HTTPFound(f"/static{self.request.path}")
|
raise HTTPFound(f"/static{self.request.path}")
|
||||||
|
raise HTTPNotFound
|
||||||
|
@ -18,7 +18,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
argparse.Namespace: generated arguments for these test cases
|
argparse.Namespace: generated arguments for these test cases
|
||||||
"""
|
"""
|
||||||
args.parser = _parser
|
args.parser = _parser
|
||||||
args.command = None
|
args.subcommand = None
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ def test_run_command(args: argparse.Namespace, configuration: Configuration, moc
|
|||||||
must run command for specific subcommand
|
must run command for specific subcommand
|
||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.command = "aur-search"
|
args.subcommand = "aur-search"
|
||||||
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
|
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
|
||||||
|
|
||||||
_, repository_id = configuration.check_loaded()
|
_, repository_id = configuration.check_loaded()
|
||||||
|
@ -19,7 +19,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
argparse.Namespace: generated arguments for these test cases
|
argparse.Namespace: generated arguments for these test cases
|
||||||
"""
|
"""
|
||||||
args.parser = _parser
|
args.parser = _parser
|
||||||
args.command = []
|
args.subcommand = []
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ def test_run_check(args: argparse.Namespace, configuration: Configuration, mocke
|
|||||||
must run command and check if command is unsafe
|
must run command and check if command is unsafe
|
||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.command = ["clean"]
|
args.subcommand = ["clean"]
|
||||||
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands",
|
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands",
|
||||||
return_value=["command"])
|
return_value=["command"])
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe")
|
check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe")
|
||||||
|
@ -88,7 +88,7 @@ def test_clear(lock: Lock) -> None:
|
|||||||
"""
|
"""
|
||||||
must remove lock file
|
must remove lock file
|
||||||
"""
|
"""
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
lock.path.touch()
|
lock.path.touch()
|
||||||
|
|
||||||
lock.clear()
|
lock.clear()
|
||||||
@ -99,7 +99,7 @@ def test_clear_missing(lock: Lock) -> None:
|
|||||||
"""
|
"""
|
||||||
must not fail on lock removal if file is missing
|
must not fail on lock removal if file is missing
|
||||||
"""
|
"""
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
lock.clear()
|
lock.clear()
|
||||||
|
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ def test_create(lock: Lock) -> None:
|
|||||||
"""
|
"""
|
||||||
must create lock
|
must create lock
|
||||||
"""
|
"""
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
|
|
||||||
lock.create()
|
lock.create()
|
||||||
assert lock.path.is_file()
|
assert lock.path.is_file()
|
||||||
@ -127,7 +127,7 @@ def test_create_exception(lock: Lock) -> None:
|
|||||||
"""
|
"""
|
||||||
must raise exception if file already exists
|
must raise exception if file already exists
|
||||||
"""
|
"""
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
lock.path.touch()
|
lock.path.touch()
|
||||||
|
|
||||||
with pytest.raises(DuplicateRunError):
|
with pytest.raises(DuplicateRunError):
|
||||||
@ -149,7 +149,7 @@ def test_create_unsafe(lock: Lock) -> None:
|
|||||||
must not raise exception if force flag set
|
must not raise exception if force flag set
|
||||||
"""
|
"""
|
||||||
lock.force = True
|
lock.force = True
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
lock.path.touch()
|
lock.path.touch()
|
||||||
|
|
||||||
lock.create()
|
lock.create()
|
||||||
@ -161,7 +161,7 @@ def test_watch(lock: Lock, mocker: MockerFixture) -> None:
|
|||||||
must check if lock file exists
|
must check if lock file exists
|
||||||
"""
|
"""
|
||||||
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
||||||
lock.path = Path(tempfile.mktemp()) # nosec
|
lock.path = Path(tempfile.gettempdir()) / "ahriman-test.lock"
|
||||||
|
|
||||||
lock.watch()
|
lock.watch()
|
||||||
wait_mock.assert_called_once_with(lock.path.is_file)
|
wait_mock.assert_called_once_with(lock.path.is_file)
|
||||||
|
@ -24,8 +24,19 @@ def test_routes() -> None:
|
|||||||
|
|
||||||
async def test_get(client_with_auth: TestClient) -> None:
|
async def test_get(client_with_auth: TestClient) -> None:
|
||||||
"""
|
"""
|
||||||
must generate status page correctly (/)
|
must redirect favicon to static files
|
||||||
"""
|
"""
|
||||||
response = await client_with_auth.get("/favicon.ico", allow_redirects=False)
|
response = await client_with_auth.get("/favicon.ico", allow_redirects=False)
|
||||||
assert response.status == 302
|
assert response.status == 302
|
||||||
assert response.headers["Location"] == "/static/favicon.ico"
|
assert response.headers["Location"] == "/static/favicon.ico"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_not_found(client_with_auth: TestClient) -> None:
|
||||||
|
"""
|
||||||
|
must raise not found if path is invalid
|
||||||
|
"""
|
||||||
|
for route in client_with_auth.app.router.routes():
|
||||||
|
if hasattr(route.handler, "ROUTES"):
|
||||||
|
route.handler.ROUTES = []
|
||||||
|
response = await client_with_auth.get("/favicon.ico", allow_redirects=False)
|
||||||
|
assert response.status == 404
|
||||||
|
Loading…
Reference in New Issue
Block a user