snowflake-connector-python 3.13.0__tar.gz → 3.13.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/DESCRIPTION.md +5 -0
  2. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/PKG-INFO +6 -1
  3. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/_auth.py +6 -1
  4. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/cache.py +11 -3
  5. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/cursor.py +6 -2
  6. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/encryption_util.py +2 -1
  7. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/file_util.py +4 -0
  8. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/ocsp_snowflake.py +161 -5
  9. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/pandas_tools.py +93 -29
  10. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/storage_client.py +7 -2
  11. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/util_text.py +5 -0
  12. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/version.py +1 -1
  13. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/PKG-INFO +6 -1
  14. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/CONTRIBUTING.md +0 -0
  15. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/LICENSE.txt +0 -0
  16. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/MANIFEST.in +0 -0
  17. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/NOTICE +0 -0
  18. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/README.md +0 -0
  19. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/SECURITY.md +0 -0
  20. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/pyproject.toml +0 -0
  21. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/setup.cfg +0 -0
  22. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/setup.py +0 -0
  23. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/__init__.py +0 -0
  24. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/_query_context_cache.py +0 -0
  25. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/_sql_util.py +0 -0
  26. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/_utils.py +0 -0
  27. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/arrow_context.py +0 -0
  28. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/__init__.py +0 -0
  29. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/by_plugin.py +0 -0
  30. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/default.py +0 -0
  31. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/idtoken.py +0 -0
  32. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/keypair.py +0 -0
  33. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/oauth.py +0 -0
  34. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/okta.py +0 -0
  35. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/pat.py +0 -0
  36. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/usrpwdmfa.py +0 -0
  37. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/auth/webbrowser.py +0 -0
  38. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/azure_storage_client.py +0 -0
  39. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/backoff_policies.py +0 -0
  40. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/bind_upload_agent.py +0 -0
  41. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/compat.py +0 -0
  42. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/config_manager.py +0 -0
  43. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/connection.py +0 -0
  44. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/connection_diagnostic.py +0 -0
  45. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/constants.py +0 -0
  46. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/converter.py +0 -0
  47. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/converter_issue23517.py +0 -0
  48. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/converter_null.py +0 -0
  49. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/converter_snowsql.py +0 -0
  50. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/dbapi.py +0 -0
  51. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/description.py +0 -0
  52. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/errorcode.py +0 -0
  53. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/errors.py +0 -0
  54. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/feature.py +0 -0
  55. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/file_compression_type.py +0 -0
  56. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/file_transfer_agent.py +0 -0
  57. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/gcs_storage_client.py +0 -0
  58. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/gzip_decoder.py +0 -0
  59. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/local_storage_client.py +0 -0
  60. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/log_configuration.py +0 -0
  61. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +0 -0
  62. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +0 -0
  63. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +0 -0
  64. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +0 -0
  65. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +0 -0
  66. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +0 -0
  67. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +0 -0
  68. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +0 -0
  69. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +0 -0
  70. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +0 -0
  71. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +0 -0
  72. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +0 -0
  73. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +0 -0
  74. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +0 -0
  75. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +0 -0
  76. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +0 -0
  77. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +0 -0
  78. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +0 -0
  79. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +0 -0
  80. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +0 -0
  81. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +0 -0
  82. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +0 -0
  83. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +0 -0
  84. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +0 -0
  85. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +0 -0
  86. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +0 -0
  87. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +0 -0
  88. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +0 -0
  89. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +0 -0
  90. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +0 -0
  91. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +0 -0
  92. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +0 -0
  93. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +0 -0
  94. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +0 -0
  95. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +0 -0
  96. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +0 -0
  97. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +0 -0
  98. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +0 -0
  99. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +0 -0
  100. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +0 -0
  101. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +0 -0
  102. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +0 -0
  103. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +0 -0
  104. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +0 -0
  105. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +0 -0
  106. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +0 -0
  107. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +0 -0
  108. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +0 -0
  109. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +0 -0
  110. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +0 -0
  111. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +0 -0
  112. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +0 -0
  113. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +0 -0
  114. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +0 -0
  115. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +0 -0
  116. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +0 -0
  117. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +0 -0
  118. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +0 -0
  119. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +0 -0
  120. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +0 -0
  121. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +0 -0
  122. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +0 -0
  123. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +0 -0
  124. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +0 -0
  125. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +0 -0
  126. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +0 -0
  127. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +0 -0
  128. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +0 -0
  129. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +0 -0
  130. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +0 -0
  131. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +0 -0
  132. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +0 -0
  133. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +0 -0
  134. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +0 -0
  135. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +0 -0
  136. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +0 -0
  137. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +0 -0
  138. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +0 -0
  139. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +0 -0
  140. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +0 -0
  141. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +0 -0
  142. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +0 -0
  143. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +0 -0
  144. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +0 -0
  145. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +0 -0
  146. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +0 -0
  147. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +0 -0
  148. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/network.py +0 -0
  149. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/ocsp_asn1crypto.py +0 -0
  150. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/options.py +0 -0
  151. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/proxy.py +0 -0
  152. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/py.typed +0 -0
  153. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/result_batch.py +0 -0
  154. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/result_set.py +0 -0
  155. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/s3_storage_client.py +0 -0
  156. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/secret_detector.py +0 -0
  157. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/sf_dirs.py +0 -0
  158. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/sfbinaryformat.py +0 -0
  159. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/sfdatetime.py +0 -0
  160. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/snow_logging.py +0 -0
  161. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/sqlstate.py +0 -0
  162. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/ssd_internal_keys.py +0 -0
  163. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/ssl_wrap_socket.py +0 -0
  164. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/telemetry.py +0 -0
  165. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/telemetry_oob.py +0 -0
  166. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/test_util.py +0 -0
  167. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/time_util.py +0 -0
  168. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/tool/__init__.py +0 -0
  169. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/tool/dump_certs.py +0 -0
  170. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/tool/dump_ocsp_response.py +0 -0
  171. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/tool/dump_ocsp_response_cache.py +0 -0
  172. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/tool/probe_connection.py +0 -0
  173. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/url_util.py +0 -0
  174. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/__init__.py +0 -0
  175. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/LICENSE +0 -0
  176. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/__init__.py +0 -0
  177. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/__version__.py +0 -0
  178. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/_internal_utils.py +0 -0
  179. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/adapters.py +0 -0
  180. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/api.py +0 -0
  181. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/auth.py +0 -0
  182. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/certs.py +0 -0
  183. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/compat.py +0 -0
  184. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/cookies.py +0 -0
  185. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/exceptions.py +0 -0
  186. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/help.py +0 -0
  187. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/hooks.py +0 -0
  188. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/models.py +0 -0
  189. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/sessions.py +0 -0
  190. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/status_codes.py +0 -0
  191. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/structures.py +0 -0
  192. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/requests/utils.py +0 -0
  193. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/LICENSE.txt +0 -0
  194. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/__init__.py +0 -0
  195. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/_collections.py +0 -0
  196. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/_version.py +0 -0
  197. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/connection.py +0 -0
  198. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/connectionpool.py +0 -0
  199. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  200. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +0 -0
  201. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
  202. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +0 -0
  203. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +0 -0
  204. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/appengine.py +0 -0
  205. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +0 -0
  206. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +0 -0
  207. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/securetransport.py +0 -0
  208. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/contrib/socks.py +0 -0
  209. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/exceptions.py +0 -0
  210. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/fields.py +0 -0
  211. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/filepost.py +0 -0
  212. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
  213. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
  214. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/packages/backports/makefile.py +0 -0
  215. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +0 -0
  216. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/packages/six.py +0 -0
  217. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/poolmanager.py +0 -0
  218. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/request.py +0 -0
  219. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/response.py +0 -0
  220. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/__init__.py +0 -0
  221. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/connection.py +0 -0
  222. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/proxy.py +0 -0
  223. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/queue.py +0 -0
  224. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/request.py +0 -0
  225. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/response.py +0 -0
  226. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/retry.py +0 -0
  227. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/ssl_.py +0 -0
  228. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +0 -0
  229. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/ssltransport.py +0 -0
  230. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/timeout.py +0 -0
  231. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/url.py +0 -0
  232. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake/connector/vendored/urllib3/util/wait.py +0 -0
  233. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/SOURCES.txt +0 -0
  234. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/dependency_links.txt +0 -0
  235. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/entry_points.txt +0 -0
  236. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/not-zip-safe +0 -0
  237. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/requires.txt +0 -0
  238. {snowflake_connector_python-3.13.0 → snowflake_connector_python-3.13.1}/src/snowflake_connector_python.egg-info/top_level.txt +0 -0
@@ -8,6 +8,11 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
8
8
 
9
9
  # Release Notes
10
10
 
11
+ - v3.13.1(January 29, 2025)
12
+ - Remedied SQL injection vulnerability in snowflake.connector.pandas_tools.write_pandas. See more https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-2vpq-fh52-j3wv
13
+ - Remedied vulnerability in deserialization of the OCSP response cache. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-m4f6-vcj4-w5mx
14
+ - Remedied vulnerability connected to cache files permissions. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-r2x6-cjg7-8r43
15
+
11
16
  - v3.13.0(January 23,2025)
12
17
  - Added a feature to limit the sizes of IO-bound ThreadPoolExecutors during PUT and GET commands.
13
18
  - Updated README.md to include instructions on how to verify package signatures using `cosign`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: snowflake-connector-python
3
- Version: 3.13.0
3
+ Version: 3.13.1
4
4
  Summary: Snowflake Connector for Python
5
5
  Home-page: https://www.snowflake.com/
6
6
  Author: Snowflake, Inc
@@ -85,6 +85,11 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
85
85
 
86
86
  # Release Notes
87
87
 
88
+ - v3.13.1(January 29, 2025)
89
+ - Remedied SQL injection vulnerability in snowflake.connector.pandas_tools.write_pandas. See more https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-2vpq-fh52-j3wv
90
+ - Remedied vulnerability in deserialization of the OCSP response cache. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-m4f6-vcj4-w5mx
91
+ - Remedied vulnerability connected to cache files permissions. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-r2x6-cjg7-8r43
92
+
88
93
  - v3.13.0(January 23,2025)
89
94
  - Added a feature to limit the sizes of IO-bound ThreadPoolExecutors during PUT and GET commands.
90
95
  - Updated README.md to include instructions on how to verify package signatures using `cosign`.
@@ -52,6 +52,7 @@ from ..errors import (
52
52
  ProgrammingError,
53
53
  ServiceUnavailableError,
54
54
  )
55
+ from ..file_util import owner_rw_opener
55
56
  from ..network import (
56
57
  ACCEPT_TYPE_APPLICATION_SNOWFLAKE,
57
58
  CONTENT_TYPE_APPLICATION_JSON,
@@ -625,7 +626,11 @@ def flush_temporary_credentials() -> None:
625
626
  )
626
627
  try:
627
628
  with open(
628
- TEMPORARY_CREDENTIAL_FILE, "w", encoding="utf-8", errors="ignore"
629
+ TEMPORARY_CREDENTIAL_FILE,
630
+ "w",
631
+ encoding="utf-8",
632
+ errors="ignore",
633
+ opener=owner_rw_opener,
629
634
  ) as f:
630
635
  json.dump(TEMPORARY_CREDENTIAL, f)
631
636
  except Exception as ex:
@@ -388,6 +388,7 @@ class SFDictFileCache(SFDictCache):
388
388
  file_path: str | dict[str, str],
389
389
  entry_lifetime: int = constants.DAY_IN_SECONDS,
390
390
  file_timeout: int = 0,
391
+ load_if_file_exists: bool = True,
391
392
  ) -> None:
392
393
  """Inits an SFDictFileCache with path, lifetime.
393
394
 
@@ -445,7 +446,7 @@ class SFDictFileCache(SFDictCache):
445
446
  self._file_lock_path = f"{self.file_path}.lock"
446
447
  self._file_lock = FileLock(self._file_lock_path, timeout=self.file_timeout)
447
448
  self.last_loaded: datetime.datetime | None = None
448
- if os.path.exists(self.file_path):
449
+ if os.path.exists(self.file_path) and load_if_file_exists:
449
450
  with self._lock:
450
451
  self._load()
451
452
  # indicate whether the cache is modified or not, this variable is for
@@ -498,7 +499,7 @@ class SFDictFileCache(SFDictCache):
498
499
  """Load cache from disk if possible, returns whether it was able to load."""
499
500
  try:
500
501
  with open(self.file_path, "rb") as r_file:
501
- other: SFDictFileCache = pickle.load(r_file)
502
+ other: SFDictFileCache = self._deserialize(r_file)
502
503
  # Since we want to know whether we are dirty after loading
503
504
  # we have to know whether the file could learn anything from self
504
505
  # so instead of calling self.update we call other.update and swap
@@ -529,6 +530,13 @@ class SFDictFileCache(SFDictCache):
529
530
  with self._lock:
530
531
  return self._load()
531
532
 
533
+ def _serialize(self):
534
+ return pickle.dumps(self)
535
+
536
+ @classmethod
537
+ def _deserialize(cls, r_file):
538
+ return pickle.load(r_file)
539
+
532
540
  def _save(self, load_first: bool = True, force_flush: bool = False) -> bool:
533
541
  """Save cache to disk if possible, returns whether it was able to save.
534
542
 
@@ -559,7 +567,7 @@ class SFDictFileCache(SFDictCache):
559
567
  # python program.
560
568
  # thus we fall back to the approach using the normal open() method to open a file and write.
561
569
  with open(tmp_file, "wb") as w_file:
562
- w_file.write(pickle.dumps(self))
570
+ w_file.write(self._serialize())
563
571
  # We write to a tmp file and then move it to have atomic write
564
572
  os.replace(tmp_file_path, self.file_path)
565
573
  self.last_loaded = datetime.datetime.fromtimestamp(
@@ -875,6 +875,7 @@ class SnowflakeCursor:
875
875
  _skip_upload_on_content_match: bool = False,
876
876
  file_stream: IO[bytes] | None = None,
877
877
  num_statements: int | None = None,
878
+ _force_qmark_paramstyle: bool = False,
878
879
  _dataframe_ast: str | None = None,
879
880
  ) -> Self | dict[str, Any] | None:
880
881
  """Executes a command/query.
@@ -910,6 +911,7 @@ class SnowflakeCursor:
910
911
  file_stream: File-like object to be uploaded with PUT
911
912
  num_statements: Query level parameter submitted in _statement_params constraining exact number of
912
913
  statements being submitted (or 0 if submitting an uncounted number) when using a multi-statement query.
914
+ _force_qmark_paramstyle: Force the use of qmark paramstyle regardless of the connection's paramstyle.
913
915
  _dataframe_ast: Base64-encoded dataframe request abstract syntax tree.
914
916
 
915
917
  Returns:
@@ -958,7 +960,7 @@ class SnowflakeCursor:
958
960
  "dataframe_ast": _dataframe_ast,
959
961
  }
960
962
 
961
- if self._connection.is_pyformat:
963
+ if self._connection.is_pyformat and not _force_qmark_paramstyle:
962
964
  query = self._preprocess_pyformat_query(command, params)
963
965
  else:
964
966
  # qmark and numeric paramstyle
@@ -1458,7 +1460,9 @@ class SnowflakeCursor:
1458
1460
  else:
1459
1461
  if re.search(";/s*$", command) is None:
1460
1462
  command = command + "; "
1461
- if self._connection.is_pyformat:
1463
+ if self._connection.is_pyformat and not kwargs.get(
1464
+ "_force_qmark_paramstyle", False
1465
+ ):
1462
1466
  processed_queries = [
1463
1467
  self._preprocess_pyformat_query(command, params)
1464
1468
  for params in seqparams
@@ -17,6 +17,7 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
17
17
 
18
18
  from .compat import PKCS5_OFFSET, PKCS5_PAD, PKCS5_UNPAD
19
19
  from .constants import UTF8, EncryptionMetadata, MaterialDescriptor, kilobyte
20
+ from .file_util import owner_rw_opener
20
21
  from .util_text import random_string
21
22
 
22
23
  block_size = int(algorithms.AES.block_size / 8) # in bytes
@@ -213,7 +214,7 @@ class SnowflakeEncryptionUtil:
213
214
 
214
215
  logger.debug("encrypted file: %s, tmp file: %s", in_filename, temp_output_file)
215
216
  with open(in_filename, "rb") as infile:
216
- with open(temp_output_file, "wb") as outfile:
217
+ with open(temp_output_file, "wb", opener=owner_rw_opener) as outfile:
217
218
  SnowflakeEncryptionUtil.decrypt_stream(
218
219
  metadata, encryption_material, infile, outfile, chunk_size
219
220
  )
@@ -21,6 +21,10 @@ from .constants import UTF8, kilobyte
21
21
  logger = getLogger(__name__)
22
22
 
23
23
 
24
+ def owner_rw_opener(path, flags) -> int:
25
+ return os.open(path, flags, mode=0o600)
26
+
27
+
24
28
  class SnowflakeFileUtil:
25
29
  @staticmethod
26
30
  def get_digest_and_size(src: IO[bytes]) -> tuple[str, int]:
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import codecs
9
+ import importlib
9
10
  import json
10
11
  import os
11
12
  import platform
@@ -30,6 +31,7 @@ from asn1crypto.ocsp import CertId, OCSPRequest, SingleResponse
30
31
  from asn1crypto.x509 import Certificate
31
32
  from OpenSSL.SSL import Connection
32
33
 
34
+ from snowflake.connector import SNOWFLAKE_CONNECTOR_VERSION
33
35
  from snowflake.connector.compat import OK, urlsplit, urlunparse
34
36
  from snowflake.connector.constants import HTTP_HEADER_USER_AGENT
35
37
  from snowflake.connector.errorcode import (
@@ -58,9 +60,10 @@ from snowflake.connector.network import PYTHON_CONNECTOR_USER_AGENT
58
60
 
59
61
  from . import constants
60
62
  from .backoff_policies import exponential_backoff
61
- from .cache import SFDictCache, SFDictFileCache
63
+ from .cache import CacheEntry, SFDictCache, SFDictFileCache
62
64
  from .telemetry import TelemetryField, generate_telemetry_data_dict
63
65
  from .url_util import extract_top_level_domain_from_hostname, url_encode_str
66
+ from .util_text import _base64_bytes_to_str
64
67
 
65
68
 
66
69
  class OCSPResponseValidationResult(NamedTuple):
@@ -72,19 +75,172 @@ class OCSPResponseValidationResult(NamedTuple):
72
75
  ts: int | None = None
73
76
  validated: bool = False
74
77
 
78
+ def _serialize(self):
79
+ def serialize_exception(exc):
80
+ # serialization exception is not supported for all exceptions
81
+ # in the ocsp_snowflake.py, most exceptions are RevocationCheckError which is easy to serialize.
82
+ # however, it would require non-trivial effort to serialize other exceptions especially 3rd part errors
83
+ # as there can be un-serializable members and nondeterministic constructor arguments.
84
+ # here we do a general best efforts serialization for other exceptions recording only the error message.
85
+ if not exc:
86
+ return None
87
+
88
+ exc_type = type(exc)
89
+ ret = {"class": exc_type.__name__, "module": exc_type.__module__}
90
+ if isinstance(exc, RevocationCheckError):
91
+ ret.update({"errno": exc.errno, "msg": exc.raw_msg})
92
+ else:
93
+ ret.update({"msg": str(exc)})
94
+ return ret
95
+
96
+ return json.dumps(
97
+ {
98
+ "exception": serialize_exception(self.exception),
99
+ "issuer": (
100
+ _base64_bytes_to_str(self.issuer.dump()) if self.issuer else None
101
+ ),
102
+ "subject": (
103
+ _base64_bytes_to_str(self.subject.dump()) if self.subject else None
104
+ ),
105
+ "cert_id": (
106
+ _base64_bytes_to_str(self.cert_id.dump()) if self.cert_id else None
107
+ ),
108
+ "ocsp_response": _base64_bytes_to_str(self.ocsp_response),
109
+ "ts": self.ts,
110
+ "validated": self.validated,
111
+ }
112
+ )
113
+
114
+ @classmethod
115
+ def _deserialize(cls, json_str: str) -> OCSPResponseValidationResult:
116
+ json_obj = json.loads(json_str)
117
+
118
+ def deserialize_exception(exception_dict: dict | None) -> Exception | None:
119
+ # as pointed out in the serialization method, here we do the best effort deserialization
120
+ # for non-RevocationCheckError exceptions. If we can not deserialize the exception, we will
121
+ # return a RevocationCheckError with a message indicating the failure.
122
+ if not exception_dict:
123
+ return
124
+ exc_class = exception_dict.get("class")
125
+ exc_module = exception_dict.get("module")
126
+ try:
127
+ if (
128
+ exc_class == "RevocationCheckError"
129
+ and exc_module == "snowflake.connector.errors"
130
+ ):
131
+ return RevocationCheckError(
132
+ msg=exception_dict["msg"],
133
+ errno=exception_dict["errno"],
134
+ )
135
+ else:
136
+ module = importlib.import_module(exc_module)
137
+ exc_cls = getattr(module, exc_class)
138
+ return exc_cls(exception_dict["msg"])
139
+ except Exception as deserialize_exc:
140
+ logger.debug(
141
+ f"hitting error {str(deserialize_exc)} while deserializing exception,"
142
+ f" the original error error class and message are {exc_class} and {exception_dict['msg']}"
143
+ )
144
+ return RevocationCheckError(
145
+ f"Got error {str(deserialize_exc)} while deserializing ocsp cache, please try "
146
+ f"cleaning up the "
147
+ f"OCSP cache under directory {OCSP_RESPONSE_VALIDATION_CACHE.file_path}",
148
+ errno=ER_OCSP_RESPONSE_LOAD_FAILURE,
149
+ )
150
+
151
+ return OCSPResponseValidationResult(
152
+ exception=deserialize_exception(json_obj.get("exception")),
153
+ issuer=(
154
+ Certificate.load(b64decode(json_obj.get("issuer")))
155
+ if json_obj.get("issuer")
156
+ else None
157
+ ),
158
+ subject=(
159
+ Certificate.load(b64decode(json_obj.get("subject")))
160
+ if json_obj.get("subject")
161
+ else None
162
+ ),
163
+ cert_id=(
164
+ CertId.load(b64decode(json_obj.get("cert_id")))
165
+ if json_obj.get("cert_id")
166
+ else None
167
+ ),
168
+ ocsp_response=(
169
+ b64decode(json_obj.get("ocsp_response"))
170
+ if json_obj.get("ocsp_response")
171
+ else None
172
+ ),
173
+ ts=json_obj.get("ts"),
174
+ validated=json_obj.get("validated"),
175
+ )
176
+
177
+
178
+ class _OCSPResponseValidationResultCache(SFDictFileCache):
179
+ def _serialize(self) -> bytes:
180
+ entries = {
181
+ (
182
+ _base64_bytes_to_str(k[0]),
183
+ _base64_bytes_to_str(k[1]),
184
+ _base64_bytes_to_str(k[2]),
185
+ ): (v.expiry.isoformat(), v.entry._serialize())
186
+ for k, v in self._cache.items()
187
+ }
188
+
189
+ return json.dumps(
190
+ {
191
+ "cache_keys": list(entries.keys()),
192
+ "cache_items": list(entries.values()),
193
+ "entry_lifetime": self._entry_lifetime.total_seconds(),
194
+ "file_path": str(self.file_path),
195
+ "file_timeout": self.file_timeout,
196
+ "last_loaded": (
197
+ self.last_loaded.isoformat() if self.last_loaded else None
198
+ ),
199
+ "telemetry": self.telemetry,
200
+ "connector_version": SNOWFLAKE_CONNECTOR_VERSION, # reserved for schema version control
201
+ }
202
+ ).encode()
203
+
204
+ @classmethod
205
+ def _deserialize(cls, opened_fd) -> _OCSPResponseValidationResultCache:
206
+ data = json.loads(opened_fd.read().decode())
207
+ cache_instance = cls(
208
+ file_path=data["file_path"],
209
+ entry_lifetime=int(data["entry_lifetime"]),
210
+ file_timeout=data["file_timeout"],
211
+ load_if_file_exists=False,
212
+ )
213
+ cache_instance.file_path = os.path.expanduser(data["file_path"])
214
+ cache_instance.telemetry = data["telemetry"]
215
+ cache_instance.last_loaded = (
216
+ datetime.fromisoformat(data["last_loaded"]) if data["last_loaded"] else None
217
+ )
218
+ for k, v in zip(data["cache_keys"], data["cache_items"]):
219
+ cache_instance._cache[
220
+ (b64decode(k[0]), b64decode(k[1]), b64decode(k[2]))
221
+ ] = CacheEntry(
222
+ datetime.fromisoformat(v[0]),
223
+ OCSPResponseValidationResult._deserialize(v[1]),
224
+ )
225
+ return cache_instance
226
+
75
227
 
76
228
  try:
77
229
  OCSP_RESPONSE_VALIDATION_CACHE: SFDictFileCache[
78
230
  tuple[bytes, bytes, bytes],
79
231
  OCSPResponseValidationResult,
80
- ] = SFDictFileCache(
232
+ ] = _OCSPResponseValidationResultCache(
81
233
  entry_lifetime=constants.DAY_IN_SECONDS,
82
234
  file_path={
83
235
  "linux": os.path.join(
84
- "~", ".cache", "snowflake", "ocsp_response_validation_cache"
236
+ "~", ".cache", "snowflake", "ocsp_response_validation_cache.json"
85
237
  ),
86
238
  "darwin": os.path.join(
87
- "~", "Library", "Caches", "Snowflake", "ocsp_response_validation_cache"
239
+ "~",
240
+ "Library",
241
+ "Caches",
242
+ "Snowflake",
243
+ "ocsp_response_validation_cache.json",
88
244
  ),
89
245
  "windows": os.path.join(
90
246
  "~",
@@ -92,7 +248,7 @@ try:
92
248
  "Local",
93
249
  "Snowflake",
94
250
  "Caches",
95
- "ocsp_response_validation_cache",
251
+ "ocsp_response_validation_cache.json",
96
252
  ),
97
253
  },
98
254
  )
@@ -85,9 +85,16 @@ def _do_create_temp_stage(
85
85
  overwrite: bool,
86
86
  use_scoped_temp_object: bool,
87
87
  ) -> None:
88
- create_stage_sql = f"CREATE {get_temp_type_for_object(use_scoped_temp_object)} STAGE /* Python:snowflake.connector.pandas_tools.write_pandas() */ {stage_location} FILE_FORMAT=(TYPE=PARQUET COMPRESSION={compression}{' BINARY_AS_TEXT=FALSE' if auto_create_table or overwrite else ''})"
89
- logger.debug(f"creating stage with '{create_stage_sql}'")
90
- cursor.execute(create_stage_sql, _is_internal=True).fetchall()
88
+ create_stage_sql = f"CREATE {get_temp_type_for_object(use_scoped_temp_object)} STAGE /* Python:snowflake.connector.pandas_tools.write_pandas() */ identifier(?) FILE_FORMAT=(TYPE=PARQUET COMPRESSION={compression}{' BINARY_AS_TEXT=FALSE' if auto_create_table or overwrite else ''})"
89
+ params = (stage_location,)
90
+ logger.debug(f"creating stage with '{create_stage_sql}'. params: %s", params)
91
+ cursor.execute(
92
+ create_stage_sql,
93
+ _is_internal=True,
94
+ _force_qmark_paramstyle=True,
95
+ params=params,
96
+ num_statements=1,
97
+ )
91
98
 
92
99
 
93
100
  def _create_temp_stage(
@@ -147,12 +154,19 @@ def _do_create_temp_file_format(
147
154
  use_scoped_temp_object: bool,
148
155
  ) -> None:
149
156
  file_format_sql = (
150
- f"CREATE {get_temp_type_for_object(use_scoped_temp_object)} FILE FORMAT {file_format_location} "
157
+ f"CREATE {get_temp_type_for_object(use_scoped_temp_object)} FILE FORMAT identifier(?) "
151
158
  f"/* Python:snowflake.connector.pandas_tools.write_pandas() */ "
152
159
  f"TYPE=PARQUET COMPRESSION={compression}{sql_use_logical_type}"
153
160
  )
154
- logger.debug(f"creating file format with '{file_format_sql}'")
155
- cursor.execute(file_format_sql, _is_internal=True)
161
+ params = (file_format_location,)
162
+ logger.debug(f"creating file format with '{file_format_sql}'. params: %s", params)
163
+ cursor.execute(
164
+ file_format_sql,
165
+ _is_internal=True,
166
+ _force_qmark_paramstyle=True,
167
+ params=params,
168
+ num_statements=1,
169
+ )
156
170
 
157
171
 
158
172
  def _create_temp_file_format(
@@ -379,14 +393,20 @@ def write_pandas(
379
393
  # Upload parquet file
380
394
  upload_sql = (
381
395
  "PUT /* Python:snowflake.connector.pandas_tools.write_pandas() */ "
382
- "'file://{path}' @{stage_location} PARALLEL={parallel}"
396
+ "'file://{path}' ? PARALLEL={parallel}"
383
397
  ).format(
384
398
  path=chunk_path.replace("\\", "\\\\").replace("'", "\\'"),
385
- stage_location=stage_location,
386
399
  parallel=parallel,
387
400
  )
388
- logger.debug(f"uploading files with '{upload_sql}'")
389
- cursor.execute(upload_sql, _is_internal=True)
401
+ params = ("@" + stage_location,)
402
+ logger.debug(f"uploading files with '{upload_sql}', params: %s", params)
403
+ cursor.execute(
404
+ upload_sql,
405
+ _is_internal=True,
406
+ _force_qmark_paramstyle=True,
407
+ params=params,
408
+ num_statements=1,
409
+ )
390
410
  # Remove chunk file
391
411
  os.remove(chunk_path)
392
412
 
@@ -403,9 +423,16 @@ def write_pandas(
403
423
  columns = quote + f"{quote},{quote}".join(snowflake_column_names) + quote
404
424
 
405
425
  def drop_object(name: str, object_type: str) -> None:
406
- drop_sql = f"DROP {object_type.upper()} IF EXISTS {name} /* Python:snowflake.connector.pandas_tools.write_pandas() */"
407
- logger.debug(f"dropping {object_type} with '{drop_sql}'")
408
- cursor.execute(drop_sql, _is_internal=True)
426
+ drop_sql = f"DROP {object_type.upper()} IF EXISTS identifier(?) /* Python:snowflake.connector.pandas_tools.write_pandas() */"
427
+ params = (name,)
428
+ logger.debug(f"dropping {object_type} with '{drop_sql}'. params: %s", params)
429
+ cursor.execute(
430
+ drop_sql,
431
+ _is_internal=True,
432
+ _force_qmark_paramstyle=True,
433
+ params=params,
434
+ num_statements=1,
435
+ )
409
436
 
410
437
  if auto_create_table or overwrite:
411
438
  file_format_location = _create_temp_file_format(
@@ -417,10 +444,17 @@ def write_pandas(
417
444
  sql_use_logical_type,
418
445
  _use_scoped_temp_object,
419
446
  )
420
- infer_schema_sql = f"SELECT COLUMN_NAME, TYPE FROM table(infer_schema(location=>'@{stage_location}', file_format=>'{file_format_location}'))"
421
- logger.debug(f"inferring schema with '{infer_schema_sql}'")
447
+ infer_schema_sql = "SELECT COLUMN_NAME, TYPE FROM table(infer_schema(location=>?, file_format=>?))"
448
+ params = (f"@{stage_location}", file_format_location)
449
+ logger.debug(f"inferring schema with '{infer_schema_sql}'. params: %s", params)
422
450
  column_type_mapping = dict(
423
- cursor.execute(infer_schema_sql, _is_internal=True).fetchall()
451
+ cursor.execute(
452
+ infer_schema_sql,
453
+ _is_internal=True,
454
+ _force_qmark_paramstyle=True,
455
+ params=params,
456
+ num_statements=1,
457
+ ).fetchall()
424
458
  )
425
459
  # Infer schema can return the columns out of order depending on the chunking we do when uploading
426
460
  # so we have to iterate through the dataframe columns to make sure we create the table with its
@@ -440,12 +474,21 @@ def write_pandas(
440
474
  )
441
475
 
442
476
  create_table_sql = (
443
- f"CREATE {table_type.upper()} TABLE IF NOT EXISTS {target_table_location} "
477
+ f"CREATE {table_type.upper()} TABLE IF NOT EXISTS identifier(?) "
444
478
  f"({create_table_columns})"
445
479
  f" /* Python:snowflake.connector.pandas_tools.write_pandas() */ "
446
480
  )
447
- logger.debug(f"auto creating table with '{create_table_sql}'")
448
- cursor.execute(create_table_sql, _is_internal=True)
481
+ params = (target_table_location,)
482
+ logger.debug(
483
+ f"auto creating table with '{create_table_sql}'. params: %s", params
484
+ )
485
+ cursor.execute(
486
+ create_table_sql,
487
+ _is_internal=True,
488
+ _force_qmark_paramstyle=True,
489
+ params=params,
490
+ num_statements=1,
491
+ )
449
492
  # need explicit casting when the underlying table schema is inferred
450
493
  parquet_columns = "$1:" + ",$1:".join(
451
494
  f"{quote}{snowflake_col}{quote}::{column_type_mapping[col]}"
@@ -464,12 +507,19 @@ def write_pandas(
464
507
 
465
508
  try:
466
509
  if overwrite and (not auto_create_table):
467
- truncate_sql = f"TRUNCATE TABLE {target_table_location} /* Python:snowflake.connector.pandas_tools.write_pandas() */"
468
- logger.debug(f"truncating table with '{truncate_sql}'")
469
- cursor.execute(truncate_sql, _is_internal=True)
510
+ truncate_sql = "TRUNCATE TABLE identifier(?) /* Python:snowflake.connector.pandas_tools.write_pandas() */"
511
+ params = (target_table_location,)
512
+ logger.debug(f"truncating table with '{truncate_sql}'. params: %s", params)
513
+ cursor.execute(
514
+ truncate_sql,
515
+ _is_internal=True,
516
+ _force_qmark_paramstyle=True,
517
+ params=params,
518
+ num_statements=1,
519
+ )
470
520
 
471
521
  copy_into_sql = (
472
- f"COPY INTO {target_table_location} /* Python:snowflake.connector.pandas_tools.write_pandas() */ "
522
+ f"COPY INTO identifier(?) /* Python:snowflake.connector.pandas_tools.write_pandas() */ "
473
523
  f"({columns}) "
474
524
  f"FROM (SELECT {parquet_columns} FROM @{stage_location}) "
475
525
  f"FILE_FORMAT=("
@@ -478,10 +528,17 @@ def write_pandas(
478
528
  f"{' BINARY_AS_TEXT=FALSE' if auto_create_table or overwrite else ''}"
479
529
  f"{sql_use_logical_type}"
480
530
  f") "
481
- f"PURGE=TRUE ON_ERROR={on_error}"
531
+ f"PURGE=TRUE ON_ERROR=?"
482
532
  )
483
- logger.debug(f"copying into with '{copy_into_sql}'")
484
- copy_results = cursor.execute(copy_into_sql, _is_internal=True).fetchall()
533
+ params = (target_table_location, on_error)
534
+ logger.debug(f"copying into with '{copy_into_sql}'. params: %s", params)
535
+ copy_results = cursor.execute(
536
+ copy_into_sql,
537
+ _is_internal=True,
538
+ _force_qmark_paramstyle=True,
539
+ params=params,
540
+ num_statements=1,
541
+ ).fetchall()
485
542
 
486
543
  if overwrite and auto_create_table:
487
544
  original_table_location = build_location_helper(
@@ -491,9 +548,16 @@ def write_pandas(
491
548
  quote_identifiers=quote_identifiers,
492
549
  )
493
550
  drop_object(original_table_location, "table")
494
- rename_table_sql = f"ALTER TABLE {target_table_location} RENAME TO {original_table_location} /* Python:snowflake.connector.pandas_tools.write_pandas() */"
495
- logger.debug(f"rename table with '{rename_table_sql}'")
496
- cursor.execute(rename_table_sql, _is_internal=True)
551
+ rename_table_sql = "ALTER TABLE identifier(?) RENAME TO identifier(?) /* Python:snowflake.connector.pandas_tools.write_pandas() */"
552
+ params = (target_table_location, original_table_location)
553
+ logger.debug(f"rename table with '{rename_table_sql}'. params: %s", params)
554
+ cursor.execute(
555
+ rename_table_sql,
556
+ _is_internal=True,
557
+ _force_qmark_paramstyle=True,
558
+ params=params,
559
+ num_statements=1,
560
+ )
497
561
  except ProgrammingError:
498
562
  if overwrite and auto_create_table:
499
563
  # drop table only if we created a new one with a random name
@@ -329,6 +329,11 @@ class SnowflakeStorageClient(ABC):
329
329
  f"{verb} with url {url} failed for exceeding maximum retries."
330
330
  )
331
331
 
332
+ def _open_intermediate_dst_path(self, mode):
333
+ if not self.intermediate_dst_path.exists():
334
+ self.intermediate_dst_path.touch(mode=0o600)
335
+ return self.intermediate_dst_path.open(mode)
336
+
332
337
  def prepare_download(self) -> None:
333
338
  # TODO: add nicer error message for when target directory is not writeable
334
339
  # but this should be done before we get here
@@ -352,13 +357,13 @@ class SnowflakeStorageClient(ABC):
352
357
  self.num_of_chunks = ceil(file_header.content_length / self.chunk_size)
353
358
 
354
359
  # Preallocate encrypted file.
355
- with self.intermediate_dst_path.open("wb+") as fd:
360
+ with self._open_intermediate_dst_path("wb+") as fd:
356
361
  fd.truncate(self.meta.src_file_size)
357
362
 
358
363
  def write_downloaded_chunk(self, chunk_id: int, data: bytes) -> None:
359
364
  """Writes given data to the temp location starting at chunk_id * chunk_size."""
360
365
  # TODO: should we use chunking and write content in smaller chunks?
361
- with self.intermediate_dst_path.open("rb+") as fd:
366
+ with self._open_intermediate_dst_path("rb+") as fd:
362
367
  fd.seek(self.chunk_size * chunk_id)
363
368
  fd.write(data)
364
369
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ import base64
8
9
  import hashlib
9
10
  import logging
10
11
  import random
@@ -292,6 +293,10 @@ def random_string(
292
293
  return "".join([prefix, random_part, suffix])
293
294
 
294
295
 
296
+ def _base64_bytes_to_str(x) -> str | None:
297
+ return base64.b64encode(x).decode("utf-8") if x else None
298
+
299
+
295
300
  def get_md5(text: str | bytes) -> bytes:
296
301
  if isinstance(text, str):
297
302
  text = text.encode("utf-8")
@@ -1,3 +1,3 @@
1
1
  # Update this for the versions
2
2
  # Don't change the forth version number from None
3
- VERSION = (3, 13, 0, None)
3
+ VERSION = (3, 13, 1, None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: snowflake-connector-python
3
- Version: 3.13.0
3
+ Version: 3.13.1
4
4
  Summary: Snowflake Connector for Python
5
5
  Home-page: https://www.snowflake.com/
6
6
  Author: Snowflake, Inc
@@ -85,6 +85,11 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
85
85
 
86
86
  # Release Notes
87
87
 
88
+ - v3.13.1(January 29, 2025)
89
+ - Remedied SQL injection vulnerability in snowflake.connector.pandas_tools.write_pandas. See more https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-2vpq-fh52-j3wv
90
+ - Remedied vulnerability in deserialization of the OCSP response cache. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-m4f6-vcj4-w5mx
91
+ - Remedied vulnerability connected to cache files permissions. See more: https://github.com/snowflakedb/snowflake-connector-python/security/advisories/GHSA-r2x6-cjg7-8r43
92
+
88
93
  - v3.13.0(January 23,2025)
89
94
  - Added a feature to limit the sizes of IO-bound ThreadPoolExecutors during PUT and GET commands.
90
95
  - Updated README.md to include instructions on how to verify package signatures using `cosign`.