plugin-scanner 2.0.552__py3-none-any.whl → 2.0.554__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.

Potentially problematic release.


This version of plugin-scanner might be problematic. Click here for more details.

@@ -235,6 +235,12 @@ def _git_run(
235
235
  return None
236
236
 
237
237
 
238
+ def _is_safe_committed_tree_path(path: str) -> bool:
239
+ if path == "" or path.startswith(("/", "\\")) or "\\" in path or "\0" in path:
240
+ return False
241
+ return all(part not in {"", ".", ".."} for part in path.split("/"))
242
+
243
+
238
244
  def _list_committed_static_files(checkout: Path, static_prefix: str) -> list[str]:
239
245
  result = _git_run(checkout, "ls-tree", "-r", "--name-only", "HEAD", "--", static_prefix)
240
246
  if result is None or result.returncode != 0:
@@ -243,13 +249,20 @@ def _list_committed_static_files(checkout: Path, static_prefix: str) -> list[str
243
249
  prefix = f"{static_prefix.rstrip('/')}/"
244
250
  for line in result.stdout.splitlines():
245
251
  relative = line.strip()
246
- if relative == "" or relative.endswith("/") or not relative.startswith(prefix):
252
+ if (
253
+ relative == ""
254
+ or relative.endswith("/")
255
+ or not relative.startswith(prefix)
256
+ or not _is_safe_committed_tree_path(relative)
257
+ ):
247
258
  continue
248
259
  files.append(relative)
249
260
  return files
250
261
 
251
262
 
252
263
  def _read_committed_file(checkout: Path, relative_path: str) -> bytes | None:
264
+ if not _is_safe_committed_tree_path(relative_path):
265
+ return None
253
266
  result = _git_run(checkout, "show", f"HEAD:{relative_path}", text=False)
254
267
  if result is None or result.returncode != 0:
255
268
  return None
@@ -263,7 +276,20 @@ def _relative_static_path(relative_path: str, static_prefix: str) -> Path | None
263
276
  normalized_prefix = static_prefix.rstrip("/")
264
277
  if not relative_path.startswith(f"{normalized_prefix}/"):
265
278
  return None
266
- return Path(relative_path.removeprefix(f"{normalized_prefix}/"))
279
+ suffix = relative_path.removeprefix(f"{normalized_prefix}/")
280
+ if not _is_safe_committed_tree_path(suffix):
281
+ return None
282
+ return Path(suffix)
283
+
284
+
285
+ def _resolve_static_export_path(installed_static: Path, relative_to_static: Path) -> Path | None:
286
+ base = installed_static.resolve()
287
+ destination = (base / relative_to_static).resolve()
288
+ try:
289
+ destination.relative_to(base)
290
+ except ValueError:
291
+ return None
292
+ return destination
267
293
 
268
294
 
269
295
  def _export_committed_static_files(
@@ -280,7 +306,9 @@ def _export_committed_static_files(
280
306
  relative_to_static = _relative_static_path(relative_path, static_prefix)
281
307
  if relative_to_static is None:
282
308
  continue
283
- dest = installed_static / relative_to_static
309
+ dest = _resolve_static_export_path(installed_static, relative_to_static)
310
+ if dest is None:
311
+ continue
284
312
  dest.parent.mkdir(parents=True, exist_ok=True)
285
313
  dest.write_bytes(payload)
286
314
  copied_count += 1
@@ -103,6 +103,7 @@ from ..package_firewall_entitlement import (
103
103
  package_firewall_block_details,
104
104
  package_firewall_operation_allowed,
105
105
  )
106
+ from ..package_shim_status import record_package_shim_audit_result
106
107
  from ..receipts.manager import build_receipt
107
108
  from ..runtime.runner import (
108
109
  GuardSyncAuthorizationExpiredError,
@@ -2027,6 +2028,8 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
2027
2028
  workspace_dir=context.workspace_dir,
2028
2029
  )
2029
2030
  audit_payload["exit_code"] = exit_code
2031
+ if exit_code == 0:
2032
+ record_package_shim_audit_result(context, audited_at=now)
2030
2033
  return audit_payload
2031
2034
  if operation == "sync":
2032
2035
  return sync_supply_chain_bundle(self.server.store) # type: ignore[attr-defined]
@@ -0,0 +1,61 @@
1
+ """Package shim status enrichment and audit proof persistence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from .adapters.base import HarnessContext
10
+
11
+
12
+ def enrich_package_shim_status_payload(
13
+ status: dict[str, object],
14
+ manifest: dict[str, object],
15
+ ) -> dict[str, object]:
16
+ bypasses = status.get("bypasses", [])
17
+ path_broken_managers = sorted(
18
+ {
19
+ str(entry["manager"])
20
+ for entry in bypasses
21
+ if isinstance(entry, dict) and isinstance(entry.get("manager"), str)
22
+ }
23
+ )
24
+ last_test_at = status.get("last_test_at", {})
25
+ tested_managers = (
26
+ sorted(manager for manager in last_test_at if isinstance(manager, str))
27
+ if isinstance(last_test_at, dict)
28
+ else []
29
+ )
30
+ last_audit_proof_at = manifest.get("last_audit_at")
31
+ normalized_last_audit = last_audit_proof_at if isinstance(last_audit_proof_at, str) else None
32
+ normalized_last_tests = last_test_at if isinstance(last_test_at, dict) else {}
33
+
34
+ enriched = dict(status)
35
+ enriched["path_broken_managers"] = path_broken_managers
36
+ enriched["tested_managers"] = tested_managers
37
+ enriched["pathBrokenManagers"] = path_broken_managers
38
+ enriched["testedManagers"] = tested_managers
39
+ enriched["last_intercept_proof_at"] = normalized_last_tests
40
+ enriched["lastInterceptProofAt"] = normalized_last_tests
41
+ enriched["detectedManagers"] = list(status.get("detected_managers", []))
42
+ enriched["protectedManagers"] = list(status.get("protected_managers", []))
43
+ enriched["installedManagers"] = list(status.get("installed_managers", []))
44
+ enriched["activeManagers"] = list(status.get("active_managers", []))
45
+ enriched["missingManagers"] = list(status.get("missing_managers", []))
46
+ enriched["undetectedManagers"] = list(status.get("undetected_managers", []))
47
+ enriched["last_audit_proof_at"] = normalized_last_audit
48
+ enriched["lastAuditProofAt"] = normalized_last_audit
49
+ return enriched
50
+
51
+
52
+ def record_package_shim_audit_result(
53
+ context: HarnessContext,
54
+ *,
55
+ audited_at: str | None = None,
56
+ ) -> None:
57
+ from .shims import _load_package_shim_manifest, _write_package_shim_manifest
58
+
59
+ manifest = _load_package_shim_manifest(context)
60
+ manifest["last_audit_at"] = audited_at if audited_at is not None else datetime.now(timezone.utc).isoformat()
61
+ _write_package_shim_manifest(context, manifest)
@@ -13,6 +13,7 @@ from pathlib import Path
13
13
  from typing import TYPE_CHECKING
14
14
 
15
15
  from .launcher import merge_guard_launcher_env
16
+ from .package_shim_status import enrich_package_shim_status_payload
16
17
  from .shim_probe import (
17
18
  SHIM_PROBE_ENV_VALUE,
18
19
  SHIM_PROBE_ENV_VAR,
@@ -448,27 +449,30 @@ def package_shim_status(context: HarnessContext) -> dict[str, object]:
448
449
  path_contains_shim_dir=path_contains_shim_dir,
449
450
  shell_profile_configured=bool(profile_status["shell_profile_configured"]),
450
451
  )
451
- return {
452
- "active_managers": active_managers,
453
- "detected_managers": detected_managers,
454
- "installed_managers": installed_managers,
455
- "last_test_at": normalized_last_tests,
456
- "protected_managers": protected_managers,
457
- "path_active": bool(installed_managers) and len(protected_managers) == len(installed_managers),
458
- "path_contains_shim_dir": path_contains_shim_dir,
459
- "path_status": activation_path_status,
460
- "bypasses": bypasses,
461
- "manager_details": manager_details,
462
- "manifest_path": str(_package_shim_manifest_path(context)),
463
- "missing_managers": missing_managers,
464
- "restart_shell_required": activation_path_status == "restart_required",
465
- "shell_profile_configured": bool(profile_status["shell_profile_configured"]),
466
- "shell_profile_path": profile_status["shell_profile_path"],
467
- "shell_hints": _path_export_hints(shim_dir),
468
- "shim_dir": str(shim_dir),
469
- "supported_managers": list(package_shim_supported_managers()),
470
- "undetected_managers": undetected_managers,
471
- }
452
+ return enrich_package_shim_status_payload(
453
+ {
454
+ "active_managers": active_managers,
455
+ "detected_managers": detected_managers,
456
+ "installed_managers": installed_managers,
457
+ "last_test_at": normalized_last_tests,
458
+ "protected_managers": protected_managers,
459
+ "path_active": bool(installed_managers) and len(protected_managers) == len(installed_managers),
460
+ "path_contains_shim_dir": path_contains_shim_dir,
461
+ "path_status": activation_path_status,
462
+ "bypasses": bypasses,
463
+ "manager_details": manager_details,
464
+ "manifest_path": str(_package_shim_manifest_path(context)),
465
+ "missing_managers": missing_managers,
466
+ "restart_shell_required": activation_path_status == "restart_required",
467
+ "shell_profile_configured": bool(profile_status["shell_profile_configured"]),
468
+ "shell_profile_path": profile_status["shell_profile_path"],
469
+ "shell_hints": _path_export_hints(shim_dir),
470
+ "shim_dir": str(shim_dir),
471
+ "supported_managers": list(package_shim_supported_managers()),
472
+ "undetected_managers": undetected_managers,
473
+ },
474
+ manifest,
475
+ )
472
476
 
473
477
 
474
478
  def package_shim_cloud_coverage(
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.552"
3
+ __version__ = "2.0.554"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.552
3
+ Version: 2.0.554
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://github.com/hashgraph-online/hol-guard
6
6
  Project-URL: Repository, https://github.com/hashgraph-online/hol-guard
@@ -25,7 +25,7 @@ codex_plugin_scanner/trust_scoring.py,sha256=t_Lw13HZ766UCJzTtNNwllZK_k2ks_x-8St
25
25
  codex_plugin_scanner/trust_skill_scoring.py,sha256=xbXZCyDlHIWL91eH65Fq97lLQrZo94HvouKlTWtx8r8,11872
26
26
  codex_plugin_scanner/trust_specs.py,sha256=edZ8UvWB4Lqotz0v5dhBO3LFePGv43eLK4tqSmg4DQU,9222
27
27
  codex_plugin_scanner/verification.py,sha256=ZqDw9-JFVgUTOplVgXjYMHQjSvsZgwJu60nCndTTjdU,27697
28
- codex_plugin_scanner/version.py,sha256=QVX17ZpIvYj4eCY2heBI9cX8KY-gazCr46TFTxxYqyc,72
28
+ codex_plugin_scanner/version.py,sha256=5HiQwN3TA5dvDGDAJwia8JTcvEtsNj3h5WLeeybvDso,72
29
29
  codex_plugin_scanner/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  codex_plugin_scanner/checks/best_practices.py,sha256=aSSDWVGoGW7KT71GgWEJ7M8kzAWO77Vr4zeYLrXUhWA,7892
31
31
  codex_plugin_scanner/checks/claude.py,sha256=cMucH5pmKgQtBnDcycOzMMlKL-Q5HQemPqUmTLF0DzE,10189
@@ -75,6 +75,7 @@ codex_plugin_scanner/guard/mcp_tool_calls.py,sha256=Np5kvR-G4KIDqva2EZJf5tMvTne3
75
75
  codex_plugin_scanner/guard/models.py,sha256=5rNzFMbvtrMru9XfmKae4bt-eSQXfO_lYsaD_cg2NiE,7190
76
76
  codex_plugin_scanner/guard/package_firewall_action_rate_limit.py,sha256=X3vq2gUYV-5rhOzc6P4YCU0qTYTJ_odqTxyiLDsHDmA,1163
77
77
  codex_plugin_scanner/guard/package_firewall_entitlement.py,sha256=Sb7dkqFmuMnpvFKd9zFXQpctEVs7bkgLpLRI-xxrmn4,11896
78
+ codex_plugin_scanner/guard/package_shim_status.py,sha256=pMUo90kHCYtScOKlklAwtiiXXXMF1E7xEMqiPD8kKfg,2471
78
79
  codex_plugin_scanner/guard/policy_bundle_parser.py,sha256=fHQGnGHOj0W3Iye4cV_6K4rIdErGYv-kPVM1nadBTlI,7889
79
80
  codex_plugin_scanner/guard/product_model.py,sha256=ku6Sa9y4G2wD0cWLgqbu2huhHYNBsQDq867tws1BtPY,14799
80
81
  codex_plugin_scanner/guard/protect.py,sha256=wx-OuBkvw5Ap3YO3LC6YiZ0538YjZrGP1r5t9SYfNhQ,34723
@@ -83,7 +84,7 @@ codex_plugin_scanner/guard/redaction.py,sha256=9y1pNnz858KWFop0nxXBFvsP5daQ-9yl4
83
84
  codex_plugin_scanner/guard/remote_pairing_constants.py,sha256=ffeZlOha06zBlmr_XSQff8j71u-r9n_EcApfkhSCP6E,163
84
85
  codex_plugin_scanner/guard/risk.py,sha256=GNQQ-WPcRLSBV_tZYTaGB1JtOK8CRobf6xD0gwdWzTU,18550
85
86
  codex_plugin_scanner/guard/shim_probe.py,sha256=uYdNWc6BymV7efLqsFWqq1Elc0QHs9mAwABZ7P08tUI,2532
86
- codex_plugin_scanner/guard/shims.py,sha256=ZXYY5pWog5RaaPriyaUlO-kG8L8lp7mw9RAWmEkRTio,37828
87
+ codex_plugin_scanner/guard/shims.py,sha256=2Q6dD5K_IcGG4O6WP_R3dd09qipISsGGhTlGWYsI9Us,38045
87
88
  codex_plugin_scanner/guard/stable_digest.py,sha256=O4Ts-kGtetRtHZPgMAaFZ8VRC2_x-pSbhZh4X-oZmm4,569
88
89
  codex_plugin_scanner/guard/store.py,sha256=6VH_n7YuUUDmYGD-A1B0XSzQ3OKgNteNv6REr-scC-E,206032
89
90
  codex_plugin_scanner/guard/store_approvals.py,sha256=k3J6Y4seRgKw7hjXUptHRefiwjctXH1nesul5NkOh-0,38486
@@ -125,7 +126,7 @@ codex_plugin_scanner/guard/cli/bootstrap.py,sha256=M3XSSl6k5E6gb0pyHa55AuiC0b30v
125
126
  codex_plugin_scanner/guard/cli/commands.py,sha256=R95TJ0-dZd291fXubmjIvqXgV6X7Ge8-24qeU0LQ1mU,435167
126
127
  codex_plugin_scanner/guard/cli/connect_flow.py,sha256=_G8JltZxSLAhGTo-K2dZtZrpw3LLQSo5mUPuDiZgjI0,45647
127
128
  codex_plugin_scanner/guard/cli/cursor_actions.py,sha256=w0jkfq_fQoyPAI_IiYWKU4AwaAOMj2wz10m-nbkSnD4,6393
128
- codex_plugin_scanner/guard/cli/dashboard_sync.py,sha256=1NvcGumOIE4FAUPWyXsGp9lTscRt0bfEyG5dZiIdSQc,9768
129
+ codex_plugin_scanner/guard/cli/dashboard_sync.py,sha256=o6vcn9WvNUSwjRtUNjmYnjd0gP2MiNy0hIVTL2U5ieE,10651
129
130
  codex_plugin_scanner/guard/cli/docs.py,sha256=oN_-tDLHr56-fLbAjw_zxF_RGBDc2tKHrFLKqJReB5w,4137
130
131
  codex_plugin_scanner/guard/cli/install_commands.py,sha256=wL__cnDt557D1UItUecJ7sKQqGKUSf9B70PXixsRd1w,17431
131
132
  codex_plugin_scanner/guard/cli/oauth_client.py,sha256=MO87ZwksEA2c_XyIreYwjm9IXvkq5K-H0xp4MQNNvMM,7135
@@ -143,7 +144,7 @@ codex_plugin_scanner/guard/daemon/client.py,sha256=S8d-rRhupMTEDJzMlnV0xdbLRaHQx
143
144
  codex_plugin_scanner/guard/daemon/dashboard_update.py,sha256=yr7ApIs4jm6rFICqVjprK-B83AGp-n05l_Murw3fzf4,6604
144
145
  codex_plugin_scanner/guard/daemon/dashboard_update_runner.py,sha256=ad6xCvCPlwn5gKzwyKo492s8_SJlJ6t8AUgQlVmvGdc,2168
145
146
  codex_plugin_scanner/guard/daemon/manager.py,sha256=PEd1mDNbEFt1L7EKoIunmpTIfpg2-nv-nVip28rpn8E,38382
146
- codex_plugin_scanner/guard/daemon/server.py,sha256=Z0Ay5u4EHTJ6S1jY3B_pPw1dWN5AFVgLxjOmnLspYmU,191998
147
+ codex_plugin_scanner/guard/daemon/server.py,sha256=d1NCzbhQ1oCkT0BiaYtp3f701ZYzbCbscyfcU8uQ50Q,192170
147
148
  codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png,sha256=thrVc0duH3ETg03qlRer9714JpRh0DGYqp2RpvVGTdc,12211
148
149
  codex_plugin_scanner/guard/daemon/static/favicon-16x16.png,sha256=jcclKW2ZXshOJUMLjY8RkvWtd7gy60dibk4gftGyY8c,519
149
150
  codex_plugin_scanner/guard/daemon/static/favicon-32x32.png,sha256=kFgVF3ZorfAwCCc5BlCL6GYaoPilCf3m5H4elkPUeso,1352
@@ -230,8 +231,8 @@ codex_plugin_scanner/integrations/cisco_skill_scanner.py,sha256=LKdGaikJKsn9DL6N
230
231
  codex_plugin_scanner/rules/__init__.py,sha256=bhAnNlVvEiAoksf_-Vd4f74JNz66pTINhUO2mMc8kvs,293
231
232
  codex_plugin_scanner/rules/registry.py,sha256=7BaRerM26teDUM0S48d3sPHbqzmq2JhuelC0_ni3364,4580
232
233
  codex_plugin_scanner/rules/specs.py,sha256=gpU0lijxqdSEZMMf28vciQxob-lvBEPcMQ4BG6N_r3I,650
233
- plugin_scanner-2.0.552.dist-info/METADATA,sha256=wT9mEHEN65gPXElHoSpHT-EkpsKRD7PnCuYE8CgnSwo,37810
234
- plugin_scanner-2.0.552.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
235
- plugin_scanner-2.0.552.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
236
- plugin_scanner-2.0.552.dist-info/licenses/LICENSE,sha256=M6h9Xc242NSFZx5h6wBOKJpEQkFl_Wmz03yNrZd0_3E,5688
237
- plugin_scanner-2.0.552.dist-info/RECORD,,
234
+ plugin_scanner-2.0.554.dist-info/METADATA,sha256=RhQZ12914LFb23Zs2y0idbI45ooS91ET0I84yafpK-I,37810
235
+ plugin_scanner-2.0.554.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
236
+ plugin_scanner-2.0.554.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
237
+ plugin_scanner-2.0.554.dist-info/licenses/LICENSE,sha256=M6h9Xc242NSFZx5h6wBOKJpEQkFl_Wmz03yNrZd0_3E,5688
238
+ plugin_scanner-2.0.554.dist-info/RECORD,,