plugin-scanner 2.2.111__py3-none-any.whl → 2.2.112__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.
@@ -1418,7 +1418,11 @@ def _build_package_protect_authority(
1418
1418
  guard_home=store.guard_home,
1419
1419
  launch_cwd=launch_cwd,
1420
1420
  )
1421
- intent = _package_intent_parser_module().parse_package_intent(shlex.join(command), workspace=launch_cwd)
1421
+ intent = _package_intent_parser_module().parse_package_intent(
1422
+ shlex.join(command),
1423
+ workspace=launch_cwd,
1424
+ environment=launch_environment,
1425
+ )
1422
1426
  if intent is None:
1423
1427
  return None
1424
1428
  sanitized_intent = replace(intent, redacted_command=shlex.join(redacted_command_tokens(command)))
@@ -10,7 +10,7 @@ import re
10
10
  import shlex
11
11
  import shutil
12
12
  import stat
13
- from collections.abc import Iterable
13
+ from collections.abc import Iterable, Mapping
14
14
  from dataclasses import dataclass, replace
15
15
  from pathlib import Path
16
16
 
@@ -61,6 +61,7 @@ _CONTROL_CONTEXT_LABELS = {
61
61
  }
62
62
  _EXECUTION_CONTEXT_HMAC_KEY = os.urandom(32)
63
63
  _ENV_ASSIGNMENT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=.*$")
64
+ _ENV_REFERENCE_RE = re.compile(r"\$(?:\{(?P<braced>[A-Za-z_][A-Za-z0-9_]*)\}|(?P<plain>[A-Za-z_][A-Za-z0-9_]*))")
64
65
  _LOCAL_EXECUTION_COMMANDS = frozenset({"bunx", "npx"})
65
66
  _PACKAGE_COMMAND_NAMES = frozenset(
66
67
  {
@@ -139,6 +140,7 @@ def parse_package_intent(
139
140
  workspace: Path | None = None,
140
141
  home_dir: Path | None = None,
141
142
  canonical_command: CanonicalCommand | None = None,
143
+ environment: Mapping[str, str] | None = None,
142
144
  ) -> PackageIntent | None:
143
145
  handlers = {
144
146
  "npm": _parse_npm_intent,
@@ -175,7 +177,12 @@ def parse_package_intent(
175
177
  "helm": _parse_helm_intent,
176
178
  }
177
179
  intents: list[PackageIntent] = []
178
- for segment in _normalized_command_segments(command_text, workspace=workspace, home_dir=home_dir):
180
+ for segment in _normalized_command_segments(
181
+ command_text,
182
+ workspace=workspace,
183
+ home_dir=home_dir,
184
+ environment=environment,
185
+ ):
179
186
  if not segment.tokens:
180
187
  continue
181
188
  command_name = _command_name(segment.tokens[0])
@@ -1191,7 +1198,9 @@ def _normalized_command_segments(
1191
1198
  *,
1192
1199
  workspace: Path | None = None,
1193
1200
  home_dir: Path | None = None,
1201
+ environment: Mapping[str, str] | None = None,
1194
1202
  ) -> tuple[_CommandSegment, ...]:
1203
+ inherited_environment = environment if environment is not None else os.environ
1195
1204
  execution_context = model_shell_execution_context(
1196
1205
  command_text,
1197
1206
  cwd=workspace,
@@ -1241,6 +1250,7 @@ def _normalized_command_segments(
1241
1250
  workspace=workspace,
1242
1251
  initial_cwd=modeled_cwd,
1243
1252
  initial_cwd_source=context_segment.cwd_source,
1253
+ environment=inherited_environment,
1244
1254
  )
1245
1255
  context_complete = validation_reason is None and context_segment.complete
1246
1256
  segments.append(
@@ -1431,10 +1441,12 @@ def _effective_execution_context(
1431
1441
  workspace: Path | None,
1432
1442
  initial_cwd: Path | None = None,
1433
1443
  initial_cwd_source: str | None = None,
1444
+ environment: Mapping[str, str] | None = None,
1434
1445
  ) -> tuple[str | None, str, Path, str]:
1446
+ supplied_environment = environment if environment is not None else os.environ
1435
1447
  effective_cwd = (initial_cwd or workspace or Path.cwd()).expanduser().resolve()
1436
1448
  cwd_source = initial_cwd_source or ("workspace" if workspace is not None else "process")
1437
- effective_path = os.environ.get("PATH")
1449
+ effective_path = supplied_environment.get("PATH")
1438
1450
  path_source = "inherited" if effective_path is not None else "inherited_unset"
1439
1451
  index, effective_path, path_source = _consume_path_assignments(
1440
1452
  raw_segment,
@@ -1442,6 +1454,7 @@ def _effective_execution_context(
1442
1454
  effective_path,
1443
1455
  path_source,
1444
1456
  direct_source="inline",
1457
+ environment=supplied_environment,
1445
1458
  )
1446
1459
  if index >= len(raw_segment):
1447
1460
  return _path_for_resolution(effective_path, effective_cwd), path_source, effective_cwd, cwd_source
@@ -1465,6 +1478,7 @@ def _effective_execution_context(
1465
1478
  effective_path,
1466
1479
  path_source,
1467
1480
  direct_source="inline",
1481
+ environment=supplied_environment,
1468
1482
  )
1469
1483
  if index >= len(raw_segment):
1470
1484
  return _path_for_resolution(effective_path, effective_cwd), path_source, effective_cwd, cwd_source
@@ -1472,7 +1486,7 @@ def _effective_execution_context(
1472
1486
  if command_name != "env":
1473
1487
  return _path_for_resolution(effective_path, effective_cwd), path_source, effective_cwd, cwd_source
1474
1488
 
1475
- inherited_environment = dict(os.environ)
1489
+ inherited_environment = dict(supplied_environment)
1476
1490
  if effective_path is None:
1477
1491
  inherited_environment.pop("PATH", None)
1478
1492
  else:
@@ -1490,10 +1504,18 @@ def _effective_execution_context(
1490
1504
  None,
1491
1505
  )
1492
1506
  if parsed_env.option_effects.search_path is not None:
1493
- effective_path = _expanded_path_assignment(parsed_env.option_effects.search_path, effective_path)
1507
+ effective_path = _expanded_path_assignment(
1508
+ parsed_env.option_effects.search_path,
1509
+ effective_path,
1510
+ environment=inherited_environment,
1511
+ )
1494
1512
  path_source = "env_search_path" if effective_path is not None else "env_search_path_unresolved"
1495
1513
  elif path_assignment is not None:
1496
- effective_path = _expanded_path_assignment(path_assignment, effective_path)
1514
+ effective_path = _expanded_path_assignment(
1515
+ path_assignment,
1516
+ effective_path,
1517
+ environment=inherited_environment,
1518
+ )
1497
1519
  path_source = "env" if effective_path is not None else "env_unresolved"
1498
1520
  elif parsed_env.option_effects.ignore_environment or path_was_unset:
1499
1521
  effective_path = os.defpath
@@ -1517,12 +1539,13 @@ def _consume_path_assignments(
1517
1539
  current_source: str,
1518
1540
  *,
1519
1541
  direct_source: str,
1542
+ environment: Mapping[str, str],
1520
1543
  ) -> tuple[int, str | None, str]:
1521
1544
  path_source = current_source
1522
1545
  while index < len(tokens) and _ENV_ASSIGNMENT_RE.match(tokens[index]):
1523
1546
  name, _, value = tokens[index].partition("=")
1524
1547
  if name == "PATH":
1525
- current_path = _expanded_path_assignment(value, current_path)
1548
+ current_path = _expanded_path_assignment(value, current_path, environment=environment)
1526
1549
  path_source = direct_source if current_path is not None else f"{direct_source}_unresolved"
1527
1550
  index += 1
1528
1551
  return index, current_path, path_source
@@ -1553,9 +1576,20 @@ def _updated_effective_cwd(current_cwd: Path, value: str) -> tuple[Path, str]:
1553
1576
  return current_cwd, "env_chdir_unresolved"
1554
1577
 
1555
1578
 
1556
- def _expanded_path_assignment(value: str, current_path: str | None) -> str | None:
1557
- expanded = value.replace("${PATH}", current_path or "").replace("$PATH", current_path or "")
1558
- expanded = os.path.expandvars(expanded)
1579
+ def _expanded_path_assignment(
1580
+ value: str,
1581
+ current_path: str | None,
1582
+ *,
1583
+ environment: Mapping[str, str],
1584
+ ) -> str | None:
1585
+ expansion_environment = dict(environment)
1586
+ expansion_environment["PATH"] = current_path or ""
1587
+
1588
+ def replace_reference(match: re.Match[str]) -> str:
1589
+ name = match.group("braced") or match.group("plain")
1590
+ return expansion_environment.get(name, match.group(0))
1591
+
1592
+ expanded = _ENV_REFERENCE_RE.sub(replace_reference, value)
1559
1593
  if "$" in expanded or "\x00" in expanded:
1560
1594
  return None
1561
1595
  return expanded
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.2.111"
3
+ __version__ = "2.2.112"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.2.111
3
+ Version: 2.2.112
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
@@ -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=e2ZatvkDrTaf1ARU9WqTwI2Tlf2HJDngTRYJ2tE9ngc,72
31
+ codex_plugin_scanner/version.py,sha256=nlMKlHr2oThwfMO6dbFGUhpNwaC9RvhwkpcoYAVLiQQ,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
@@ -112,7 +112,7 @@ codex_plugin_scanner/guard/inventory_item_description.py,sha256=vSSxbQLAYQHGE0oY
112
112
  codex_plugin_scanner/guard/launcher.py,sha256=2iD2taiyxGTdnWV-9PCIgVMJwEG7iowmE0K0Yt5mCC0,2533
113
113
  codex_plugin_scanner/guard/local_authority_integrity.py,sha256=dS_7IUhg__Ea5esUUklEL0ZBOgSTnqBcQ982V1bO6_Q,5832
114
114
  codex_plugin_scanner/guard/local_dashboard_session.py,sha256=LpSDyNjhblUyD589uQQUyFdsecpPmw2yWThgAKIjyHI,1722
115
- codex_plugin_scanner/guard/local_supply_chain.py,sha256=pOBbNgwCZsjgSdtSopb_McXlIQg5bhwOBgmiDKkuNhw,171701
115
+ codex_plugin_scanner/guard/local_supply_chain.py,sha256=6lRbkKbzFO6Fbu30RdMUIGb3nS3ySDuvdIwyS1YiqhY,171764
116
116
  codex_plugin_scanner/guard/local_trust_contract.py,sha256=F2J3KygnvXrGtuBJ9I96RBLJg-NFqxE3gQGSPx8n-3g,14903
117
117
  codex_plugin_scanner/guard/local_trust_controller.py,sha256=6AY-kf-Q1OjPE63F4La5uX6UQqGcWhYXKkyw23jSwiU,10853
118
118
  codex_plugin_scanner/guard/managed_install_proof.py,sha256=GecgR6J6jjnV0zZ25cAJvrTfJTycuVDbCJjFn7DeCVs,3343
@@ -585,7 +585,7 @@ codex_plugin_scanner/guard/runtime/offline_archive_worker.py,sha256=mimHsG9u6O4K
585
585
  codex_plugin_scanner/guard/runtime/package_execution_policy.py,sha256=duV4_QIDmkb6JGXOIYK9ilgfd3R0gFE8I1ON89QTuEQ,555
586
586
  codex_plugin_scanner/guard/runtime/package_intent.py,sha256=rqiGU_XnLE-xk6gN6_eVRVIIYXSBGmrBzdjwnI95BWk,681
587
587
  codex_plugin_scanner/guard/runtime/package_intent_common.py,sha256=dZizvm7vKw978ntat-uR4OzQLu-3_a-TjzlYxLtVkFg,23883
588
- codex_plugin_scanner/guard/runtime/package_intent_parser.py,sha256=-RNnHw_RRmZO-hZzC9CFUFdWmvdUMysbQOxakeVOL6k,65069
588
+ codex_plugin_scanner/guard/runtime/package_intent_parser.py,sha256=VCh2qU0pGnghjD9AXvJWlhFxgDjSjm_aFzGKTGtWxcw,66214
589
589
  codex_plugin_scanner/guard/runtime/package_manager_command.py,sha256=KTxy8LFadce-GxprijT83_vxSrz2otiyoiPnvsA4dMg,5213
590
590
  codex_plugin_scanner/guard/runtime/package_manifest_diff.py,sha256=49pranXVP4qNdm0wJB232WUG_lckqeLSAn1EPEQXJpA,26327
591
591
  codex_plugin_scanner/guard/runtime/persistence_rules.py,sha256=SP8JPsL_B_ebICm2l9QG7btcblrb90VjaIeYN3WaYno,6587
@@ -699,8 +699,8 @@ codex_plugin_scanner/integrations/cisco_skill_scanner.py,sha256=3tW9Ya5riLsIbU9Y
699
699
  codex_plugin_scanner/rules/__init__.py,sha256=bhAnNlVvEiAoksf_-Vd4f74JNz66pTINhUO2mMc8kvs,293
700
700
  codex_plugin_scanner/rules/registry.py,sha256=7BaRerM26teDUM0S48d3sPHbqzmq2JhuelC0_ni3364,4580
701
701
  codex_plugin_scanner/rules/specs.py,sha256=gpU0lijxqdSEZMMf28vciQxob-lvBEPcMQ4BG6N_r3I,650
702
- plugin_scanner-2.2.111.dist-info/METADATA,sha256=D-4utaCuLhWmbPskoNk_4CnHy4GHf0MlsXWry_20Vvo,47988
703
- plugin_scanner-2.2.111.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
704
- plugin_scanner-2.2.111.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
705
- plugin_scanner-2.2.111.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
706
- plugin_scanner-2.2.111.dist-info/RECORD,,
702
+ plugin_scanner-2.2.112.dist-info/METADATA,sha256=qjrxsOUFH9jWL_rdeB4NSIYSLrF8Eca9x8Mvtda6E74,47988
703
+ plugin_scanner-2.2.112.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
704
+ plugin_scanner-2.2.112.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
705
+ plugin_scanner-2.2.112.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
706
+ plugin_scanner-2.2.112.dist-info/RECORD,,