Gate Packages | Kamiwaza Docs

Documentation for Kamiwaza 1.0.1

Version: 1.0.1

Gate packages let you install custom ExecutionGate and AttributeGate classes onto a paired cluster from a Python package index — without rebuilding the platform image. Shipped in kamiwaza-mesh-v1.0.0.

A gate package is an ordinary Python package whose modules contribute one or more gate classes (subclasses of ExecutionGate or AttributeGate). The cluster's kz.gates.packages API (Python module: kamiwaza_sdk.gates.packages) installs the package into an isolated per-package directory, makes its classes reachable from kz.gates.discover, and persists the install record. The classes are then bindable via the existing cluster.set_execution_gate(...) and datasets.set_gate(...) APIs covered in Execution Gates.

When to use this

Use gate packages when:

Don't use gate packages for:

Lifecycle overview

install ─▶ discover ─▶ bind ─▶ (job submit / dataset access) ─▶ replace ─▶ uninstall

│

└─ atomic in-place

(no unbound-gate window)

Each lifecycle action is an SDK call:

Action SDK call Required permission
Install kz.gates.packages.install(spec, hash_digest=..., index_url=...) admin
List installed kz.gates.packages.list() admin
Get one kz.gates.packages.get(name) admin
Atomic replace kz.gates.packages.replace(name, new_spec, hash_digest=..., index_url=...) admin
Uninstall kz.gates.packages.uninstall(name) admin
Discover a class kz.gates.discover(classpath) viewer or above
Bind as ExecutionGate kz.cluster.set_execution_gate(type=..., config=...) admin
Bind as AttributeGate kz.datasets.set_gate(urn=..., type=..., config=...) admin

Installing a gate package

from kamiwaza_sdk import KamiwazaClient

kz = KamiwazaClient(base_url="https://kamiwaza.example.com/api")

# Hash-pin to the exact wheel you've verified out-of-band.
# pip refuses installs whose downloaded artifact doesn't match.

result = kz.gates.packages.install(
    "acme-gates==1.0.0",
    hash_digest="sha256:<sha256-of-the-wheel>",
    index_url="https://pypi.example.com/simple",
)

print(result.package.name, result.package.version)
print(result.package.classpaths)  # ['acme_gates.gate.AcmeAttributeGate', ...]

The install path:

  1. Resolves the wheel from index_url (any PEP 503 simple index is acceptable, including PyPI, a private mirror, or a local file index served over HTTP)
  2. Validates the SHA-256 digest against the supplied hash_digest via pip install --require-hashes — if pip can't verify, install fails before any files are written
  3. Installs into a per-package directory under the gate-packages PVC (mounted on the Ray head, the scheduler, and the API server pods)
  4. Scans the installed package for ExecutionGate/AttributeGate subclasses and records the resulting classpaths in the cluster_gate_packages table
  5. Extends the API server's classpath allowlist and sys.path so kz.gates.discover sees the new gate immediately

Discovering and binding

Once installed, the gate classpath is reachable via discover:

gate = kz.gates.discover("acme_gates.gate.AcmeAttributeGate")

print(gate.name, gate.kind, gate.config_schema)

Bind as a cluster ExecutionGate (if the class implements that protocol) or as a per-dataset AttributeGate (if the class implements that protocol). The same APIs work whether the class came from a built-in module or an installed gate package — there's no separate binding path for installed gates.

Atomic replace

Replace updates the package in place without leaving a window where the bound gate class is unimportable. The platform installs the new version into a staging sibling directory, validates that the new version's classpath set is a superset of the old version's bound classpaths, then performs a two-rename POSIX swap.

result = kz.gates.packages.replace(
    "acme-gates",
    "acme-gates==1.0.1",
    hash_digest="sha256:<sha256-of-the-new-wheel>",
    index_url="https://pypi.example.com/simple",
)

If the new version drops a classpath that's currently bound, the replace is refused with GatePackageClasspathDropError and the live tree is unchanged. This is the classpath-superset guarantee: an actively-bound gate can never be silently removed by an upgrade.

Hash-mismatch refusal

The platform refuses an install or replace whose downloaded artifact doesn't match the supplied hash:

from kamiwaza_sdk.exceptions import GatePackageHashMismatchError

try:
    kz.gates.packages.replace(
        "acme-gates",
        "acme-gates==1.0.1",
        hash_digest="sha256:" + "0" * 64,  # wrong on purpose
        index_url="https://pypi.example.com/simple",
    )
except GatePackageHashMismatchError as exc:
    print(exc.body["detail"])

The refusal is enforced by pip's --require-hashes mode; the platform doesn't compute or trust a separately-derived hash. The live tree is untouched.

Uninstall

kz.gates.packages.uninstall("acme-gates")

The uninstall path checks for active bindings: any cluster ExecutionGate or per-dataset AttributeGate whose classpath matches one contributed by the package will cause the uninstall to refuse with GatePackageUninstallBlockedError, naming the bound classpath(s). Unbind the gate first, then retry.

Security model

The gate-packages feature ships with several boundaries:

Limits and trade-offs

Reference