-
Notifications
You must be signed in to change notification settings - Fork 35
refactor(set): validate blocklist instead of allowlist #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| kind: added | ||
| body: Refactored `set` command validation to use blocklist approach instead of allowlist, allowing any query parameter except explicitly blocked ones | ||
| time: 2026-01-29T13:38:02.881103993Z | ||
| custom: | ||
| Author: may-hartov | ||
| AuthorLink: https://github.com/may-hartov |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,13 +11,15 @@ | |
| from fabric_cli.utils import fab_mem_store as utils_mem_store | ||
| from fabric_cli.utils import fab_ui as utils_ui | ||
|
|
||
| JMESPATH_UPDATE_DOMAINS = ["contributorsScope", "description", "displayName"] | ||
| INVALID_QUERIES = ["parentDomainId"] | ||
|
|
||
|
|
||
| def exec(virtual_ws_item: VirtualWorkspaceItem, args: Namespace) -> None: | ||
| query = args.query | ||
|
|
||
| utils_set.validate_expression(query, JMESPATH_UPDATE_DOMAINS) | ||
| # Validate against invalid queries - allow users to set any query parameter | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please remove unnecessary comments |
||
| # and let the API validate if it's supported | ||
| utils_set.validate_query_not_in_blocklist(query, INVALID_QUERIES) | ||
|
|
||
| utils_set.print_set_warning() | ||
| if args.force or utils_ui.prompt_confirm(): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,17 +11,22 @@ | |
| from fabric_cli.utils import fab_mem_store as utils_mem_store | ||
| from fabric_cli.utils import fab_ui as utils_ui | ||
|
|
||
| JMESPATH_UPDATE_WORKSPACE = [ | ||
| "description", | ||
| "displayName", | ||
| "sparkSettings", | ||
| INVALID_QUERIES = [ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just a thought - do we want to expose those lists to users via set --help?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure. This list represents the minimal set of explicitly blocked queries; the API may block additional ones. From the user’s perspective, it’s transparent whether the failure occurs on the CLI side or the API side. This is merely an optimization for early failure and not the source of truth for the complete blocklist. |
||
| "capacityId", | ||
| "capacityRegion", | ||
| "apiEndpoint", | ||
| "domainId", | ||
| "oneLakeEndpoints", | ||
| "workspaceIdentity", | ||
| "managedPrivateEndpoints", | ||
| "roleAssignments", | ||
| ] | ||
|
|
||
|
|
||
| def exec(workspace: Workspace, args: Namespace) -> None: | ||
| query = args.query | ||
|
|
||
| utils_set.validate_expression(query, JMESPATH_UPDATE_WORKSPACE) | ||
| utils_set.validate_query_not_in_blocklist(query, INVALID_QUERIES) | ||
|
|
||
| # Get workspace | ||
| args.deep_traversal = True | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ def validate_item_query(query_value: str, item=None) -> None: | |
| allowed_keys = fab_constant.ITEM_SET_ALLOWED_METADATA_KEYS + [ | ||
| fab_constant.ITEM_QUERY_DEFINITION | ||
| ] | ||
| validate_expression(query_value, allowed_keys) | ||
| validate_query_in_allowlist(query_value, allowed_keys) | ||
|
|
||
| if not utils_jmespath.is_simple_path_expression(query_value): | ||
| raise FabricCLIError( | ||
|
|
@@ -47,7 +47,7 @@ def validate_item_query(query_value: str, item=None) -> None: | |
| ) | ||
|
|
||
|
|
||
| def validate_expression(expression: str, allowed_keys: list[str]) -> None: | ||
| def validate_query_in_allowlist(expression: str, allowed_keys: list[str]) -> None: | ||
| if not any( | ||
| expression == key or expression.startswith(f"{key}.") for key in allowed_keys | ||
| ): | ||
|
|
@@ -58,6 +58,42 @@ def validate_expression(expression: str, allowed_keys: list[str]) -> None: | |
| ) | ||
|
|
||
|
|
||
| def validate_query_not_in_blocklist( | ||
| query: str, resource_specific_invalid_queries: list = None | ||
| ) -> None: | ||
| """Validate that a query is not blocklisted. | ||
|
|
||
may-hartov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Blocks queries from SET_COMMAND_INVALID_QUERIES or resource_specific_invalid_queries, | ||
| or JMESPath expressions containing filters/wildcards. | ||
|
|
||
| Args: | ||
| query: Query string to validate. | ||
| resource_specific_invalid_queries: Optional additional invalid queries. | ||
|
|
||
| Raises: | ||
| FabricCLIError: If query is blocklisted or contains filters/wildcards. | ||
| """ | ||
| # Validate it's a simple path expression (no filters, wildcards, etc.) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please remove comments |
||
| if not utils_jmespath.is_simple_path_expression(query): | ||
| raise FabricCLIError( | ||
| CommonErrors.query_contains_filters_or_wildcards(query), | ||
| fab_constant.ERROR_INVALID_QUERY, | ||
| ) | ||
|
|
||
| # Combine common invalid queries with resource-specific ones | ||
| all_invalid_queries = fab_constant.SET_COMMAND_INVALID_QUERIES.copy() | ||
| if resource_specific_invalid_queries: | ||
| all_invalid_queries.extend(resource_specific_invalid_queries) | ||
|
|
||
| # Check if query matches or is a sub-path of any invalid key | ||
| for invalid_key in all_invalid_queries: | ||
| if query == invalid_key or query.startswith(f"{invalid_key}."): | ||
| raise FabricCLIError( | ||
| CommonErrors.query_not_supported_for_set(query), | ||
| fab_constant.ERROR_INVALID_QUERY, | ||
| ) | ||
|
|
||
|
|
||
| def ensure_notebook_dependency(decoded_item_def: dict, query: str) -> dict: | ||
| dependency_types = ["lakehouse", "warehouse", "environment"] | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.