From 8f654603329ef18800da51f35fd77ce7d92b6efb Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 1 Jul 2026 22:55:08 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Validate=20app=20logs=20tail=20l?= =?UTF-8?q?imit=20before=20request?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shortcake-Parent: main --- src/fastapi_cloud_cli/commands/logs.py | 14 +++++++++++++- tests/test_logs.py | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/fastapi_cloud_cli/commands/logs.py b/src/fastapi_cloud_cli/commands/logs.py index 2bcbd4b..645d215 100644 --- a/src/fastapi_cloud_cli/commands/logs.py +++ b/src/fastapi_cloud_cli/commands/logs.py @@ -40,6 +40,8 @@ } SINCE_PATTERN = re.compile(r"^\d+[smhd]$") +MIN_LOG_TAIL = 1 +MAX_LOG_TAIL = 1000 class AppLogsOutput(BaseModel): @@ -57,6 +59,15 @@ def _validate_since(value: str) -> str: return value +def _validate_tail(value: int) -> int: + if not MIN_LOG_TAIL <= value <= MAX_LOG_TAIL: + raise typer.BadParameter( + f"Invalid value. Use a number between {MIN_LOG_TAIL} and {MAX_LOG_TAIL}." + ) + + return value + + def _get_log_bullet(log: AppLogEntry) -> str: """Colored indicator rendered in the emoji bullet column. @@ -214,8 +225,9 @@ def logs( 100, "--tail", "-t", - help="Number of log lines to show before streaming.", + help=f"Number of log lines to show before streaming (max {MAX_LOG_TAIL}).", show_default=True, + callback=_validate_tail, ), since: str = typer.Option( "5m", diff --git a/tests/test_logs.py b/tests/test_logs.py index e7725a4..0a3dfde 100644 --- a/tests/test_logs.py +++ b/tests/test_logs.py @@ -540,6 +540,19 @@ def test_rejects_invalid_since_format( assert "Invalid format" in result.output +@pytest.mark.parametrize("invalid_tail", [0, 1001]) +def test_rejects_invalid_tail( + logged_in_cli: None, + configured_app: ConfiguredApp, + invalid_tail: int, +) -> None: + with changing_dir(configured_app.path): + result = runner.invoke(app, ["logs", "--tail", str(invalid_tail)]) + + assert result.exit_code == 2 + assert "between 1 and 1000" in result.output + + @pytest.mark.respx @pytest.mark.parametrize( "valid_since",