From 248354135657ce3a498a2fbbccbe37957acafcbb Mon Sep 17 00:00:00 2001 From: Juan Denis Date: Mon, 15 Jun 2026 23:55:03 -0400 Subject: [PATCH] fix(storage): create the config file's own dir in save_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit save_config() ran os.makedirs(SERVERKIT_CONFIG_DIR) unconditionally rather than the directory of the file it actually writes (cls.CONFIG_FILE). When a caller overrides CONFIG_FILE (test_storage_secret_encrypted_at_rest points it at a pytest tmp dir), creating the real config dir failed on the sandboxed CI runner and — because the surrounding except swallows it and returns {success: False} — the file was never written, surfacing as a confusing FileNotFoundError. Now makedirs(dirname(CONFIG_FILE)); production behavior is unchanged (there dirname(CONFIG_FILE) == SERVERKIT_CONFIG_DIR). 8/8 encryption tests pass; full backend suite was 241 passed / 1 failed -> now green. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/app/services/storage_provider_service.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/app/services/storage_provider_service.py b/backend/app/services/storage_provider_service.py index 935d1a50..9d7931e8 100644 --- a/backend/app/services/storage_provider_service.py +++ b/backend/app/services/storage_provider_service.py @@ -84,7 +84,14 @@ class StorageProviderService: def save_config(cls, config: Dict) -> Dict: """Save storage provider configuration.""" try: - os.makedirs(paths.SERVERKIT_CONFIG_DIR, exist_ok=True) + # Ensure the parent of the file we actually write exists. Using + # cls.CONFIG_FILE (not the hardcoded SERVERKIT_CONFIG_DIR) honors a + # CONFIG_FILE override — e.g. tests pointing it at a tmp dir — and + # is identical in production, where CONFIG_FILE lives in + # SERVERKIT_CONFIG_DIR. Previously this tried to create the real + # config dir unconditionally, which raised on a sandboxed CI runner + # and (because the except below swallows it) left the file unwritten. + os.makedirs(os.path.dirname(cls.CONFIG_FILE) or '.', exist_ok=True) # Merge with existing config to preserve unmasked secrets existing = cls.get_config()