diff --git a/tests/fixtures/language.sh b/tests/fixtures/language.sh index ac827e0..a27b689 100644 --- a/tests/fixtures/language.sh +++ b/tests/fixtures/language.sh @@ -20,7 +20,7 @@ wget --user=admin --password= https://localhost mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS" # Noncompliant -API_TOKEN=${PLACEHOLDER-YXNkZmZmZmZm_HARDcoded} +API_TOKEN=${API_TOKEN:-YXNkZmZmZmZm_HARDcoded} export DANGER_GITHUB_API_TOKEN=YXNkZmZmZmZm_HARDcoded export DANGER_GITHUB_API_TOKEN="YXNkZmZmZmZm_HARDcoded" # export COMMENTED_API_TOKEN="YXNkZmZmZmZm_HARDcoded" diff --git a/whispers/core/utils.py b/whispers/core/utils.py index d811b2f..2389ac2 100644 --- a/whispers/core/utils.py +++ b/whispers/core/utils.py @@ -20,7 +20,7 @@ REGEX_PATH = re.compile(r"^((([A-Z]|file|root):)?(\.+)?[/\\]+).*$", flags=re.IGNORECASE) REGEX_IAC = re.compile(r"\![A-Za-z]+ .+", flags=re.IGNORECASE) REGEX_PRIVKEY_FILE = re.compile(r"(rsa|dsa|ed25519|ecdsa|pem|crt|cer|ca-bundle|p7b|p7c|p7s|ppk|pkcs12|pfx|p12)") -REGEX_ENVVAR = re.compile(r"^\$\$?[A-Z0-9_]+$") +REGEX_ENVVAR = re.compile(r"^\$\$?\{?[A-Z0-9_]+\}?$") def global_exception_handler(file: Union[str, Path], data: str): diff --git a/whispers/plugins/shell.py b/whispers/plugins/shell.py index fe10d31..4fefa4c 100644 --- a/whispers/plugins/shell.py +++ b/whispers/plugins/shell.py @@ -38,22 +38,26 @@ def read_commands(self, filepath: Path) -> Tuple[str, int]: yield " ".join(ret), lineno ret = [] - def variables(self, cmd: List[str], lineno: int) -> Iterator[KeyValuePair]: + def variables(self, cmd: List[str], lineno: int = 0) -> Iterator[KeyValuePair]: """ Checks if Shell variables contain a hardcoded or a default value. Examples: password="defaultPassword" - password=${ENV_VAR-defaultPassword} + password=${ENV_VAR:-defaultPassword} """ - for item in cmd: - if "=" in item and len(item.split("=")) == 2: - key, value = item.split("=") # Variable assignment + for value in cmd: + key = "" - if value.startswith("${") and value.endswith("}"): - if "-" in value: - value = value.split("-")[1].strip("}") # Default value + if "=" in value and len(value.split("=")) == 2: + key, value = value.split("=") # Variable assignment - yield KeyValuePair(key, value, line=lineno) + if ":-" in value and value.startswith("${") and value.endswith("}"): + key, value = value[2:-1].split(":-") # Default value + + if not (key or value): + continue + + yield KeyValuePair(key, value, line=lineno) def curl(self, cmd: List[str], lineno: int) -> Iterator[KeyValuePair]: key = "password" diff --git a/whispers/plugins/traverse.py b/whispers/plugins/traverse.py index 9d5b324..b9890f5 100644 --- a/whispers/plugins/traverse.py +++ b/whispers/plugins/traverse.py @@ -2,6 +2,7 @@ from whispers.models.pair import KeyValuePair from whispers.plugins.common import Common +from whispers.plugins.shell import Shell class StructuredDocument: @@ -34,11 +35,7 @@ def traverse(self, code, key=None) -> Optional[Iterator[KeyValuePair]]: yield from self.traverse(item, key=key) elif isinstance(code, str): - if "=" in code: - item = code.split("=") - if len(item) == 2: - yield KeyValuePair(item[0], item[1], list(self.keypath)) - + yield from Shell().variables([code]) yield from Common(self.keypath).pairs(code) def cloudformation(self, code: dict) -> Iterator[KeyValuePair]: