diff --git a/changelog/1240.bugfix.rst b/changelog/1240.bugfix.rst new file mode 100644 index 00000000..e94ff704 --- /dev/null +++ b/changelog/1240.bugfix.rst @@ -0,0 +1,2 @@ +``twine`` now catches ``configparser.Error`` to prevent accidental +leaks of secret tokens or passwords to the user's console. diff --git a/tests/test_utils.py b/tests/test_utils.py index 88e324fc..37c8fad7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -227,6 +227,36 @@ def test_get_repository_config_missing_repository(write_config_file): utils.get_repository_from_config(config_file, "missing-repository") +@pytest.mark.parametrize( + "invalid_config", + [ + # No surrounding [server] section + """ + username = testuser + password = testpassword + """, + # Valid section but bare API token + """ + [pypi] + pypi-lolololol + """, + # No section, bare API token + """ + pypi-lolololol + """, + ], +) +def test_get_repository_config_invalid_syntax(write_config_file, invalid_config): + """Raise an exception when the .pypirc has invalid syntax.""" + config_file = write_config_file(invalid_config) + + with pytest.raises( + exceptions.InvalidConfiguration, + match="Malformed configuration", + ): + utils.get_repository_from_config(config_file, "pypi") + + @pytest.mark.parametrize("repository", ["pypi", "missing-repository"]) def test_get_repository_config_missing_file(repository): """Raise an exception when a custom config file doesn't exist.""" diff --git a/twine/utils.py b/twine/utils.py index 2bc56d0b..2ea9ca9f 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -159,6 +159,13 @@ def get_repository_from_config( f"Missing '{repository}' section from {config_file}.\n" f"More info: https://packaging.python.org/specifications/pypirc/ " ) + except configparser.Error: + # NOTE: We intentionally fully mask the configparser exception here, + # since it could leak tokens and other sensitive values. + raise exceptions.InvalidConfiguration( + f"Malformed configuration in {config_file}.\n" + f"More info: https://packaging.python.org/specifications/pypirc/ " + ) config["repository"] = normalize_repository_url(cast(str, config["repository"])) return config