Feature/app custom domain#27
Open
bmaisonneuve wants to merge 7 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds support for assigning a readable custom subdomain to Streamlit/Reflex apps as a front-only nginx alias (while keeping the id-based host canonical), and introduces an explicit app access mode model (AUTHENTICATED vs PUBLIC) with optional system-user token fallback for front components.
Changes:
- Add custom subdomain persistence + validation + uniqueness checks on
AppResource, and propagate the subdomain to running processes with live nginx re-registration. - Introduce
AppAccessModeand update app launch/bootstrap logic to support PUBLIC (anonymous) apps, including optionalfallback_to_system_userfor Streamlit/Reflex front components. - Replace the stop-policy entity action plugin with a consolidated app management plugin (stop policy + custom subdomain) and update tests accordingly.
Reviewed changes
Copilot reviewed 42 out of 43 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_gws_core/test_streamlit_app.py | Adds tests for canonical host + custom alias host behavior, validation, and uniqueness. |
| tests/test_gws_core/test_reflex_app.py | Adds tests for front-only alias + backend CORS allow-list behavior in Reflex. |
| tests/test_gws_core/entity_action/test_app_stop_policy_action_plugin.py | Removes tests for the old stop-policy-only plugin. |
| tests/test_gws_core/entity_action/test_app_resource_action_plugin.py | Adds tests for the new consolidated app resource action plugin. |
| src/gws_core/impl/apps/streamlit_showcase/generate_streamlit_showcase_app.py | Adds optional custom_subdomain task param for generated Streamlit showcase apps. |
| src/gws_core/impl/apps/streamlit_showcase/_streamlit_showcase_app/dev_config.json | Updates dev config to include access_mode. |
| src/gws_core/impl/apps/streamlit_showcase/_streamlit_showcase_app/app_pages/resources_page.py | Enables fallback_to_system_user in showcase components (with warnings). |
| src/gws_core/impl/apps/streamlit_showcase/_streamlit_showcase_app/app_pages/processes_page.py | Enables fallback_to_system_user in showcase task runner usage (with warnings). |
| src/gws_core/impl/apps/reflex_showcase/generate_reflex_showcase_app.py | Adds optional custom_subdomain task param for generated Reflex showcase apps. |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/reflex.lock/package.json | Dependency lock update (vite). |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/reflex.lock/bun.lock | Dependency lock update (vite/rolldown/etc). |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/reflex_showcase/pages/rich_text_page.py | Enables fallback_to_system_user for the rich text component demo (with warnings). |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/reflex_showcase/pages/rich_text_advanced_page.py | Enables fallback_to_system_user for the advanced rich text component demo (with warnings). |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/reflex_showcase/pages/resource_components_page.py | Enables fallback_to_system_user for resource select demo (with warnings). |
| src/gws_core/impl/apps/reflex_showcase/_reflex_showcase_app/dev_config.json | Updates dev config to include access_mode. |
| src/gws_core/apps/streamlit/streamlit_resource.py | Switches resource init from boolean auth flag to AppAccessMode. |
| src/gws_core/apps/streamlit/streamlit_process.py | Uses get_front_server_names() so nginx front answers on canonical + alias hosts. |
| src/gws_core/apps/streamlit/_gws_streamlit/gws_streamlit_main/gws_streamlit_main_state.py | Allows PUBLIC apps to run without authenticated user; adds system fallback auth info. |
| src/gws_core/apps/streamlit/_gws_streamlit/gws_streamlit_main/gws_components/streamlit_task_runner.py | Adds fallback_to_system_user option and threads auth info accordingly. |
| src/gws_core/apps/streamlit/_gws_streamlit/gws_streamlit_main/gws_components/streamlit_resource_select.py | Adds fallback_to_system_user option and threads auth info accordingly. |
| src/gws_core/apps/streamlit/_gws_streamlit/gws_streamlit_main/CLAUDE.md | Documents PUBLIC-mode behavior and fallback_to_system_user risks for Streamlit components. |
| src/gws_core/apps/streamlit/_gws_streamlit/gws_streamlit_base/streamlit_main_state_base.py | Reworks bootstrap auth/token checks for PUBLIC vs AUTHENTICATED access modes + system token support. |
| src/gws_core/apps/reflex/reflex_resource.py | Switches resource init from boolean auth flag to AppAccessMode. |
| src/gws_core/apps/reflex/reflex_process.py | Uses front server-name alias list and updates backend CORS allow-list for custom front origin(s). |
| src/gws_core/apps/reflex/_gws_reflex/gws_reflex_main/reflex_main_state.py | Adds system-fallback auth info var for components that need API access in PUBLIC apps. |
| src/gws_core/apps/reflex/_gws_reflex/gws_reflex_main/gws_components/reflex_select_resource_2_component/reflex_select_resource_2_component.py | Adds fallback_to_system_user option selecting the correct auth-info var. |
| src/gws_core/apps/reflex/_gws_reflex/gws_reflex_main/gws_components/reflex_rich_text_component/reflex_rich_text_component.py | Adds fallback_to_system_user option selecting the correct auth-info var. |
| src/gws_core/apps/reflex/_gws_reflex/gws_reflex_main/CLAUDE.md | Documents PUBLIC-mode behavior and fallback_to_system_user risks for Reflex components. |
| src/gws_core/apps/reflex/_gws_reflex/gws_reflex_base/reflex_main_state_base.py | Reworks auth/token checks for PUBLIC vs AUTHENTICATED access modes + system token support. |
| src/gws_core/apps/apps_manager.py | Adds set_custom_subdomain API to persist + live-apply alias updates on running processes. |
| src/gws_core/apps/app_stop_policy_action_plugin.py | Removes the old stop-policy-only entity action plugin. |
| src/gws_core/apps/app_resource.py | Adds persisted _custom_subdomain, validation, uniqueness check, access-mode API, and propagation into default_view. |
| src/gws_core/apps/app_resource_action_plugin.py | New consolidated entity action plugin: stop policy + custom subdomain form/action. |
| src/gws_core/apps/app_process.py | Implements canonical host + alias host, server_name lists, PUBLIC-mode URL behavior, and live nginx refresh hooks. |
| src/gws_core/apps/app_plugin_downloader.py | Bumps dashboard components version. |
| src/gws_core/apps/app_nginx_service.py | Allows multiple server names; adds multi-origin CORS support for redirect services. |
| src/gws_core/apps/app_instance.py | Adds AppAccessMode, custom subdomain field, token-in-URL behavior, and DTO population. |
| src/gws_core/apps/app_dto.py | Introduces AppAccessMode; adds custom subdomain fields to DTOs. |
| src/gws_core/apps/app_controller.py | Adds REST endpoints to set/clear custom subdomain. |
| src/gws_core/init.py | Exposes AppAccessMode from the package root. |
| gws_cli/gws_cli/utils/dev_config_generator.py | Adds access_mode to dev config model. |
| gws_cli/gws_cli/app_cli.py | Applies access_mode from dev config when starting apps. |
| docs/todo/app_custom_subdomain_plan.md | Updates implementation plan to reflect alias/front-only/live behavior. |
Comment on lines
+274
to
+289
| self_id = self.get_model_id() | ||
|
|
||
| resource_models: list[ResourceModel] = list( | ||
| ResourceModel.select_by_type_and_sub_types(AppResource) | ||
| ) | ||
|
|
||
| for resource_model in resource_models: | ||
| # skip the current resource (e.g. when updating its own subdomain) | ||
| if self_id is not None and resource_model.id == self_id: | ||
| continue | ||
|
|
||
| other = resource_model.get_resource(resource_type=AppResource) | ||
| if other.get_custom_subdomain() == subdomain: | ||
| raise BadRequestException( | ||
| f"The custom subdomain '{subdomain}' is already used by another app." | ||
| ) |
Comment on lines
+108
to
+117
| subdomain = config_params.get(self.SUBDOMAIN_PARAM) | ||
|
|
||
| # AppsManager.set_custom_subdomain validates, checks uniqueness, persists and | ||
| # applies the change live; a falsy value clears the subdomain. | ||
| AppsManager.set_custom_subdomain(entity.id, subdomain) | ||
|
|
||
| if subdomain: | ||
| message = f"Custom subdomain set to '{subdomain}'." | ||
| else: | ||
| message = "Custom subdomain cleared, the default host is restored." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.