plugin-scanner 2.2.110__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.
- codex_plugin_scanner/guard/local_supply_chain.py +41 -2
- codex_plugin_scanner/guard/runtime/package_intent_parser.py +44 -10
- codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.2.110.dist-info → plugin_scanner-2.2.112.dist-info}/METADATA +1 -1
- {plugin_scanner-2.2.110.dist-info → plugin_scanner-2.2.112.dist-info}/RECORD +8 -8
- {plugin_scanner-2.2.110.dist-info → plugin_scanner-2.2.112.dist-info}/WHEEL +0 -0
- {plugin_scanner-2.2.110.dist-info → plugin_scanner-2.2.112.dist-info}/entry_points.txt +0 -0
- {plugin_scanner-2.2.110.dist-info → plugin_scanner-2.2.112.dist-info}/licenses/LICENSE +0 -0
|
@@ -1365,6 +1365,37 @@ def _bound_external_archive_launch_command(
|
|
|
1365
1365
|
return bound_command
|
|
1366
1366
|
|
|
1367
1367
|
|
|
1368
|
+
def _package_manager_launch_environment(
|
|
1369
|
+
environment: Mapping[str, str],
|
|
1370
|
+
*,
|
|
1371
|
+
guard_home: Path,
|
|
1372
|
+
launch_cwd: Path,
|
|
1373
|
+
) -> dict[str, str]:
|
|
1374
|
+
"""Exclude Guard's interception shim from the reviewed and executed package-manager path."""
|
|
1375
|
+
|
|
1376
|
+
launch_environment = dict(environment)
|
|
1377
|
+
try:
|
|
1378
|
+
shim_dir = (guard_home / "package-shims" / "bin").expanduser().resolve()
|
|
1379
|
+
except (OSError, RuntimeError, ValueError):
|
|
1380
|
+
raise ValueError("Guard's package shim path could not be verified") from None
|
|
1381
|
+
path_entries = environment.get("PATH", "").split(os.pathsep)
|
|
1382
|
+
filtered_entries: list[str] = []
|
|
1383
|
+
for entry in path_entries:
|
|
1384
|
+
if not entry:
|
|
1385
|
+
continue
|
|
1386
|
+
try:
|
|
1387
|
+
path_entry = Path(entry).expanduser()
|
|
1388
|
+
if not path_entry.is_absolute():
|
|
1389
|
+
path_entry = launch_cwd / path_entry
|
|
1390
|
+
resolved_entry = path_entry.resolve()
|
|
1391
|
+
except (OSError, RuntimeError, ValueError):
|
|
1392
|
+
raise ValueError("package manager PATH could not be verified") from None
|
|
1393
|
+
if resolved_entry != shim_dir:
|
|
1394
|
+
filtered_entries.append(entry)
|
|
1395
|
+
launch_environment["PATH"] = os.pathsep.join(filtered_entries)
|
|
1396
|
+
return launch_environment
|
|
1397
|
+
|
|
1398
|
+
|
|
1368
1399
|
def _build_package_protect_authority(
|
|
1369
1400
|
*,
|
|
1370
1401
|
command: Sequence[str],
|
|
@@ -1382,8 +1413,16 @@ def _build_package_protect_authority(
|
|
|
1382
1413
|
raise ValueError("package workspace must resolve to an existing directory") from None
|
|
1383
1414
|
if not launch_cwd.is_dir():
|
|
1384
1415
|
raise ValueError("package workspace must resolve to an existing directory")
|
|
1385
|
-
launch_environment =
|
|
1386
|
-
|
|
1416
|
+
launch_environment = _package_manager_launch_environment(
|
|
1417
|
+
os.environ,
|
|
1418
|
+
guard_home=store.guard_home,
|
|
1419
|
+
launch_cwd=launch_cwd,
|
|
1420
|
+
)
|
|
1421
|
+
intent = _package_intent_parser_module().parse_package_intent(
|
|
1422
|
+
shlex.join(command),
|
|
1423
|
+
workspace=launch_cwd,
|
|
1424
|
+
environment=launch_environment,
|
|
1425
|
+
)
|
|
1387
1426
|
if intent is None:
|
|
1388
1427
|
return None
|
|
1389
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
1557
|
-
|
|
1558
|
-
|
|
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
|
codex_plugin_scanner/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plugin-scanner
|
|
3
|
-
Version: 2.2.
|
|
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=
|
|
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=
|
|
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
|
|
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.
|
|
703
|
-
plugin_scanner-2.2.
|
|
704
|
-
plugin_scanner-2.2.
|
|
705
|
-
plugin_scanner-2.2.
|
|
706
|
-
plugin_scanner-2.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|