feat: stateless certified shared worker

Implements stateless singleton component model for certified shared Workers, integrating with SDK 0.7.0.
This commit is contained in:
RockChinQ
2026-09-28 13:25:40 +08:00
committed by GitHub
parent e778445982
commit b51a448b1e
8 changed files with 81 additions and 19 deletions
+21 -10
View File
@@ -10,7 +10,7 @@ ZIP digest without extracting the payload.
Core retains the artifact SHA-256, normalized digest
(`normalized_zip_digest()`), verification state, declared shared-runtime
profile, key ID, selected admission profile, and stable admission code in the
profile, `stateless-v1` component model, key ID, selected admission profile, and stable admission code in the
durable plugin `install_info._certification` record. The record belongs to the
installation row; no schema migration is needed for this additive JSON
metadata.
@@ -48,11 +48,11 @@ dedicated profile.
| Deployment | SDK verification | Explicit `administrator_force` | Result |
| --- | --- | --- | --- |
| Cloud | valid envelope declaring `shared-runtime-v1` | any | admitted to the shared profile |
| Cloud | valid envelope declaring `shared-runtime-v1` + `stateless-v1` | any | admitted to the shared singleton profile |
| Cloud | absent | any | reject before storage with `CERTIFIED_PLUGIN_CLOUD_CERTIFICATE_REQUIRED` |
| Cloud | malformed, untrusted, invalid, or non-shared | any | reject before storage with `CERTIFIED_PLUGIN_CLOUD_CERTIFICATE_INVALID` |
| OSS | absent legacy envelope | any | admitted to the dedicated profile |
| OSS | valid envelope declaring `shared-runtime-v1` | any | selected shared profile |
| OSS | valid envelope declaring `shared-runtime-v1` + `stateless-v1` | any | selected shared singleton profile |
| OSS | declaration signed by a **key this instance resolves** | false | reject with `CERTIFIED_PLUGIN_OSS_FORCE_REQUIRED` |
| OSS | declaration signed by a **key this instance resolves** | true | admitted to the dedicated profile |
| OSS | declaration this instance **cannot resolve** (empty ring) | any | admitted to the dedicated profile |
@@ -69,9 +69,10 @@ the existing `oss_dev` dedicated profile and records
withholds the shared profile rather than granting it.
A declaration is "resolvable" only when its `key_id` is present in the
configured ring. When the ring is configured and the declaration still fails
(malformed, `signature_invalid`, `digest_mismatch`, `unsupported_schema`, ...),
admission stays explicit and requires `administrator_force`.
configured ring. A parseable declaration from a resolved key that fails
signature, digest, identity, profile, or component-model validation requires
`administrator_force` in OSS. Malformed or unsupported envelopes without a
resolved certificate identity are treated as untrusted and stay dedicated.
`administrator_force` is deliberately strict: it is recognized only when the
install request carries boolean `true`. The local upload endpoint accepts the
@@ -81,8 +82,9 @@ protects those endpoints. A force never creates a Cloud dedicated fallback.
## Runtime and logs
SDK 0.6.2 carries an installation-level execution mode in both apply and
authoritative reconcile payloads. Core selects `shared-runtime-v1` only when
The first stateless-compatible SDK release will carry the v2 certificate and
singleton component contract; its final version is assigned only at release.
Core must pin that release before sending or selecting the new contract. Core selects `shared-runtime-v1` only when
the persisted certification record says verification was valid, both the
certificate and admission profiles are `shared-runtime-v1`, the admission code
is shared-eligible, and the record's artifact SHA-256 exactly matches the
@@ -90,6 +92,13 @@ installation row. Missing, malformed, stale, invalid, or dedicated admission
facts select `dedicated`. Install, upgrade, configuration revision, restart,
and reconnect all use this same persisted-fact derivation.
The certificate must also bind `component_model=stateless-v1`. This profile
creates one `BasePlugin` and one instance of each component per digest Worker.
Installation slots contain immutable config snapshots and authority only;
task-local invocation context selects the active slot. Older certificates that
do not bind the component model are not eligible for shared placement. Their
source packages remain compatible on dedicated Workers under OSS policy.
The existing public plugin-log boundary already applies the immutable
installation binding (including workspace UUID) through
`RuntimeConnectionHandler.installation_scope()` before requesting logs. This is
@@ -100,5 +109,7 @@ same existing installation scope.
## SDK versioning
Core pins `langbot-plugin==0.6.2`, the first published SDK release carrying the
canonical installation execution-mode contract.
Ship in dependency order: SDK v2 certificate support, then Core exact pin and
lockfile, then Space signing, then Runtime/Core rollout. Legacy v1 envelopes
remain verifiable but do not carry `stateless-v1`, so they never select shared
singleton placement without re-review and v2 re-signing.
+1 -1
View File
@@ -71,7 +71,7 @@ dependencies = [
"langchain-text-splitters>=1.1.2",
"chromadb>=1.0.0,<2.0.0",
"qdrant-client (>=1.15.1,<2.0.0)",
"langbot-plugin==0.6.20",
"langbot-plugin==0.7.0",
"asyncpg>=0.30.0",
"line-bot-sdk>=3.19.0",
"matrix-nio>=0.25.2",
+10 -1
View File
@@ -18,6 +18,7 @@ from langbot_plugin.entities.io.context import PluginExecutionMode
SHARED_RUNTIME_V1 = 'shared-runtime-v1'
STATELESS_COMPONENT_MODEL_V1 = 'stateless-v1'
DEDICATED_RUNTIME = 'dedicated'
@@ -66,11 +67,16 @@ class CertificateFacts:
verification: CertificateVerification
runtime_profile: str | None = None
component_model: str | None = None
certificate_id: str | None = None
@property
def is_valid_shared_runtime(self) -> bool:
return self.verification is CertificateVerification.VALID and self.runtime_profile == SHARED_RUNTIME_V1
return (
self.verification is CertificateVerification.VALID
and self.runtime_profile == SHARED_RUNTIME_V1
and self.component_model == STATELESS_COMPONENT_MODEL_V1
)
@property
def is_declared(self) -> bool:
@@ -153,6 +159,7 @@ def verify_plugin_archive_certificate(
verification = verify_archive(archive, key_ring.get)
envelope = verification.envelope
runtime_profile = envelope.shared_runtime if envelope is not None else None
component_model = envelope.component_model if envelope is not None else None
# Record the issuer identity only when this instance actually resolved it
# through the configured ring. When the ring is empty (for example a
# self-hosted deployment that never configured
@@ -170,6 +177,7 @@ def verify_plugin_archive_certificate(
certificate=CertificateFacts(
verification=state,
runtime_profile=runtime_profile,
component_model=component_model,
certificate_id=certificate_id,
),
)
@@ -299,6 +307,7 @@ def execution_mode_for_persisted_installation(
'artifact_digest': artifact_digest,
'verification': CertificateVerification.VALID.value,
'certificate_runtime_profile': SHARED_RUNTIME_V1,
'certificate_component_model': STATELESS_COMPONENT_MODEL_V1,
'runtime_profile': SHARED_RUNTIME_V1,
'admission_code': AdmissionCode.SHARED_ELIGIBLE.value,
}
+1
View File
@@ -1809,6 +1809,7 @@ class PluginRuntimeConnector(ManagedRuntimeConnector):
'normalized_digest': facts.artifact_digest,
'verification': facts.certificate.verification.value,
'certificate_runtime_profile': facts.certificate.runtime_profile,
'certificate_component_model': facts.certificate.component_model,
'certificate_id': facts.certificate.certificate_id,
'runtime_profile': decision.runtime_profile,
'admission_code': decision.code.value,
@@ -370,7 +370,7 @@ def _legacy_shared_certification(**overrides):
@pytest.mark.asyncio
async def test_certification_artifact_digest_backfill_is_safe_and_enables_shared_placement(convergence_engine):
async def test_certification_artifact_digest_backfill_is_safe_and_keeps_legacy_dedicated(convergence_engine):
engine = convergence_engine
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
@@ -461,7 +461,7 @@ async def test_certification_artifact_digest_backfill_is_safe_and_enables_shared
artifact_digest=eligible_digest,
install_info=eligible_info,
)
is PluginExecutionMode.SHARED_CERTIFIED
is PluginExecutionMode.DEDICATED
)
for name, (original_certification, artifact_digest) in rows.items():
@@ -249,7 +249,10 @@ def _connector(deployment: str, trusted_public_keys: dict[str, str]):
def _archive(kind: str) -> tuple[bytes, dict[str, str]]:
manifest = {
'metadata': {'author': 'certified', 'name': 'example', 'version': '1.0.0'},
'execution': {'sharedRuntime': 'shared-runtime-v1'},
'execution': {
'sharedRuntime': 'shared-runtime-v1',
'componentModel': 'stateless-v1',
},
}
if kind == 'legacy':
manifest.pop('execution')
@@ -85,6 +85,11 @@ def test_admission_policy_enforces_certification_matrix(
certificate=CertificateFacts(
verification=CertificateVerification(verification),
runtime_profile=runtime_profile,
component_model=(
'stateless-v1'
if verification == 'valid' and runtime_profile == 'shared-runtime-v1'
else None
),
certificate_id=certificate_id,
),
)
@@ -102,6 +107,33 @@ def test_admission_policy_enforces_certification_matrix(
)
def test_legacy_shared_certificate_without_stateless_contract_is_not_shared() -> None:
from langbot.pkg.plugin.certification import (
AdmissionDisposition,
CertificateFacts,
CertificateVerification,
DeploymentMode,
PluginCertificationFacts,
decide_plugin_admission,
)
decision = decide_plugin_admission(
deployment=DeploymentMode.CLOUD,
facts=PluginCertificationFacts(
installation_uuid='00000000-0000-4000-8000-000000000001',
artifact_digest='a' * 64,
certificate=CertificateFacts(
verification=CertificateVerification.VALID,
runtime_profile='shared-runtime-v1',
component_model=None,
certificate_id='legacy-issuer',
),
),
)
assert decision.disposition is AdmissionDisposition.REJECTED
def test_archive_inspection_preserves_legacy_tuple_and_exposes_certificate_facts() -> None:
from langbot.pkg.plugin.archive import (
ArchiveCertificateState,
@@ -181,6 +213,7 @@ def test_log_visibility_policy_only_scopes_valid_shared_certifications(
certificate=CertificateFacts(
verification=CertificateVerification(verification),
runtime_profile='shared-runtime-v1',
component_model='stateless-v1',
),
)
@@ -195,6 +228,7 @@ def _complete_persisted_certification() -> dict[str, object]:
'normalized_digest': 'b' * 64,
'verification': 'valid',
'certificate_runtime_profile': 'shared-runtime-v1',
'certificate_component_model': 'stateless-v1',
'certificate_id': 'ed25519:trusted-issuer',
'runtime_profile': 'shared-runtime-v1',
'admission_code': 'CERTIFIED_PLUGIN_SHARED_ELIGIBLE',
@@ -261,6 +295,7 @@ def test_persisted_certification_selects_shared_execution_only_for_exact_admitte
'normalized_digest',
'verification',
'certificate_runtime_profile',
'certificate_component_model',
'certificate_id',
'runtime_profile',
'admission_code',
@@ -303,6 +338,9 @@ def test_persisted_certification_requires_every_shared_admission_fact(missing_fi
('certificate_runtime_profile', None),
('certificate_runtime_profile', 123),
('certificate_runtime_profile', ''),
('certificate_component_model', None),
('certificate_component_model', 123),
('certificate_component_model', ''),
('runtime_profile', None),
('runtime_profile', 123),
('runtime_profile', ''),
Generated
+4 -4
View File
@@ -2185,7 +2185,7 @@ requires-dist = [
{ name = "gewechat-client", specifier = ">=0.1.5" },
{ name = "html2text", specifier = ">=2024.2.26" },
{ name = "httpx", extras = ["socks"], specifier = ">=0.28.1" },
{ name = "langbot-plugin", specifier = "==0.6.20" },
{ name = "langbot-plugin", specifier = "==0.7.0" },
{ name = "langchain", specifier = ">=1.3.9" },
{ name = "langchain-core", specifier = ">=1.3.3" },
{ name = "langchain-text-splitters", specifier = ">=1.1.2" },
@@ -2255,7 +2255,7 @@ dev = [
[[package]]
name = "langbot-plugin"
version = "0.6.20"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiofiles" },
@@ -2276,9 +2276,9 @@ dependencies = [
{ name = "watchdog" },
{ name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/dd/bb/08bfa37c29a9b6823678e0b837adddacab162b982b36737e0b5e7bea6c40/langbot_plugin-0.6.20.tar.gz", hash = "sha256:86b3803fb83e67379db4a6cf166dec67a8233fbfbc1dbbf744b2b765d0615879", size = 663741, upload-time = "2026-09-27T08:56:36.473Z" }
sdist = { url = "https://files.pythonhosted.org/packages/43/0a/b06aea51c8fe2611952e920002933046888ca20f040e27ef5d14531376ec/langbot_plugin-0.7.0.tar.gz", hash = "sha256:4709cbeedf5abea8b0bd1cccf8449857c1b22e81f843c5ac0db349795f216732", size = 669519, upload-time = "2026-09-28T04:35:18.244Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/48/28/f537c212f67afd3820bb56920b9b29783b68096fb6b2ca1a388d268dd27c/langbot_plugin-0.6.20-py3-none-any.whl", hash = "sha256:b110878d880b24ac739b26b3eb158067fb4d0be8b55ba3baf97d2092da920f10", size = 429929, upload-time = "2026-09-27T08:56:34.995Z" },
{ url = "https://files.pythonhosted.org/packages/b9/1e/2177341166347aa7e594eaf5cdf7cae56eb1087b63c696edcdae9e598eb2/langbot_plugin-0.7.0-py3-none-any.whl", hash = "sha256:5c3c9a22b0dc7072467fb5901abdeb2f24a6a07d53662ce3eaf666b1bf4c3c59", size = 432251, upload-time = "2026-09-28T04:35:16.744Z" },
]
[[package]]