Skip to main content

Locker Secrets Python SDK

PyPI Python License: Apache-2.0

The official Python SDK for reading and managing secrets in Locker Secrets Manager.

The PyPI distribution is named lockersm; the Python import package is named locker. Version 2 communicates with the Locker CLI through the stable locker.sdk JSON-RPC protocol instead of parsing human-facing command output. It supports both Locker Cloud and self-hosted Locker deployments.

Install

python -m pip install --upgrade lockersm

You do not need to install the Locker CLI separately in the standard managed mode. The SDK downloads a supported binary on first use and verifies the release signature, SHA-256 digest, platform, architecture, and protocol compatibility before execution.

Support matrix

Component Supported versions
Python 3.10, 3.11, 3.12, 3.13, 3.14
Linux managed CLI x86-64, ARM64
macOS managed CLI Intel, Apple silicon
Windows managed CLI x86-64
SDK protocol locker.sdk v1

For an air-gapped or centrally managed deployment, provide an explicit Locker CLI path with LOCKER_CLI_PATH or binary_path.

Quick start

Create an access key in your Locker Secrets project, then expose the credentials to the application environment.

Linux and macOS:

export LOCKER_ACCESS_KEY_ID="your-access-key-id"
export LOCKER_SECRET_ACCESS_KEY="your-secret-access-key"

Windows PowerShell:

$env:LOCKER_ACCESS_KEY_ID = "your-access-key-id"
$env:LOCKER_SECRET_ACCESS_KEY = "your-secret-access-key"

Read a required secret:

from locker import Locker

client = Locker.from_env()
database_password = client.get_required(
    "DATABASE_PASSWORD",
    environment_name="production",
)

# Pass database_password directly to the component that needs it.
# Never print or log secret values.

get_required() raises ResourceNotFoundError when the key does not exist. Use get() only when a fallback is intentionally safe:

log_level = client.get(
    "LOG_LEVEL",
    environment_name="production",
    default_value="info",
)

The default value is returned only for a genuine not-found response. Authentication, permission, network, protocol, storage, and server failures are still raised.

Configure the client

Locker.from_env() is the recommended constructor. It recognizes:

Environment variable Purpose
LOCKER_ACCESS_KEY_ID Project access key ID
LOCKER_SECRET_ACCESS_KEY Project secret access key
LOCKER_API_BASE Cloud or self-hosted API base URL
LOCKER_CLI_PATH Absolute path to a deployment-managed CLI
LOCKER_LOG debug, info, warning, or error

The default cloud endpoint is https://api.locker.io/locker_secrets.

Self-hosted deployment:

from locker import Locker

client = Locker.from_env(
    api_base="https://secrets.example.com/locker_secrets",
)

Deployment-managed CLI:

from locker import Locker

client = Locker.from_env(
    binary_path="/opt/locker/bin/locker",
)

The CLI path must be absolute and point to a regular, non-link file. Explicit paths bypass managed updates and are never resolved through ambient PATH.

For migration from version 1, the SDK still recognizes ACCESS_KEY_ID, SECRET_ACCESS_KEY, LOCKER_ACCESS_KEY_SECRET, and ACCESS_KEY_SECRET. New deployments should use only the canonical LOCKER_* names.

Secrets

Read secret metadata

retrieve() returns the complete secret resource object:

secret = client.retrieve(
    "DATABASE_PASSWORD",
    environment_name="production",
)
print(secret.id, secret.key, secret.environment_name)

Secret objects contain plaintext values. Do not serialize, print, or include them in logs.

List secrets

for secret in client.list(environment_name="production"):
    print(secret.id, secret.key, secret.environment_name)

For large projects, use bounded cursor pagination:

cursor = None

while True:
    page = client.list_page(
        environment_name="production",
        page_size=100,
        cursor=cursor,
    )
    for secret in page.items:
        print(secret.id, secret.key)
    cursor = page.next_cursor
    if cursor is None:
        break

Create and update secrets

Read secret input without echoing it in a terminal:

from getpass import getpass

created = client.create(
    key="PAYMENT_API_KEY",
    value=getpass("New secret value: "),
    environment_name="staging",
)

updated = client.modify(
    key=created.key,
    value=getpass("Updated secret value: "),
    environment_name="staging",
)

Secret values are sent to locker sdk in the JSON request on standard input. They are not placed in process arguments or logs.

Export secrets

export() returns a plaintext str in dotenv or compact json format:

dotenv_payload = client.export(
    environment_name="production",
    output_format="dotenv",
)

Treat the returned string as sensitive. Avoid logs, shell arguments, command history, and unprotected files.

Secret deletion is not part of protocol v1. The canonical Locker client does not expose a delete method; legacy resource-object delete helpers fail closed with InvalidRequestError.

Environments

environments = client.list_environments()
for environment in environments:
    print(environment.name, environment.external_url)

Use list_environments_page() for cursor pagination.

The two lookup methods intentionally have different not-found contracts:

  • get_environment("production") returns None.
  • retrieve_environment("production") raises ResourceNotFoundError.

Create or update an environment:

created = client.create_environment(
    name="staging",
    external_url="https://staging.example.com",
)

updated = client.modify_environment(
    name=created.name,
    external_url="https://new-staging.example.com",
)

Environment deletion is not part of protocol v1.

Errors

Locker-defined transport, protocol, authentication, and API failures derive from locker.error.LockerError. Standard Python argument errors can still be raised for locally invalid values.

import logging

from locker.error import LockerError, RateLimitError

try:
    value = client.get_required("PAYMENT_API_KEY")
except RateLimitError as exc:
    logging.warning(
        "Locker request was rate limited (request_id=%s, retryable=%s)",
        exc.request_id,
        exc.retryable,
    )
    raise
except LockerError as exc:
    logging.error(
        "Locker request failed (type=%s, code=%s, kind=%s, request_id=%s)",
        type(exc).__name__,
        exc.code,
        exc.kind,
        exc.request_id,
    )
    raise
RPC code Exception Meaning
-32001 AuthenticationError Credentials were rejected
-32003 PermissionDeniedError Access is not permitted
-32004 ResourceNotFoundError Resource does not exist
-32029 RateLimitError Request was rate limited
-32050 APIConnectionError Locker API could not be reached
-32051 APIServerError Locker API failed the request
-32060 LocalStorageError Local secure state failed
-32700 to -32600 ProtocolError Invalid JSON-RPC exchange

Each exception exposes code, kind, retryable, and request_id. Avoid logging exception bodies or application data around a secret operation.

CLI management and verification

Importing locker and constructing Locker are side-effect free. The SDK does not create a cache directory, access the network, or start a process until the first operation or an explicit install_cli() call.

Managed mode:

  1. Checks the signed release channel on first use and at most once every six hours after a successful check.
  2. Verifies the embedded Locker Ed25519 trust root, signed latest document, signed manifest, artifact size, SHA-256, detached signature, executable header, and protocol range.
  3. Installs releases into immutable ~/.locker/sdk-cli/python/bin/releases/<version>/ directories.
  4. Switches the current pointer only after complete verification.
  5. Rejects rollback attempts and same-version mutation.

Force an immediate signed update check:

installed_path = client.install_cli()

If the release service is temporarily unreachable, a previously accepted binary may be reused only after its cached metadata and artifact are verified again. Invalid signatures, rollback state, incompatible platforms, and protocol errors always fail closed.

Logging

Set LOCKER_LOG or the constructor's log argument:

export LOCKER_LOG="info"
client = Locker.from_env(log="info")

SDK logs contain operational metadata such as method, request ID, duration, and process status. The SDK never emits credentials, request or response bodies, custom headers, or secret values.

Migrating to 2.x

Version 2:

  • Requires Python 3.10 or newer.
  • Uses the stable locker.sdk JSON-RPC protocol v1.
  • Downloads only signed Locker CLI releases in managed mode.
  • Uses canonical LOCKER_ACCESS_KEY_ID and LOCKER_SECRET_ACCESS_KEY variables.
  • Adds Locker.from_env(), get_required(), typed pagination, and explicit CLI lifecycle methods.
  • Returns a default value only for ResourceNotFoundError.

Applications must use this SDK or the locker sdk protocol. Do not parse human-facing CLI output.

Versioning and releases

The package follows Semantic Versioning and publishes canonical PEP 440 versions:

  • PyPI package: MAJOR.MINOR.PATCH
  • Git tag and GitLab Release: vMAJOR.MINOR.PATCH

Every accepted merge commit on protected main automatically runs the complete release flow: derive version, build deterministic wheel and source distribution, verify metadata and the CLI trust root, publish to PyPI, and create the matching source tag and GitLab Release. There is no manual publish or pre-created tag step.

The version is deterministic for the commit's first-parent position on main. Retrying the same pipeline reuses the same version, and concurrent main pipelines cannot assign the same version. Release builds and source tags share the version through setuptools-scm, so installing a tag reproduces its published package version. CI rejects direct, fast-forward, rebase, or single-parent updates to the release line.

Development

Install the reviewed development toolchain:

python -m pip install -r requirements-dev.txt

Run the supported-Python test matrix:

tox

Useful focused commands:

tox -e py310
tox -e lint
tox -e type
python scripts/verify_ci_supply_chain.py

Integration tests are opt-in. A protocol handshake needs an explicit released CLI:

LOCKER_TEST_CLI_PATH=/absolute/path/to/locker

Live vault tests additionally require:

LOCKER_RUN_INTEGRATION=1
LOCKER_TEST_ACCESS_KEY_ID=your-test-access-key
LOCKER_TEST_SECRET_ACCESS_KEY=your-test-secret-key

Run them with tox -e integration.

Security

If you discover a security issue, email contact@locker.io. Do not disclose vulnerabilities in a public issue.

General product documentation and support are available at support.locker.io.

License

Copyright CyStack Corporation.

Licensed under the Apache License 2.0. Locker is developed and maintained by CyStack.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lockersm-2.0.0.tar.gz (59.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lockersm-2.0.0-py3-none-any.whl (64.5 kB view details)

Uploaded Python 3

File details

Details for the file lockersm-2.0.0.tar.gz.

File metadata

  • Download URL: lockersm-2.0.0.tar.gz
  • Upload date:
  • Size: 59.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for lockersm-2.0.0.tar.gz
Algorithm Hash digest
SHA256 b75f3d26bbab435eeb47f05f38567f9e49190939c71bb83a6c447bf4e6a0edcf
MD5 f04a9985def199d7565cf3be684c3f8b
BLAKE2b-256 6ab4c6f7cf4de09d92c9d95d5eb501946a903dc8e103ce6b235c68f0050c9412

See more details on using hashes here.

File details

Details for the file lockersm-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: lockersm-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 64.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for lockersm-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0da13a5887771689687bf9c9545409be2ae2d9e37fff04fad277eaabdb79d0a3
MD5 f1c1fd2aa3f27f72fd8e45123f39ee7e
BLAKE2b-256 397875e19f5df551b81d56f442695f02127ad11ec36dda335d979620f196668d

See more details on using hashes here.

Release history Release notifications | RSS feed

2.0.7

2 files

2.0.6

2 files

2.0.5

2 files

2.0.4

2 files

2.0.3

2 files

2.0.2

2 files

2.0.1

2 files

This release

2.0.0 This release

2 files

1.0.6

1 file

1.0.5

1 file

1.0.4

1 file

1.0.3

1 file

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page