diff --git a/src/fastapi_cloud_cli/commands/env.py b/src/fastapi_cloud_cli/commands/env.py index 87af87d..e592fdb 100644 --- a/src/fastapi_cloud_cli/commands/env.py +++ b/src/fastapi_cloud_cli/commands/env.py @@ -206,6 +206,13 @@ def set( help="A path to the folder containing the app you want to deploy" ), ] = None, + secret: Annotated[ + bool, + typer.Option( + "--secret", + help="Mark the environment variable as secret", + ), + ] = False, ) -> Any: """ Set an environment variable for the app. @@ -233,12 +240,18 @@ def set( raise typer.Exit(1) if not name: - name = toolkit.input("Enter the name of the environment variable to set:") + if secret: + name = toolkit.input("Enter the name of the secret to set:") + else: + name = toolkit.input( + "Enter the name of the environment variable to set:" + ) if not value: - value = toolkit.input( - "Enter the value of the environment variable to set:", password=True - ) + if secret: + value = toolkit.input("Enter the secret value:", password=True) + else: + value = toolkit.input("Enter the value of the environment variable:") with toolkit.progress( "Setting environment variable", transient=True @@ -247,6 +260,9 @@ def set( assert value is not None with handle_http_errors(progress): - _set_environment_variable(app_config.app_id, name, value) + _set_environment_variable(app_config.app_id, name, value, secret) - toolkit.print(f"Environment variable [bold]{name}[/] set.") + if secret: + toolkit.print(f"Secret environment variable [bold]{name}[/] set.") + else: + toolkit.print(f"Environment variable [bold]{name}[/] set.") diff --git a/tests/test_env_set.py b/tests/test_env_set.py index 5cd7738..2c32893 100644 --- a/tests/test_env_set.py +++ b/tests/test_env_set.py @@ -47,7 +47,10 @@ def test_shows_a_message_if_app_is_not_configured(logged_in_cli: None) -> None: def test_shows_a_message_if_something_is_wrong( logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path ) -> None: - respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(500)) + respx_mock.post( + "/apps/123/environment-variables/", + json={"name": "SOME_VAR", "value": "secret", "is_secret": False}, + ).mock(return_value=Response(500)) with changing_dir(configured_app): result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret"]) @@ -63,7 +66,10 @@ def test_shows_a_message_if_something_is_wrong( def test_shows_message_when_it_sets( logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path ) -> None: - respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(200)) + respx_mock.post( + "/apps/123/environment-variables/", + json={"name": "SOME_VAR", "value": "secret", "is_secret": False}, + ).mock(return_value=Response(200)) with changing_dir(configured_app): result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret"]) @@ -78,7 +84,10 @@ def test_asks_for_name_and_value( ) -> None: steps = [*"SOME_VAR", Keys.ENTER, *"secret", Keys.ENTER] - respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(200)) + respx_mock.post( + "/apps/123/environment-variables/", + json={"name": "SOME_VAR", "value": "secret", "is_secret": False}, + ).mock(return_value=Response(200)) with ( changing_dir(configured_app), @@ -93,4 +102,45 @@ def test_asks_for_name_and_value( assert "Environment variable SOME_VAR set" in result.output + +@pytest.mark.respx(base_url=settings.base_api_url) +def test_asks_for_name_and_value_for_secret( + logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path +) -> None: + steps = [*"SOME_VAR", Keys.ENTER, *"secret", Keys.ENTER] + + respx_mock.post( + "/apps/123/environment-variables/", + json={"name": "SOME_VAR", "value": "secret", "is_secret": True}, + ).mock(return_value=Response(200)) + + with ( + changing_dir(configured_app), + patch("rich_toolkit.container.getchar", side_effect=steps), + ): + result = runner.invoke(app, ["env", "set", "--secret"]) + + assert result.exit_code == 0 + + assert "Enter the name of the secret" in result.output + assert "Enter the secret value" in result.output + + assert "Secret environment variable SOME_VAR set" in result.output + assert "*" * 6 in result.output + + +@pytest.mark.respx(base_url=settings.base_api_url) +def test_sets_secret_flag( + logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path +) -> None: + respx_mock.post( + "/apps/123/environment-variables/", + json={"name": "SOME_VAR", "value": "secret", "is_secret": True}, + ).mock(return_value=Response(200)) + + with changing_dir(configured_app): + result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret", "--secret"]) + + assert result.exit_code == 0 + assert "Secret environment variable SOME_VAR set" in result.output