Skip to content

Commit 331c18c

Browse files
committed
fix(prowler): contain secret CLI environments (#422)
1 parent 4ebb788 commit 331c18c

3 files changed

Lines changed: 18 additions & 4 deletions

File tree

prowler/prowler/_core/cli_engine/adapters/binary_resolver.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class WhichBinaryResolver:
1313
def validate(self, specification: ExecutionSpecification) -> ResolutionError | None:
1414
"""Check the executable using only the specification environment."""
1515
path = dict(specification.environment).get("PATH")
16+
if path is not None and not isinstance(path, str):
17+
return ResolutionError(
18+
"PATH must be an ordinary non-blank string when provided"
19+
)
1620
if not Path(specification.executable).is_absolute() and (
1721
not path or not path.strip()
1822
):

prowler/prowler/_core/cli_engine/adapters/subprocess_executor.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import subprocess
44

5+
from pydantic import SecretStr
6+
57
from ..contracts import ExecutionSpecification, ProcessOutcome
68
from ..errors import ExecutionError
79

@@ -13,14 +15,18 @@ def execute(
1315
self, specification: ExecutionSpecification
1416
) -> ProcessOutcome | ExecutionError:
1517
"""Capture exact bytes and envelope startup and timeout failures."""
18+
environment = {
19+
name: value.get_secret_value() if isinstance(value, SecretStr) else value
20+
for name, value in specification.environment
21+
}
1622
try:
1723
completed = subprocess.run( # noqa: S603 - policy-approved structured argv
1824
specification.argv,
1925
input=specification.input_bytes,
2026
stdout=subprocess.PIPE,
2127
stderr=subprocess.PIPE,
2228
cwd=specification.working_directory,
23-
env=dict(specification.environment),
29+
env=environment,
2430
timeout=specification.timeout_seconds,
2531
shell=False,
2632
check=False,
@@ -37,6 +43,6 @@ def execute(
3743
return ExecutionError(
3844
"process could not be started",
3945
kind="process_start_failed",
40-
cause=f"{type(error).__name__}: {error}",
46+
cause=type(error).__name__,
4147
)
4248
return ProcessOutcome(completed.returncode, completed.stdout, completed.stderr)

prowler/prowler/_core/cli_engine/contracts.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from dataclasses import dataclass
55
from typing import Any
66

7+
from pydantic import SecretStr
8+
9+
EnvironmentValue = str | SecretStr
10+
711

812
@dataclass(frozen=True)
913
class OutputSpecification:
@@ -19,7 +23,7 @@ class ValidatedCommandRequest:
1923

2024
executable: str
2125
arguments: Sequence[str]
22-
environment: Mapping[str, str] | Sequence[tuple[str, str]]
26+
environment: Mapping[str, EnvironmentValue] | Sequence[tuple[str, EnvironmentValue]]
2327
working_directory: str | None
2428
input_bytes: bytes
2529
output: OutputSpecification
@@ -33,7 +37,7 @@ class ExecutionSpecification:
3337

3438
executable: str
3539
arguments: tuple[str, ...]
36-
environment: tuple[tuple[str, str], ...]
40+
environment: tuple[tuple[str, EnvironmentValue], ...]
3741
working_directory: str | None
3842
input_bytes: bytes
3943
output: OutputSpecification

0 commit comments

Comments
 (0)