blun-king-cli 9.1.597 → 9.1.600
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +17 -1
- package/agent-spine-plugin/CHANGELOG.md +1 -1
- package/agent-spine-plugin/docs/host-integration.md +1 -15
- package/agent-spine-plugin/docs/preflight-recall.md +1 -1
- package/agent-spine-plugin/scripts/check-install.js +1 -6
- package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
- package/agent-spine-plugin/scripts/release-check.js +2 -3
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
- package/agent-spine-plugin/src/hook.js +40 -40
- package/agent-spine-plugin/src/lib/briefing.js +6 -3
- package/agent-spine-plugin/src/lib/hook-context.js +63 -64
- package/agent-spine-plugin/src/lib/hook-output.js +115 -94
- package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
- package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
- package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
- package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
- package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
- package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
- package/agent-spine-plugin/src/lib/source-roots.js +26 -16
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
- package/bin/core-bootstrap.js +18 -10
- package/bin/launcher-mode.js +5 -0
- package/bin/launcher-runtime.js +27 -0
- package/bin/verify-bundled-agent-sources.cjs +28 -2
- package/blun.mjs +798 -143
- package/bundled-agent-sources.json +192 -155
- package/package.json +1 -1
- package/standard-skills/translate-native/README.md +1334 -1
- package/standard-skills/translate-native/SKILL.md +1 -1
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
- package/standard-skills/translate-native/integrations/website_localization.py +234 -10
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
- package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
- package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
- package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
- package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
- package/standard-skills/translate-native/provenance.json +2 -2
- package/standard-skills/translate-native/references/commercial-localization.md +96 -17
- package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/VERSION +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +3 -1
- package/standard-tools/language-guard/check_commercial_review.py +69 -9
- package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/provenance.json +2 -2
- package/standard-tools/manifest.json +1 -1
- package/worker-host.mjs +215 -82
- package/agent-spine-plugin/scripts/check-install-king.js +0 -37
|
@@ -192,6 +192,14 @@ def _valid_sha256(value: Any, *, optional: bool = False) -> bool:
|
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
|
|
195
|
+
def _capability_pin(value: Any, name: str) -> str | None:
|
|
196
|
+
if value is None:
|
|
197
|
+
return None
|
|
198
|
+
if not isinstance(value, str) or SHA256.fullmatch(value) is None:
|
|
199
|
+
raise ValueError(f"{name} must be a lowercase SHA-256 digest")
|
|
200
|
+
return value
|
|
201
|
+
|
|
202
|
+
|
|
195
203
|
def _valid_nonnegative_number(value: Any) -> bool:
|
|
196
204
|
return (
|
|
197
205
|
not isinstance(value, bool)
|
|
@@ -357,6 +365,8 @@ class CMSLocalizationHTTPClient:
|
|
|
357
365
|
allow_loopback_http: bool = False,
|
|
358
366
|
clock: Callable[[], float | int] = time.time,
|
|
359
367
|
request_id_factory: Callable[[], str] | None = None,
|
|
368
|
+
capabilities_sha256: str | None = None,
|
|
369
|
+
commercial_rendering_registry_sha256: str | None = None,
|
|
360
370
|
):
|
|
361
371
|
if not isinstance(allow_loopback_http, bool):
|
|
362
372
|
raise TypeError("allow_loopback_http must be boolean")
|
|
@@ -380,6 +390,14 @@ class CMSLocalizationHTTPClient:
|
|
|
380
390
|
raise TypeError("transport must provide post")
|
|
381
391
|
self.timeout = float(timeout)
|
|
382
392
|
self.clock = clock
|
|
393
|
+
self._capabilities_sha256 = _capability_pin(
|
|
394
|
+
capabilities_sha256,
|
|
395
|
+
"capabilities_sha256",
|
|
396
|
+
)
|
|
397
|
+
self._commercial_rendering_registry_sha256 = _capability_pin(
|
|
398
|
+
commercial_rendering_registry_sha256,
|
|
399
|
+
"commercial_rendering_registry_sha256",
|
|
400
|
+
)
|
|
383
401
|
self.request_id_factory = (
|
|
384
402
|
(lambda: secrets.token_hex(16))
|
|
385
403
|
if request_id_factory is None else request_id_factory
|
|
@@ -387,6 +405,16 @@ class CMSLocalizationHTTPClient:
|
|
|
387
405
|
if not callable(self.request_id_factory):
|
|
388
406
|
raise TypeError("request_id_factory must be callable")
|
|
389
407
|
|
|
408
|
+
@property
|
|
409
|
+
def capabilities_sha256(self) -> str | None:
|
|
410
|
+
"""Return the constructor-fixed complete capability deployment pin."""
|
|
411
|
+
return self._capabilities_sha256
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def commercial_rendering_registry_sha256(self) -> str | None:
|
|
415
|
+
"""Return the constructor-fixed commercial rendering registry pin."""
|
|
416
|
+
return self._commercial_rendering_registry_sha256
|
|
417
|
+
|
|
390
418
|
def submit_change(self, change: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
391
419
|
request = _copy_request(
|
|
392
420
|
change, schema=_CMS.CHANGE_SCHEMA, code="change_invalid",
|
|
@@ -520,6 +548,25 @@ class CMSLocalizationHTTPClient:
|
|
|
520
548
|
or not self._valid_capabilities(response)
|
|
521
549
|
):
|
|
522
550
|
raise CMSClientFailed("response_binding", retryable=True)
|
|
551
|
+
capabilities = response["capabilities"]
|
|
552
|
+
if (
|
|
553
|
+
self.capabilities_sha256 is not None
|
|
554
|
+
and capabilities["sha256"] != self.capabilities_sha256
|
|
555
|
+
):
|
|
556
|
+
raise CMSClientFailed(
|
|
557
|
+
"capabilities_pin_mismatch",
|
|
558
|
+
retryable=False,
|
|
559
|
+
)
|
|
560
|
+
registry = capabilities["commercial_rendering_registry"]
|
|
561
|
+
if (
|
|
562
|
+
self.commercial_rendering_registry_sha256 is not None
|
|
563
|
+
and registry["sha256"]
|
|
564
|
+
!= self.commercial_rendering_registry_sha256
|
|
565
|
+
):
|
|
566
|
+
raise CMSClientFailed(
|
|
567
|
+
"commercial_rendering_registry_pin_mismatch",
|
|
568
|
+
retryable=False,
|
|
569
|
+
)
|
|
523
570
|
return response
|
|
524
571
|
|
|
525
572
|
def _read_request(
|
|
@@ -827,6 +874,42 @@ class CMSLocalizationHTTPClient:
|
|
|
827
874
|
digest = unsigned_capabilities.pop("sha256", None)
|
|
828
875
|
unsigned_contract = dict(contract)
|
|
829
876
|
contract_digest = unsigned_contract.pop("sha256", None)
|
|
877
|
+
commercial = capabilities.get("commercial_profile")
|
|
878
|
+
rendering_registry = capabilities.get("commercial_rendering_registry")
|
|
879
|
+
expected_locales = []
|
|
880
|
+
try:
|
|
881
|
+
for profile in _CMS._PLANNER.EU_OFFICIAL_LOCALES:
|
|
882
|
+
commercial_quality = (
|
|
883
|
+
_CMS._PLANNER.commercial_quality_profile_for(profile.locale)
|
|
884
|
+
)
|
|
885
|
+
expected_locales.append({
|
|
886
|
+
"locale": profile.locale,
|
|
887
|
+
"eu_code": profile.eu_code,
|
|
888
|
+
"language": profile.language,
|
|
889
|
+
"native_name": profile.native_name,
|
|
890
|
+
"script": profile.script,
|
|
891
|
+
"direction": profile.direction,
|
|
892
|
+
"quality_profile_version": profile.quality_profile_version,
|
|
893
|
+
"quality_profile_sha256": profile.quality_profile_sha256,
|
|
894
|
+
"commercial_quality_profile_version": (
|
|
895
|
+
commercial_quality["version"]
|
|
896
|
+
),
|
|
897
|
+
"commercial_quality_profile_sha256": (
|
|
898
|
+
commercial_quality["sha256"]
|
|
899
|
+
),
|
|
900
|
+
})
|
|
901
|
+
expected_commercial = _CMS._COMMERCIAL.public_profile(
|
|
902
|
+
_CMS._PLANNER.COMMERCIAL_PROFILE,
|
|
903
|
+
)
|
|
904
|
+
expected_rendering_registry = (
|
|
905
|
+
_CMS._PLANNER.commercial_rendering_registry()
|
|
906
|
+
)
|
|
907
|
+
expected_publication_http = (
|
|
908
|
+
_CMS.WebsiteLocalizationCMSBridge
|
|
909
|
+
._publication_http_capabilities()
|
|
910
|
+
)
|
|
911
|
+
except Exception:
|
|
912
|
+
return False
|
|
830
913
|
if (
|
|
831
914
|
not isinstance(digest, str)
|
|
832
915
|
or SHA256.fullmatch(digest) is None
|
|
@@ -846,6 +929,39 @@ class CMSLocalizationHTTPClient:
|
|
|
846
929
|
or contract.get("schema") != _API.API_CAPABILITIES_SCHEMA
|
|
847
930
|
or contract.get("api_schema") != _API.API_SCHEMA
|
|
848
931
|
or contract.get("error_schema") != _API.API_SCHEMA
|
|
932
|
+
or set(capabilities) != {
|
|
933
|
+
"schema", "change_schema", "cancellation_schema",
|
|
934
|
+
"tombstone_schema", "publication_schema",
|
|
935
|
+
"tombstone_delivery_schema", "plan_schema", "job_schema",
|
|
936
|
+
"eu_language_source", "default_target_policy",
|
|
937
|
+
"content_types", "quality_passes", "commercial_profile",
|
|
938
|
+
"commercial_rendering_registry", "publication_http",
|
|
939
|
+
"locales", "sha256",
|
|
940
|
+
}
|
|
941
|
+
or capabilities.get("schema") != _CMS.CAPABILITIES_SCHEMA
|
|
942
|
+
or capabilities.get("change_schema") != _CMS.CHANGE_SCHEMA
|
|
943
|
+
or capabilities.get("cancellation_schema")
|
|
944
|
+
!= _CMS.CANCELLATION_SCHEMA
|
|
945
|
+
or capabilities.get("tombstone_schema") != _CMS.TOMBSTONE_SCHEMA
|
|
946
|
+
or capabilities.get("publication_schema")
|
|
947
|
+
!= _CMS.PUBLICATION_SCHEMA
|
|
948
|
+
or capabilities.get("tombstone_delivery_schema")
|
|
949
|
+
!= _CMS.TOMBSTONE_DELIVERY_SCHEMA
|
|
950
|
+
or capabilities.get("plan_schema") != _CMS._PLANNER.SCHEMA
|
|
951
|
+
or capabilities.get("job_schema") != _CMS._PLANNER.JOB_SCHEMA
|
|
952
|
+
or capabilities.get("eu_language_source")
|
|
953
|
+
!= _CMS._PLANNER.EU_LANGUAGE_SOURCE
|
|
954
|
+
or capabilities.get("default_target_policy")
|
|
955
|
+
!= _CMS._DEFAULT_TARGET_POLICY
|
|
956
|
+
or capabilities.get("content_types")
|
|
957
|
+
!= sorted(_CMS._PLANNER.CONTENT_TYPES)
|
|
958
|
+
or capabilities.get("quality_passes")
|
|
959
|
+
!= list(_CMS._PLANNER.QUALITY_PASSES)
|
|
960
|
+
or commercial != expected_commercial
|
|
961
|
+
or rendering_registry != expected_rendering_registry
|
|
962
|
+
or capabilities.get("publication_http")
|
|
963
|
+
!= expected_publication_http
|
|
964
|
+
or capabilities.get("locales") != expected_locales
|
|
849
965
|
):
|
|
850
966
|
return False
|
|
851
967
|
operations = contract.get("operations")
|
|
@@ -156,6 +156,27 @@ class HealthChecker(Protocol):
|
|
|
156
156
|
def __call__(self, probe: VerifiedHealthProbe) -> Mapping[str, Any]: ...
|
|
157
157
|
|
|
158
158
|
|
|
159
|
+
def release_evidence_is_current(
|
|
160
|
+
value: Any,
|
|
161
|
+
*,
|
|
162
|
+
locale: Any,
|
|
163
|
+
target_sha256: Any,
|
|
164
|
+
approval_id: Any,
|
|
165
|
+
require_current_locale_quality: bool = True,
|
|
166
|
+
) -> bool:
|
|
167
|
+
"""Apply the same current release contract at ingress and durable reads."""
|
|
168
|
+
|
|
169
|
+
return _CMS._valid_release_evidence(
|
|
170
|
+
value,
|
|
171
|
+
locale=locale,
|
|
172
|
+
target_sha256=target_sha256,
|
|
173
|
+
approval_id=approval_id,
|
|
174
|
+
require_current_locale_quality=(
|
|
175
|
+
require_current_locale_quality
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
159
180
|
class PublicationExpectationResolver(Protocol):
|
|
160
181
|
def __call__(
|
|
161
182
|
self, publication: VerifiedPublication,
|
|
@@ -302,6 +323,30 @@ def _signature(value: Any) -> Any:
|
|
|
302
323
|
)
|
|
303
324
|
|
|
304
325
|
|
|
326
|
+
def message_signature_is_valid(
|
|
327
|
+
payload: Any,
|
|
328
|
+
signature: Any,
|
|
329
|
+
authority: Any,
|
|
330
|
+
) -> bool:
|
|
331
|
+
"""Verify one canonical message without trusting stored signature fields."""
|
|
332
|
+
|
|
333
|
+
if (
|
|
334
|
+
not isinstance(payload, bytes)
|
|
335
|
+
or not payload
|
|
336
|
+
or not callable(getattr(authority, "verify", None))
|
|
337
|
+
):
|
|
338
|
+
return False
|
|
339
|
+
try:
|
|
340
|
+
normalized = (
|
|
341
|
+
signature
|
|
342
|
+
if isinstance(signature, _CMS.CMSMessageSignature)
|
|
343
|
+
else _signature(signature)
|
|
344
|
+
)
|
|
345
|
+
return authority.verify(payload, normalized) is True
|
|
346
|
+
except Exception:
|
|
347
|
+
return False
|
|
348
|
+
|
|
349
|
+
|
|
305
350
|
def _timestamp(value: Any) -> float:
|
|
306
351
|
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
307
352
|
raise CMSReceiverBlocked(
|
|
@@ -365,11 +410,12 @@ def _verify_publication(value: Any, payload_sha256: str, *, now: float) -> bytes
|
|
|
365
410
|
or not isinstance(approval_id, str)
|
|
366
411
|
or TOKEN.fullmatch(approval_id) is None
|
|
367
412
|
or _timestamp(item.get("approval_expires_at")) <= now
|
|
368
|
-
or not
|
|
413
|
+
or not release_evidence_is_current(
|
|
369
414
|
item.get("release_evidence"),
|
|
370
415
|
locale=locale,
|
|
371
416
|
target_sha256=target_sha256,
|
|
372
417
|
approval_id=approval_id,
|
|
418
|
+
require_current_locale_quality=False,
|
|
373
419
|
)
|
|
374
420
|
):
|
|
375
421
|
raise CMSReceiverBlocked(
|
|
@@ -466,9 +512,57 @@ def _verify_expectation(
|
|
|
466
512
|
)
|
|
467
513
|
for item in localizations:
|
|
468
514
|
evidence = item["release_evidence"]
|
|
515
|
+
try:
|
|
516
|
+
profile = _CMS._PLANNER.quality_profile_for(item["locale"])
|
|
517
|
+
if (
|
|
518
|
+
not isinstance(profile, dict)
|
|
519
|
+
or profile.get("locale") != item["locale"]
|
|
520
|
+
or not isinstance(profile.get("version"), str)
|
|
521
|
+
or TOKEN.fullmatch(profile["version"]) is None
|
|
522
|
+
or not isinstance(profile.get("sha256"), str)
|
|
523
|
+
or SHA256.fullmatch(profile["sha256"]) is None
|
|
524
|
+
):
|
|
525
|
+
raise ValueError("quality profile is invalid")
|
|
526
|
+
except Exception:
|
|
527
|
+
raise CMSReceiverBlocked(
|
|
528
|
+
"receiver.release_scope", retryable=False, http_status=409,
|
|
529
|
+
) from None
|
|
530
|
+
expected_quality = {
|
|
531
|
+
"locale": profile["locale"],
|
|
532
|
+
"version": profile["version"],
|
|
533
|
+
"sha256": profile["sha256"],
|
|
534
|
+
}
|
|
535
|
+
expected_commercial_quality = None
|
|
536
|
+
if expectation.content_type == "commercial":
|
|
537
|
+
try:
|
|
538
|
+
profile = _CMS._PLANNER.commercial_quality_profile_for(
|
|
539
|
+
item["locale"],
|
|
540
|
+
)
|
|
541
|
+
if (
|
|
542
|
+
not isinstance(profile, dict)
|
|
543
|
+
or not isinstance(profile.get("commercial_profile"), str)
|
|
544
|
+
or TOKEN.fullmatch(profile["commercial_profile"]) is None
|
|
545
|
+
or not isinstance(profile.get("version"), str)
|
|
546
|
+
or TOKEN.fullmatch(profile["version"]) is None
|
|
547
|
+
or not isinstance(profile.get("sha256"), str)
|
|
548
|
+
or SHA256.fullmatch(profile["sha256"]) is None
|
|
549
|
+
):
|
|
550
|
+
raise ValueError("commercial quality profile is invalid")
|
|
551
|
+
except Exception:
|
|
552
|
+
raise CMSReceiverBlocked(
|
|
553
|
+
"receiver.release_scope", retryable=False, http_status=409,
|
|
554
|
+
) from None
|
|
555
|
+
expected_commercial_quality = {
|
|
556
|
+
"profile": profile["commercial_profile"],
|
|
557
|
+
"version": profile["version"],
|
|
558
|
+
"sha256": profile["sha256"],
|
|
559
|
+
}
|
|
469
560
|
if (
|
|
470
561
|
evidence["content_type"] != expectation.content_type
|
|
562
|
+
or evidence["quality_profile"] != expected_quality
|
|
471
563
|
or evidence["commercial_profile"] != expectation.commercial_profile
|
|
564
|
+
or evidence["commercial_quality_profile"]
|
|
565
|
+
!= expected_commercial_quality
|
|
472
566
|
):
|
|
473
567
|
raise CMSReceiverBlocked(
|
|
474
568
|
"receiver.release_scope", retryable=False, http_status=409,
|
|
@@ -630,11 +724,9 @@ def _verify_publication_transport(
|
|
|
630
724
|
"receiver.framing_invalid", retryable=False, http_status=400,
|
|
631
725
|
)
|
|
632
726
|
signature = _signature(envelope.get("signature"))
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
verified = False
|
|
637
|
-
if not verified:
|
|
727
|
+
if not message_signature_is_valid(
|
|
728
|
+
payload_bytes, signature, publication_authority,
|
|
729
|
+
):
|
|
638
730
|
raise CMSReceiverBlocked(
|
|
639
731
|
"receiver.signature_invalid", retryable=False, http_status=401,
|
|
640
732
|
)
|
|
@@ -706,11 +798,9 @@ def _verify_tombstone_transport(
|
|
|
706
798
|
"receiver.framing_invalid", retryable=False, http_status=400,
|
|
707
799
|
)
|
|
708
800
|
signature = _signature(envelope.get("signature"))
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
verified = False
|
|
713
|
-
if not verified:
|
|
801
|
+
if not message_signature_is_valid(
|
|
802
|
+
payload_bytes, signature, publication_authority,
|
|
803
|
+
):
|
|
714
804
|
raise CMSReceiverBlocked(
|
|
715
805
|
"receiver.signature_invalid", retryable=False, http_status=401,
|
|
716
806
|
)
|
package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py
CHANGED
|
@@ -380,7 +380,18 @@ def open_durable_cms_receiver(
|
|
|
380
380
|
"CMS receiver database could not be opened"
|
|
381
381
|
) from error
|
|
382
382
|
try:
|
|
383
|
-
store = _STORE.DurableCMSReceiverStore(
|
|
383
|
+
store = _STORE.DurableCMSReceiverStore(
|
|
384
|
+
connection,
|
|
385
|
+
release_evidence_validator=(
|
|
386
|
+
_RECEIVER.release_evidence_is_current
|
|
387
|
+
),
|
|
388
|
+
publication_signature_validator=lambda payload, signature: (
|
|
389
|
+
_RECEIVER.message_signature_is_valid(
|
|
390
|
+
payload, signature, publication_authority,
|
|
391
|
+
)
|
|
392
|
+
),
|
|
393
|
+
clock=clock,
|
|
394
|
+
)
|
|
384
395
|
database_guard()
|
|
385
396
|
synchronized_store = _SynchronizedStore(
|
|
386
397
|
connection, store, database_guard,
|