plugin-scanner 2.2.111__py3-none-any.whl → 2.2.113__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 +5 -1
- codex_plugin_scanner/guard/runtime/command_builtin_extension_registry.py +7 -3
- codex_plugin_scanner/guard/runtime/command_builtin_rules.py +8 -0
- codex_plugin_scanner/guard/runtime/compound_git_inspection.py +1 -1
- codex_plugin_scanner/guard/runtime/git_index_inspection.py +408 -0
- codex_plugin_scanner/guard/runtime/package_intent_parser.py +44 -10
- codex_plugin_scanner/guard/runtime/secret_file_request_services/developer_routines.py +3 -2
- codex_plugin_scanner/guard/runtime/secret_file_request_services/source_edit_context.py +10 -5
- codex_plugin_scanner/guard/runtime/secret_file_request_services/tool_action_requests.py +20 -2
- codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.2.111.dist-info → plugin_scanner-2.2.113.dist-info}/METADATA +1 -1
- {plugin_scanner-2.2.111.dist-info → plugin_scanner-2.2.113.dist-info}/RECORD +15 -14
- {plugin_scanner-2.2.111.dist-info → plugin_scanner-2.2.113.dist-info}/WHEEL +0 -0
- {plugin_scanner-2.2.111.dist-info → plugin_scanner-2.2.113.dist-info}/entry_points.txt +0 -0
- {plugin_scanner-2.2.111.dist-info → plugin_scanner-2.2.113.dist-info}/licenses/LICENSE +0 -0
|
@@ -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(
|
|
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)))
|
|
@@ -53,12 +53,16 @@ _CORE_COMMAND_EXTENSION_SPECS: Final[tuple[CommandExtensionSpec, ...]] = (
|
|
|
53
53
|
CommandExtensionSpec(
|
|
54
54
|
extension_id="command.git",
|
|
55
55
|
name="Git protection",
|
|
56
|
-
description=
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
description=(
|
|
57
|
+
"Reviews local and remote Git operations that can discard work, replace history, "
|
|
58
|
+
"or read a staged index Guard cannot bound."
|
|
59
|
+
),
|
|
60
|
+
action_classes=("git destructive command", "git index inspection"),
|
|
61
|
+
risk_classes=("destructive_shell", "local_secret_read"),
|
|
59
62
|
safer_alternatives=(
|
|
60
63
|
"Preview affected files and refs before destructive repository operations.",
|
|
61
64
|
"Create a temporary branch or stash before discarding local work.",
|
|
65
|
+
"Inspect the staged index with git diff --cached --check or lockfile excludes.",
|
|
62
66
|
),
|
|
63
67
|
reference_urls=(),
|
|
64
68
|
required=True,
|
|
@@ -42,6 +42,7 @@ COMMAND_ACTION_RISK_CLASSES: dict[str, tuple[str, ...]] = {
|
|
|
42
42
|
"github pr body shell substitution": ("execution",),
|
|
43
43
|
"filesystem destructive command": ("destructive_shell",),
|
|
44
44
|
"git destructive command": ("destructive_shell",),
|
|
45
|
+
"git index inspection": ("local_secret_read",),
|
|
45
46
|
"system destructive command": ("destructive_shell",),
|
|
46
47
|
"windows destructive command": ("destructive_shell",),
|
|
47
48
|
"kubernetes destructive command": ("destructive_shell", "network_egress"),
|
|
@@ -243,6 +244,13 @@ BUILT_IN_COMMAND_RULES = (
|
|
|
243
244
|
action_class="GitHub PR body shell substitution",
|
|
244
245
|
safer_alternative="Use a literal body file whose contents can be reviewed before submission.",
|
|
245
246
|
),
|
|
247
|
+
_compatibility_rule(
|
|
248
|
+
rule_id="command.git.index-inspection",
|
|
249
|
+
title="Git index inspection",
|
|
250
|
+
description="Identifies staged-index Git reads that Guard cannot verify as a bounded inspection.",
|
|
251
|
+
action_class="git index inspection",
|
|
252
|
+
safer_alternative="Run git diff --cached --check, or exclude lockfiles and scan the staged patch on stdin.",
|
|
253
|
+
),
|
|
246
254
|
_structured_rule(
|
|
247
255
|
rule_id="command.filesystem.recursive-delete",
|
|
248
256
|
title="Recursive filesystem deletion",
|
|
@@ -131,7 +131,7 @@ def is_low_risk_git_inspection_segment(segment: ShellExecutionSegment) -> bool:
|
|
|
131
131
|
if operation == "rev-parse":
|
|
132
132
|
return _safe_rev_parse_args(args)
|
|
133
133
|
if operation == "diff":
|
|
134
|
-
return _safe_diff_args(args)
|
|
134
|
+
return _safe_diff_args(args) and _git_show_has_execution_free_config(segment, repository_path=repository_path)
|
|
135
135
|
if operation == "ls-files":
|
|
136
136
|
return _safe_ls_files_args(args)
|
|
137
137
|
if operation == "show":
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""Staged-index Git inspection recognition for allow and extension ownership."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Final, Literal
|
|
9
|
+
|
|
10
|
+
from .compound_git_inspection import (
|
|
11
|
+
_git_show_has_execution_free_config,
|
|
12
|
+
_safe_repository_path,
|
|
13
|
+
is_low_risk_git_inspection_segment,
|
|
14
|
+
is_low_risk_standalone_git_routine,
|
|
15
|
+
)
|
|
16
|
+
from .secret_file_request_services.shell_tokenization import _shell_segment_primary_command
|
|
17
|
+
from .shell_execution_context import ShellExecutionContext, ShellExecutionSegment, model_shell_execution_context
|
|
18
|
+
|
|
19
|
+
_CONTROL_PREFIXES: Final = frozenset({"!", "elif", "else", "fi", "if", "then"})
|
|
20
|
+
_ALLOWED_CONTROLS: Final = frozenset({"&&", "||", "|", ";", "\n"})
|
|
21
|
+
_RG_BOOLEAN_FLAGS: Final = frozenset({"--ignore-case", "--line-number", "--no-config", "-i", "-in", "-n", "-ni"})
|
|
22
|
+
_GIT_GLOBAL_FLAG_OPTIONS: Final = frozenset(
|
|
23
|
+
{
|
|
24
|
+
"--literal-pathspecs",
|
|
25
|
+
"--no-advice",
|
|
26
|
+
"--no-lazy-fetch",
|
|
27
|
+
"--no-optional-locks",
|
|
28
|
+
"--no-pager",
|
|
29
|
+
"--no-replace-objects",
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
_GIT_GLOBAL_VALUE_OPTIONS: Final = frozenset(
|
|
33
|
+
{"--config-env", "--exec-path", "--git-dir", "--namespace", "--super-prefix", "--work-tree", "-C", "-c"}
|
|
34
|
+
)
|
|
35
|
+
_EXECUTION_ROUTING_OPTIONS: Final = frozenset({"-c", "--config-env", "--exec-path"})
|
|
36
|
+
_REPOSITORY_SELECTOR_OPTIONS: Final = frozenset(
|
|
37
|
+
{"--bare", "--git-dir", "--namespace", "--paginate", "--super-prefix", "--work-tree", "-P", "-p"}
|
|
38
|
+
)
|
|
39
|
+
_INDEX_DIFF_FLAGS: Final = frozenset({"--cached", "--staged"})
|
|
40
|
+
_CACHED_DIFF_KIND = Literal["owned", "routed"]
|
|
41
|
+
_MAX_SEGMENTS: Final = 32
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def executable_tokens(tokens: tuple[str, ...]) -> tuple[str, ...] | None:
|
|
45
|
+
"""Strip shell reserved-word prefixes. Empty means a no-op such as fi."""
|
|
46
|
+
|
|
47
|
+
index = 0
|
|
48
|
+
while index < len(tokens) and tokens[index] in _CONTROL_PREFIXES:
|
|
49
|
+
if tokens[index] == "fi" and len(tokens) != 1:
|
|
50
|
+
return None
|
|
51
|
+
index += 1
|
|
52
|
+
return tokens[index:]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _static_echo_arg_is_safe(arg: str) -> bool:
|
|
56
|
+
if "`" in arg or "$(" in arg or "<(" in arg or ">(" in arg:
|
|
57
|
+
return False
|
|
58
|
+
return "$" not in arg.replace("$?", "")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _index_scan_rg_args_are_safe(args: tuple[str, ...]) -> bool:
|
|
62
|
+
"""Accept stdin-only ripgrep with one inline pattern after a cached diff."""
|
|
63
|
+
|
|
64
|
+
if os.environ.get("RIPGREP_CONFIG_PATH") and "--no-config" not in args:
|
|
65
|
+
return False
|
|
66
|
+
saw_pattern = False
|
|
67
|
+
for arg in args:
|
|
68
|
+
if arg.startswith("RIPGREP_CONFIG_PATH="):
|
|
69
|
+
return False
|
|
70
|
+
if arg in _RG_BOOLEAN_FLAGS:
|
|
71
|
+
continue
|
|
72
|
+
if not arg or arg.startswith("-"):
|
|
73
|
+
return False
|
|
74
|
+
if saw_pattern:
|
|
75
|
+
return False
|
|
76
|
+
if "$" in arg or any(marker in arg for marker in ("$(", "`", "<(", ">(", "\x00")):
|
|
77
|
+
return False
|
|
78
|
+
saw_pattern = True
|
|
79
|
+
return saw_pattern
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _tokens_are_cached_diff(tokens: tuple[str, ...]) -> bool:
|
|
83
|
+
kind = cached_diff_kind(tokens)
|
|
84
|
+
return kind == "owned"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def cached_diff_kind(tokens: tuple[str, ...]) -> _CACHED_DIFF_KIND | None:
|
|
88
|
+
"""Classify one segment as an owned or execution-routed cached diff."""
|
|
89
|
+
|
|
90
|
+
stripped = executable_tokens(tokens)
|
|
91
|
+
if not stripped:
|
|
92
|
+
return None
|
|
93
|
+
command_name, command_index = _shell_segment_primary_command(list(stripped))
|
|
94
|
+
if command_name != "git" or command_index is None:
|
|
95
|
+
return None
|
|
96
|
+
args = stripped[command_index + 1 :]
|
|
97
|
+
index = 0
|
|
98
|
+
routed = False
|
|
99
|
+
while index < len(args):
|
|
100
|
+
token = args[index]
|
|
101
|
+
option_name = token.partition("=")[0]
|
|
102
|
+
if token in _GIT_GLOBAL_FLAG_OPTIONS:
|
|
103
|
+
index += 1
|
|
104
|
+
continue
|
|
105
|
+
if token == "-c" or (token.startswith("-c") and not token.startswith("-C")):
|
|
106
|
+
routed = True
|
|
107
|
+
if token == "-c":
|
|
108
|
+
if index + 1 >= len(args):
|
|
109
|
+
return None
|
|
110
|
+
index += 2
|
|
111
|
+
continue
|
|
112
|
+
index += 1
|
|
113
|
+
continue
|
|
114
|
+
if option_name in _GIT_GLOBAL_VALUE_OPTIONS:
|
|
115
|
+
if option_name in _EXECUTION_ROUTING_OPTIONS:
|
|
116
|
+
routed = True
|
|
117
|
+
if "=" in token:
|
|
118
|
+
if not token.partition("=")[2]:
|
|
119
|
+
return None
|
|
120
|
+
index += 1
|
|
121
|
+
continue
|
|
122
|
+
if index + 1 >= len(args):
|
|
123
|
+
return None
|
|
124
|
+
index += 2
|
|
125
|
+
continue
|
|
126
|
+
if token.startswith("-"):
|
|
127
|
+
index += 1
|
|
128
|
+
continue
|
|
129
|
+
if token != "diff":
|
|
130
|
+
return None
|
|
131
|
+
operands = args[index + 1 :]
|
|
132
|
+
options = operands[: operands.index("--")] if "--" in operands else operands
|
|
133
|
+
if not _INDEX_DIFF_FLAGS.intersection(options):
|
|
134
|
+
return None
|
|
135
|
+
return "routed" if routed else "owned"
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def command_has_execution_routed_git_cached_diff(segments: tuple[tuple[str, ...], ...]) -> bool:
|
|
140
|
+
"""Return whether any cached-diff segment overrides Git execution routing."""
|
|
141
|
+
|
|
142
|
+
return any(cached_diff_kind(tokens) == "routed" for tokens in segments)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def command_has_owned_git_cached_diff(segments: tuple[tuple[str, ...], ...]) -> bool:
|
|
146
|
+
"""Return whether the command contains a named cached-diff Guard can own."""
|
|
147
|
+
|
|
148
|
+
if command_has_execution_routed_git_cached_diff(segments):
|
|
149
|
+
return False
|
|
150
|
+
return any(cached_diff_kind(tokens) == "owned" for tokens in segments)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def is_low_risk_git_index_inspection(
|
|
154
|
+
command_text: str,
|
|
155
|
+
*,
|
|
156
|
+
cwd: Path | None,
|
|
157
|
+
home_dir: Path | None = None,
|
|
158
|
+
) -> bool:
|
|
159
|
+
"""Recognize a repo-bound staged-index inspection, including if/then scans."""
|
|
160
|
+
|
|
161
|
+
return index_inspection_execution_context(command_text, cwd=cwd, home_dir=home_dir) is not None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def index_inspection_execution_context(
|
|
165
|
+
command_text: str,
|
|
166
|
+
*,
|
|
167
|
+
cwd: Path | None,
|
|
168
|
+
home_dir: Path | None = None,
|
|
169
|
+
) -> ShellExecutionContext | None:
|
|
170
|
+
"""Return the modeled context when a staged-index scan is repo-bound."""
|
|
171
|
+
|
|
172
|
+
if cwd is None:
|
|
173
|
+
return None
|
|
174
|
+
try:
|
|
175
|
+
execution_cwd = cwd.resolve()
|
|
176
|
+
except (OSError, RuntimeError):
|
|
177
|
+
return None
|
|
178
|
+
context = model_shell_execution_context(
|
|
179
|
+
command_text,
|
|
180
|
+
cwd=execution_cwd,
|
|
181
|
+
workspace_root=execution_cwd,
|
|
182
|
+
home_dir=home_dir,
|
|
183
|
+
)
|
|
184
|
+
if not _context_is_low_risk_git_index_inspection(context, home_dir=home_dir):
|
|
185
|
+
return None
|
|
186
|
+
return context
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _segment_has_mutating_redirection(tokens: tuple[str, ...]) -> bool:
|
|
190
|
+
for token in tokens:
|
|
191
|
+
if token in {">", ">>", ">|", "1>", "1>>", "1>|"}:
|
|
192
|
+
return True
|
|
193
|
+
if ">" in token and not token.startswith("--"):
|
|
194
|
+
return True
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _flow_controls(controls: tuple[str, ...]) -> tuple[str, ...]:
|
|
199
|
+
return tuple(control for control in controls if control != "\n")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _context_is_low_risk_git_index_inspection(
|
|
203
|
+
context: ShellExecutionContext,
|
|
204
|
+
*,
|
|
205
|
+
home_dir: Path | None,
|
|
206
|
+
) -> bool:
|
|
207
|
+
if not context.segments or len(context.segments) > _MAX_SEGMENTS:
|
|
208
|
+
return False
|
|
209
|
+
if not context.complete and context.reason_code != "shell_cwd_unresolved_syntax":
|
|
210
|
+
return False
|
|
211
|
+
saw_cached_diff = False
|
|
212
|
+
previous_was_cached_diff = False
|
|
213
|
+
for segment in context.segments:
|
|
214
|
+
if any(control not in _ALLOWED_CONTROLS for control in (*segment.control_before, *segment.control_after)):
|
|
215
|
+
return False
|
|
216
|
+
tokens = executable_tokens(segment.tokens)
|
|
217
|
+
if tokens is None:
|
|
218
|
+
return False
|
|
219
|
+
if not tokens:
|
|
220
|
+
previous_was_cached_diff = False
|
|
221
|
+
continue
|
|
222
|
+
if _segment_has_mutating_redirection(segment.tokens):
|
|
223
|
+
return False
|
|
224
|
+
command_name, command_index = _shell_segment_primary_command(list(tokens))
|
|
225
|
+
if command_name is None or command_index is None:
|
|
226
|
+
return False
|
|
227
|
+
executable = tokens[command_index]
|
|
228
|
+
if "/" in executable or "\\" in executable:
|
|
229
|
+
return False
|
|
230
|
+
args = tokens[command_index + 1 :]
|
|
231
|
+
if command_name == "git":
|
|
232
|
+
if not _git_cached_diff_segment_is_safe(segment, tokens, home_dir=home_dir):
|
|
233
|
+
return False
|
|
234
|
+
saw_cached_diff = True
|
|
235
|
+
previous_was_cached_diff = True
|
|
236
|
+
continue
|
|
237
|
+
if command_name == "echo":
|
|
238
|
+
if not all(_static_echo_arg_is_safe(arg) for arg in args):
|
|
239
|
+
return False
|
|
240
|
+
previous_was_cached_diff = False
|
|
241
|
+
continue
|
|
242
|
+
if command_name == "rg":
|
|
243
|
+
if _flow_controls(segment.control_before) != ("|",) or not previous_was_cached_diff:
|
|
244
|
+
return False
|
|
245
|
+
if any(token.startswith("RIPGREP_CONFIG_PATH=") for token in segment.tokens) and "--no-config" not in args:
|
|
246
|
+
return False
|
|
247
|
+
if not _index_scan_rg_args_are_safe(args):
|
|
248
|
+
return False
|
|
249
|
+
previous_was_cached_diff = False
|
|
250
|
+
continue
|
|
251
|
+
return False
|
|
252
|
+
return saw_cached_diff
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def owned_git_index_inspection_action_class(
|
|
256
|
+
command_text: str,
|
|
257
|
+
*,
|
|
258
|
+
cwd: Path | None,
|
|
259
|
+
home_dir: Path | None,
|
|
260
|
+
) -> str | None:
|
|
261
|
+
"""Return the Git-protection action class for an unproven cached diff."""
|
|
262
|
+
|
|
263
|
+
if "git" not in command_text or "diff" not in command_text or "--cached" not in command_text:
|
|
264
|
+
return None
|
|
265
|
+
parsing_cwd = cwd or home_dir or Path.cwd()
|
|
266
|
+
context = model_shell_execution_context(
|
|
267
|
+
command_text,
|
|
268
|
+
cwd=parsing_cwd,
|
|
269
|
+
workspace_root=parsing_cwd,
|
|
270
|
+
home_dir=home_dir,
|
|
271
|
+
)
|
|
272
|
+
segment_tokens = tuple(segment.tokens for segment in context.segments)
|
|
273
|
+
if command_has_execution_routed_git_cached_diff(segment_tokens):
|
|
274
|
+
return None
|
|
275
|
+
if not command_has_owned_git_cached_diff(segment_tokens):
|
|
276
|
+
return None
|
|
277
|
+
if cwd is not None and is_low_risk_git_index_inspection(command_text, cwd=cwd, home_dir=home_dir):
|
|
278
|
+
return None
|
|
279
|
+
if cwd is not None and is_low_risk_standalone_git_routine(context):
|
|
280
|
+
return None
|
|
281
|
+
return "git index inspection"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
_SAFE_CACHED_DIFF_FLAGS: Final = frozenset(
|
|
285
|
+
{"--cached", "--check", "--name-only", "--name-status", "--staged", "--stat", "HEAD"}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _safe_exclude_pathspec(value: str) -> bool:
|
|
290
|
+
if not value.startswith((":!", ":^")):
|
|
291
|
+
return False
|
|
292
|
+
remainder = value[2:]
|
|
293
|
+
if not remainder or remainder.startswith((":", "/", "~")):
|
|
294
|
+
return False
|
|
295
|
+
return _safe_repository_path(remainder)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _cached_diff_operands_are_safe(args: tuple[str, ...]) -> bool:
|
|
299
|
+
if len(args) > 20:
|
|
300
|
+
return False
|
|
301
|
+
if "--" not in args:
|
|
302
|
+
return bool(_INDEX_DIFF_FLAGS.intersection(args)) and all(
|
|
303
|
+
arg in _SAFE_CACHED_DIFF_FLAGS or arg == "--cached" for arg in args
|
|
304
|
+
)
|
|
305
|
+
separator = args.index("--")
|
|
306
|
+
revisions = args[:separator]
|
|
307
|
+
if not _INDEX_DIFF_FLAGS.intersection(revisions):
|
|
308
|
+
return False
|
|
309
|
+
paths = args[separator + 1 :]
|
|
310
|
+
if not paths or len(paths) > 16:
|
|
311
|
+
return False
|
|
312
|
+
if any(arg not in _SAFE_CACHED_DIFF_FLAGS for arg in revisions):
|
|
313
|
+
return False
|
|
314
|
+
return all(_safe_repository_path(path) or _safe_exclude_pathspec(path) for path in paths)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _proof_cached_diff_tokens(tokens: tuple[str, ...]) -> tuple[str, ...]:
|
|
318
|
+
command_name, command_index = _shell_segment_primary_command(list(tokens))
|
|
319
|
+
if command_name != "git" or command_index is None:
|
|
320
|
+
return ("git", "diff", "--cached", "--check")
|
|
321
|
+
prefix = tokens[: command_index + 1]
|
|
322
|
+
args = tokens[command_index + 1 :]
|
|
323
|
+
if args[:1] == ("-C",) and len(args) >= 2:
|
|
324
|
+
return (*prefix, "-C", args[1], "diff", "--cached", "--check")
|
|
325
|
+
return (*prefix, "diff", "--cached", "--check")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _args_have_repository_selector(args: tuple[str, ...]) -> bool:
|
|
329
|
+
index = 0
|
|
330
|
+
while index < len(args):
|
|
331
|
+
token = args[index]
|
|
332
|
+
option_name = token.partition("=")[0]
|
|
333
|
+
if token == "-C" or token.startswith("-C") or option_name in _REPOSITORY_SELECTOR_OPTIONS:
|
|
334
|
+
return True
|
|
335
|
+
if token in _GIT_GLOBAL_FLAG_OPTIONS:
|
|
336
|
+
index += 1
|
|
337
|
+
continue
|
|
338
|
+
if option_name in _GIT_GLOBAL_VALUE_OPTIONS:
|
|
339
|
+
index += 1 if "=" in token else 2
|
|
340
|
+
continue
|
|
341
|
+
if token.startswith("-"):
|
|
342
|
+
index += 1
|
|
343
|
+
continue
|
|
344
|
+
return False
|
|
345
|
+
return False
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _has_unproven_repository_selector(tokens: tuple[str, ...]) -> bool:
|
|
349
|
+
stripped = executable_tokens(tokens)
|
|
350
|
+
if not stripped:
|
|
351
|
+
return True
|
|
352
|
+
command_name, command_index = _shell_segment_primary_command(list(stripped))
|
|
353
|
+
if command_name != "git" or command_index is None:
|
|
354
|
+
return True
|
|
355
|
+
args = stripped[command_index + 1 :]
|
|
356
|
+
if args[:1] == ("-C",):
|
|
357
|
+
if len(args) < 2 or not args[1] or args[1].startswith("-"):
|
|
358
|
+
return True
|
|
359
|
+
return _args_have_repository_selector(args[2:])
|
|
360
|
+
return _args_have_repository_selector(args)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _git_cached_diff_segment_is_safe(
|
|
364
|
+
segment: ShellExecutionSegment,
|
|
365
|
+
tokens: tuple[str, ...],
|
|
366
|
+
*,
|
|
367
|
+
home_dir: Path | None,
|
|
368
|
+
) -> bool:
|
|
369
|
+
if not _tokens_are_cached_diff(tokens) or _has_unproven_repository_selector(tokens):
|
|
370
|
+
return False
|
|
371
|
+
operands = git_diff_operands(tokens)
|
|
372
|
+
if operands is None or not _cached_diff_operands_are_safe(operands):
|
|
373
|
+
return False
|
|
374
|
+
synthetic = replace(segment, tokens=_proof_cached_diff_tokens(tokens))
|
|
375
|
+
repository_path = tokens[2] if tokens[:2] == ("git", "-C") and len(tokens) > 2 else None
|
|
376
|
+
return is_low_risk_git_inspection_segment(synthetic) and _git_show_has_execution_free_config(
|
|
377
|
+
synthetic, repository_path=repository_path
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def git_diff_operands(tokens: tuple[str, ...]) -> tuple[str, ...] | None:
|
|
382
|
+
kind = cached_diff_kind(tokens)
|
|
383
|
+
if kind != "owned":
|
|
384
|
+
return None
|
|
385
|
+
stripped = executable_tokens(tokens)
|
|
386
|
+
if not stripped:
|
|
387
|
+
return None
|
|
388
|
+
command_name, command_index = _shell_segment_primary_command(list(stripped))
|
|
389
|
+
if command_name != "git" or command_index is None:
|
|
390
|
+
return None
|
|
391
|
+
args = stripped[command_index + 1 :]
|
|
392
|
+
index = 0
|
|
393
|
+
while index < len(args):
|
|
394
|
+
token = args[index]
|
|
395
|
+
option_name = token.partition("=")[0]
|
|
396
|
+
if token in _GIT_GLOBAL_FLAG_OPTIONS:
|
|
397
|
+
index += 1
|
|
398
|
+
continue
|
|
399
|
+
if option_name in _GIT_GLOBAL_VALUE_OPTIONS:
|
|
400
|
+
index += 1 if "=" in token else 2
|
|
401
|
+
continue
|
|
402
|
+
if token.startswith("-"):
|
|
403
|
+
index += 1
|
|
404
|
+
continue
|
|
405
|
+
if token != "diff":
|
|
406
|
+
return None
|
|
407
|
+
return args[index + 1 :]
|
|
408
|
+
return None
|
|
@@ -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
|
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
from ..compound_git_inspection import is_low_risk_git_inspection_segment
|
|
8
8
|
from ..git_execution_safety import trusted_git_binary_for_cwd
|
|
9
|
+
from ..git_index_inspection import is_low_risk_git_index_inspection
|
|
9
10
|
from ..kubernetes_commands import kubernetes_read_only_inventory_args
|
|
10
11
|
from ..shell_command_wrappers import is_trusted_absolute_command_path
|
|
11
12
|
from ..shell_execution_context import ShellExecutionContext, ShellExecutionSegment, model_shell_execution_context
|
|
@@ -75,7 +76,7 @@ def _looks_like_safe_compound_developer_inspection(
|
|
|
75
76
|
|
|
76
77
|
graph = _compound_developer_effect_graph(command_text, cwd=cwd, home_dir=home_dir)
|
|
77
78
|
if graph is None or not graph.context.complete:
|
|
78
|
-
return
|
|
79
|
+
return is_low_risk_git_index_inspection(command_text, cwd=cwd, home_dir=home_dir)
|
|
79
80
|
silently_verified_effects = {
|
|
80
81
|
DeveloperShellEffect.DIRECTORY,
|
|
81
82
|
DeveloperShellEffect.LOCAL_READ,
|
|
@@ -151,7 +152,7 @@ def _git_segment_is_silently_verified(
|
|
|
151
152
|
return "|" not in (*segment.control_before, *segment.control_after) and is_low_risk_git_inspection_segment(
|
|
152
153
|
segment
|
|
153
154
|
)
|
|
154
|
-
if operation in {"blame", "branch", "show", "worktree"}:
|
|
155
|
+
if operation in {"blame", "branch", "diff", "show", "worktree"}:
|
|
155
156
|
return is_low_risk_git_inspection_segment(segment)
|
|
156
157
|
return operation in {"ls-files", "rev-parse"}
|
|
157
158
|
|
|
@@ -7,6 +7,7 @@ import re
|
|
|
7
7
|
from dataclasses import replace
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
+
from ..git_index_inspection import index_inspection_execution_context
|
|
10
11
|
from ..shell_execution_context import ShellExecutionContext, model_shell_execution_context
|
|
11
12
|
from .developer_inspection import (
|
|
12
13
|
_low_risk_compound_developer_execution_context,
|
|
@@ -37,11 +38,15 @@ def low_risk_compound_developer_execution_context(
|
|
|
37
38
|
)
|
|
38
39
|
return replace(recovered, command_text=command_text) if recovered is not None else None
|
|
39
40
|
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
return (
|
|
42
|
+
_low_risk_compound_developer_execution_context(
|
|
43
|
+
command_text,
|
|
44
|
+
cwd=cwd,
|
|
45
|
+
home_dir=home_dir,
|
|
46
|
+
)
|
|
47
|
+
or index_inspection_execution_context(command_text, cwd=cwd, home_dir=home_dir)
|
|
48
|
+
or _bounded_verified_source_edit_execution_context(command_text, home_dir=home_dir)
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
def _bounded_verified_source_edit_execution_context(
|
|
@@ -10,6 +10,7 @@ from typing import cast
|
|
|
10
10
|
from ..command_model import CanonicalCommand
|
|
11
11
|
from ..compound_git_inspection import is_low_risk_git_inspection_segment, is_low_risk_standalone_git_routine
|
|
12
12
|
from ..git_execution_safety import git_status_args_are_read_only, git_status_has_execution_free_config
|
|
13
|
+
from ..git_index_inspection import owned_git_index_inspection_action_class
|
|
13
14
|
from ..kubernetes_commands import kubernetes_secret_read_source
|
|
14
15
|
from ..shell_command_wrappers import normalize_transparent_shell_command
|
|
15
16
|
from ..shell_execution_context import ShellExecutionContext, model_shell_execution_context
|
|
@@ -266,7 +267,7 @@ def _unverified_git_fetch_request(
|
|
|
266
267
|
cwd: Path | None,
|
|
267
268
|
home_dir: Path | None,
|
|
268
269
|
) -> ToolActionRequestMatch | None:
|
|
269
|
-
if "git" not in command_text
|
|
270
|
+
if "git" not in command_text:
|
|
270
271
|
return None
|
|
271
272
|
parsing_cwd = cwd or home_dir or Path.cwd()
|
|
272
273
|
context = model_shell_execution_context(
|
|
@@ -276,7 +277,24 @@ def _unverified_git_fetch_request(
|
|
|
276
277
|
home_dir=home_dir,
|
|
277
278
|
)
|
|
278
279
|
if not any(_segment_invokes_git_fetch(segment.tokens) for segment in context.segments):
|
|
279
|
-
|
|
280
|
+
action_class = owned_git_index_inspection_action_class(
|
|
281
|
+
command_text,
|
|
282
|
+
cwd=cwd,
|
|
283
|
+
home_dir=home_dir,
|
|
284
|
+
)
|
|
285
|
+
if action_class is None:
|
|
286
|
+
return None
|
|
287
|
+
return ToolActionRequestMatch(
|
|
288
|
+
tool_name=tool_name,
|
|
289
|
+
normalized_tool_name=normalized_tool_name,
|
|
290
|
+
command_text=command_text,
|
|
291
|
+
action_class=action_class,
|
|
292
|
+
reason=(
|
|
293
|
+
"Git cached diff needs a repository-bound index inspection Guard can verify. "
|
|
294
|
+
"Use git diff --cached with check/stat flags or lockfile excludes, "
|
|
295
|
+
"or confirm the exact index read in Guard."
|
|
296
|
+
),
|
|
297
|
+
)
|
|
280
298
|
if cwd is not None and is_low_risk_standalone_git_routine(context):
|
|
281
299
|
return None
|
|
282
300
|
if context.complete and all(
|
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.113
|
|
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=KgFbHTUEzOtocytyfrjipxG2nB-W_SCggizSg8V1BW0,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
|
|
@@ -462,8 +462,8 @@ codex_plugin_scanner/guard/runtime/command_activity_lifecycle.py,sha256=N6MZQsCH
|
|
|
462
462
|
codex_plugin_scanner/guard/runtime/command_activity_privacy.py,sha256=X9ytuqSTDtIDRlo294MbImLVlUjAnl5-O_FnaaXqfaM,12695
|
|
463
463
|
codex_plugin_scanner/guard/runtime/command_backup_extensions.py,sha256=9lX8La9_YIicQ8J76iBC9fPGsJhxhH4YzBuzamY0GLU,10105
|
|
464
464
|
codex_plugin_scanner/guard/runtime/command_builtin_extension_catalog.py,sha256=Yogu6iiOCWQU7DaPr4gfa8gOsTmu-HJns5c2DsaZUrE,2200
|
|
465
|
-
codex_plugin_scanner/guard/runtime/command_builtin_extension_registry.py,sha256=
|
|
466
|
-
codex_plugin_scanner/guard/runtime/command_builtin_rules.py,sha256
|
|
465
|
+
codex_plugin_scanner/guard/runtime/command_builtin_extension_registry.py,sha256=2gXikIL5m0iO_CNRkZUgb5UMnLKcucX0wFEXySgyZqw,8139
|
|
466
|
+
codex_plugin_scanner/guard/runtime/command_builtin_rules.py,sha256=-sWYS27t0kmE7vRDrnic_hZAnq4O4iMyQQ8wGGsaVXU,20185
|
|
467
467
|
codex_plugin_scanner/guard/runtime/command_capability.py,sha256=12xyfo2T8YYqnX9NCcKE3eNdKKgRvyJRmgUKjZeh9Fw,25185
|
|
468
468
|
codex_plugin_scanner/guard/runtime/command_cicd_extensions.py,sha256=QSyP5EP0pdeAKsTf3cZL_mEX3fyihG6KazoD7TdFEJc,6819
|
|
469
469
|
codex_plugin_scanner/guard/runtime/command_cloud_extensions.py,sha256=-C9NJvqRXbIBZa11t-hh4qHwYkgjinKCoVomsHy1UEU,9601
|
|
@@ -506,7 +506,7 @@ codex_plugin_scanner/guard/runtime/command_tokens.py,sha256=GY9ehRZB8O_CGHxGh3xh
|
|
|
506
506
|
codex_plugin_scanner/guard/runtime/command_verified_read_candidates.py,sha256=Qh_0bMm3VCp6GUkEeagcLtwYvtO0X1A_HN9_lgU-6eI,6599
|
|
507
507
|
codex_plugin_scanner/guard/runtime/command_workspace_write_candidates.py,sha256=AANBnFfGC-Jzg3RL6nYkamF3ndn7obB6LhKuaH1DdaE,6633
|
|
508
508
|
codex_plugin_scanner/guard/runtime/composition_rules.py,sha256=5oo0b1kL6hmFYyMSD9kCKcgA-m6fDKWy4pDeq3i1Ajk,6797
|
|
509
|
-
codex_plugin_scanner/guard/runtime/compound_git_inspection.py,sha256=
|
|
509
|
+
codex_plugin_scanner/guard/runtime/compound_git_inspection.py,sha256=XxQ_pqurgsYN621nEEW2RPEZgT1iS8QRVUevZxU9t6A,17787
|
|
510
510
|
codex_plugin_scanner/guard/runtime/containment_contract.py,sha256=8UN1_-Qmr8i3VmBGddlxz3Vt7Pr3q-HHQBC10hBumq0,17963
|
|
511
511
|
codex_plugin_scanner/guard/runtime/containment_executor.py,sha256=RYQ2GnxRy3kHPyxTYaVEYjwIL__fMDzL5zsF2EPUHck,16454
|
|
512
512
|
codex_plugin_scanner/guard/runtime/containment_health.py,sha256=Ji0wdiLjACZL0f-r5JHtOenoXEFv1JkNIELrA0iALkM,13292
|
|
@@ -530,6 +530,7 @@ codex_plugin_scanner/guard/runtime/extension_control_resolver.py,sha256=aNmVrVjt
|
|
|
530
530
|
codex_plugin_scanner/guard/runtime/extension_evidence.py,sha256=6gS05shn1OI5bmuFxGu5El4rHuICsvpI65WJV7oezmY,10583
|
|
531
531
|
codex_plugin_scanner/guard/runtime/false_positive_rules.py,sha256=OcXN1FItvuapKosg7kRNiys9YcJN4ALVzN2hKdX4VCw,24316
|
|
532
532
|
codex_plugin_scanner/guard/runtime/git_execution_safety.py,sha256=D2Ma5jnvTFosfoTt9hmN2c95ZZGLOc1NTxFR9E_57HY,28722
|
|
533
|
+
codex_plugin_scanner/guard/runtime/git_index_inspection.py,sha256=XlQwb_cFmdjfWoTTC3nGzJfjVEt3BIb9Gyt7_q1EQqY,14467
|
|
533
534
|
codex_plugin_scanner/guard/runtime/git_pathspecs.py,sha256=skNNsz-60pnFUqsaYJI9RRkwzUGGttCF-fvMdpOq7iE,12785
|
|
534
535
|
codex_plugin_scanner/guard/runtime/github_actions_read_workflow.py,sha256=-SFO8GLLBFw1iURh9TePVFCid1DCJPzKkzx45u92VCY,16904
|
|
535
536
|
codex_plugin_scanner/guard/runtime/github_capability_contract.py,sha256=c7OLPdG6X_naoOrq-XpFyeoB2i0BvBzj_ynYPTjcILE,13091
|
|
@@ -585,7 +586,7 @@ codex_plugin_scanner/guard/runtime/offline_archive_worker.py,sha256=mimHsG9u6O4K
|
|
|
585
586
|
codex_plugin_scanner/guard/runtime/package_execution_policy.py,sha256=duV4_QIDmkb6JGXOIYK9ilgfd3R0gFE8I1ON89QTuEQ,555
|
|
586
587
|
codex_plugin_scanner/guard/runtime/package_intent.py,sha256=rqiGU_XnLE-xk6gN6_eVRVIIYXSBGmrBzdjwnI95BWk,681
|
|
587
588
|
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
|
|
589
|
+
codex_plugin_scanner/guard/runtime/package_intent_parser.py,sha256=VCh2qU0pGnghjD9AXvJWlhFxgDjSjm_aFzGKTGtWxcw,66214
|
|
589
590
|
codex_plugin_scanner/guard/runtime/package_manager_command.py,sha256=KTxy8LFadce-GxprijT83_vxSrz2otiyoiPnvsA4dMg,5213
|
|
590
591
|
codex_plugin_scanner/guard/runtime/package_manifest_diff.py,sha256=49pranXVP4qNdm0wJB232WUG_lckqeLSAn1EPEQXJpA,26327
|
|
591
592
|
codex_plugin_scanner/guard/runtime/persistence_rules.py,sha256=SP8JPsL_B_ebICm2l9QG7btcblrb90VjaIeYN3WaYno,6587
|
|
@@ -650,7 +651,7 @@ codex_plugin_scanner/guard/runtime/secret_file_request_services/constants_patter
|
|
|
650
651
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/credential_exfiltration.py,sha256=y-knVxmSJyMTcgsmnbzBbcbaInmHFIJuejAvBlylLyA,12911
|
|
651
652
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/destructive_shell_detection.py,sha256=-KO2-JEBIn820jHxdwe0xiSI5EZPtQ8aj6MM13Nz33s,12148
|
|
652
653
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/developer_inspection.py,sha256=3YImzaN_7G020orTLn6TQ4xoavSgPkdX5D_mzi29z7c,22430
|
|
653
|
-
codex_plugin_scanner/guard/runtime/secret_file_request_services/developer_routines.py,sha256=
|
|
654
|
+
codex_plugin_scanner/guard/runtime/secret_file_request_services/developer_routines.py,sha256=UnufG04UyQ7xbwhxZHdzofIwjKlbYUjOPHiewqgBa4k,11240
|
|
654
655
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/docker_requests.py,sha256=c-8PEQVOG6KbryJaDKZQw9wCIlaniV_ULKPG48BC5Eg,15308
|
|
655
656
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/encoded_payloads.py,sha256=kiEG_GxK1Rwhji3G8mZE0VZBQ32RDqHoEEIqGgLJI7A,16106
|
|
656
657
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/git_routines.py,sha256=xsfuu3TPK8Ox1lFUDukN3xHG838-8Bm7FTJgbRChjWI,10335
|
|
@@ -684,8 +685,8 @@ codex_plugin_scanner/guard/runtime/secret_file_request_services/shell_request_cl
|
|
|
684
685
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/shell_static_safety.py,sha256=h1ew2l9euL5fIQYn2hj8b0PQiM7CUvHGR-WsS-gJ4WA,15237
|
|
685
686
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/shell_stdin_sources.py,sha256=dvGdc8dJvYjFF29fdQNtixuyQsjUEXo54cx7Pf_RN_g,9887
|
|
686
687
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/shell_tokenization.py,sha256=2beHCIfbvsPoF2qfqrZ5rpgpJORFf1qeSH9JNPsZTCo,12861
|
|
687
|
-
codex_plugin_scanner/guard/runtime/secret_file_request_services/source_edit_context.py,sha256=
|
|
688
|
-
codex_plugin_scanner/guard/runtime/secret_file_request_services/tool_action_requests.py,sha256=
|
|
688
|
+
codex_plugin_scanner/guard/runtime/secret_file_request_services/source_edit_context.py,sha256=iV5Z2PtenR8nWixOta4nxOYcxGYqxGRdupi-x5JjvBw,11067
|
|
689
|
+
codex_plugin_scanner/guard/runtime/secret_file_request_services/tool_action_requests.py,sha256=Q8LUU6SNM8z6tCrX-AYmCwnH_7blbTJ7ypWM5M4vcVk,17352
|
|
689
690
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/typescript_graphql_safety.py,sha256=OFj97zDy-WjVgbVu76eONG315Z1rPUMapySb-9b52RU,13041
|
|
690
691
|
codex_plugin_scanner/guard/runtime/secret_file_request_services/upload_arguments.py,sha256=25ZGoYVG5kiCK1SChRt6OdyWuDc5M6CjZS6rSNW7k1U,10579
|
|
691
692
|
codex_plugin_scanner/guard/schemas/__init__.py,sha256=YFJmxLMTfLclVIQ7ngTwRkeRLdBJEAF_ljc2jJTgvjE,220
|
|
@@ -699,8 +700,8 @@ codex_plugin_scanner/integrations/cisco_skill_scanner.py,sha256=3tW9Ya5riLsIbU9Y
|
|
|
699
700
|
codex_plugin_scanner/rules/__init__.py,sha256=bhAnNlVvEiAoksf_-Vd4f74JNz66pTINhUO2mMc8kvs,293
|
|
700
701
|
codex_plugin_scanner/rules/registry.py,sha256=7BaRerM26teDUM0S48d3sPHbqzmq2JhuelC0_ni3364,4580
|
|
701
702
|
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.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|