nullbridge

1.0.1

AI Agent Identity Governance — NullBridge Python SDK

License
Unknown license
Published
June 4, 2026
4h ago
Package Registry
README badge Customize →
License Sources
SourceLicenseClass
Licensie (detected)
Pending-
PyPI (reported)
Not reported-

License detection is still in progress for this version.

Loading dependencies…
License File
import threading
import logging
from .errors import NullBridgeLicenseError

logger = logging.getLogger("nullbridge")


class LicenseClient:
    def __init__(self, config: dict, http):
        self._config = config
        self._http = http
        self._watcher_timer: threading.Timer = None

    def validate(self) -> dict:
        try:
            status, body = self._http.post(
                self._config["server_url"],
                "/api/validate",
                {"key": self._config["license_key"]},
            )
            if status == 200 and body.get("valid"):
                return {
                    "valid": True,
                    "customer": body.get("customer"),
                    "company": body.get("company"),
                    "plan": body.get("plan"),
                    "max_agents": body.get("max_agents"),
                    "expires_at": body.get("expires_at"),
                }
            reason = body.get("reason", "INVALID")
            message = body.get("message", "Invalid or expired license key.")
            raise NullBridgeLicenseError(
                reason,
                f"{message} Contact brian@nullbridge.ai to renew or obtain a license key.",
            )
        except NullBridgeLicenseError:
            raise
        except Exception:
            logger.warning("[NullBridge] License server unreachable — continuing in offline mode.")
            return {
                "valid": True,
                "reason": "SERVER_UNREACHABLE",
                "offline": True,
                "customer": "Unknown",
                "plan": "unknown",
            }

    def start_watcher(self, on_status_change):
        interval = self._config.get("check_interval", 86400)

        def check():
            try:
                result = self.validate()
                if not result.get("valid"):
                    on_status_change(False, result.get("reason"))
            except NullBridgeLicenseError as e:
                on_status_change(False, e.reason)
            finally:
                self._schedule_watcher(on_status_change, interval)

        self._schedule_watcher(on_status_change, interval)

    def _schedule_watcher(self, on_status_change, interval):
        self._watcher_timer = threading.Timer(interval, lambda: self._run_check(on_status_change, interval))
        self._watcher_timer.daemon = True
        self._watcher_timer.start()

    def _run_check(self, on_status_change, interval):
        try:
            result = self.validate()
            if not result.get("valid"):
                on_status_change(False, result.get("reason"))
        except NullBridgeLicenseError as e:
            on_status_change(False, e.reason)
        finally:
            self._schedule_watcher(on_status_change, interval)

    def stop_watcher(self):
        if self._watcher_timer:
            self._watcher_timer.cancel()
            self._watcher_timer = None
Versions
2 versions
VersionLicensePublishedStatus
1.0.1 Latest Viewing-Jun 4, 2026 Pending
1.0.0 -Jun 4, 2026 Pending