From efeb55ba367a01118cd50c9b70ac1595c0402ef7 Mon Sep 17 00:00:00 2001 From: Aditya Jain Date: Wed, 19 Aug 2026 23:39:36 -0700 Subject: [PATCH] Fix UnboundLocalError in ConfigFileWriter._update_subattributes for empty nested sections current_indent (and the loop index i) were only assigned when a sub-option line matched OPTION_REGEX. Updating a nested section that currently has no sub-keys (e.g. `s3 =` immediately followed by another [section] header, or as the last line of the file) left these variables unbound, raising UnboundLocalError instead of writing the value. Initialize current_indent to None and i to the pre-loop index so both previously-crashing cases insert the new values correctly, matching the behavior of the equivalent non-empty-section cases. Fixes #10587 --- .../next-release/bugfix-configure-10587.json | 5 ++++ awscli/customizations/configure/writer.py | 2 ++ .../customizations/configure/test_writer.py | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 .changes/next-release/bugfix-configure-10587.json diff --git a/.changes/next-release/bugfix-configure-10587.json b/.changes/next-release/bugfix-configure-10587.json new file mode 100644 index 000000000000..5497115a7c46 --- /dev/null +++ b/.changes/next-release/bugfix-configure-10587.json @@ -0,0 +1,5 @@ +{ + "type": "bugfix", + "category": "configure", + "description": "Fixed an `UnboundLocalError` raised by `aws configure set` when updating a nested config section (e.g. `s3`, `s3api`) that currently has no sub-keys under it." +} diff --git a/awscli/customizations/configure/writer.py b/awscli/customizations/configure/writer.py index 83825a53dab6..6b5f4be7c315 100644 --- a/awscli/customizations/configure/writer.py +++ b/awscli/customizations/configure/writer.py @@ -215,6 +215,8 @@ def _update_section_contents(self, contents, section_name, new_values): def _update_subattributes(self, index, contents, values, starting_indent): index += 1 + current_indent = None + i = index - 1 for i in range(index, len(contents)): line = contents[i] match = self.OPTION_REGEX.search(line) diff --git a/tests/unit/customizations/configure/test_writer.py b/tests/unit/customizations/configure/test_writer.py index 9c85516762ef..cf662ab33299 100644 --- a/tests/unit/customizations/configure/test_writer.py +++ b/tests/unit/customizations/configure/test_writer.py @@ -326,6 +326,34 @@ def test_updated_nested_attribute_new_section(self): '[profile foo]\n' 'foo = bar\n') + def test_add_to_empty_nested_stanza_followed_by_section(self): + original = ( + '[default]\n' + 's3 =\n' + '[profile foo]\n' + 'foo = bar\n' + ) + self.assert_update_config( + original, {'__section__': 'default', + 's3': {'signature_version': 'newval'}}, + '[default]\n' + 's3 =\n' + ' signature_version = newval\n' + '[profile foo]\n' + 'foo = bar\n') + + def test_add_to_empty_nested_stanza_at_eof(self): + original = ( + '[default]\n' + 's3 =\n' + ) + self.assert_update_config( + original, {'__section__': 'default', + 's3': {'signature_version': 'newval'}}, + '[default]\n' + 's3 =\n' + ' signature_version = newval\n') + def test_update_nested_attr_no_prior_nesting(self): original = ( '[default]\n'