plugin-scanner 2.2.113__py3-none-any.whl → 2.2.115__py3-none-any.whl

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.
@@ -563,18 +563,33 @@ def update_guard_settings(
563
563
  if key not in EDITABLE_GUARD_SETTING_KEYS:
564
564
  continue
565
565
  next_payload[key] = _coerce_editable_setting(key, value)
566
+ effective_next_payload = next_payload
566
567
  if current_config.managed_policy is not None:
567
- composed = apply_managed_policy(next_payload, current_config.managed_policy)
568
+ effective_next_payload = apply_managed_policy(next_payload, current_config.managed_policy)
568
569
  missing = object()
569
570
  weakened = [
570
571
  key
571
572
  for key in current_config.managed_locked_settings
572
573
  if (requested := _nested_setting_value(next_payload, key, missing)) is not missing
573
- and _nested_setting_value(composed, key, missing) != requested
574
+ and _nested_setting_value(effective_next_payload, key, missing) != requested
574
575
  ]
575
576
  if weakened:
576
577
  raise ValueError(f"Managed policy locks prevent weakening: {', '.join(sorted(weakened))}")
577
- if next_payload.get("sync") is True and not cloud_sync_entitled:
578
+ preserving_sync_while_switching_to_watch_only = (
579
+ current.get("sync") is True
580
+ and current_config.sync is True
581
+ and next_payload.get("sync") is True
582
+ and current.get("mode") != "observe"
583
+ and current_config.mode != "observe"
584
+ and payload.get("mode") == "observe"
585
+ and next_payload.get("mode") == "observe"
586
+ and effective_next_payload.get("mode") == "observe"
587
+ )
588
+ if (
589
+ next_payload.get("sync") is True
590
+ and not cloud_sync_entitled
591
+ and not preserving_sync_while_switching_to_watch_only
592
+ ):
578
593
  raise ValueError("Cloud sync requires a paid team plan.")
579
594
  _write_guard_config(guard_home / "config.toml", next_payload)
580
595
  return load_guard_config(guard_home)
@@ -33,7 +33,7 @@ from .hook_process_worker import (
33
33
  _HOOK_PROCESS_MAX_LIMIT = 16
34
34
  _HOOK_PROCESS_TIMEOUT_SECONDS = 2.8
35
35
  _HOOK_PROCESS_READY_TIMEOUT_SECONDS = 14.0
36
- _HOOK_PROCESS_BACKFILL_DELAY_SECONDS = 2.0
36
+ _HOOK_PROCESS_BACKFILL_DELAY_SECONDS = 30.0
37
37
  _HOOK_PROCESS_BACKFILL_MAX_DEFERRAL_SECONDS = 5.0
38
38
  _HOOK_PROCESS_RETRY_MAX_SECONDS = 5.0
39
39
  _HOOK_PROCESS_RETRY_READY_SECONDS = 0.75
@@ -378,8 +378,16 @@ class HookProcessRunner:
378
378
  if adaptive_capacity is None:
379
379
  return
380
380
  adaptive_capacity.observe_load(queue_p95_ms=queue_p95_ms, queued=queued)
381
+ if queued > 0:
382
+ self.notify_queued_work()
381
383
  self._refresh_capacity_policy()
382
384
 
385
+ def notify_queued_work(self) -> None:
386
+ with self._state_lock:
387
+ self._backfill_not_before = 0.0
388
+ self._backfill_force_after = 0.0
389
+ self._recovery_event.set()
390
+
383
391
  def close(self) -> None:
384
392
  _ = self.close_contained()
385
393
 
@@ -48,6 +48,7 @@ class RuntimeHookScheduler:
48
48
  per_client_queued_limit: int = 32,
49
49
  retained_bytes_limit: int = 32 * 1024 * 1024,
50
50
  monotonic: Callable[[], float] = time.monotonic,
51
+ queue_listener: Callable[[], None] | None = None,
51
52
  ):
52
53
  limits = (
53
54
  active_limit,
@@ -66,6 +67,7 @@ class RuntimeHookScheduler:
66
67
  self._per_client_queued_limit = per_client_queued_limit
67
68
  self._retained_bytes_limit = retained_bytes_limit
68
69
  self._monotonic = monotonic
70
+ self._queue_listener = queue_listener
69
71
  self._condition = threading.Condition()
70
72
  self._queues: dict[
71
73
  RuntimeHookLane,
@@ -156,6 +158,8 @@ class RuntimeHookScheduler:
156
158
  else:
157
159
  self._retained_bytes += payload_bytes
158
160
  self._dispatch()
161
+ if not item.admitted and self._queue_listener is not None:
162
+ self._queue_listener()
159
163
  while not item.admitted and item.rejection_reason is None:
160
164
  remaining = resolved_deadline.expires_at - self._monotonic()
161
165
  if remaining <= 0:
@@ -275,6 +279,10 @@ class RuntimeHookScheduler:
275
279
  self._active_limit = active_limit
276
280
  self._dispatch()
277
281
 
282
+ def set_queue_listener(self, listener: Callable[[], None]) -> None:
283
+ with self._condition:
284
+ self._queue_listener = listener
285
+
278
286
  def _reject(self, reason_code: RuntimeHookAdmissionReason) -> RuntimeHookAdmission:
279
287
  self._rejected[reason_code] = self._rejected.get(reason_code, 0) + 1
280
288
  return RuntimeHookAdmission(None, reason_code)
@@ -551,6 +551,7 @@ class _GuardDaemonHttpServer(HTTPServer):
551
551
  self.unclassified_watchdog_thread = None
552
552
  self.hook_process_runner = HookProcessRunner(guard_home=store.guard_home)
553
553
  self.hook_process_runner.set_capacity_listener(self.runtime_hook_process_scheduler.set_active_limit)
554
+ self.runtime_hook_process_scheduler.set_queue_listener(self.hook_process_runner.notify_queued_work)
554
555
  self.runtime_heartbeat = RuntimeHeartbeatWriter(
555
556
  store=store,
556
557
  session_id=runtime_session_id,
@@ -3842,7 +3843,15 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
3842
3843
  return managers, None
3843
3844
 
3844
3845
  def _supply_chain_entitlement(self) -> dict[str, object]:
3845
- return resolve_package_firewall_entitlement_with_refresh(self.server.store) # type: ignore[attr-defined]
3846
+ server = self.server # type: ignore[attr-defined]
3847
+ with server.guard_cloud_browser_session_lock:
3848
+ cloud_connect = _copy_guard_cloud_connect_state(server)
3849
+ package_connect = _copy_package_firewall_connect_state(server)
3850
+ if _guard_cloud_connect_state_is_in_flight(cloud_connect) or _guard_cloud_connect_state_is_in_flight(
3851
+ package_connect
3852
+ ):
3853
+ return resolve_package_firewall_entitlement(server.store)
3854
+ return resolve_package_firewall_entitlement_with_refresh(server.store)
3846
3855
 
3847
3856
  def _handle_get_supply_chain_bundle(self) -> None:
3848
3857
  store = self.server.store # type: ignore[attr-defined]
@@ -7711,10 +7720,7 @@ class GuardDaemonServer:
7711
7720
  self._thread = threading.Thread(target=self._serve_forever, daemon=True)
7712
7721
  self._thread.start()
7713
7722
  serve_thread_started = True
7714
- self._server.hook_process_runner.enable_full_capacity(
7715
- delay_seconds=0,
7716
- active_deferral_seconds=0,
7717
- )
7723
+ self._server.hook_process_runner.enable_full_capacity()
7718
7724
  except BaseException as error:
7719
7725
  self._diagnostics.record_exception("daemon_start_thread_failed")
7720
7726
  serve_thread_contained = True
@@ -7737,10 +7743,7 @@ class GuardDaemonServer:
7737
7743
 
7738
7744
  def serve(self) -> None:
7739
7745
  self._begin_service()
7740
- self._server.hook_process_runner.enable_full_capacity(
7741
- delay_seconds=0,
7742
- active_deferral_seconds=0,
7743
- )
7746
+ self._server.hook_process_runner.enable_full_capacity()
7744
7747
  self._serve_forever()
7745
7748
 
7746
7749
  def stop(self) -> None:
@@ -75,6 +75,10 @@ KNOWN_SKILL_DOC_ROOT_SUFFIXES = (
75
75
  ".agents/skills",
76
76
  ".claude/skills",
77
77
  )
78
+ KNOWN_AGENT_DOC_SUFFIXES = (
79
+ ".codex/docs/harness-engineering.md",
80
+ ".codex/docs/token-discipline.md",
81
+ )
78
82
  FD_OPTION_VALUE_FLAGS = frozenset(
79
83
  {
80
84
  "-d",
@@ -152,6 +156,15 @@ def target_is_known_skill_doc_path(target: str, *, home_dir: Path | None = None)
152
156
  root=root,
153
157
  ):
154
158
  return True
159
+ for suffix in KNOWN_AGENT_DOC_SUFFIXES:
160
+ expected = f"{home}/{suffix}"
161
+ if (
162
+ normalized == expected
163
+ and os.path.isfile(expected)
164
+ and not os.path.islink(home)
165
+ and not _path_has_symlink_component(normalized, root=home)
166
+ ):
167
+ return True
155
168
  return False
156
169
 
157
170
 
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.2.113"
3
+ __version__ = "2.2.115"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.2.113
3
+ Version: 2.2.115
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://hol.org/guard
6
6
  Project-URL: Security, https://hol.org/guard/security
@@ -9,6 +9,7 @@ Project-URL: Documentation, https://github.com/hashgraph-online/hol-guard/tree/m
9
9
  Project-URL: Repository, https://github.com/hashgraph-online/hol-guard
10
10
  Project-URL: Issues, https://github.com/hashgraph-online/hol-guard/issues
11
11
  Project-URL: Changelog, https://github.com/hashgraph-online/hol-guard/releases
12
+ Project-URL: Dataset, https://huggingface.co/datasets/HashgraphOnline/hol-plugin-security
12
13
  Author-email: HOL <support@hol.org>
13
14
  License-Expression: Apache-2.0
14
15
  License-File: LICENSE
@@ -949,6 +950,7 @@ Plugins that pass the scanner with a high score are candidates for listing in th
949
950
  ## Resources
950
951
 
951
952
  - [HOL Plugin Registry](https://hol.org/registry/plugins)
953
+ - [HOL Plugin Security dataset on Hugging Face](https://huggingface.co/datasets/HashgraphOnline/hol-plugin-security)
952
954
  - [HOL Standards Documentation](https://hol.org/docs/standards)
953
955
  - [OpenAI Codex Plugin Documentation](https://developers.openai.com/codex/plugins)
954
956
  - [Model Context Protocol Documentation](https://modelcontextprotocol.io)
@@ -956,6 +958,8 @@ Plugins that pass the scanner with a high score are candidates for listing in th
956
958
  - [Cisco AI MCP Scanner](https://pypi.org/project/cisco-ai-mcp-scanner/)
957
959
  - [HOL GitHub Organization](https://github.com/hashgraph-online)
958
960
 
961
+ A scan is not a safety guarantee. Runtime benchmark fixtures in the dataset are modeled, not live attacks. The dataset's ~205 scored plugins are the plugin catalog, not the Registry Broker agent catalog. Hashgraph Online's org-wide GitHub star total is not a star count for this repository.
962
+
959
963
  ## License
960
964
 
961
965
  Apache-2.0
@@ -28,7 +28,7 @@ codex_plugin_scanner/trust_scoring.py,sha256=t_Lw13HZ766UCJzTtNNwllZK_k2ks_x-8St
28
28
  codex_plugin_scanner/trust_skill_scoring.py,sha256=e-SrMBgAruzFn4RD0pGpP9rtPXxc2ji_CKpcnFPRh3M,12542
29
29
  codex_plugin_scanner/trust_specs.py,sha256=aYGSB8M9RQp1uwhsRaWlVa1M9Vk51kUIxmBXkW8noZU,10729
30
30
  codex_plugin_scanner/verification.py,sha256=J2nsnYlxNYecSvmSQhV_leImLslCOotIK2FSmEoIjg0,27896
31
- codex_plugin_scanner/version.py,sha256=KgFbHTUEzOtocytyfrjipxG2nB-W_SCggizSg8V1BW0,72
31
+ codex_plugin_scanner/version.py,sha256=JXWXgt0gmKSN9EVXj5CPjdQPxrIAGpASQT6Y45ltqm8,72
32
32
  codex_plugin_scanner/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  codex_plugin_scanner/checks/best_practices.py,sha256=uB3DXLggqxjfyBMH_1yvX4nyFhpIvaRHjTyyueoO-GQ,8473
34
34
  codex_plugin_scanner/checks/claude.py,sha256=cMucH5pmKgQtBnDcycOzMMlKL-Q5HQemPqUmTLF0DzE,10189
@@ -92,7 +92,7 @@ codex_plugin_scanner/guard/codex_hook_sources.py,sha256=eVc0ZQa7gQnc0BTdoDTAllaw
92
92
  codex_plugin_scanner/guard/codex_hook_windows_job.py,sha256=OudOk-RS-0nFFLxfZ4zrdkyDDyvEka6CWWRF3qYJTCM,13215
93
93
  codex_plugin_scanner/guard/codex_resume.py,sha256=t7xDUNu2SNXkmXraCSaxKZT6Go2JS_Dx1N7rNWGj0o8,15287
94
94
  codex_plugin_scanner/guard/codex_skill_config.py,sha256=XRTY74DiZBf41hdB2HEAr0MzxElhPoN8m9ATle5BzYY,3888
95
- codex_plugin_scanner/guard/config.py,sha256=sLjWWrWa6_j28c_Ikl14mJHAsxqZXCetDHSvGdeMFCU,46772
95
+ codex_plugin_scanner/guard/config.py,sha256=-9pCQlMLu8DqUWTVJceEUcs-KGVSpAI6o6Xdyw1c6u8,47354
96
96
  codex_plugin_scanner/guard/contained_node_execution.py,sha256=jMZjMAG-T2-Sr-wW1ATF195teCtHL2VX0jpUcLvsXA4,10142
97
97
  codex_plugin_scanner/guard/contained_package_script_execution.py,sha256=CfXrKpchS1nKLgYIMGHXOBpIFd7T1aInYQ6xtz0RY5U,9821
98
98
  codex_plugin_scanner/guard/contained_typescript_execution.py,sha256=daiudtJEkzvWl9yFItDE9cuWiUsxp3-qLtdCfjALP50,9701
@@ -379,7 +379,7 @@ codex_plugin_scanner/guard/daemon/hook_process_capacity.py,sha256=slI6INGDoze-Ql
379
379
  codex_plugin_scanner/guard/daemon/hook_process_entrypoint.py,sha256=9EEP1bU1R2mXW5cLJaNQPv2xpplI3qWbad5_bfAj5Fs,10105
380
380
  codex_plugin_scanner/guard/daemon/hook_process_metrics.py,sha256=QzZm_476SgDj2lZubrJaqEIgwhMTVZtWjvKZ9HOYSMU,1186
381
381
  codex_plugin_scanner/guard/daemon/hook_process_protocol.py,sha256=rJPrSUh5zpxVVqy-iv51d1jZ1isI1KUex06jFwehLcU,2886
382
- codex_plugin_scanner/guard/daemon/hook_process_runner.py,sha256=BJD-nij6aUzsupU4Mk7NXTMMrJGUPpl_RBanYphZQ58,30068
382
+ codex_plugin_scanner/guard/daemon/hook_process_runner.py,sha256=FCHW112Z9HH0pDHIqwvPcI6VhJL1OdaWFFaxsNUMMOc,30328
383
383
  codex_plugin_scanner/guard/daemon/hook_process_spawner.py,sha256=Ddt6csH4NKsY-3BgolcvWJOAFw4PPJOwKgPNTSoh_V8,2510
384
384
  codex_plugin_scanner/guard/daemon/hook_process_worker.py,sha256=JmU9w4LYfvN4UVheSutOTr8iiOllpLRH5GogIOVgq4U,5341
385
385
  codex_plugin_scanner/guard/daemon/hook_worker.py,sha256=Kxh71Va1YCO8YmuWgkM_HbvAPX5Gkylre63E5C8lD3o,13522
@@ -390,11 +390,11 @@ codex_plugin_scanner/guard/daemon/request_executor.py,sha256=kaQlyO3mFFQwvpkO_ix
390
390
  codex_plugin_scanner/guard/daemon/runtime_heartbeat.py,sha256=m7Rsx-XZ8yr8KFBb0WLlBOlJQwoubjbFClSKU5KVj-w,3250
391
391
  codex_plugin_scanner/guard/daemon/runtime_hook_deadline.py,sha256=A0eahNg0qESgx6w8hoeDBGsLX--eHTEb09szX5nFbzg,2127
392
392
  codex_plugin_scanner/guard/daemon/runtime_hook_evidence_writer.py,sha256=ik4CdGOONj2dliINuz5F0ABhkOAPq3ewzOpH9ivfMK0,17142
393
- codex_plugin_scanner/guard/daemon/runtime_hook_scheduler.py,sha256=lbhZRhLJJNIyCmhmBLjD3Yj244VaYC18VV7TVt4Vgdk,23096
393
+ codex_plugin_scanner/guard/daemon/runtime_hook_scheduler.py,sha256=be9VH8FP6AnNsNBcRsLTXBPkQju8Sn0u_1HoHCITO-0,23457
394
394
  codex_plugin_scanner/guard/daemon/runtime_hook_scheduler_contracts.py,sha256=xRA1qtZmR0ahj9uemONijTnMKL1YborwH91n4bJ41Cg,4712
395
395
  codex_plugin_scanner/guard/daemon/runtime_hook_scheduler_types.py,sha256=MvLMtsPRep3IxloxVCcfJMLuErfo2BYE1XZtTt57tEs,361
396
396
  codex_plugin_scanner/guard/daemon/runtime_hook_work_item.py,sha256=6MqBrA14jydaLHJ8B2x0tdkPq_weaVeNV6oIlB0va2Y,1246
397
- codex_plugin_scanner/guard/daemon/server.py,sha256=jruYNaVv286RN0yPXckNjIcFE40-zX2QYci0ot9qFeY,372657
397
+ codex_plugin_scanner/guard/daemon/server.py,sha256=PjajE4KYb2XZK_4w6OnIO3NdD7cdr3EZEkxiVZph5Kw,373059
398
398
  codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png,sha256=thrVc0duH3ETg03qlRer9714JpRh0DGYqp2RpvVGTdc,12211
399
399
  codex_plugin_scanner/guard/daemon/static/favicon-16x16.png,sha256=jcclKW2ZXshOJUMLjY8RkvWtd7gy60dibk4gftGyY8c,519
400
400
  codex_plugin_scanner/guard/daemon/static/favicon-32x32.png,sha256=kFgVF3ZorfAwCCc5BlCL6GYaoPilCf3m5H4elkPUeso,1352
@@ -528,7 +528,7 @@ codex_plugin_scanner/guard/runtime/extension_control_contract.py,sha256=t2NLJP5D
528
528
  codex_plugin_scanner/guard/runtime/extension_control_proof.py,sha256=uHrDTkunxlFrpFULiZXyrh8v4H6jbTKFyWhkSmbsgkE,6194
529
529
  codex_plugin_scanner/guard/runtime/extension_control_resolver.py,sha256=aNmVrVjtKv6EAZlFhU64BijfzBABWXutvZDZly5B-4s,8420
530
530
  codex_plugin_scanner/guard/runtime/extension_evidence.py,sha256=6gS05shn1OI5bmuFxGu5El4rHuICsvpI65WJV7oezmY,10583
531
- codex_plugin_scanner/guard/runtime/false_positive_rules.py,sha256=OcXN1FItvuapKosg7kRNiys9YcJN4ALVzN2hKdX4VCw,24316
531
+ codex_plugin_scanner/guard/runtime/false_positive_rules.py,sha256=JgrrdxI_2af9AdklCzOAHTJ38tVPpFtStqSL1A9p8gI,24746
532
532
  codex_plugin_scanner/guard/runtime/git_execution_safety.py,sha256=D2Ma5jnvTFosfoTt9hmN2c95ZZGLOc1NTxFR9E_57HY,28722
533
533
  codex_plugin_scanner/guard/runtime/git_index_inspection.py,sha256=XlQwb_cFmdjfWoTTC3nGzJfjVEt3BIb9Gyt7_q1EQqY,14467
534
534
  codex_plugin_scanner/guard/runtime/git_pathspecs.py,sha256=skNNsz-60pnFUqsaYJI9RRkwzUGGttCF-fvMdpOq7iE,12785
@@ -700,8 +700,8 @@ codex_plugin_scanner/integrations/cisco_skill_scanner.py,sha256=3tW9Ya5riLsIbU9Y
700
700
  codex_plugin_scanner/rules/__init__.py,sha256=bhAnNlVvEiAoksf_-Vd4f74JNz66pTINhUO2mMc8kvs,293
701
701
  codex_plugin_scanner/rules/registry.py,sha256=7BaRerM26teDUM0S48d3sPHbqzmq2JhuelC0_ni3364,4580
702
702
  codex_plugin_scanner/rules/specs.py,sha256=gpU0lijxqdSEZMMf28vciQxob-lvBEPcMQ4BG6N_r3I,650
703
- plugin_scanner-2.2.113.dist-info/METADATA,sha256=fiqzYiXI-fXoa2tKa1TR-zZ9k33Zrj4y4t7qoMj1Jdg,47988
704
- plugin_scanner-2.2.113.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
705
- plugin_scanner-2.2.113.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
706
- plugin_scanner-2.2.113.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
707
- plugin_scanner-2.2.113.dist-info/RECORD,,
703
+ plugin_scanner-2.2.115.dist-info/METADATA,sha256=FfYtwLepDhWnO6diFUleazcOrGe5Yx5tKAHAjc7LywI,48487
704
+ plugin_scanner-2.2.115.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
705
+ plugin_scanner-2.2.115.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
706
+ plugin_scanner-2.2.115.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
707
+ plugin_scanner-2.2.115.dist-info/RECORD,,