Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
8694dfe
SNOW-2306184: config refactory entry point guarded by env
sfc-gh-mraba Oct 2, 2025
7a178e0
SNOW-2306184: config refactory entry point guarded by env - fix snapshot
sfc-gh-mraba Oct 3, 2025
0808a88
SNOW-2306184: config refactory - core abstraction
sfc-gh-mraba Oct 3, 2025
b1fd701
SNOW-2306184: config refactory - top tier configuration sources
sfc-gh-mraba Oct 3, 2025
807b786
SNOW-2306184: config refactory - env vars discovery
sfc-gh-mraba Oct 6, 2025
2613e47
SNOW-2306184: config refactory - move key mappings to module level
sfc-gh-mraba Oct 6, 2025
a2b25df
SNOW-2306184: config refactory - SnowSQL config files behaviour
sfc-gh-mraba Oct 6, 2025
9d43613
SNOW-2306184: config refactory - resolver history
sfc-gh-mraba Oct 6, 2025
f417de5
SNOW-2306184: config refactory - integrate new config
sfc-gh-mraba Oct 7, 2025
28b958f
SNOW-2306184: config refactory - helpers command integration
sfc-gh-mraba Oct 7, 2025
6dbc22d
SNOW-2306184: config refactory - config testing setup
sfc-gh-mraba Oct 8, 2025
d1f569e
SNOW-2306184: config refactory - fix snowsql config format parsing
sfc-gh-mraba Oct 8, 2025
dc506f1
SNOW-2306184: config refactory - drop tests for language functionality
sfc-gh-mraba Oct 8, 2025
2b51f76
SNOW-2306184: config refactory - drop tests for language functionalit…
sfc-gh-mraba Oct 8, 2025
e11d294
SNOW-2306184: config refactory - cleanup source config handlers naming
sfc-gh-mraba Oct 8, 2025
1b9e9f4
SNOW-2306184: config refactory - cleanup source ConfigValue creation
sfc-gh-mraba Oct 8, 2025
4364081
SNOW-2306184: config refactor - simplify abstractions
sfc-gh-mraba Oct 8, 2025
f60495b
SNOW-2306184: config refactor - simplified implementation
sfc-gh-mraba Oct 9, 2025
59b18b9
SNOW-2306184: config refactor - gh workflows
sfc-gh-mraba Oct 9, 2025
f34bfb3
SNOW-2306184: config refactor - cli env update
sfc-gh-mraba Oct 9, 2025
92ba812
SNOW-2306184: config refactor - snowsql env support
sfc-gh-mraba Oct 9, 2025
c2d4c75
SNOW-2306184: config refactor - restore temp conn
sfc-gh-mraba Oct 9, 2025
d1419aa
SNOW-2306184: config refactor - tests-ng fix
sfc-gh-mraba Oct 9, 2025
2fbbd23
SNOW-2306184: config refactor - integrations ng
sfc-gh-mraba Oct 9, 2025
f021e26
SNOW-2306184: config refactor - old & new unit tests pass
sfc-gh-mraba Oct 9, 2025
dd71995
SNOW-2306184: config refactor - old & new unit tests
sfc-gh-mraba Oct 10, 2025
2a339a9
SNOW-2306184: config refactor - plugin tests in JSON format
sfc-gh-mraba Oct 10, 2025
0caa52c
SNOW-2306184: config refactor - e2e fix attempt
sfc-gh-mraba Oct 10, 2025
048e62b
SNOW-2306184: config refactor - e2e fix attempt 3
sfc-gh-mraba Oct 10, 2025
f9f1b35
SNOW-2306184: config refactor - e2e fix attempt 4
sfc-gh-mraba Oct 10, 2025
03edd7c
SNOW-2306184: config refactor - e2e fix attempt 5
sfc-gh-mraba Oct 10, 2025
67ed4be
SNOW-2306184: config refactor - e2e fix attempt 5a
sfc-gh-mraba Oct 10, 2025
187f833
SNOW-2306184: config refactor - e2e fix attempt 5b
sfc-gh-mraba Oct 10, 2025
d28e4ef
SNOW-2306184: config refactor - config_snapshot to distingush between…
sfc-gh-mraba Oct 13, 2025
e8680d4
SNOW-2306184: config refactor - invalidate singleton between tests
sfc-gh-mraba Oct 13, 2025
f19c289
SNOW-2306184: config refactor - list connections --all
sfc-gh-mraba Oct 13, 2025
2c8183e
SNOW-2306184: config refactor - snapshot COLUMNS=200
sfc-gh-mraba Oct 13, 2025
3b11fe7
SNOW-2306184: config refactor - snapshot fix 2
sfc-gh-mraba Oct 13, 2025
0e6f52e
SNOW-2306184: config refactor - snapshot fix 3
sfc-gh-mraba Oct 13, 2025
e77f0b1
SNOW-2306184: config refactor - show-config-sources tests
sfc-gh-mraba Oct 13, 2025
ad64e0d
SNOW-2306184: config refactor - more merging tests
sfc-gh-mraba Oct 14, 2025
8e177a0
SNOW-2306184: config refactor - connections toml merging split
sfc-gh-mraba Oct 15, 2025
0e38f93
SNOW-2306184: config refactor - cleanup 1
sfc-gh-mraba Oct 15, 2025
9b5dd26
SNOW-2306184: config refactor - cleanup 2
sfc-gh-mraba Oct 15, 2025
70215d6
SNOW-2306184: config refactor - cleanup 3
sfc-gh-mraba Oct 15, 2025
ade4605
SNOW-2306184: config refactor - cleanup 4
sfc-gh-mraba Oct 15, 2025
8139f54
SNOW-2306184: config refactor - cleanup 5
sfc-gh-mraba Oct 15, 2025
e841d24
SNOW-2306184: config refactor - connections.toml legacy behaviour
sfc-gh-mraba Oct 15, 2025
a50e5f6
SNOW-2306184: config refactor - improve resolution raport
sfc-gh-mraba Oct 15, 2025
918ef34
SNOW-2306184: config refactor - improve connections env parsing
sfc-gh-mraba Oct 15, 2025
a9c7896
SNOW-2306184: config refactor - clean tmp files
sfc-gh-mraba Oct 15, 2025
bfe85b4
SNOW-2306184: config refactor - connection level overwrite for config…
sfc-gh-mraba Oct 16, 2025
0b549d0
SNOW-2306184: config refactor - variables merge
sfc-gh-mraba Oct 16, 2025
2f20e32
SNOW-2306184: config refactor - separate parsing from reading and mov…
sfc-gh-mraba Oct 20, 2025
8194a60
SNOW-2306184: config refactor - Release Notes
sfc-gh-mraba Oct 21, 2025
af5d0d0
SNOW-2306184: config refactor - telemetry
sfc-gh-mraba Oct 22, 2025
29208dc
SNOW-2306184: config refactor - telemetry test update
sfc-gh-mraba Oct 22, 2025
17a2999
SNOW-2306184: config refactor - allow empty connections
sfc-gh-mraba Oct 23, 2025
a64e423
SNOW-2306184: config refactor - allow empty connections test fix
sfc-gh-mraba Oct 23, 2025
c1e4956
SNOW-2306184: config refactor - after rebase fixes
sfc-gh-mraba Oct 23, 2025
3425638
SNOW-2306184: config refactor - after rebase fixes 2
sfc-gh-mraba Oct 23, 2025
843c1fa
SNOW-2306184: config refactor - remove comments
sfc-gh-mraba Oct 24, 2025
3d80a44
SNOW-2306184: config refactor - value masking for ResolutionHistory
sfc-gh-mraba Nov 17, 2025
df5960a
SNOW-2306184: config refactor - in memory pk
sfc-gh-mraba Nov 18, 2025
cbac3ab
SNOW-2306184: config refactor - ensure file permissions checks
sfc-gh-mraba Nov 18, 2025
a7d8843
SNOW-2306184: config refactor - tests for value masking
sfc-gh-mraba Nov 18, 2025
4468fa9
SNOW-2306184: config refactor - oauth typo
sfc-gh-mraba Nov 18, 2025
c594a76
SNOW-2306184: config refactor - thread safe singleton
sfc-gh-mraba Nov 18, 2025
463b436
SNOW-2306184: config refactor - try_cast_to_bool compatibility added
sfc-gh-mraba Nov 18, 2025
e9e0225
SNOW-2306184: config refactor - sanitize logging
sfc-gh-mraba Nov 18, 2025
c949d3a
SNOW-2306184: config refactor - remove tomli conditional import
sfc-gh-mraba Nov 18, 2025
bf7273b
SNOW-2306184: config refactor - test fix
sfc-gh-mraba Nov 18, 2025
7b64a33
SNOW-2306184: config refactor - test fix 2
sfc-gh-mraba Nov 18, 2025
b2dafe4
SNOW-2306184: config refactor - ensure file permissions checks - plug…
sfc-gh-mraba Nov 19, 2025
5994714
SNOW-2306184: config refactor - top level conn params
sfc-gh-mraba Nov 19, 2025
da8f5ef
SNOW-2306184: config refactor - improve performance for key discovery
sfc-gh-mraba Nov 24, 2025
dc214c2
SNOW-2306184: config refactor - silent exceptions logged as warning w…
sfc-gh-mraba Nov 24, 2025
26d2396
SNOW-2306184: config refactor - silent exceptions logged as warning w…
sfc-gh-mraba Nov 24, 2025
f57daf1
SNOW-2306184: config refactor - track resolution history only when re…
sfc-gh-mraba Nov 25, 2025
8fe3463
SNOW-2306184: config refactor - track resolution history only when re…
sfc-gh-mraba Nov 25, 2025
124e9e0
SNOW-2306184: config refactor - track resolution history only when re…
sfc-gh-mraba Nov 25, 2025
589e82e
SNOW-2306184: config refactor - move from Literal to Enum
sfc-gh-mraba Dec 2, 2025
4b45a3e
SNOW-2306184: config refactor - SnowSQL default fallback
sfc-gh-mraba Dec 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- features/*

env:
TERM: unknown # Disables colors in rich
TERM: unknown # Disables colors in rich

permissions:
contents: read
Expand Down Expand Up @@ -43,3 +43,29 @@ jobs:
- name: Test with hatch
run: hatch run test-cov
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24

tests-config-ng:
needs: define-matrix
strategy:
fail-fast: true
matrix:
os: ${{ fromJSON(needs.define-matrix.outputs.os) }}
python-version: ${{ fromJSON(needs.define-matrix.outputs.python) }}
runs-on: ${{ matrix.os }}
env:
SNOWFLAKE_CLI_CONFIG_V2_ENABLED: 1
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install hatch
run: |
pip install -U click==8.2.1 hatch
hatch env create default
- name: Test with hatch
run: hatch run test-cov
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
28 changes: 28 additions & 0 deletions .github/workflows/test_trusted.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,31 @@ jobs:
SNOWFLAKE_CONNECTIONS_INTEGRATION_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_PRIVATE_KEY_RAW: ${{ secrets.SNOWFLAKE_PRIVATE_KEY_RAW }}
run: python -m hatch run ${{ inputs.hatch-run }}

tests-trusted-ng:
runs-on: ${{ inputs.runs-on }}
env:
SNOWFLAKE_CLI_CONFIG_V2_ENABLED: 1
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip click==8.2.1 hatch
python -m hatch env create ${{ inputs.python-env }}
- name: Run integration tests
env:
GH_TOKEN: ${{ secrets.SNOWFLAKE_GITHUB_TOKEN }}
TERM: unknown
SNOWFLAKE_CONNECTIONS_INTEGRATION_AUTHENTICATOR: SNOWFLAKE_JWT
SNOWFLAKE_CONNECTIONS_INTEGRATION_HOST: ${{ secrets.SNOWFLAKE_HOST }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
SNOWFLAKE_CONNECTIONS_INTEGRATION_PRIVATE_KEY_RAW: ${{ secrets.SNOWFLAKE_PRIVATE_KEY_RAW }}
run: python -m hatch run ${{ inputs.hatch-run }}
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
-->
# Unreleased version
## Backward incompatibility
* **Configuration System (NG)**: File-based configuration sources (`snowsql_config`, `cli_config_toml`, `connections_toml`) now use **connection-level replacement** instead of field-level merging. When a later file source defines a connection, it completely replaces the entire connection from earlier file sources - fields are NOT inherited. Environment variables and CLI arguments continue to overlay per-field on top of the file-derived connection. This provides more predictable configuration behavior where file-defined connections are atomic units.

## Deprecations

Expand Down
51 changes: 51 additions & 0 deletions src/snowflake/cli/_app/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class CLITelemetryField(Enum):
COMMAND_CI_ENVIRONMENT = "command_ci_environment"
# Configuration
CONFIG_FEATURE_FLAGS = "config_feature_flags"
CONFIG_PROVIDER_TYPE = "config_provider_type"
CONFIG_SOURCES_USED = "config_sources_used"
CONFIG_SOURCE_WINS = "config_source_wins"
CONFIG_TOTAL_KEYS_RESOLVED = "config_total_keys_resolved"
CONFIG_KEYS_WITH_OVERRIDES = "config_keys_with_overrides"
# Metrics
COUNTERS = "counters"
SPANS = "spans"
Expand Down Expand Up @@ -219,6 +224,51 @@ def python_version() -> str:
return f"{py_ver.major}.{py_ver.minor}.{py_ver.micro}"


def _get_config_telemetry() -> TelemetryDict:
"""Get configuration resolution telemetry data."""
try:
from snowflake.cli.api.config_provider import (
AlternativeConfigProvider,
get_config_provider_singleton,
)

provider = get_config_provider_singleton()

# Identify which config provider is being used
provider_type = (
"ng" if isinstance(provider, AlternativeConfigProvider) else "legacy"
)

result: TelemetryDict = {CLITelemetryField.CONFIG_PROVIDER_TYPE: provider_type}

# Get detailed telemetry if using ng config
if isinstance(provider, AlternativeConfigProvider):
payload = provider.resolution_summary

# Map payload keys to telemetry fields
if payload:
if "config_sources_used" in payload:
result[CLITelemetryField.CONFIG_SOURCES_USED] = payload[
"config_sources_used"
]
if "config_source_wins" in payload:
result[CLITelemetryField.CONFIG_SOURCE_WINS] = payload[
"config_source_wins"
]
if "config_total_keys_resolved" in payload:
result[CLITelemetryField.CONFIG_TOTAL_KEYS_RESOLVED] = payload[
"config_total_keys_resolved"
]
if "config_keys_with_overrides" in payload:
result[CLITelemetryField.CONFIG_KEYS_WITH_OVERRIDES] = payload[
"config_keys_with_overrides"
]

return result
except Exception:
return {}


class CLITelemetryClient:
@property
def _ctx(self) -> _CliGlobalContextAccess:
Expand All @@ -239,6 +289,7 @@ def generate_telemetry_data_dict(
k: str(v) for k, v in get_feature_flags_section().items()
},
**_find_command_info(),
**_get_config_telemetry(),
**telemetry_payload,
}
# To map Enum to string, so we don't have to use .value every time
Expand Down
39 changes: 30 additions & 9 deletions src/snowflake/cli/_plugins/connection/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
set_config_value,
unset_config_value,
)
from snowflake.cli.api.config_ng.masking import mask_sensitive_value
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.constants import ObjectType
from snowflake.cli.api.output.types import (
Expand All @@ -85,25 +86,45 @@ def __repr__(self):
return "optional"


def _mask_sensitive_parameters(connection_params: dict):
if "password" in connection_params:
connection_params["password"] = "****"
if "oauth_client_secret" in connection_params:
connection_params["oauth_client_secret"] = "****"
return connection_params
def mask_sensitive_parameters(connection_params: dict):
return {
key: mask_sensitive_value(key, value)
for key, value in connection_params.items()
}


@app.command(name="list")
def list_connections(**options) -> CommandResult:
def list_connections(
all_sources: bool = typer.Option(
False,
"--all",
"-a",
help="Include connections from all sources (environment variables, SnowSQL config). "
"By default, only shows connections from configuration files.",
),
**options,
) -> CommandResult:
"""
Lists configured connections.
"""
connections = get_all_connections()
from snowflake.cli.api.config_provider import (
get_config_provider_singleton,
is_alternative_config_enabled,
)

# Use provider directly for config_ng to pass the flag
if is_alternative_config_enabled():
provider = get_config_provider_singleton()
connections = provider.get_all_connections(include_env_connections=all_sources)
else:
# Legacy provider ignores the flag
connections = get_all_connections()

default_connection = get_default_connection_name()
result = (
{
"connection_name": connection_name,
"parameters": _mask_sensitive_parameters(
"parameters": mask_sensitive_parameters(
connection_config.to_dict_of_known_non_empty_values()
),
"is_default": connection_name == default_connection,
Expand Down
87 changes: 87 additions & 0 deletions src/snowflake/cli/_plugins/helpers/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
get_all_connections,
set_config_value,
)
from snowflake.cli.api.config_provider import ALTERNATIVE_CONFIG_ENV_VAR
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.output.types import (
CollectionResult,
Expand Down Expand Up @@ -317,3 +318,89 @@ def check_snowsql_env_vars(**options):

results.append(MessageResult(summary))
return MultipleResults(results)


@app.command(
name="show-config-sources",
requires_connection=False,
hidden=os.environ.get(ALTERNATIVE_CONFIG_ENV_VAR, "").lower()
not in ("1", "true", "yes", "on"),
)
def show_config_sources(
key: Optional[str] = typer.Argument(
None,
help="Specific configuration key to show resolution for (e.g., 'account', 'user'). If not provided, shows summary for all keys.",
),
show_details: bool = typer.Option(
False,
"--show-details",
"-d",
help="Show detailed resolution chains for all sources consulted.",
),
export_file: Optional[Path] = typer.Option(
None,
"--export",
"-e",
help="Export complete resolution history to JSON file for support or debugging.",
file_okay=True,
dir_okay=False,
),
**options,
) -> CommandResult:
"""
Show where configuration values come from.

This command displays the configuration resolution process, showing which
source (CLI arguments, environment variables, or config files) provided
each configuration value. Useful for debugging configuration issues.

Examples:

# Show summary of all configuration resolution
snow helpers show-config-sources

# Show detailed resolution for all keys
snow helpers show-config-sources --show-details

# Show resolution for a specific key
snow helpers show-config-sources account

# Show detailed resolution for a specific key
snow helpers show-config-sources account --show-details

# Export complete resolution history to file
snow helpers show-config-sources --export config_debug.json

Note: This command requires the enhanced configuration system to be enabled.
Set SNOWFLAKE_CLI_CONFIG_V2_ENABLED=true to enable it.
"""
from snowflake.cli.api.config_ng import (
export_resolution_history,
is_resolution_logging_available,
)
from snowflake.cli.api.config_ng.resolution_logger import (
get_configuration_explanation_results,
)

if not is_resolution_logging_available():
return MessageResult(
f"⚠️ Configuration resolution logging is not available.\n\n"
f"To enable it, set the environment variable:\n"
f" export {ALTERNATIVE_CONFIG_ENV_VAR}=true\n\n"
f"Then run this command again to see where configuration values come from."
)

# Export if requested
if export_file:
success = export_resolution_history(export_file)
if not success:
return MessageResult(
f"❌ Failed to export resolution history to {export_file}"
)
return MessageResult(
f"✅ Resolution history exported to: {export_file}\n\n"
f"This file contains complete details about configuration resolution "
f"and can be attached to support tickets."
)

return get_configuration_explanation_results(key=key, verbose=show_details)
7 changes: 3 additions & 4 deletions src/snowflake/cli/_plugins/sql/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
)
from snowflake.cli.api.commands.overrideable_parameter import OverrideableOption
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
from snowflake.cli.api.commands.utils import parse_key_value_variables
from snowflake.cli.api.exceptions import CliArgumentError
from snowflake.cli.api.output.types import (
CommandResult,
Expand Down Expand Up @@ -136,9 +135,9 @@ def execute_sql(
The command supports variable substitution that happens on client-side.
"""

data = {}
if data_override:
data = {v.key: v.value for v in parse_key_value_variables(data_override)}
from snowflake.cli.api.config_ng import get_merged_variables

data = get_merged_variables(data_override)

template_syntax_config = _parse_template_syntax_config(enabled_templating)

Expand Down
8 changes: 6 additions & 2 deletions src/snowflake/cli/_plugins/stage/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
OnErrorType,
Variable,
)
from snowflake.cli.api.commands.utils import parse_key_value_variables
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.constants import PYTHON_3_12
from snowflake.cli.api.exceptions import CliError
Expand Down Expand Up @@ -608,7 +607,12 @@ def execute(
filtered_file_list, key=lambda f: (path.dirname(f), path.basename(f))
)

parsed_variables = parse_key_value_variables(variables)
from snowflake.cli.api.config_ng import get_merged_variables

# Get merged variables from SnowSQL config and CLI -D parameters
merged_vars_dict = get_merged_variables(variables)
# Convert dict back to List[Variable] for compatibility with existing methods
parsed_variables = [Variable(k, v) for k, v in merged_vars_dict.items()]
sql_variables = self.parse_execute_variables(parsed_variables)
python_variables = self._parse_python_variables(parsed_variables)
results = []
Expand Down
Loading
Loading