diff --git a/example/example.py b/example/example.py index d5586cb4..e7c7c4b5 100644 --- a/example/example.py +++ b/example/example.py @@ -32,6 +32,14 @@ async def main(): print(item.title) # [developer-docs.sdk.python.list-items]-end + # [developer-docs.sdk.python.validate-secret-reference]-start + # Validate secret reference to ensure no syntax errors + try: + Secrets.validate_secret_reference("op://vault/item/field") + except Exception as error: + print(error) + # [developer-docs.sdk.python.validate-secret-reference]-end + # [developer-docs.sdk.python.resolve-secret]-start # Retrieves a secret from 1Password. Takes a secret reference as input and returns the secret to which it points. value = await client.secrets.resolve("op://vault/item/field") @@ -42,25 +50,25 @@ async def main(): # Create an Item and add it to your vault. to_create = ItemCreateParams( title="MyName", - category="Login", + category=ItemCategory.LOGIN, vault_id="7turaasywpymt3jecxoxk5roli", fields=[ ItemField( id="username", title="username", - field_type="Text", + field_type=ItemFieldType.TEXT, value="mynameisjeff", ), ItemField( id="password", title="password", - field_type="Concealed", + field_type=ItemFieldType.CONCEALED, value="jeff", ), ItemField( id="onetimepassword", title="one-time-password", - field_type="Totp", + field_type=ItemFieldType.TOTP, section_id="totpsection", value="otpauth://totp/my-example-otp?secret=jncrjgbdjnrncbjsr&issuer=1Password", ), @@ -74,7 +82,7 @@ async def main(): Website( label="my custom website", url="https://example.com", - autofill_behavior="AnywhereOnWebsite", + autofill_behavior=AutofillBehavior.NEVER, ) ], ) @@ -115,7 +123,7 @@ async def main(): Website( label="my custom website 2", url="https://example2.com", - autofill_behavior="Never", + autofill_behavior=AutofillBehavior.NEVER, ), ) updated_item = await client.items.put(item) diff --git a/setup.py b/setup.py index 210a89fd..f4cf939b 100644 --- a/setup.py +++ b/setup.py @@ -69,6 +69,7 @@ def get_shared_library_data_to_include(): "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" "License :: OSI Approved :: MIT License", ], cmdclass={"bdist_wheel": bdist_wheel}, diff --git a/src/onepassword/build_number.py b/src/onepassword/build_number.py index 9e4bfc3b..619d0b48 100644 --- a/src/onepassword/build_number.py +++ b/src/onepassword/build_number.py @@ -1 +1 @@ -SDK_BUILD_NUMBER = "0010301" +SDK_BUILD_NUMBER = "0010401" diff --git a/src/onepassword/core.py b/src/onepassword/core.py index d5a85251..c3cf8e68 100644 --- a/src/onepassword/core.py +++ b/src/onepassword/core.py @@ -23,6 +23,7 @@ async def _init_client(client_config): async def _invoke(invoke_config): return await core.invoke(json.dumps(invoke_config)) + # Invoke calls specified business logic from the SDK core. def _invoke_sync(invoke_config): return core.invoke_sync(json.dumps(invoke_config)) diff --git a/src/onepassword/items.py b/src/onepassword/items.py index 287b25fd..8365f907 100644 --- a/src/onepassword/items.py +++ b/src/onepassword/items.py @@ -1,6 +1,6 @@ # Code generated by op-codegen - DO NO EDIT MANUALLY -from .core import _invoke +from .core import _invoke, _invoke_sync from json import loads from .iterator import SDKIterator from .types import Item, ItemOverview @@ -96,6 +96,7 @@ async def list_all(self, vault_id): } } ) + response_data = loads(response) objects = [ItemOverview.model_validate(data) for data in response_data] diff --git a/src/onepassword/lib/aarch64/libop_uniffi_core.dylib b/src/onepassword/lib/aarch64/libop_uniffi_core.dylib index 1fca9288..c8e37960 100755 Binary files a/src/onepassword/lib/aarch64/libop_uniffi_core.dylib and b/src/onepassword/lib/aarch64/libop_uniffi_core.dylib differ diff --git a/src/onepassword/lib/aarch64/libop_uniffi_core.so b/src/onepassword/lib/aarch64/libop_uniffi_core.so index 00ec419e..8eff2c25 100755 Binary files a/src/onepassword/lib/aarch64/libop_uniffi_core.so and b/src/onepassword/lib/aarch64/libop_uniffi_core.so differ diff --git a/src/onepassword/lib/aarch64/op_uniffi_core.py b/src/onepassword/lib/aarch64/op_uniffi_core.py index 65b0d49a..9f5dbf24 100644 --- a/src/onepassword/lib/aarch64/op_uniffi_core.py +++ b/src/onepassword/lib/aarch64/op_uniffi_core.py @@ -481,6 +481,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_op_uniffi_core_checksum_func_invoke() != 29143: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_op_uniffi_core_checksum_func_invoke_sync() != 49373: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_op_uniffi_core_checksum_func_release_client() != 57155: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -496,6 +498,11 @@ def _uniffi_check_api_checksums(lib): _UniffiRustBuffer, ) _UniffiLib.uniffi_op_uniffi_core_fn_func_invoke.restype = ctypes.c_void_p +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync.restype = _UniffiRustBuffer _UniffiLib.uniffi_op_uniffi_core_fn_func_release_client.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -775,6 +782,9 @@ def _uniffi_check_api_checksums(lib): _UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.argtypes = ( ) _UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.restype = ctypes.c_uint16 +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke_sync.argtypes = ( +) +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke_sync.restype = ctypes.c_uint16 _UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.argtypes = ( ) _UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.restype = ctypes.c_uint16 @@ -949,6 +959,13 @@ def invoke(invocation: "str"): _UniffiConverterTypeError, ) +def invoke_sync(invocation: "str") -> "str": + _UniffiConverterString.check_lower(invocation) + + return _UniffiConverterString.lift(_rust_call_with_error(_UniffiConverterTypeError,_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync, + _UniffiConverterString.lower(invocation))) + + def release_client(client_id: "str"): _UniffiConverterString.check_lower(client_id) @@ -961,6 +978,7 @@ def release_client(client_id: "str"): "Error", "init_client", "invoke", + "invoke_sync", "release_client", ] diff --git a/src/onepassword/lib/x86_64/libop_uniffi_core.dylib b/src/onepassword/lib/x86_64/libop_uniffi_core.dylib index 71f000d3..3509fb5e 100755 Binary files a/src/onepassword/lib/x86_64/libop_uniffi_core.dylib and b/src/onepassword/lib/x86_64/libop_uniffi_core.dylib differ diff --git a/src/onepassword/lib/x86_64/libop_uniffi_core.so b/src/onepassword/lib/x86_64/libop_uniffi_core.so index cb952d43..c8c569ae 100755 Binary files a/src/onepassword/lib/x86_64/libop_uniffi_core.so and b/src/onepassword/lib/x86_64/libop_uniffi_core.so differ diff --git a/src/onepassword/lib/x86_64/op_uniffi_core.dll b/src/onepassword/lib/x86_64/op_uniffi_core.dll index 56a56af7..5e6739db 100644 Binary files a/src/onepassword/lib/x86_64/op_uniffi_core.dll and b/src/onepassword/lib/x86_64/op_uniffi_core.dll differ diff --git a/src/onepassword/lib/x86_64/op_uniffi_core.py b/src/onepassword/lib/x86_64/op_uniffi_core.py index 65b0d49a..9f5dbf24 100644 --- a/src/onepassword/lib/x86_64/op_uniffi_core.py +++ b/src/onepassword/lib/x86_64/op_uniffi_core.py @@ -481,6 +481,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_op_uniffi_core_checksum_func_invoke() != 29143: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_op_uniffi_core_checksum_func_invoke_sync() != 49373: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_op_uniffi_core_checksum_func_release_client() != 57155: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -496,6 +498,11 @@ def _uniffi_check_api_checksums(lib): _UniffiRustBuffer, ) _UniffiLib.uniffi_op_uniffi_core_fn_func_invoke.restype = ctypes.c_void_p +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync.restype = _UniffiRustBuffer _UniffiLib.uniffi_op_uniffi_core_fn_func_release_client.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -775,6 +782,9 @@ def _uniffi_check_api_checksums(lib): _UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.argtypes = ( ) _UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.restype = ctypes.c_uint16 +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke_sync.argtypes = ( +) +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke_sync.restype = ctypes.c_uint16 _UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.argtypes = ( ) _UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.restype = ctypes.c_uint16 @@ -949,6 +959,13 @@ def invoke(invocation: "str"): _UniffiConverterTypeError, ) +def invoke_sync(invocation: "str") -> "str": + _UniffiConverterString.check_lower(invocation) + + return _UniffiConverterString.lift(_rust_call_with_error(_UniffiConverterTypeError,_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke_sync, + _UniffiConverterString.lower(invocation))) + + def release_client(client_id: "str"): _UniffiConverterString.check_lower(client_id) @@ -961,6 +978,7 @@ def release_client(client_id: "str"): "Error", "init_client", "invoke", + "invoke_sync", "release_client", ] diff --git a/src/onepassword/secrets.py b/src/onepassword/secrets.py index f083cec5..580ca888 100644 --- a/src/onepassword/secrets.py +++ b/src/onepassword/secrets.py @@ -1,6 +1,6 @@ # Code generated by op-codegen - DO NO EDIT MANUALLY -from .core import _invoke +from .core import _invoke, _invoke_sync from json import loads from .iterator import SDKIterator @@ -30,3 +30,19 @@ async def resolve(self, secret_reference): } ) return str(loads(response)) + + @staticmethod + def validate_secret_reference(secret_reference): + """ + Validate the secret reference to ensure there are no syntax errors. + """ + _invoke_sync( + { + "invocation": { + "parameters": { + "name": "ValidateSecretReference", + "parameters": {"secret_reference": secret_reference}, + } + } + } + ) diff --git a/src/onepassword/test_client.py b/src/onepassword/test_client.py index bab4717e..8549166c 100644 --- a/src/onepassword/test_client.py +++ b/src/onepassword/test_client.py @@ -46,7 +46,7 @@ async def test_invalid_resolve(): async def test_client_construction_no_auth(): with pytest.raises( Exception, - match="invalid user input: encountered the following errors: service account token was not specified; service account token had invalid format", + match="invalid user input: encountered the following errors: service account token was not specified", ): await onepassword.Client.authenticate( auth="", diff --git a/src/onepassword/types.py b/src/onepassword/types.py index 53126805..bea42a4f 100644 --- a/src/onepassword/types.py +++ b/src/onepassword/types.py @@ -1,54 +1,66 @@ """ -Generated by typeshare 1.11.0 +Generated by typeshare 1.12.0 """ from __future__ import annotations +from enum import Enum from pydantic import BaseModel, ConfigDict, Field -from typing import Annotated, List, Literal, Optional - - -ItemCategory = Literal[ - "Login", - "SecureNote", - "CreditCard", - "CryptoWallet", - "Identity", - "Password", - "Document", - "ApiCredentials", - "BankAccount", - "Database", - "DriverLicense", - "Email", - "MedicalRecord", - "Membership", - "OutdoorLicense", - "Passport", - "Rewards", - "Router", - "Server", - "SshKey", - "SocialSecurityNumber", - "SoftwareLicense", - "Person", - "Unsupported", -] - -ItemFieldType = Literal[ - "Text", "Concealed", "CreditCardType", "Phone", "Url", "Totp", "Unsupported" -] +from typing import List, Literal, Optional + + +class ItemCategory(str, Enum): + LOGIN = "Login" + SECURENOTE = "SecureNote" + CREDITCARD = "CreditCard" + CRYPTOWALLET = "CryptoWallet" + IDENTITY = "Identity" + PASSWORD = "Password" + DOCUMENT = "Document" + APICREDENTIALS = "ApiCredentials" + BANKACCOUNT = "BankAccount" + DATABASE = "Database" + DRIVERLICENSE = "DriverLicense" + EMAIL = "Email" + MEDICALRECORD = "MedicalRecord" + MEMBERSHIP = "Membership" + OUTDOORLICENSE = "OutdoorLicense" + PASSPORT = "Passport" + REWARDS = "Rewards" + ROUTER = "Router" + SERVER = "Server" + SSHKEY = "SshKey" + SOCIALSECURITYNUMBER = "SocialSecurityNumber" + SOFTWARELICENSE = "SoftwareLicense" + PERSON = "Person" + UNSUPPORTED = "Unsupported" + + +class ItemFieldType(str, Enum): + TEXT = "Text" + CONCEALED = "Concealed" + CREDITCARDTYPE = "CreditCardType" + PHONE = "Phone" + URL = "Url" + TOTP = "Totp" + UNSUPPORTED = "Unsupported" + + +class ItemFieldDetailsTypes(str, Enum): + OTP = "Otp" class ItemFieldDetailsOtp(BaseModel): - type: Literal["Otp"] + """ + The computed OTP code and other details + """ + + type: Literal[ItemFieldDetailsTypes.OTP] = ItemFieldDetailsTypes.OTP content: OtpFieldDetails +# Field type-specific attributes. ItemFieldDetails = ItemFieldDetailsOtp -""" -Field type-specific attributes. -""" class ItemField(BaseModel): @@ -66,11 +78,11 @@ class ItemField(BaseModel): """ The field's title """ - section_id: Annotated[Optional[str], Field(alias="sectionId")] = None + section_id: Optional[str] = Field(alias="sectionId", default=None) """ The ID of the section containing the field. Built-in fields such as usernames and passwords don't require a section. """ - field_type: Annotated[ItemFieldType, Field(alias="fieldType")] + field_type: ItemFieldType = Field(alias="fieldType") """ The field's type """ @@ -78,7 +90,7 @@ class ItemField(BaseModel): """ The string representation of the field's value """ - details: Optional[ItemFieldDetails] = None + details: Optional[ItemFieldDetails] = Field(default=None) """ Field type-specific attributes. """ @@ -99,7 +111,10 @@ class ItemSection(BaseModel): """ -AutofillBehavior = Literal["AnywhereOnWebsite", "ExactDomain", "Never"] +class AutofillBehavior(str, Enum): + ANYWHEREONWEBSITE = "AnywhereOnWebsite" + EXACTDOMAIN = "ExactDomain" + NEVER = "Never" class Website(BaseModel): @@ -113,7 +128,7 @@ class Website(BaseModel): """ The label of the website, e.g. 'website', 'sign-in address' """ - autofill_behavior: Annotated[AutofillBehavior, Field(alias="autofillBehavior")] + autofill_behavior: AutofillBehavior = Field(alias="autofillBehavior") """ The auto-fill behavior of the website @@ -140,7 +155,7 @@ class Item(BaseModel): """ The item's category """ - vault_id: Annotated[str, Field(alias="vaultId")] + vault_id: str = Field(alias="vaultId") """ The ID of the vault where the item is saved """ @@ -173,7 +188,7 @@ class ItemCreateParams(BaseModel): """ The item's category """ - vault_id: Annotated[str, Field(alias="vaultId")] + vault_id: str = Field(alias="vaultId") """ The ID of the vault where the item is saved """ @@ -181,19 +196,19 @@ class ItemCreateParams(BaseModel): """ The item's title """ - fields: Optional[List[ItemField]] = None + fields: Optional[List[ItemField]] = Field(default=None) """ The item's fields """ - sections: Optional[List[ItemSection]] = None + sections: Optional[List[ItemSection]] = Field(default=None) """ The item's sections """ - tags: Optional[List[str]] = None + tags: Optional[List[str]] = Field(default=None) """ The item's tags """ - websites: Optional[List[Website]] = None + websites: Optional[List[Website]] = Field(default=None) """ The websites used for autofilling for items of the Login and Password categories. """ @@ -218,7 +233,7 @@ class ItemOverview(BaseModel): """ The item's category """ - vault_id: Annotated[str, Field(alias="vaultId")] + vault_id: str = Field(alias="vaultId") """ The ID of the vault where the item is saved """ @@ -235,11 +250,11 @@ class OtpFieldDetails(BaseModel): model_config = ConfigDict(populate_by_name=True) - code: Optional[str] = None + code: Optional[str] = Field(default=None) """ The OTP code, if successfully computed """ - error_message: Annotated[Optional[str], Field(alias="errorMessage")] = None + error_message: Optional[str] = Field(alias="errorMessage", default=None) """ The error message, if the OTP code could not be computed """ diff --git a/src/onepassword/vaults.py b/src/onepassword/vaults.py index 959a0115..5dbee83b 100644 --- a/src/onepassword/vaults.py +++ b/src/onepassword/vaults.py @@ -1,6 +1,6 @@ # Code generated by op-codegen - DO NO EDIT MANUALLY -from .core import _invoke +from .core import _invoke, _invoke_sync from json import loads from .iterator import SDKIterator from .types import VaultOverview @@ -26,6 +26,7 @@ async def list_all(self): } } ) + response_data = loads(response) objects = [VaultOverview.model_validate(data) for data in response_data] diff --git a/src/release/RELEASE-NOTES b/src/release/RELEASE-NOTES index f8bed511..0f48c2b1 100644 --- a/src/release/RELEASE-NOTES +++ b/src/release/RELEASE-NOTES @@ -1,2 +1,2 @@ -The v0.1.3 release of the Python SDK brings: -* Support for item websites. You can now create, get, and edit websites within your 1Password items using item CRUD functions. +The v0.1.4 release of the Python SDK brings: +* Support for validating secret references. You can now check that a secret reference is formatted correctly without having to resolve it or even authenticate, using the 'ValidateSecretReference' function. diff --git a/src/release/scripts/build-wheels.sh b/src/release/scripts/build-wheels.sh index 6488bfed..484875d3 100755 --- a/src/release/scripts/build-wheels.sh +++ b/src/release/scripts/build-wheels.sh @@ -49,16 +49,16 @@ build_wheels() { macos_version= # Min MacOS version for Python 3.13+ is 10.13 python_version=$(pyenv exec python3 --version 2>&1) - if [[ "$python_version" == "Python 3.13"* ]]; then - macos_version="10.13" - else if [[ "$machine_platform" == "x86_64" ]]; then + if [[ "$python_version" == "Python 3.13"* ]]; then + macos_version="10.13" + else macos_version=$macOS_version_x86_64 + fi else macos_version=$macOS_version_arm64 fi - fi export _PYTHON_HOST_PLATFORM="macosx-${macos_version}-${PYTHON_MACHINE_PLATFORM}" ;; diff --git a/version.py b/version.py index 387ff3a6..11e8a1e8 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -SDK_VERSION = "0.1.3" +SDK_VERSION = "0.1.4"