From bf515341f12e589ac56755fa5a98d7aef789961f Mon Sep 17 00:00:00 2001 From: tytv2 Date: Sun, 12 Apr 2026 16:29:45 +0700 Subject: [PATCH] security: remove GRN_CLIENT_ID/SECRET env var support, update CLAUDE.md doc rules --- CLAUDE.md | 11 +++++++---- README.md | 4 +--- docs/configuration.md | 2 -- grncli/customizations/configure/list.py | 5 ----- grncli/session.py | 8 +------- tests/functional/test_cli_integration.py | 2 -- tests/unit/test_session.py | 10 ---------- 7 files changed, 9 insertions(+), 33 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d88f209..8750bdd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -76,11 +76,14 @@ python -m pytest tests/ -v 2. **CHANGELOG**: Add changelog fragment via `./scripts/new-change` -3. **Spec** (`docs/superpowers/specs/2026-04-10-greenode-cli-design.md`): - - Update command list in Section 4 - - Update file structure in Section 2 if new files added +3. **README.md**: Update if installation, configuration, or basic commands change -This is not optional. Code without docs is not done. +4. **CLAUDE.md**: Update if conventions, security rules, or key files change + +**After ANY change to business logic, security, configuration, or commands:** +Review ALL docs above and update what's affected. If unsure whether a doc needs updating, read it and check. + +Code without docs is not done. ## Key files diff --git a/README.md b/README.md index 4535940..9c751ea 100644 --- a/README.md +++ b/README.md @@ -59,11 +59,9 @@ Default output format [json]: Credentials are obtained from the [VNG Cloud IAM Portal](https://hcm-3.console.vngcloud.vn/iam/) under Service Accounts. -You can also configure credentials via environment variables: +You can also configure the region via environment variable: ```bash -export GRN_CLIENT_ID= -export GRN_CLIENT_SECRET= export GRN_DEFAULT_REGION=HCM-3 ``` diff --git a/docs/configuration.md b/docs/configuration.md index ccb0d88..001b152 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -84,8 +84,6 @@ grn vks list-clusters | Variable | Description | |----------|-------------| -| `GRN_CLIENT_ID` | Client ID (overrides config file) | -| `GRN_CLIENT_SECRET` | Client Secret (overrides config file) | | `GRN_DEFAULT_REGION` | Default region | | `GRN_PROFILE` | Profile name | | `GRN_DEFAULT_OUTPUT` | Output format | diff --git a/grncli/customizations/configure/list.py b/grncli/customizations/configure/list.py index 7cfbf92..4c903e7 100644 --- a/grncli/customizations/configure/list.py +++ b/grncli/customizations/configure/list.py @@ -45,11 +45,6 @@ def _resolve_profile(self, profile): return ('profile', '', 'None', 'None') def _resolve_credential(self, key): - env_map = {'client_id': 'GRN_CLIENT_ID', 'client_secret': 'GRN_CLIENT_SECRET'} - env_var = env_map.get(key, '') - env_val = os.environ.get(env_var) - if env_val: - return (key, self._mask_value(env_val), 'env', env_var) try: creds = self._session.get_credentials() value = creds.get(key) diff --git a/grncli/session.py b/grncli/session.py index 1854057..19e02c9 100644 --- a/grncli/session.py +++ b/grncli/session.py @@ -31,8 +31,7 @@ class Session: """Manages config, credentials, region, and service endpoints. Credential resolution order (high → low priority): - 1. Environment variables: GRN_CLIENT_ID, GRN_CLIENT_SECRET - 2. Profile in ~/.greenode/credentials + 1. Profile in ~/.greenode/credentials """ def __init__( @@ -98,11 +97,6 @@ def emit_first_non_none(self, event_name: str, **kwargs) -> Any: return self._emitter.emit_first_non_none(event_name, **kwargs) def get_credentials(self) -> dict[str, str]: - env_id = os.environ.get('GRN_CLIENT_ID') - env_secret = os.environ.get('GRN_CLIENT_SECRET') - if env_id and env_secret: - return {'client_id': env_id, 'client_secret': env_secret} - if self._credentials_cache is not None: return self._credentials_cache diff --git a/tests/functional/test_cli_integration.py b/tests/functional/test_cli_integration.py index bf166c4..59c6154 100644 --- a/tests/functional/test_cli_integration.py +++ b/tests/functional/test_cli_integration.py @@ -24,8 +24,6 @@ def greenode_config(tmp_path): config.write_text("[default]\nregion = HCM-3\noutput = json\n") with patch.dict(os.environ, {}, clear=False): - os.environ.pop('GRN_CLIENT_ID', None) - os.environ.pop('GRN_CLIENT_SECRET', None) os.environ.pop('GRN_DEFAULT_REGION', None) os.environ.pop('GRN_PROFILE', None) diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py index 813e291..5ebdbdb 100644 --- a/tests/unit/test_session.py +++ b/tests/unit/test_session.py @@ -49,16 +49,6 @@ def test_load_profile_credentials(self, config_dir): assert creds['client_id'] == 'staging-id' assert creds['client_secret'] == 'staging-secret' - def test_env_vars_override_file(self, config_dir): - with patch.dict(os.environ, { - 'GRN_CLIENT_ID': 'env-id', - 'GRN_CLIENT_SECRET': 'env-secret', - }): - session = Session(config_dir=str(config_dir)) - creds = session.get_credentials() - assert creds['client_id'] == 'env-id' - assert creds['client_secret'] == 'env-secret' - def test_missing_credentials_raises(self, tmp_path): session = Session(config_dir=str(tmp_path)) with pytest.raises(Exception, match="credentials"):