Metadata-Version: 2.4
Name: licantha-sdk
Version: 0.1.0
Summary: License-gated, encrypted-model SDK for on-prem AI services.
Author-email: Baratov Sokhibjon <sokhin.op@proton.me>
Project-URL: Homepage, https://github.com/humblebeeai/int-sdk-python-licensing
Project-URL: Documentation, https://docs.licantha.dev
Project-URL: Repository, https://github.com/humblebeeai/int-sdk-python-licensing.git
Project-URL: Issues, https://github.com/humblebeeai/int-sdk-python-licensing/issues
Project-URL: Changelog, https://github.com/humblebeeai/int-sdk-python-licensing/blob/main/CHANGELOG.md
Keywords: licantha,licensing,keygen,encryption,on-prem,ai,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Security :: Cryptography
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: <4.0,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: python-dotenv<2.0.0,>=1.0.1
Requires-Dist: pydantic[email,timezone]<3.0.0,>=2.0.3
Requires-Dist: pydantic-settings<3.0.0,>=2.2.1
Requires-Dist: requests<3,>=2.32
Requires-Dist: cryptography<46,>=43
Requires-Dist: py-machineid<1,>=0.6
Provides-Extra: test
Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "test"
Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "test"
Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "test"
Provides-Extra: build
Requires-Dist: setuptools<83.0.0,>=70.3.0; extra == "build"
Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "build"
Requires-Dist: build<2.0.0,>=1.1.1; extra == "build"
Requires-Dist: twine<7.0.0,>=6.0.1; extra == "build"
Provides-Extra: docs
Requires-Dist: zensical<1.0.0,>=0.0.2; extra == "docs"
Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "docs"
Provides-Extra: dev
Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "dev"
Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "dev"
Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "dev"
Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "dev"
Requires-Dist: setuptools<83.0.0,>=70.3.0; extra == "dev"
Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "dev"
Requires-Dist: build<2.0.0,>=1.1.1; extra == "dev"
Requires-Dist: twine<7.0.0,>=6.0.1; extra == "dev"
Requires-Dist: zensical<1.0.0,>=0.0.2; extra == "dev"
Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "dev"
Requires-Dist: pyright<2.0.0,>=1.1.392; extra == "dev"
Requires-Dist: pre-commit<5.0.0,>=4.0.1; extra == "dev"
Dynamic: license-file

# Licantha SDK

License-gated, encrypted-model SDK for on-prem AI services.

The SDK validates a customer's license against a Keygen.sh server (or an
offline Ed25519-signed `.lic` file for air-gapped deployments), activates
this machine, runs a background heartbeat, and decrypts AES-256-GCM
encrypted model files using keys delivered through license metadata.

## ✨ Features

- Online activation against a self-hosted Keygen server (`SecureClient`)
- Offline / air-gapped mode via signed `.lic` files
- AES-256-GCM model envelope with embedded `model_id` for multi-model licenses
- Background heartbeat daemon with clean SIGTERM-safe shutdown
- Pluggable `KeyProvider` abstraction (lease today, GPU-attestation tomorrow)
- Pydantic-validated config (`SecureClientConfigPM`) and `.env` loader (`SecureClientCliConfig`)
- Self-contained example mini-apps for every flow

---

## 🛠 Installation

### 1. 🚧 Prerequisites

- Install **Python (>= v3.10)** and **pip (>= 23)**:
    - **[RECOMMENDED] [Miniconda (v3)](https://www.anaconda.com/docs/getting-started/miniconda/install)**
    - *[arm64/aarch64] [Miniforge (v3)](https://github.com/conda-forge/miniforge)*
    - *[Python virtual environment] [venv](https://docs.python.org/3/library/venv.html)*

[OPTIONAL] For **DEVELOPMENT** environment:

- Install [**git**](https://git-scm.com/downloads)
- Setup an [**SSH key**](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh)

### 2. 📥 Download or clone the repository

[TIP] Skip this step, if you're going to install the package directly from **PyPi** or **GitHub** repository.

**2.1.** Prepare projects directory (if not exists):

```sh
# Create projects directory:
mkdir -pv ~/workspaces/projects

# Enter into projects directory:
cd ~/workspaces/projects
```

**2.2.** Follow one of the below options **[A]**, **[B]** or **[C]**:

**OPTION A.** Clone the repository:

```sh
git clone https://github.com/humblebeeai/int-sdk-python-licensing.git && \
    cd int-sdk-python-licensing
```

**OPTION B.** Clone the repository (for **DEVELOPMENT**: git + ssh key):

```sh
git clone git@github.com:humblebeeai/int-sdk-python-licensing.git && \
    cd int-sdk-python-licensing
```

**OPTION C.** Download source code:

1. Download archived **zip** file from [**releases**](https://github.com/humblebeeai/int-sdk-python-licensing/releases).
2. Extract it into the projects directory.

### 3. 📦 Install the package

[NOTE] Choose one of the following methods to install the package **[A ~ F]**:

**OPTION A.** [**RECOMMENDED**] Install from **PyPi**:

```sh
# Install from staging TestPyPi:
pip install -i https://test.pypi.org/simple -U licantha-sdk

# Or install from production PyPi:
# pip install -U licantha-sdk
```

**OPTION B.** Install latest version directly from **GitHub** repository:

```sh
pip install git+https://github.com/humblebeeai/int-sdk-python-licensing.git
```

**OPTION C.** Install from the downloaded **source code**:

```sh
# Install directly from the source code:
pip install .

# Or install with editable mode:
pip install -e .
```

**OPTION D.** Install for **DEVELOPMENT** environment:

```sh
pip install -e .[dev]

# Install pre-commit hooks:
pre-commit install
```

**OPTION E.** Install from **pre-built release** files:

1. Download **`.whl`** or **`.tar.gz`** file from [**releases**](https://github.com/humblebeeai/int-sdk-python-licensing/releases)
2. Install with pip:

```sh
# Install from .whl file:
pip install ./licantha-sdk-[VERSION]-py3-none-any.whl

# Or install from .tar.gz file:
pip install ./licantha-sdk-[VERSION].tar.gz
```

**OPTION F.** Copy the **module** into the project directory (for **testing**):

```sh
# Install python dependencies:
pip install -r ./requirements.txt

# Copy the module source code into the project:
cp -r ./src/licantha_sdk [PROJECT_DIR]
# For example:
cp -r ./src/licantha_sdk /some/path/project/
```

## 🚸 Usage/Examples

### Simple

[**`examples/simple/main.py`**](./examples/simple/main.py):

```python
# Standard libraries
import sys
import logging
from pathlib import Path

# Third-party libraries
from dotenv import load_dotenv

# Internal modules
from licantha_sdk import LicenseError, SecureClient, SecureClientCliConfig


HERE = Path(__file__).parent
load_dotenv(HERE / ".env")
logger = logging.getLogger("quickstart")


def serve(weights: bytes) -> None:
    logger.info(f"model loaded — {len(weights)} bytes")


def main() -> int:
    logging.basicConfig(level=logging.INFO)

    _config = SecureClientCliConfig()  # picks up LICANTHA_SDK_* from .env / env
    with SecureClient(config=_config) as _client:
        try:
            _weights = _client.decrypt_model(str(HERE / "model.encrypted"))
        except LicenseError as _e:
            logger.critical(f"cannot start: {_e}")
            return 2
        serve(_weights)
    return 0


if __name__ == "__main__":
    sys.exit(main())
```

See [`examples/`](./examples) for offline / custom-inference / multi-model / manual-lifecycle / error-shape variants.

---

## ⚙️ Configuration

Production callers construct `SecureClientConfigPM` explicitly — they do
NOT pull env vars from inside a compiled binary:

```python
from licantha_sdk import SecureClient, SecureClientConfigPM

config = SecureClientConfigPM(
    account_id="...",
    license_key="...",
    public_key="...",   # 64-char hex Ed25519
    app_id="my-product",
    api_url="https://licensing.your-company.com",
)
with SecureClient(config=config) as client:
    weights = client.decrypt_model("model.enc")
```

Dev / examples can load from `.env` via `SecureClientCliConfig` instead.

### 🌎 Environment Variables

[**`.env.example`**](./.env.example):

```sh
# Required:
LICANTHA_SDK_ACCOUNT_ID=
LICANTHA_SDK_LICENSE_KEY=
LICANTHA_SDK_PUBLIC_KEY=

# Optional:
# LICANTHA_SDK_APP_ID=licantha-default
# LICANTHA_SDK_API_URL=https://licensing.your-company.com
# LICANTHA_SDK_OFFLINE_LICENSE_PATH=./license.lic
# LICANTHA_SDK_HEARTBEAT_INTERVAL=60
# LICANTHA_SDK_DEACTIVATE_ON_EXIT=true
```

---

## 🧪 Running Tests

To run tests, run the following command:

```sh
# Install python test dependencies:
pip install .[test]

# Run tests:
python -m pytest -sv -o log_cli=true
# Or use the test script:
./scripts/test.sh -l -v -c
```

## 🏗️ Build Package

To build the python package, run the following command:

```sh
# Install python build dependencies:
pip install -r ./requirements/requirements.build.txt

# Build python package:
python -m build
# Or use the build script:
./scripts/build.sh
```

## 📝 Generate Docs

To build the documentation, run the following command:

```sh
# Install python documentation dependencies:
pip install -r ./requirements/requirements.docs.txt

# Serve documentation locally (for development):
mkdocs serve -a 0.0.0.0:8000 --livereload
# Or use the docs script:
./scripts/docs.sh

# Or build documentation:
mkdocs build
# Or use the docs script:
./scripts/docs.sh -b
```

## 📚 Documentation

- [Docs](./docs)

---

## 📑 References

- <https://packaging.python.org/en/latest/tutorials/packaging-projects>
- <https://python-packaging.readthedocs.io/en/latest>
