From 41c2b23b650aa5bcda766ddc9d3cd271defc4b16 Mon Sep 17 00:00:00 2001 From: evanlowe <62918515+evanlowe@users.noreply.github.com> Date: Mon, 24 Aug 2026 11:22:30 +0800 Subject: [PATCH] fix(cli): confirm deploy when IAM precheck fails --- tests/cli/test_studio_deploy_permissions.py | 80 +++++++++++++++++++-- veadk/cli/cli_frontend.py | 15 +++- 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/tests/cli/test_studio_deploy_permissions.py b/tests/cli/test_studio_deploy_permissions.py index 466737fbd..4d8e52f01 100644 --- a/tests/cli/test_studio_deploy_permissions.py +++ b/tests/cli/test_studio_deploy_permissions.py @@ -202,8 +202,35 @@ def test_renderer_localizes_byteplus_purposes_and_summary(capsys) -> None: assert permissions.IAM_CONFIG_URLS["byteplus"] in output -def test_cli_stops_before_cloud_writes_when_permission_is_missing( - monkeypatch, +@pytest.mark.parametrize( + ("provider_args", "expected_prompt", "expected_message"), + [ + ( + [ + "--volcengine-access-key", + "ak", + "--volcengine-secret-key", + "sk", + ], + "是否仍要继续部署?", + "缺少 Studio 部署所需的 IAM 权限", + ), + ( + [ + "--provider", + "byteplus", + "--byteplus-access-key", + "ak", + "--byteplus-secret-key", + "sk", + ], + "Continue deployment anyway?", + "required IAM Actions are missing", + ), + ], +) +def test_cli_stops_before_cloud_writes_when_missing_permission_is_declined( + monkeypatch, provider_args, expected_prompt, expected_message ) -> None: identity_called = False @@ -228,6 +255,47 @@ def _identity(**_kwargs): _identity, ) + result = CliRunner().invoke( + studio, + [ + "deploy", + "--vefaas-app-name", + "studio-test", + *provider_args, + ], + input="n\n", + ) + + assert result.exit_code != 0 + assert expected_prompt in result.output + assert expected_message in result.output + assert identity_called is False + + +def test_cli_continues_when_missing_permission_is_accepted(monkeypatch) -> None: + identity_called = False + + def _precheck(*, specs, **_kwargs): + return [ + permissions.PermissionResult(spec=spec, satisfied=index != 0) + for index, spec in enumerate(specs) + ] + + def _identity(**_kwargs): + nonlocal identity_called + identity_called = True + raise RuntimeError("identity provisioning reached") + + monkeypatch.setattr( + permissions, + "run_studio_deploy_permission_precheck", + _precheck, + ) + monkeypatch.setattr( + "veadk.cli.cli_frontend._resolve_or_create_studio_identity_resources", + _identity, + ) + result = CliRunner().invoke( studio, [ @@ -239,11 +307,15 @@ def _identity(**_kwargs): "--volcengine-secret-key", "sk", ], + input="y\n", ) assert result.exit_code != 0 - assert "缺少 Studio 部署所需的 IAM 权限" in result.output - assert identity_called is False + assert "是否仍要继续部署?" in result.output + assert "已确认忽略缺失的 IAM 权限,继续部署。" in result.output + assert identity_called is True + assert isinstance(result.exception, RuntimeError) + assert str(result.exception) == "identity provisioning reached" def test_cli_precheck_only_exits_before_cloud_writes(monkeypatch) -> None: diff --git a/veadk/cli/cli_frontend.py b/veadk/cli/cli_frontend.py index afcf2c9de..882ac5386 100644 --- a/veadk/cli/cli_frontend.py +++ b/veadk/cli/cli_frontend.py @@ -10853,7 +10853,20 @@ def frontend_deploy( if provider_id == "byteplus" else "缺少 Studio 部署所需的 IAM 权限,已在创建云资源前终止。" ) - raise click.ClickException(message) + if precheck_only: + raise click.ClickException(message) + prompt = ( + "Some required IAM Actions are missing. Continue deployment anyway?" + if provider_id == "byteplus" + else "部分 Studio 部署所需的 IAM 权限未满足,是否仍要继续部署?" + ) + if not click.confirm(prompt, default=False): + raise click.ClickException(message) + click.echo( + "Continuing deployment despite missing IAM Actions." + if provider_id == "byteplus" + else "已确认忽略缺失的 IAM 权限,继续部署。" + ) if precheck_only: click.echo( "Pre-check only: no cloud resources were created."