فهرست منبع

[REF-1042] Hosting CLI: check the user selected app name (#2102)

Martin Xu 1 سال پیش
والد
کامیت
4a526620ac
3فایلهای تغییر یافته به همراه57 افزوده شده و 9 حذف شده
  1. 10 1
      reflex/reflex.py
  2. 46 7
      reflex/utils/hosting.py
  3. 1 1
      tests/utils/test_hosting.py

+ 10 - 1
reflex/reflex.py

@@ -460,7 +460,10 @@ def makemigrations(
 @cli.command()
 @cli.command()
 def deploy(
 def deploy(
     key: Optional[str] = typer.Option(
     key: Optional[str] = typer.Option(
-        None, "-k", "--deployment-key", help="The name of the deployment."
+        None,
+        "-k",
+        "--deployment-key",
+        help="The name of the deployment. Domain name safe characters only.",
     ),
     ),
     app_name: str = typer.Option(
     app_name: str = typer.Option(
         config.app_name,
         config.app_name,
@@ -539,6 +542,12 @@ def deploy(
     # Check if we are set up.
     # Check if we are set up.
     prerequisites.check_initialized(frontend=True)
     prerequisites.check_initialized(frontend=True)
     enabled_regions = None
     enabled_regions = None
+    # If there is already a key, then it is passed in from CLI option in the non-interactive mode
+    if key is not None and not hosting.is_valid_deployment_key(key):
+        console.error(
+            f"Deployment key {key} is not valid. Please use only domain name safe characters."
+        )
+        raise typer.Exit(1)
     try:
     try:
         # Send a request to server to obtain necessary information
         # Send a request to server to obtain necessary information
         # in preparation of a deployment. For example,
         # in preparation of a deployment. For example,

+ 46 - 7
reflex/utils/hosting.py

@@ -148,6 +148,21 @@ def save_token_to_config(token: str, code: str | None = None):
         )
         )
 
 
 
 
+def requires_access_token() -> str:
+    """Fetch the access token from the existing config if applicable.
+
+    Returns:
+        The access token. If not found, return empty string for it instead.
+    """
+    # Check if the user is authenticated
+
+    access_token, _ = get_existing_access_token()
+    if not access_token:
+        console.debug("No access token found from the existing config.")
+
+    return access_token
+
+
 def authenticated_token() -> tuple[str, str]:
 def authenticated_token() -> tuple[str, str]:
     """Fetch the access token from the existing config if applicable and validate it.
     """Fetch the access token from the existing config if applicable and validate it.
 
 
@@ -339,7 +354,7 @@ class DeploymentsPostParam(Base):
     """Params for hosted instance deployment POST request."""
     """Params for hosted instance deployment POST request."""
 
 
     # Key is the name of the deployment, it becomes part of the URL
     # Key is the name of the deployment, it becomes part of the URL
-    key: str = Field(..., regex=r"^[a-zA-Z0-9-]+$")
+    key: str = Field(..., regex=r"^[a-z0-9-]+$")
     # Name of the app
     # Name of the app
     app_name: str = Field(..., min_length=1)
     app_name: str = Field(..., min_length=1)
     # json encoded list of regions to deploy to
     # json encoded list of regions to deploy to
@@ -414,7 +429,7 @@ def deploy(
         The response containing the URL of the site to be deployed if successful, None otherwise.
         The response containing the URL of the site to be deployed if successful, None otherwise.
     """
     """
     # Check if the user is authenticated
     # Check if the user is authenticated
-    if not (token := requires_authenticated()):
+    if not (token := requires_access_token()):
         raise Exception("not authenticated")
         raise Exception("not authenticated")
 
 
     try:
     try:
@@ -551,15 +566,15 @@ def fetch_token(request_id: str) -> tuple[str, str]:
         access_token = (resp_json := resp.json()).get("access_token", "")
         access_token = (resp_json := resp.json()).get("access_token", "")
         invitation_code = resp_json.get("code", "")
         invitation_code = resp_json.get("code", "")
     except httpx.RequestError as re:
     except httpx.RequestError as re:
-        console.error(f"Unable to fetch token due to request error: {re}")
+        console.debug(f"Unable to fetch token due to request error: {re}")
     except httpx.HTTPError as he:
     except httpx.HTTPError as he:
-        console.error(f"Unable to fetch token due to {he}")
+        console.debug(f"Unable to fetch token due to {he}")
     except json.JSONDecodeError as jde:
     except json.JSONDecodeError as jde:
-        console.error(f"Server did not respond with valid json: {jde}")
+        console.debug(f"Server did not respond with valid json: {jde}")
     except KeyError as ke:
     except KeyError as ke:
-        console.error(f"Server response format unexpected: {ke}")
+        console.debug(f"Server response format unexpected: {ke}")
     except Exception:
     except Exception:
-        console.error("Unexpected errors: {ex}")
+        console.debug("Unexpected errors: {ex}")
 
 
     return access_token, invitation_code
     return access_token, invitation_code
 
 
@@ -902,6 +917,18 @@ def validate_token_with_retries(access_token: str) -> bool:
     return False
     return False
 
 
 
 
+def is_valid_deployment_key(key: str):
+    """Helper function to check if the deployment key is valid. Must be a domain name safe string.
+
+    Args:
+        key: The deployment key to check.
+
+    Returns:
+        True if the key contains only domain name safe characters, False otherwise.
+    """
+    return re.match(r"^[a-zA-Z0-9-]*$", key)
+
+
 def interactive_get_deployment_key_from_user_input(
 def interactive_get_deployment_key_from_user_input(
     pre_deploy_response: DeploymentPrepareResponse,
     pre_deploy_response: DeploymentPrepareResponse,
     app_name: str,
     app_name: str,
@@ -940,6 +967,18 @@ def interactive_get_deployment_key_from_user_input(
             f"Choose a name for your deployed app. Enter to use default.",
             f"Choose a name for your deployed app. Enter to use default.",
             default=key_candidate,
             default=key_candidate,
         ):
         ):
+            if not is_valid_deployment_key(key_input):
+                console.error(
+                    "Invalid key input, should only contain domain name safe characters: letters, digits, or hyphens."
+                )
+                continue
+
+            elif any(x.isupper() for x in key_input):
+                key_input = key_input.lower()
+                console.info(
+                    f"Domain name is case insensitive, automatically converting to all lower cases: {key_input}"
+                )
+
             try:
             try:
                 pre_deploy_response = prepare_deploy(
                 pre_deploy_response = prepare_deploy(
                     app_name,
                     app_name,

+ 1 - 1
tests/utils/test_hosting.py

@@ -194,7 +194,7 @@ def test_prepare_deploy_success(mocker):
 
 
 def test_deploy(mocker):
 def test_deploy(mocker):
     mocker.patch(
     mocker.patch(
-        "reflex.utils.hosting.requires_authenticated", return_value="fake_token"
+        "reflex.utils.hosting.requires_access_token", return_value="fake_token"
     )
     )
     mocker.patch("builtins.open")
     mocker.patch("builtins.open")
     mocker.patch(
     mocker.patch(