Thank you for improving Locker. Keep changes focused, include tests for changed behavior, and never commit real access keys, secret values, CLI signing keys, or PyPI credentials.
Locker SDK 2.x supports Python 3.10 through 3.14.
python -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements-dev.txtOn PowerShell, activate with .\.venv\Scripts\Activate.ps1 instead.
Run the supported-Python test matrix:
toxRun focused checks:
tox -e py310
tox -e lint
tox -e type
python scripts/verify_ci_supply_chain.pyUnit tests must not require network access, a real Locker vault, or ambient
credentials. Integration tests belong under tests/integration and must remain
explicitly opt-in.
- Preserve the
locker.sdkJSON-RPC protocol boundary. Do not parse human-facing CLI output. - Do not place credentials or secret values in command arguments, logs, test failure messages, or fixtures.
- Keep imports and client construction side-effect free.
- Keep new public APIs typed and covered by unit tests.
- Keep the resulting merge commit title concise and user-facing; it becomes the automatic GitLab Release summary.
- Update
CHANGELOG.mdfor user-visible behavior. - Update
README.mdwhen configuration or public usage changes.
Merging into protected main is the release action. After all validation jobs
pass, CI automatically derives the version, builds and verifies both Python
distributions, publishes them to PyPI, and creates the matching GitLab tag and
Release. Do not publish or tag a normal release manually.
Public names are:
- Package version:
MAJOR.MINOR.PATCH - Source tag:
vMAJOR.MINOR.PATCH
Patch releases are derived from first-parent order on main, so a retry of the
same commit keeps the same version and concurrent pipelines cannot collide.
CI injects that derived version into the build, while setuptools-scm
reconstructs the same version from vMAJOR.MINOR.PATCH for source installs.
The repository settings are part of this release contract:
- Keep
mainas the project default branch, protect it, and disable force pushes and direct pushes. - Use GitLab's Merge commit method. Do not use fast-forward or rebase
updates for
main. - Require a successful pipeline before merge.
- Ensure a runner with the
cs_newgen_dockertag accepts protected-branch jobs. - Protect
v*tags. Every role or user allowed to mergemainmust also be allowed to create these tags. - Protect the
pypienvironment without deployment approvals, because an approval would turn the automatic release into a manual one. Every role or user allowed to mergemainmust also be allowed to deploy this environment. - Set the
lockersm-pypiresource group's process mode tooldest_firstthrough the GitLab Resource Groups API. GitLab's defaultunorderedmode serializes jobs but does not preserve release order. - Reject
[ci skip]and[skip ci]inmaincommit messages with a push rule. Use a pipeline execution policy to prevent theci.skipandci.no_pipelinepush options where the installed GitLab tier supports it.
Configure these protected, pypi-scoped CI variables:
TWINE_USERNAME=__token__TWINE_PASSWORD=<project-scoped PyPI API token>LOCKER_CLI_RELEASE_PUBLIC_KEY=<locker/locker-cli-release.json.public_key>
Mask and hide TWINE_PASSWORD. LOCKER_CLI_RELEASE_PUBLIC_KEY is public, does
not need masking, and must exactly match the bundled value. The built-in
CI_JOB_TOKEN creates and reconciles the GitLab Release; do not add a
long-lived GitLab access token. If fine-grained job-token permissions are
enabled, grant READ_RELEASES and ADMIN_RELEASES.
After the first pipeline has created the resource group, a Maintainer can set its ordering once:
curl --request PUT \
--header "PRIVATE-TOKEN: <maintainer-token>" \
--data "process_mode=oldest_first" \
"https://git.cystack.org/api/v4/projects/<project-id>/resource_groups/lockersm-pypi"For a new backward-compatible feature line, update the version in
locker/__about__.json and tool.setuptools_scm.fallback_version in
pyproject.toml to the next MAJOR.MINOR.0. For a breaking API change, update
both to the next MAJOR.0.0. In the same merge request:
- Set
baseline_commitinscripts/release_policy.jsonto the full SHA of the currentmaincommit on which the change is based. - Keep
first_release_distanceat1. - Keep
mainline_modeset tomerge_commit. - Add the new release line to
CHANGELOG.md. - Run the release and packaging tests locally.
Immediately before merging a new release-line MR, update it from main and
set baseline_commit to that exact main SHA. Merge no other MR ahead of it:
the baseline must be the new merge commit's immediate first parent. The first
merge then receives the configured base version; subsequent main merge commits
increment its patch component.
Do not open a public issue for a suspected vulnerability. Send details to contact@locker.io.