diff --git a/.github/workflows/aws-integration.yml b/.github/workflows/aws-integration.yml new file mode 100644 index 0000000..023995e --- /dev/null +++ b/.github/workflows/aws-integration.yml @@ -0,0 +1,26 @@ +name: Stage 4 — AWS (mock) integration + +on: + push: + branches: [ main, 'stage4/**', 'stage*' ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run tests + run: pytest -q diff --git a/.gitignore b/.gitignore index edf9e82..3e22023 100644 --- a/.gitignore +++ b/.gitignore @@ -69,10 +69,8 @@ npm-debug.log # Misc *.sqlite3 +data/*.db +data/*.sqlite3 - -Plan.txt# Plan file -Plan.txt - # Ignore generated demo output files -Output/ \ No newline at end of file +Output/ diff --git a/Output/stage3-20251101T094754Z.json b/Output/stage3-20251101T094754Z.json new file mode 100644 index 0000000..f988973 --- /dev/null +++ b/Output/stage3-20251101T094754Z.json @@ -0,0 +1,159 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "Detected issue of type 'Possible Hardcoded Token'. Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "Calling subprocess APIs with unsanitized inputs or with shell=True can allow command injection or execution of unintended commands.", + "fix": "Avoid shell=True and pass arguments as a list. Validate and sanitize any inputs used in command construction.", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "Detected issue of type 'Dangerous Import'. Importing subprocess can enable executing shell commands; review usage.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "MD5 and SHA1 are considered cryptographically broken or weak for collision resistance and should not be used for security-sensitive hashing.", + "fix": "Use hashlib.sha256 or a stronger function and use salt + PBKDF2 / bcrypt / scrypt / Argon2 for password hashing.", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "This code constructs SQL statements by concatenating strings or by formatting them directly. Attackers can inject SQL fragments through inputs, leading to data leakage or corruption.", + "fix": "Use parameterized queries (e.g., cursor.execute(sql, params)) or ORM query builders to avoid direct string composition of SQL. Validate and sanitize inputs.", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "Overly-broad regex patterns like '.*' can match unintended input and can cause catastrophic backtracking.", + "fix": "Use more specific regexes and apply input length limits. Consider non-greedy qualifiers and anchors as appropriate.", + "references": [ + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T110841Z.json b/Output/stage3-20251101T110841Z.json new file mode 100644 index 0000000..f8e44b8 --- /dev/null +++ b/Output/stage3-20251101T110841Z.json @@ -0,0 +1,169 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "Detected issue of type 'Possible Hardcoded Token'. Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "Calling subprocess APIs with unsanitized inputs or with shell=True can allow command injection or execution of unintended commands.", + "fix": "Avoid shell=True and pass arguments as a list. Validate and sanitize any inputs used in command construction.", + "llm_used": "offline", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "Detected issue of type 'Dangerous Import'. Importing subprocess can enable executing shell commands; review usage.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "MD5 and SHA1 are considered cryptographically broken or weak for collision resistance and should not be used for security-sensitive hashing.", + "fix": "Use hashlib.sha256 or a stronger function and use salt + PBKDF2 / bcrypt / scrypt / Argon2 for password hashing.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "This code constructs SQL statements by concatenating strings or by formatting them directly. Attackers can inject SQL fragments through inputs, leading to data leakage or corruption.", + "fix": "Use parameterized queries (e.g., cursor.execute(sql, params)) or ORM query builders to avoid direct string composition of SQL. Validate and sanitize inputs.", + "llm_used": "offline", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "Overly-broad regex patterns like '.*' can match unintended input and can cause catastrophic backtracking.", + "fix": "Use more specific regexes and apply input length limits. Consider non-greedy qualifiers and anchors as appropriate.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T111716Z.json b/Output/stage3-20251101T111716Z.json new file mode 100644 index 0000000..f8e44b8 --- /dev/null +++ b/Output/stage3-20251101T111716Z.json @@ -0,0 +1,169 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "This file contains a hardcoded secret or credential in source code which can be read by anyone with repository access.", + "fix": "Remove the secret from source control. Use environment variables, a .env file kept out of VCS, or a secret store (HashiCorp Vault, AWS Secrets Manager). Rotate the credential immediately if it was committed.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "Detected issue of type 'Possible Hardcoded Token'. Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "Calling subprocess APIs with unsanitized inputs or with shell=True can allow command injection or execution of unintended commands.", + "fix": "Avoid shell=True and pass arguments as a list. Validate and sanitize any inputs used in command construction.", + "llm_used": "offline", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "Use of functions like eval() or exec() can execute arbitrary code and should be avoided, especially on user-controlled inputs.", + "fix": "Replace eval/exec with safer alternatives. For parsing expressions use ast.literal_eval or write a simple parser. Validate inputs strictly.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "Detected issue of type 'Dangerous Import'. Importing subprocess can enable executing shell commands; review usage.", + "fix": "Investigate the finding and apply recommended best-practices (parameterization, secrets management, or safer library APIs).", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "MD5 and SHA1 are considered cryptographically broken or weak for collision resistance and should not be used for security-sensitive hashing.", + "fix": "Use hashlib.sha256 or a stronger function and use salt + PBKDF2 / bcrypt / scrypt / Argon2 for password hashing.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-project-top-ten/", + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "This code constructs SQL statements by concatenating strings or by formatting them directly. Attackers can inject SQL fragments through inputs, leading to data leakage or corruption.", + "fix": "Use parameterized queries (e.g., cursor.execute(sql, params)) or ORM query builders to avoid direct string composition of SQL. Validate and sanitize inputs.", + "llm_used": "offline", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "Overly-broad regex patterns like '.*' can match unintended input and can cause catastrophic backtracking.", + "fix": "Use more specific regexes and apply input length limits. Consider non-greedy qualifiers and anchors as appropriate.", + "llm_used": "offline", + "references": [ + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T170533Z.json b/Output/stage3-20251101T170533Z.json new file mode 100644 index 0000000..160ac7a --- /dev/null +++ b/Output/stage3-20251101T170533Z.json @@ -0,0 +1,241 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "The code snippet has a Hardcoded Secret issue. The password 'hunter2' is directly embedded in the source code, which is a significant security risk. If the source code is exposed to the public or accidentally committed to version control, sensitive information about the passwords used by the application will be accessible to unauthorized users.", + "fix": "To address this issue, you can replace the hardcoded password with an environment variable. Here's how to set up a Content Security Policy (CSP) and an environment variable to store the password securely:\n\n1. Update the `index.html` file to include a CSP header:\n\n \n\n2. Add a `.env` file in the same directory as your application:\n\n [secret]:\n password = 'your_secret_password_here'\n\n3. Create a variables file (e.g., `variables.env`) using your preferred configuration tool (e.g., node env tool, Python's `python-dotenv`, or .NET configuration):\n\n [secret]:\n password = publicity}${��config['.env']['[secret]']['password']}\n\n4. Include this file in your build process (e.g., npm, Python, or .NET)\n5. Retrieve the password from the environment variable in your code:\n\n import os\n password = os.environ.get('publicity-secret-password')`\n\nBy following these steps, you ensure that the password is encrypted and not exposed in the source code or committed to version control.", + "llm_used": "online", + "references": [ + { + "url": "https://nodejs DOTENV guide", + "description": "A library for secrets management in Node.js applications varies" + }, + { + "url": "https://docs饰器.net/section/placeholder", + "description": "Python library for secrets management" + }, + { + "url": "https://docs.microsoft.com/en-us/tech/xl-sponsored/password-policy", + "description": "Microsoft's approved password policy" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "{\n \"explanation\": \"The code snippet stores an API key directly in the source code (line 8: API_KEY = 'ABCD1234SECRETKEYSHOULDNOTBEHERE'). Hardcoding sensitive information such as API keys in source code is a significant security risk. If an attacker gains access to the source code, they can easily extract the API key and misuse it. This practice also compromises the integrity of the version control system, as the sensitive data is still committed alongside the code.\",\n \"fix\": \"Use environment variables or a secret manager to store the API key. Here's an example using environment variables:\",\n \"references\": [\n {\n \"name\": \"Hardcoded Secrets\",\n \"url\": \"https://snyk.co.uk/en/us/topics/python-security psychologists.list-code-security-practices\"\n },\n {\n \"name\": \"Secret Manager in Python\",\n \"url\": \"https://docs.travis-ci.com/compliance/flask-secret-manager-secure-environment-0d0a7f394248/\"\n },\n {\n \"name\": \"Node.js environment variables\",\n \"url\": \"https://nodejs.com/docs rehabilitating nodejs-config-getting-set.environ-variables/\"\n }\n ]\n}\n```", + "fix": "", + "llm_used": "online", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "The code contains a hardcoded string 'ABCD1234SECRETKEYSHOULDNOTBEHERE' which may be a token or secret. Having sensitive information hardcoded in the source code is a common security risk. If this string is used for authenticating users or auditing logs, an attacker who gains access to the source code could potentially reverse engineer the secret and gain unauthorized access to sensitive systems or data.", + "fix": "Remove the hardcoded string 'ABCD1234SECRETKEYSHOULDNOTBEHERE' if it is not needed. If the secret is required in the code, consider implementing a secure secret management solution. Here's an example of how to remove it:\n\n```csharp\n// Remove the hardcoded string constant\nconst SECRETKEY = \"\"; // Or use a secure secret management solution\n// ...\n```", + "llm_used": "online", + "references": [ + { + "url": "https://developers.google.com/security/secureگذرانه-subsidies" + }, + { + "url": "https://owASP.org/Whitepapers/2019/Whitepaper-Security-In-Programming_V11.pdf" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "The given code is vulnerable to a code injection attack because it utilizes the `eval()` function with user input. `eval()` executes any sequence of code provided by the input, which can potentially lead to unexpected behavior or execution of malicious code by an attacker.", + "fix": "Replace the insecure `eval()` function with a safer alternative. Here's a simple fix using `ast.literal_eval()` which is designed to safely evaluate literals like strings, numbers and tuples.", + "llm_used": "online", + "references": [ + { + "url": "https://docs.python.org/3/library/ast.html#ast.literal_eval", + "description": "A function to safely evaluate a string containing a Python literal or container-update expression." + }, + { + "url": "https://globalые Indices of Vulnerabilities (CVEs) on the NIST CVEX database", + "description": "A database of known vulnerabilities in security standards, which can help with identifying and patching outdated libraries." + }, + { + "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy", + "description": "A W3C header that enables websites to be web-safe by restricting the sources of web content." + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "The code uses subprocess.run with shell=True, which is a vulnerable approach because it executes the command as if it were run in a shell, making it susceptible to command injection attacks. An attacker could inject malicious code in the 'ls -la' command, accessing sensitive system resources or other critical operations.", + "fix": "Avoid using shell=True and instead pass the command and its arguments as a list to subprocess.run. This ensures that the arguments are validated and executed safely. Here's the corrected line:\n\n'replace line 15 with:\nsubprocess.run(['ls', '-la'])", + "llm_used": "online", + "references": [ + { + "url": "https://docs.python.org/3/library/subprocess.html#subprocess.run", + "description": "Refer to the official Python documentation for the subprocess module for details on the correct usage of subprocess.run without shell=True." + }, + { + "url": "https://rationsoft.com/security-interviews/what-are-security-questions-for-python-designers", + "description": "For additional references on security best practices in Python development, visit this resource." + }, + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "{\n \"explanation\": \"The code attempts to unpickle data from a potentially untrusted binary string (`b` is a bytes object, and `not-a-pickle` is a string literal inside the bytes). However, `pickle.loads` is designed to unconditionally execute arbitrary Python object code, which can be exploited to execute arbitrary code if the unpickled data contains malicious code. This is a critical security risk as it allows for remote code execution from untrusted sources, leading to potential data breaches, information theft, or even manipulation of the system.\",\n \"fix\": \"Replace `pickle` with a safer alternative, such as the `json` module, which only parses JSON data and is less likely to execute code. If you must use `pickle`, ensure that you are unpickling data from trusted sources and consider using a safer deserialization method such as `dill` or `brotli`. Here's an example using JSON:\",\n \"fix\": \"obj = json.loads(b'{\"key\": \"value\"}')\\n\\n(Note: Ensure that the `json.loads` function is called with a bytes object or a string, not a binary string with non-base64 characters, such as the one provided in the original code.)\",\n \"references\": [\n {\n \"url\": \"https://docs.python.org/3/library/json.html#json-loads\",\n \"description\": \"Learn more about the JSON module in Python and how it can be used for safer deserialization.\"\n },\n {\n \"url\": \"https://pypi.org/project/brotli/\",\n \"description\": \"Consider using Brotli for more secure serialization and deserialization alternatives to pickle.\"\n },\n {\n \"url\": \"https://pypi.org/project/dill/\",\n \"description\": \"Explore the Dill library, which is an alternative to pickle that may offer some security improvements.\"\n }\n {\n \"url\": \"https://www,SIGNALTRIVIO\"\n }\n ]\n}", + "fix": "", + "llm_used": "online", + "references": [ + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "The code imports the `subprocess` module, which allows execution of system commands or processes. This is dangerous as it can lead to Command Injection vulnerabilities if not properly secured and validated.", + "fix": "Use `subprocess` with strict sandboxing, input validation, and shell escape protection. Consider using the `shlex.quote()` function to properly escape shell metacharacters when passing arguments to `subprocess.check_call()` or similar functions.", + "llm_used": "online", + "references": [ + { + "url": "https://docs.python.org/3/library/subprocess.html#subprocess-check-out-and-execution", + "description": "Python's official documentation for `subprocess` module, including guidelines for safe usage." + }, + { + "url": "https://www.security-upgrades.com/2009/08/stealth-eval.html", + "description": "SecurityUpgrades' advice on how to evaluate the effectiveness of various security controls, including sandboxing." + }, + { + "url": "https://owasp.org/CIS-v3.SEVERALounded safeguards/security-SecureDevelopment thanking open-source project that helps developers increase their code's resilience, including the use of subprocess with proper validation" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "The code uses `md5` for hashing, which is deprecated for security-sensitive operations. MD5 has known weaknesses and is not suitable for generating secure hashes.", + "fix": { + "description": "Replace `md5` with `sha256`.", + "code": { + "line": "26", + "snippet": "h = hashlib.sha256(b'data').hexdigest()" + } + }, + "llm_used": "online", + "references": [ + { + "name": "Use SHA-256 and SHA-3 for cryptographic purposes", + "url": "https://cryptosecurity.stackexchange.com/questions/45232/why-is-md5-and-sha1-considered-weak-hash-algorithms" + }, + { + "name": "Hashico documentation on SHA-256", + "url": "https://hashico.github.io/docs/pro Hornet a secure hash and salt storage" + }, + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "The code at line 36 uses a potentially unsafe way to build a SQL query via string formatting/concatenation. This can lead to SQL Injection vulnerabilities if user inputs are directly used.", + "fix": "Use parameterized queries to safely pass user data to SQL queries. In this example, we'll use Python's `format()` method with a whitelist of allowed characters for a simple fix. However, the recommended approach is to use Python's database connectors which support parameterized queries for more security and protection.", + "llm_used": "online", + "references": [ + { + "title": "SQL Injection (OWASP)", + "url": "https://owasp.org/Top10/2017-SQL-Injection.html" + }, + { + "title": "Parameterized Queries (SQL)", + "url": "https://en.wikipedia.org/wiki/SQL_parameterized_queries" + }, + { + "title": "Python Database API", + "url": "https://docs.python.org/3/library/sqlite3.html" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "{\n \"explanation\": \"The given regex pattern '.*' is overly-broad, allowing it to match the entire input string regardless of content. This can lead to excessive backtracking in the matching process, slowing down or even crashing the application. Additionally, such a broad pattern may also result in unintended matches that were not expected, potentially leading to security vulnerabilities in the application.\",\n \"fix\": {\n \"description\": \"Modify the regex pattern to anchor it to the entire input string and use a quantifier with a maximum limit for better performance and security.\",\n \"code\": \"pat = re.compile(r'^.*$')\" // Anchors the pattern to match the entire string, no change to the quantifier\n },\n \"references\": [\n {\n \"url\": \"https://stackoverflow.com/questions/30027144/what-is-the-difference-between-the-greedy-quantifier-and-the-non-greedy-quantifier\",\n \"description\": \"This Stack Overflow post discusses the use of quantifiers in regular expressions, including how to limit their greediness for performance reasons.\"\n },\n {\n \"url\": \"https://www.geeksforgeeks.org/python-tutors-re-grouping-characters/\",\n \"description\": \"This tutorial would explain in detail how regular expressions work in Python, including the need for specificity in the pattern matching process.\"\n }\n ]\n}", + "fix": "", + "llm_used": "online", + "references": [ + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T171830Z.cleaned.json b/Output/stage3-20251101T171830Z.cleaned.json new file mode 100644 index 0000000..aaa94d8 --- /dev/null +++ b/Output/stage3-20251101T171830Z.cleaned.json @@ -0,0 +1,259 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "The code snippet hardcodes the password 'hunter2' directly in the application's source code. This practice is dangerous because it exposes the secret to anyone who has access to the source code. If the code is shared, discussed, or submitted to a version control system, the password will become publicly known. This could lead to unauthorized access to the application or service that uses the password.", + "fix": "Replace the hardcoded password with an environment variable that holds the password value. This ensures that the password is not exposed in the source code and can be easily updated or retrieved from the environment.", + "llm_used": "online", + "references": [ + { + "url": "https://docs.python.org/3/library/os.environ.html", + "description": "Environment Variables in Python" + }, + { + "url": "https://docs.python.org/3/library/os.environ.html# Environment-Variables", + "description": "Python Environment Variables Management" + }, + { + "url": "https://security-center.github.io/secret managerial页面存档备份標帖https://github.com/python-one/accessible-secrets", + "description": "Python Secrets Manager" + }, + { + "url": "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + }, + { + "url": "https://owasp.org/www-project-top-ten/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "Hardcoding API keys directly into the source code is a security issue. By storing secrets like API keys in the source code, there is an increased risk of exposure through backup files, accidental submissions to version control, or if the code is ever shared or released prematurely. This can lead to unauthorized access or misuse of the API key, causing financial losses or other security breaches.", + "fix": "Use environment variables or a secret manager to store API keys in the application. Here's an example of how to configure an environment variable in your project:", + "llm_used": "online", + "references": [ + { + "url": "https://example.com/configuring-environment-variables-in-python" + }, + { + "url": "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + }, + { + "url": "https://owasp.org/www-project-top-ten/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "The code contains a hardcoded and potentially sensitive token or secret key stored in plain text as a string constant. This issue is known as a Hardcoded Token vulnerability. It makes the application more insecure because if the token or secret is compromised, an attacker could use it to gain unauthorized access to sensitive information or perform malicious actions.", + "fix": "Remove the hardcoded token or secret from the code and consider using a secure method to generate, store, and access the token or secret. Here's an example fix assuming the string is a simple hardcoded key:---// Example fix (replace with the actual secure method)const SECRET_KEY = processPasswordSecret(); // Assuming a proper secure method is implemented---For the given example in Line 8, the fix would be to remove the entire line with the hardcoded token or secret:// Remove the hardcoded token or secret// const ABCD1234SECRETKEYSHOULDNOTBEHERE;", + "llm_used": "online", + "references": [ + { + "url": "https://www.opensecuritygroup.com/owasp-top-ten-lists-and-anagrams", + "description": "OWASP Top Ten Lists" + }, + { + "url": "https://whatnodoes.net/xkcd-120/", + "description": "Hardcode and XKCD 120" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "The given code uses `eval(user_input)` which can lead to code injection attacks if `user_input` is untrusted. An attacker can execute arbitrary code, leading to potential security vulnerabilities, data breaches, or system compromise.", + "fix": "Replace the insecure `eval()` usage with a safer alternative. Here's an example of how to use a restricted evaluator (Python's `ast.literal_eval()`) to safely evaluate simple Python literals.", + "llm_used": "online", + "references": [ + { + "url": "https://python.org/doc/howashtools/safety/", + "description": "Learn about safe ways to evaluate Python literals using `ast.literal_eval()`" + }, + { + "url": "https://owASP.org/Top10/Dos_ WhatsAppッシュ underestimate the importance of input validation", + "description": "Understand the risks of input validation and the importance of using secure methods like `ast.literal_eval()`" + }, + { + "url": "https://owasp.org/www-community/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "{ \"explanation\": \"The code uses subprocess.run with shell=True, which is a susceptible way of executing arbitrary commands. This leaves the application vulnerable to command injection attacks. An attacker could potentially inject malicious code through the command's arguments, leading to unauthorized access or modification of system resources. This issue is related to a Common Vulnerability Scoring System (CVSS) base score of 8, as it directly allows for remote code execution.\", \"fix\": \"Avoid using shell=True and instead pass the command and its arguments as separate arguments to subprocess.run. Ensure that inputs are properly validated to prevent injection attacks. Here's the corrected line:\", \"fix\": \"subprocess.run('ls', '-la')\", \"references\": [ { \"name\": \"Python Subprocess Safety\", \"url\": \"https://docs.python.org/3/library/subprocess.html#security-vulnerabilities\" }, { \"name\": \"Command Injection Prevention\", \"url\": \"https:// OWASP.org/Vulnerabilities-list/Command-injection\" }, { \"name\": \"CVSS Database\", \"url\": \"https://cune hostebin.org/cvss/\" // To search for the CVSS entry for this vulnerability patterns } ]}", + "fix": "", + "llm_used": "online", + "references": [ + { + "url": "https://cheatsheetseries.owasp.org/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "The code is attempting to use `pickle.loads()` with a suspicious input in the format of a string preceded by the literal 'not-a-pickle'. This is likely intended to obfuscate or mislead, but the actual issue is the lack of trust in the source of the input. Unpickling data from untrusted sources, such as user input or network data, can execute arbitrary code, leading to security vulnerabilities like Remote Code Execution (RCE) and information disclosure.", + "fix": "Validating and sanitizing the input to ensure it's a trusted source before unpickling is crucial. However, using `pickle` directly remains risky. Instead, consider using safer alternatives like Vault's Secret Service or AWS Secret Store for storing and managing sensitive data and tokens.", + "llm_used": "online", + "references": [ + { + "url": "https://owasp.org/www-community/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "The code imports the `subprocess` module, which allows execution of system commands directly from Python. Without proper restrictions or validation, this could lead to unintended shell command executions, potentially causing unauthorized access, data leakage, or other security vulnerabilities if the input is compromised.", + "fix": { + "description": "Use a safer way to execute commands without shell injection. Here's a suggestion using `os.system` instead, which does not take input but also has its own risks. Alternatively, use the Python `run` function in `pyfiglet` for a more secure approach to executing commands.", + "code": "import os\ncommand = 'ls'\nos.system(command)" + }, + "llm_used": "online", + "references": [ + { + "url": "https://security.stackexchange.com/questions/18713/be-careful-with-shell-command-execution-in-python" + }, + { + "url": "https://stackoverflow.com/questions/13117660/use-os-system-instead-of-subprocess-when-command-execution-is-needed" + }, + { + "url": "https://pypi.org/project/pyfiglet/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "The code uses the MD5 hash algorithm, which is considered weak and has been known to have collisions, making it unsuitable for security-critical purposes such as password hashing. Using MD5 can lead to vulnerabilities where different inputs may produce the same hash, granting unauthorized access.", + "fix": "Replace `md5` with a more secure algorithm like `sha256`. Here's the corrected line: `h = hashlib.sha256(b'data').hexdigest()`", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/security-top-10/2006/pet10b-java.html" + }, + { + "url": "https://passwordhashing.bestpractices.io/" + }, + { + "url": "https://www.ipa.go.jp/security/english/" + }, + { + "url": "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "The code at line 36 is vulnerable to SQL Injection because the 'query' variable is used directly in a cursor.execute() call without validation or sanitization. An attacker could inject malicious SQL code by manipulating the 'query' variable, leading to unauthorized data modification, data leakage, or other unintended consequences.", + "fix": "Replace the line with a parameterized query to prevent SQL Injection. Use placeholders for query parameters and pass them as a separate parameter to cursor.execute().", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/www.ReturningReturns/WSenheimans_12.html", + "description": "SQL Injection is a type of computer attack that involves the injection of unintended SQL or SQL-like code into a computer database management system." + }, + { + "url": "https://information-security.stackexchange.com/questions/5068/how-to-prevent-sql-injection-attacks", + "description": "SQL Injection can be prevented with proper input validation, canonicalization, and sanitization. Parameterized queries can further protect against SQL Injection." + }, + { + "url": "https://docs.python.org/3/library/sqlite3.html#using-parameterized-queries", + "description": "Python's sqlite3 and MySQLdb modules provide support for parameterized queries, making it easier to prevent SQL Injection." + }, + { + "url": "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html" + }, + { + "url": "https://owasp.org/www-community/attacks/SQL_Injection" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "The given regex pattern '.*' is overly-broad, potentially leading to excessive backtracking and unintended matches. This can cause performance issues or security vulnerabilities if the pattern is used to match input in a dynamic code execution context.", + "fix": "Replace '.*' with a more precise regex pattern. For example, if matching text, use '^[^\\n]*$' to match all non-newline characters or '^[^\\t\\n\\r\\v\\f]*$' for shorter lines. Always anchor your regex and use limit quantifiers to restrict the number of matches.", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/textbook/JavaSecurityHardeningTips152.html", + "description": "JP0B: Session Manager - Uncontrolled Session and Request which can be exploited through use of classids and instances." + }, + { + "url": "https://iðeland.fmi.pl/regex-regions/en/current/", + "description": "Regular Expressions (regex) in various programming languages" + }, + { + "url": "https://owasp.org/www-community/" + } + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T171830Z.json b/Output/stage3-20251101T171830Z.json new file mode 100644 index 0000000..035e3b1 --- /dev/null +++ b/Output/stage3-20251101T171830Z.json @@ -0,0 +1,257 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "The code snippet hardcodes the password 'hunter2' directly in the application's source code. This practice is dangerous because it exposes the secret to anyone who has access to the source code. If the code is shared, discussed, or submitted to a version control system, the password will become publicly known. This could lead to unauthorized access to the application or service that uses the password.", + "fix": "Replace the hardcoded password with an environment variable that holds the password value. This ensures that the password is not exposed in the source code and can be easily updated or retrieved from the environment.", + "llm_used": "online", + "references": [ + { + "name": "Environment Variables in Python", + "url": "https://docs.python.org/3/library/os.environ.html" + }, + { + "name": "Python Environment Variables Management", + "url": "https://docs.python.org/3/library/os.environ.html# Environment-Variables" + }, + { + "name": "Python Secrets Manager", + "url": "https://security-center.github.io/secret managerial页面存档备份標帖https://github.com/python-one/accessible-secrets" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "Hardcoding API keys directly into the source code is a security issue. By storing secrets like API keys in the source code, there is an increased risk of exposure through backup files, accidental submissions to version control, or if the code is ever shared or released prematurely. This can lead to unauthorized access or misuse of the API key, causing financial losses or other security breaches.", + "fix": "Use environment variables or a secret manager to store API keys in the application. Here's an example of how to configure an environment variable in your project:", + "llm_used": "online", + "references": [ + { + "url": "https://example.com/configuring-environment-variables-in-python" + }, + { + "url": "https:// OWASP.org/Top-Threats maka-_OAuth-Token-Vulnerability-2021-12" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "The code contains a hardcoded and potentially sensitive token or secret key stored in plain text as a string constant. This issue is known as a Hardcoded Token vulnerability. It makes the application more insecure because if the token or secret is compromised, an attacker could use it to gain unauthorized access to sensitive information or perform malicious actions.", + "fix": "Remove the hardcoded token or secret from the code and consider using a secure method to generate, store, and access the token or secret. Here's an example fix assuming the string is a simple hardcoded key:\n\n---\n\n// Example fix (replace with the actual secure method)\nconst SECRET_KEY = processPasswordSecret(); // Assuming a proper secure method is implemented\n---\n\nFor the given example in Line 8, the fix would be to remove the entire line with the hardcoded token or secret:\n\n// Remove the hardcoded token or secret\n// const ABCD1234SECRETKEYSHOULDNOTBEHERE;", + "llm_used": "online", + "references": [ + { + "name": "OWASP Top Ten Lists", + "url": "https://www.opensecuritygroup.com/owasp-top-ten-lists-and-anagrams" + }, + { + "name": "Hardcode and XKCD 120", + "url": "https://whatnodoes.net/xkcd-120/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "The given code uses `eval(user_input)` which can lead to code injection attacks if `user_input` is untrusted. An attacker can execute arbitrary code, leading to potential security vulnerabilities, data breaches, or system compromise.", + "fix": "Replace the insecure `eval()` usage with a safer alternative. Here's an example of how to use a restricted evaluator (Python's `ast.literal_eval()`) to safely evaluate simple Python literals.", + "llm_used": "online", + "references": [ + { + "url": "https://python.org/doc/howashtools/safety/", + "description": "Learn about safe ways to evaluate Python literals using `ast.literal_eval()`" + }, + { + "url": "https://owASP.org/Top10/Dos_ WhatsAppッシュ underestimate the importance of input validation", + "description": "Understand the risks of input validation and the importance of using secure methods like `ast.literal_eval()`" + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "{\n \"explanation\": \"The code uses subprocess.run with shell=True, which is a susceptible way of executing arbitrary commands. This leaves the application vulnerable to command injection attacks. An attacker could potentially inject malicious code through the command's arguments, leading to unauthorized access or modification of system resources. This issue is related to a Common Vulnerability Scoring System (CVSS) base score of 8, as it directly allows for remote code execution.\",\n \"fix\": \"Avoid using shell=True and instead pass the command and its arguments as separate arguments to subprocess.run. Ensure that inputs are properly validated to prevent injection attacks. Here's the corrected line:\",\n \"fix\": \"subprocess.run('ls', '-la')\",\n \"references\": [\n {\n \"name\": \"Python Subprocess Safety\",\n \"url\": \"https://docs.python.org/3/library/subprocess.html#security-vulnerabilities\"\n },\n {\n \"name\": \"Command Injection Prevention\",\n \"url\": \"https:// OWASP.org/Vulnerabilities-list/Command-injection\"\n },\n {\n \"name\": \"CVSS Database\",\n \"url\": \"https://cune hostebin.org/cvss/\" // To search for the CVSS entry for this vulnerability patterns\n }\n ]\n}", + "fix": "", + "llm_used": "online", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "The code is attempting to use `pickle.loads()` with a suspicious input in the format of a string preceded by the literal 'not-a-pickle'. This is likely intended to obfuscate or mislead, but the actual issue is the lack of trust in the source of the input. Unpickling data from untrusted sources, such as user input or network data, can execute arbitrary code, leading to security vulnerabilities like Remote Code Execution (RCE) and information disclosure.", + "fix": "Validating and sanitizing the input to ensure it's a trusted source before unpickling is crucial. However, using `pickle` directly remains risky. Instead, consider using safer alternatives like Vault's Secret Service or AWS Secret Store for storing and managing sensitive data and tokens.", + "llm_used": "online", + "references": [ + { + "url": "https:// pickle.codeЂ « If you're not sure, you might want to read some more materials about the Python pickle module. In particular, this one is about the typical public concern about the functionality of the pickle module. Specifically the concern about its security and the recommended improvements, you can find it here. link (changes to fit example purposes)" + }, + { + "url": "https:// security Harrison.orgvasive " + }, + { + "url": "https:// netikax.com " + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "The code imports the `subprocess` module, which allows execution of system commands directly from Python. Without proper restrictions or validation, this could lead to unintended shell command executions, potentially causing unauthorized access, data leakage, or other security vulnerabilities if the input is compromised.", + "fix": { + "description": "Use a safer way to execute commands without shell injection. Here's a suggestion using `os.system` instead, which does not take input but also has its own risks. Alternatively, use the Python `run` function in `pyfiglet` for a more secure approach to executing commands.", + "code": "import os\ncommand = 'ls'\nos.system(command)" + }, + "llm_used": "online", + "references": [ + { + "title": "Be careful with shell command execution in Python", + "url": "https://security.stackexchange.com/questions/18713/be-careful-with-shell-command-execution-in-python" + }, + { + "title": "Use os.system instead of subprocess when command execution is needed", + "url": "https://stackoverflow.com/questions/13117660/use-os-system-instead-of-subprocess-when-command-execution-is-needed" + }, + { + "title": "Python run function based on figlet", + "url": "https://pypi.org/project/pyfiglet/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "The code uses the MD5 hash algorithm, which is considered weak and has been known to have collisions, making it unsuitable for security-critical purposes such as password hashing. Using MD5 can lead to vulnerabilities where different inputs may produce the same hash, granting unauthorized access.", + "fix": "Replace `md5` with a more secure algorithm like `sha256`. Here's the corrected line: `h = hashlib.sha256(b'data').hexdigest()`", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/security-top-10/2006/pet10b-java.html" + }, + { + "url": "https://passwordhashing.bestpractices.io/" + }, + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "The code at line 36 is vulnerable to SQL Injection because the 'query' variable is used directly in a cursor.execute() call without validation or sanitization. An attacker could inject malicious SQL code by manipulating the 'query' variable, leading to unauthorized data modification, data leakage, or other unintended consequences.", + "fix": "Replace the line with a parameterized query to prevent SQL Injection. Use placeholders for query parameters and pass them as a separate parameter to cursor.execute().", + "llm_used": "online", + "references": [ + { + "name": "SQL Injection", + "description": "SQL Injection is a type of computer attack that involves the injection of unintended SQL or SQL-like code into a computer database management system.", + "url": "https://owASP.org/www.ReturningReturns/WSenheimans_12.html" + }, + { + "name": "SQL Injection Mitigation", + "description": "SQL Injection can be prevented with proper input validation, canonicalization, and sanitization. Parameterized queries can further protect against SQL Injection.", + "url": "https://information-security.stackexchange.com/questions/5068/how-to-prevent-sql-injection-attacks" + }, + { + "name": "SQL Injection in Python", + "description": "Python's sqlite3 and MySQLdb modules provide support for parameterized queries, making it easier to prevent SQL Injection.", + "url": "https://docs.python.org/3/library/sqlite3.html#using-parameterized-queries" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "The given regex pattern '.*' is overly-broad, potentially leading to excessive backtracking and unintended matches. This can cause performance issues or security vulnerabilities if the pattern is used to match input in a dynamic code execution context.", + "fix": "Replace '.*' with a more precise regex pattern. For example, if matching text, use '^[^\\n]*$' to match all non-newline characters or '^[^\\t\\n\\r\\v\\f]*$' for shorter lines. Always anchor your regex and use limit quantifiers to restrict the number of matches.", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/textbook/JavaSecurityHardeningTips152.html", + "description": "JP0B: Session Manager - Uncontrolled Session and Request which can be exploited through use of classids and instances." + }, + { + "url": "https:// लगाते.OracleCSHR.com/choose-language/regex.html", + "description": "Basic regular expression in various programming languages with examples in C, C++, and SQL" + }, + { + "url": "https://iðeland.fmi.pl/regex-regions/en/current/", + "description": "Regular Expressions (regex) in various programming languages" + }, + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T172426Z.cleaned.json b/Output/stage3-20251101T172426Z.cleaned.json new file mode 100644 index 0000000..035e3b1 --- /dev/null +++ b/Output/stage3-20251101T172426Z.cleaned.json @@ -0,0 +1,257 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "The code snippet hardcodes the password 'hunter2' directly in the application's source code. This practice is dangerous because it exposes the secret to anyone who has access to the source code. If the code is shared, discussed, or submitted to a version control system, the password will become publicly known. This could lead to unauthorized access to the application or service that uses the password.", + "fix": "Replace the hardcoded password with an environment variable that holds the password value. This ensures that the password is not exposed in the source code and can be easily updated or retrieved from the environment.", + "llm_used": "online", + "references": [ + { + "name": "Environment Variables in Python", + "url": "https://docs.python.org/3/library/os.environ.html" + }, + { + "name": "Python Environment Variables Management", + "url": "https://docs.python.org/3/library/os.environ.html# Environment-Variables" + }, + { + "name": "Python Secrets Manager", + "url": "https://security-center.github.io/secret managerial页面存档备份標帖https://github.com/python-one/accessible-secrets" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "Hardcoding API keys directly into the source code is a security issue. By storing secrets like API keys in the source code, there is an increased risk of exposure through backup files, accidental submissions to version control, or if the code is ever shared or released prematurely. This can lead to unauthorized access or misuse of the API key, causing financial losses or other security breaches.", + "fix": "Use environment variables or a secret manager to store API keys in the application. Here's an example of how to configure an environment variable in your project:", + "llm_used": "online", + "references": [ + { + "url": "https://example.com/configuring-environment-variables-in-python" + }, + { + "url": "https:// OWASP.org/Top-Threats maka-_OAuth-Token-Vulnerability-2021-12" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "The code contains a hardcoded and potentially sensitive token or secret key stored in plain text as a string constant. This issue is known as a Hardcoded Token vulnerability. It makes the application more insecure because if the token or secret is compromised, an attacker could use it to gain unauthorized access to sensitive information or perform malicious actions.", + "fix": "Remove the hardcoded token or secret from the code and consider using a secure method to generate, store, and access the token or secret. Here's an example fix assuming the string is a simple hardcoded key:\n\n---\n\n// Example fix (replace with the actual secure method)\nconst SECRET_KEY = processPasswordSecret(); // Assuming a proper secure method is implemented\n---\n\nFor the given example in Line 8, the fix would be to remove the entire line with the hardcoded token or secret:\n\n// Remove the hardcoded token or secret\n// const ABCD1234SECRETKEYSHOULDNOTBEHERE;", + "llm_used": "online", + "references": [ + { + "name": "OWASP Top Ten Lists", + "url": "https://www.opensecuritygroup.com/owasp-top-ten-lists-and-anagrams" + }, + { + "name": "Hardcode and XKCD 120", + "url": "https://whatnodoes.net/xkcd-120/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "The given code uses `eval(user_input)` which can lead to code injection attacks if `user_input` is untrusted. An attacker can execute arbitrary code, leading to potential security vulnerabilities, data breaches, or system compromise.", + "fix": "Replace the insecure `eval()` usage with a safer alternative. Here's an example of how to use a restricted evaluator (Python's `ast.literal_eval()`) to safely evaluate simple Python literals.", + "llm_used": "online", + "references": [ + { + "url": "https://python.org/doc/howashtools/safety/", + "description": "Learn about safe ways to evaluate Python literals using `ast.literal_eval()`" + }, + { + "url": "https://owASP.org/Top10/Dos_ WhatsAppッシュ underestimate the importance of input validation", + "description": "Understand the risks of input validation and the importance of using secure methods like `ast.literal_eval()`" + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "{\n \"explanation\": \"The code uses subprocess.run with shell=True, which is a susceptible way of executing arbitrary commands. This leaves the application vulnerable to command injection attacks. An attacker could potentially inject malicious code through the command's arguments, leading to unauthorized access or modification of system resources. This issue is related to a Common Vulnerability Scoring System (CVSS) base score of 8, as it directly allows for remote code execution.\",\n \"fix\": \"Avoid using shell=True and instead pass the command and its arguments as separate arguments to subprocess.run. Ensure that inputs are properly validated to prevent injection attacks. Here's the corrected line:\",\n \"fix\": \"subprocess.run('ls', '-la')\",\n \"references\": [\n {\n \"name\": \"Python Subprocess Safety\",\n \"url\": \"https://docs.python.org/3/library/subprocess.html#security-vulnerabilities\"\n },\n {\n \"name\": \"Command Injection Prevention\",\n \"url\": \"https:// OWASP.org/Vulnerabilities-list/Command-injection\"\n },\n {\n \"name\": \"CVSS Database\",\n \"url\": \"https://cune hostebin.org/cvss/\" // To search for the CVSS entry for this vulnerability patterns\n }\n ]\n}", + "fix": "", + "llm_used": "online", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "The code is attempting to use `pickle.loads()` with a suspicious input in the format of a string preceded by the literal 'not-a-pickle'. This is likely intended to obfuscate or mislead, but the actual issue is the lack of trust in the source of the input. Unpickling data from untrusted sources, such as user input or network data, can execute arbitrary code, leading to security vulnerabilities like Remote Code Execution (RCE) and information disclosure.", + "fix": "Validating and sanitizing the input to ensure it's a trusted source before unpickling is crucial. However, using `pickle` directly remains risky. Instead, consider using safer alternatives like Vault's Secret Service or AWS Secret Store for storing and managing sensitive data and tokens.", + "llm_used": "online", + "references": [ + { + "url": "https:// pickle.codeЂ « If you're not sure, you might want to read some more materials about the Python pickle module. In particular, this one is about the typical public concern about the functionality of the pickle module. Specifically the concern about its security and the recommended improvements, you can find it here. link (changes to fit example purposes)" + }, + { + "url": "https:// security Harrison.orgvasive " + }, + { + "url": "https:// netikax.com " + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "The code imports the `subprocess` module, which allows execution of system commands directly from Python. Without proper restrictions or validation, this could lead to unintended shell command executions, potentially causing unauthorized access, data leakage, or other security vulnerabilities if the input is compromised.", + "fix": { + "description": "Use a safer way to execute commands without shell injection. Here's a suggestion using `os.system` instead, which does not take input but also has its own risks. Alternatively, use the Python `run` function in `pyfiglet` for a more secure approach to executing commands.", + "code": "import os\ncommand = 'ls'\nos.system(command)" + }, + "llm_used": "online", + "references": [ + { + "title": "Be careful with shell command execution in Python", + "url": "https://security.stackexchange.com/questions/18713/be-careful-with-shell-command-execution-in-python" + }, + { + "title": "Use os.system instead of subprocess when command execution is needed", + "url": "https://stackoverflow.com/questions/13117660/use-os-system-instead-of-subprocess-when-command-execution-is-needed" + }, + { + "title": "Python run function based on figlet", + "url": "https://pypi.org/project/pyfiglet/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "The code uses the MD5 hash algorithm, which is considered weak and has been known to have collisions, making it unsuitable for security-critical purposes such as password hashing. Using MD5 can lead to vulnerabilities where different inputs may produce the same hash, granting unauthorized access.", + "fix": "Replace `md5` with a more secure algorithm like `sha256`. Here's the corrected line: `h = hashlib.sha256(b'data').hexdigest()`", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/security-top-10/2006/pet10b-java.html" + }, + { + "url": "https://passwordhashing.bestpractices.io/" + }, + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "The code at line 36 is vulnerable to SQL Injection because the 'query' variable is used directly in a cursor.execute() call without validation or sanitization. An attacker could inject malicious SQL code by manipulating the 'query' variable, leading to unauthorized data modification, data leakage, or other unintended consequences.", + "fix": "Replace the line with a parameterized query to prevent SQL Injection. Use placeholders for query parameters and pass them as a separate parameter to cursor.execute().", + "llm_used": "online", + "references": [ + { + "name": "SQL Injection", + "description": "SQL Injection is a type of computer attack that involves the injection of unintended SQL or SQL-like code into a computer database management system.", + "url": "https://owASP.org/www.ReturningReturns/WSenheimans_12.html" + }, + { + "name": "SQL Injection Mitigation", + "description": "SQL Injection can be prevented with proper input validation, canonicalization, and sanitization. Parameterized queries can further protect against SQL Injection.", + "url": "https://information-security.stackexchange.com/questions/5068/how-to-prevent-sql-injection-attacks" + }, + { + "name": "SQL Injection in Python", + "description": "Python's sqlite3 and MySQLdb modules provide support for parameterized queries, making it easier to prevent SQL Injection.", + "url": "https://docs.python.org/3/library/sqlite3.html#using-parameterized-queries" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "The given regex pattern '.*' is overly-broad, potentially leading to excessive backtracking and unintended matches. This can cause performance issues or security vulnerabilities if the pattern is used to match input in a dynamic code execution context.", + "fix": "Replace '.*' with a more precise regex pattern. For example, if matching text, use '^[^\\n]*$' to match all non-newline characters or '^[^\\t\\n\\r\\v\\f]*$' for shorter lines. Always anchor your regex and use limit quantifiers to restrict the number of matches.", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/textbook/JavaSecurityHardeningTips152.html", + "description": "JP0B: Session Manager - Uncontrolled Session and Request which can be exploited through use of classids and instances." + }, + { + "url": "https:// लगाते.OracleCSHR.com/choose-language/regex.html", + "description": "Basic regular expression in various programming languages with examples in C, C++, and SQL" + }, + { + "url": "https://iðeland.fmi.pl/regex-regions/en/current/", + "description": "Regular Expressions (regex) in various programming languages" + }, + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Output/stage3-20251101T172426Z.json b/Output/stage3-20251101T172426Z.json new file mode 100644 index 0000000..035e3b1 --- /dev/null +++ b/Output/stage3-20251101T172426Z.json @@ -0,0 +1,257 @@ +{ + "results": { + "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 7, + "snippet": "password = \"hunter2\"", + "message": "Avoid hardcoding passwords in source code; use environment variables or secret stores.", + "severity": "High", + "explanation": "The code snippet hardcodes the password 'hunter2' directly in the application's source code. This practice is dangerous because it exposes the secret to anyone who has access to the source code. If the code is shared, discussed, or submitted to a version control system, the password will become publicly known. This could lead to unauthorized access to the application or service that uses the password.", + "fix": "Replace the hardcoded password with an environment variable that holds the password value. This ensures that the password is not exposed in the source code and can be easily updated or retrieved from the environment.", + "llm_used": "online", + "references": [ + { + "name": "Environment Variables in Python", + "url": "https://docs.python.org/3/library/os.environ.html" + }, + { + "name": "Python Environment Variables Management", + "url": "https://docs.python.org/3/library/os.environ.html# Environment-Variables" + }, + { + "name": "Python Secrets Manager", + "url": "https://security-center.github.io/secret managerial页面存档备份標帖https://github.com/python-one/accessible-secrets" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Hardcoded Secret", + "line": 8, + "snippet": "API_KEY = \"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Avoid hardcoding API keys or credentials in source code; use environment variables or secret managers.", + "severity": "High", + "explanation": "Hardcoding API keys directly into the source code is a security issue. By storing secrets like API keys in the source code, there is an increased risk of exposure through backup files, accidental submissions to version control, or if the code is ever shared or released prematurely. This can lead to unauthorized access or misuse of the API key, causing financial losses or other security breaches.", + "fix": "Use environment variables or a secret manager to store API keys in the application. Here's an example of how to configure an environment variable in your project:", + "llm_used": "online", + "references": [ + { + "url": "https://example.com/configuring-environment-variables-in-python" + }, + { + "url": "https:// OWASP.org/Top-Threats maka-_OAuth-Token-Vulnerability-2021-12" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/www-project-top-ten/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible Hardcoded Token", + "line": 8, + "snippet": "\"ABCD1234SECRETKEYSHOULDNOTBEHERE\"", + "message": "Found a long string constant which might be a token or secret; verify and remove from code if sensitive.", + "severity": "High", + "explanation": "The code contains a hardcoded and potentially sensitive token or secret key stored in plain text as a string constant. This issue is known as a Hardcoded Token vulnerability. It makes the application more insecure because if the token or secret is compromised, an attacker could use it to gain unauthorized access to sensitive information or perform malicious actions.", + "fix": "Remove the hardcoded token or secret from the code and consider using a secure method to generate, store, and access the token or secret. Here's an example fix assuming the string is a simple hardcoded key:\n\n---\n\n// Example fix (replace with the actual secure method)\nconst SECRET_KEY = processPasswordSecret(); // Assuming a proper secure method is implemented\n---\n\nFor the given example in Line 8, the fix would be to remove the entire line with the hardcoded token or secret:\n\n// Remove the hardcoded token or secret\n// const ABCD1234SECRETKEYSHOULDNOTBEHERE;", + "llm_used": "online", + "references": [ + { + "name": "OWASP Top Ten Lists", + "url": "https://www.opensecuritygroup.com/owasp-top-ten-lists-and-anagrams" + }, + { + "name": "Hardcode and XKCD 120", + "url": "https://whatnodoes.net/xkcd-120/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 12, + "snippet": "res = eval(user_input)", + "message": "Use of eval() can lead to code injection or unexpected behavior. Avoid using it with untrusted input.", + "severity": "Medium", + "explanation": "The given code uses `eval(user_input)` which can lead to code injection attacks if `user_input` is untrusted. An attacker can execute arbitrary code, leading to potential security vulnerabilities, data breaches, or system compromise.", + "fix": "Replace the insecure `eval()` usage with a safer alternative. Here's an example of how to use a restricted evaluator (Python's `ast.literal_eval()`) to safely evaluate simple Python literals.", + "llm_used": "online", + "references": [ + { + "url": "https://python.org/doc/howashtools/safety/", + "description": "Learn about safe ways to evaluate Python literals using `ast.literal_eval()`" + }, + { + "url": "https://owASP.org/Top10/Dos_ WhatsAppッシュ underestimate the importance of input validation", + "description": "Understand the risks of input validation and the importance of using secure methods like `ast.literal_eval()`" + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Suspicious Subprocess Call", + "line": 15, + "snippet": "subprocess.run(\"ls -la\", shell=True)", + "message": "Use of subprocess APIs can run external commands; ensure inputs are sanitized. Detected shell=True which increases risk of injection.", + "severity": "Medium", + "explanation": "{\n \"explanation\": \"The code uses subprocess.run with shell=True, which is a susceptible way of executing arbitrary commands. This leaves the application vulnerable to command injection attacks. An attacker could potentially inject malicious code through the command's arguments, leading to unauthorized access or modification of system resources. This issue is related to a Common Vulnerability Scoring System (CVSS) base score of 8, as it directly allows for remote code execution.\",\n \"fix\": \"Avoid using shell=True and instead pass the command and its arguments as separate arguments to subprocess.run. Ensure that inputs are properly validated to prevent injection attacks. Here's the corrected line:\",\n \"fix\": \"subprocess.run('ls', '-la')\",\n \"references\": [\n {\n \"name\": \"Python Subprocess Safety\",\n \"url\": \"https://docs.python.org/3/library/subprocess.html#security-vulnerabilities\"\n },\n {\n \"name\": \"Command Injection Prevention\",\n \"url\": \"https:// OWASP.org/Vulnerabilities-list/Command-injection\"\n },\n {\n \"name\": \"CVSS Database\",\n \"url\": \"https://cune hostebin.org/cvss/\" // To search for the CVSS entry for this vulnerability patterns\n }\n ]\n}", + "fix": "", + "llm_used": "online", + "references": [ + "https://cheatsheetseries.owasp.org/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Function Usage", + "line": 21, + "snippet": "obj = pickle.loads(b\"not-a-pickle\")", + "message": "Unpickling data from untrusted sources can lead to remote code execution.", + "severity": "Medium", + "explanation": "The code is attempting to use `pickle.loads()` with a suspicious input in the format of a string preceded by the literal 'not-a-pickle'. This is likely intended to obfuscate or mislead, but the actual issue is the lack of trust in the source of the input. Unpickling data from untrusted sources, such as user input or network data, can execute arbitrary code, leading to security vulnerabilities like Remote Code Execution (RCE) and information disclosure.", + "fix": "Validating and sanitizing the input to ensure it's a trusted source before unpickling is crucial. However, using `pickle` directly remains risky. Instead, consider using safer alternatives like Vault's Secret Service or AWS Secret Store for storing and managing sensitive data and tokens.", + "llm_used": "online", + "references": [ + { + "url": "https:// pickle.codeЂ « If you're not sure, you might want to read some more materials about the Python pickle module. In particular, this one is about the typical public concern about the functionality of the pickle module. Specifically the concern about its security and the recommended improvements, you can find it here. link (changes to fit example purposes)" + }, + { + "url": "https:// security Harrison.orgvasive " + }, + { + "url": "https:// netikax.com " + }, + "https://owasp.org/www-community/" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Dangerous Import", + "line": 2, + "snippet": "import subprocess", + "message": "Importing subprocess can enable executing shell commands; review usage.", + "severity": "Medium", + "explanation": "The code imports the `subprocess` module, which allows execution of system commands directly from Python. Without proper restrictions or validation, this could lead to unintended shell command executions, potentially causing unauthorized access, data leakage, or other security vulnerabilities if the input is compromised.", + "fix": { + "description": "Use a safer way to execute commands without shell injection. Here's a suggestion using `os.system` instead, which does not take input but also has its own risks. Alternatively, use the Python `run` function in `pyfiglet` for a more secure approach to executing commands.", + "code": "import os\ncommand = 'ls'\nos.system(command)" + }, + "llm_used": "online", + "references": [ + { + "title": "Be careful with shell command execution in Python", + "url": "https://security.stackexchange.com/questions/18713/be-careful-with-shell-command-execution-in-python" + }, + { + "title": "Use os.system instead of subprocess when command execution is needed", + "url": "https://stackoverflow.com/questions/13117660/use-os-system-instead-of-subprocess-when-command-execution-is-needed" + }, + { + "title": "Python run function based on figlet", + "url": "https://pypi.org/project/pyfiglet/" + } + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Deprecated Hash", + "line": 26, + "snippet": "h = hashlib.md5(b\"data\").hexdigest()", + "message": "Use of md5 is deprecated for security-sensitive hashing. Use sha256 or stronger algorithms.", + "severity": "Medium", + "explanation": "The code uses the MD5 hash algorithm, which is considered weak and has been known to have collisions, making it unsuitable for security-critical purposes such as password hashing. Using MD5 can lead to vulnerabilities where different inputs may produce the same hash, granting unauthorized access.", + "fix": "Replace `md5` with a more secure algorithm like `sha256`. Here's the corrected line: `h = hashlib.sha256(b'data').hexdigest()`", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/security-top-10/2006/pet10b-java.html" + }, + { + "url": "https://passwordhashing.bestpractices.io/" + }, + "https://www.ipa.go.jp/security/english/", + "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Possible SQL Injection", + "line": 36, + "snippet": "cursor.execute(query)", + "message": "Detected SQL execution using a variable that appears to be built via string formatting/concatenation. Use parameterized queries.", + "severity": "High", + "explanation": "The code at line 36 is vulnerable to SQL Injection because the 'query' variable is used directly in a cursor.execute() call without validation or sanitization. An attacker could inject malicious SQL code by manipulating the 'query' variable, leading to unauthorized data modification, data leakage, or other unintended consequences.", + "fix": "Replace the line with a parameterized query to prevent SQL Injection. Use placeholders for query parameters and pass them as a separate parameter to cursor.execute().", + "llm_used": "online", + "references": [ + { + "name": "SQL Injection", + "description": "SQL Injection is a type of computer attack that involves the injection of unintended SQL or SQL-like code into a computer database management system.", + "url": "https://owASP.org/www.ReturningReturns/WSenheimans_12.html" + }, + { + "name": "SQL Injection Mitigation", + "description": "SQL Injection can be prevented with proper input validation, canonicalization, and sanitization. Parameterized queries can further protect against SQL Injection.", + "url": "https://information-security.stackexchange.com/questions/5068/how-to-prevent-sql-injection-attacks" + }, + { + "name": "SQL Injection in Python", + "description": "Python's sqlite3 and MySQLdb modules provide support for parameterized queries, making it easier to prevent SQL Injection.", + "url": "https://docs.python.org/3/library/sqlite3.html#using-parameterized-queries" + }, + "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html", + "https://owasp.org/www-community/attacks/SQL_Injection" + ] + }, + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "type": "Insecure Regex", + "line": 29, + "snippet": "pat = re.compile('.*')", + "message": "Found an overly-broad regex pattern which may lead to excessive backtracking or unintended matches.", + "severity": "Medium", + "explanation": "The given regex pattern '.*' is overly-broad, potentially leading to excessive backtracking and unintended matches. This can cause performance issues or security vulnerabilities if the pattern is used to match input in a dynamic code execution context.", + "fix": "Replace '.*' with a more precise regex pattern. For example, if matching text, use '^[^\\n]*$' to match all non-newline characters or '^[^\\t\\n\\r\\v\\f]*$' for shorter lines. Always anchor your regex and use limit quantifiers to restrict the number of matches.", + "llm_used": "online", + "references": [ + { + "url": "https://owASP.org/textbook/JavaSecurityHardeningTips152.html", + "description": "JP0B: Session Manager - Uncontrolled Session and Request which can be exploited through use of classids and instances." + }, + { + "url": "https:// लगाते.OracleCSHR.com/choose-language/regex.html", + "description": "Basic regular expression in various programming languages with examples in C, C++, and SQL" + }, + { + "url": "https://iðeland.fmi.pl/regex-regions/en/current/", + "description": "Regular Expressions (regex) in various programming languages" + }, + "https://owasp.org/www-community/" + ] + } + ] + }, + "summary": { + "counts": { + "High": 4, + "Medium": 6, + "Low": 0 + }, + "risk": "High", + "total_issues": 10, + "score": 0.76, + "rationale": "4 high-severity issue(s), 6 medium-severity issue(s).", + "top_files": [ + { + "file": "C:\\Users\\HP\\Desktop\\CodeGuardian\\input\\test_insecure.py", + "score": 38, + "issues": 10 + } + ] + } +} \ No newline at end of file diff --git a/Plan.txt b/Plan.txt index abb99e8..54d5771 100644 --- a/Plan.txt +++ b/Plan.txt @@ -196,6 +196,6 @@ It detects and fixes vulnerabilities It’s fully agentic, impactful, and visually appealing. -https://build.nvidia.com/nvidia/llama-3_1-nemotron-nano-8b-v1/deploy +https://build.nvidia.com/nvidia/llama-3_1-nemotron-nano-8b-v1/deploy - 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 -https://build.nvidia.com/nvidia/nv-embedcode-7b-v1?snippet_tab=Shell \ No newline at end of file +https://build.nvidia.com/nvidia/nv-embedcode-7b-v1?snippet_tab=Shell - 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 \ No newline at end of file diff --git a/agent/llm_client.py b/agent/llm_client.py index 585ac97..fef3cf9 100644 --- a/agent/llm_client.py +++ b/agent/llm_client.py @@ -168,7 +168,7 @@ def _explain_online( # look for 'Fix:' or 'Remediation:' markers for i, l in enumerate(lines): if l.lower().startswith("fix:") or l.lower().startswith("remediation:"): - fix = " ".join(lines[i : i + 3]) + fix = " ".join(lines[i:i+3]) if l.lower().startswith("http"): refs.append(l.strip()) return {"explanation": explanation, "fix": fix, "references": refs} @@ -231,7 +231,7 @@ def _explain_sagemaker( refs = [] for i, l in enumerate(lines): if l.lower().startswith("fix:") or l.lower().startswith("remediation:"): - fix = " ".join(lines[i : i + 3]) + fix = " ".join(lines[i:i+3]) if l.lower().startswith("http"): refs.append(l.strip()) return {"explanation": explanation, "fix": fix, "references": refs} diff --git a/agent/persistence.py b/agent/persistence.py new file mode 100644 index 0000000..77da3bc --- /dev/null +++ b/agent/persistence.py @@ -0,0 +1,186 @@ +"""Simple persistence layer for analysis reports using SQLite. + +Provides a tiny API: init_db(path), save_report(report_dict), list_reports(limit=50). +Uses a local file under data/reports.db by default. +""" +from __future__ import annotations + +import json +import os +import sqlite3 +from datetime import datetime, timezone +from typing import Dict, Any, List, Optional + +DEFAULT_DB = os.environ.get("CODEGUARDIAN_DB", "data/reports.db") + + +def _ensure_dir(path: str): + d = os.path.dirname(path) + if d and not os.path.exists(d): + os.makedirs(d, exist_ok=True) + + +def init_db(path: Optional[str] = None): + path = path or DEFAULT_DB + _ensure_dir(path) + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute( + """ + CREATE TABLE IF NOT EXISTS reports ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + filename TEXT, + timestamp TEXT, + summary TEXT, + payload TEXT + ) + """ + ) + conn.commit() + conn.close() + + +def save_report(filename: str, summary: Dict[str, Any], payload: Dict[str, Any], path: Optional[str] = None) -> int: + path = path or DEFAULT_DB + _ensure_dir(path) + init_db(path) + conn = sqlite3.connect(path) + cur = conn.cursor() + ts = datetime.now(timezone.utc).isoformat() + cur.execute( + "INSERT INTO reports (filename, timestamp, summary, payload) VALUES (?, ?, ?, ?)", + (filename, ts, json.dumps(summary), json.dumps(payload)), + ) + conn.commit() + rowid = cur.lastrowid or 0 + conn.close() + return rowid + + +def list_reports(limit: int = 50, path: Optional[str] = None) -> List[Dict[str, Any]]: + path = path or DEFAULT_DB + if not os.path.exists(path): + return [] + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("SELECT id, filename, timestamp, summary FROM reports ORDER BY id DESC LIMIT ?", (limit,)) + rows = cur.fetchall() + conn.close() + out: List[Dict[str, Any]] = [] + for r in rows: + _id, filename, ts, summary_json = r + try: + summary = json.loads(summary_json) + except Exception: + summary = {"raw": summary_json} + out.append({"id": _id, "filename": filename, "timestamp": ts, "summary": summary}) + return out + + +def get_report(report_id: int, path: Optional[str] = None) -> Optional[Dict[str, Any]]: + """Return the full report payload and metadata for a given id, or None.""" + path = path or DEFAULT_DB + if not os.path.exists(path): + return None + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("SELECT id, filename, timestamp, summary, payload FROM reports WHERE id = ?", (report_id,)) + row = cur.fetchone() + conn.close() + if not row: + return None + _id, filename, ts, summary_json, payload_json = row + try: + summary = json.loads(summary_json) + except Exception: + summary = {"raw": summary_json} + try: + payload = json.loads(payload_json) + except Exception: + payload = {"raw": payload_json} + return {"id": _id, "filename": filename, "timestamp": ts, "summary": summary, "payload": payload} + + +# ------------------ chat session persistence helpers ------------------ + + +def _default_chat_db() -> str: + return os.environ.get("CHAT_DB", "data/sessions.db") + + +def init_chat_db(path: Optional[str] = None): + path = path or _default_chat_db() + _ensure_dir(path) + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute( + """ + CREATE TABLE IF NOT EXISTS sessions ( + session_id TEXT PRIMARY KEY, + messages TEXT, + last_active TEXT + ) + """ + ) + conn.commit() + conn.close() + + +def save_session(session_id: str, messages: List[Dict[str, Any]], last_active: str, path: Optional[str] = None) -> None: + path = path or _default_chat_db() + _ensure_dir(path) + init_chat_db(path) + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute( + "REPLACE INTO sessions (session_id, messages, last_active) VALUES (?, ?, ?)", + (session_id, json.dumps(messages), last_active), + ) + conn.commit() + conn.close() + + +def load_session(session_id: str, path: Optional[str] = None) -> Optional[Dict[str, Any]]: + path = path or _default_chat_db() + if not os.path.exists(path): + return None + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("SELECT messages, last_active FROM sessions WHERE session_id = ?", (session_id,)) + row = cur.fetchone() + conn.close() + if not row: + return None + messages_json, last_active = row + try: + messages = json.loads(messages_json) + except Exception: + messages = [] + return {"session_id": session_id, "messages": messages, "last_active": last_active} + + +def delete_session(session_id: str, path: Optional[str] = None) -> None: + path = path or _default_chat_db() + if not os.path.exists(path): + return + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("DELETE FROM sessions WHERE session_id = ?", (session_id,)) + conn.commit() + conn.close() + + +def list_sessions(path: Optional[str] = None) -> List[Dict[str, Any]]: + """Return list of sessions with metadata (session_id, last_active).""" + path = path or _default_chat_db() + if not os.path.exists(path): + return [] + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("SELECT session_id, last_active FROM sessions") + rows = cur.fetchall() + conn.close() + out: List[Dict[str, Any]] = [] + for sid, last_active in rows: + out.append({"session_id": sid, "last_active": last_active}) + return out diff --git a/app/app.py b/app/app.py index 80b2e4d..ddcdd43 100644 --- a/app/app.py +++ b/app/app.py @@ -13,6 +13,9 @@ from agent.engine import engine from agent import parser as stage2_parser from agent.reasoning import reasoner, Reasoner +from agent import persistence +from fastapi import Depends +from app.routes_chat import router as chat_router # Load local .env for development (safe: .env is gitignored) @@ -20,6 +23,9 @@ app = FastAPI(title="CodeGuardian API") +# include chat routes +app.include_router(chat_router) + class ScanResult(BaseModel): filename: str @@ -258,6 +264,11 @@ async def analyze( # If user provided Stage 2 JSON directly if stage2: enriched = req_reasoner.enrich(stage2) + # persist the report (best-effort) + try: + persistence.save_report("stage2_input", enriched.get("summary", {}), enriched) + except Exception: + pass return JSONResponse(enriched) results = [] @@ -271,6 +282,11 @@ async def analyze( continue issues = stage2_parser.analyze_code("uploaded:" + (f.filename or "file")) enriched = req_reasoner.enrich({f.filename or "uploaded": issues}) + # persist + try: + persistence.save_report(f.filename or "uploaded", enriched.get("summary", {}), enriched) + except Exception: + pass results.append(enriched) return JSONResponse({"results": results}) @@ -287,8 +303,13 @@ async def analyze( tf.write(code) tf.flush() issues = stage2_parser.analyze_code(tf.name) - enriched = req_reasoner.enrich({fn: issues}) - return JSONResponse(enriched) + + enriched = req_reasoner.enrich({fn: issues}) + try: + persistence.save_report(fn, enriched.get("summary", {}), enriched) + except Exception: + pass + return JSONResponse(enriched) return JSONResponse({"error": "No input provided to analyze"}, status_code=400) @@ -308,3 +329,25 @@ def summary(path: Optional[str] = None): enriched = reasoner.enrich(findings) # keep only summary return JSONResponse({"summary": enriched.get("summary")}) + + +@app.get("/history") +def history(limit: int = 50): + """Return recent analysis summaries (id, filename, timestamp, summary).""" + try: + reports = persistence.list_reports(limit=limit) + return JSONResponse({"reports": reports}) + except Exception: + return JSONResponse({"error": "Failed to read history"}, status_code=500) + + +@app.get("/history/{report_id}") +def history_get(report_id: int): + """Return a full saved report by id.""" + try: + rep = persistence.get_report(report_id) + if rep is None: + return JSONResponse({"error": "Not found"}, status_code=404) + return JSONResponse({"report": rep}) + except Exception: + return JSONResponse({"error": "Failed to read report"}, status_code=500) diff --git a/app/routes_chat.py b/app/routes_chat.py new file mode 100644 index 0000000..7d10730 --- /dev/null +++ b/app/routes_chat.py @@ -0,0 +1,274 @@ +from __future__ import annotations + +from typing import Dict, List, Optional +from fastapi import APIRouter, HTTPException, status +from pydantic import BaseModel +from uuid import uuid4 +import os +from datetime import datetime, timezone + +from agent.llm_client import LLMClient +from agent import persistence +import asyncio +from typing import Callable + +router = APIRouter() + +# In-memory sessions: session_id -> {messages: [...], last_active: isotimestamp} +SESSIONS: Dict[str, Dict] = {} + +# session TTL in seconds; 0 means never expire. Default 3600s +DEFAULT_TTL = int(os.environ.get("CHAT_SESSION_TTL_SECONDS", "3600")) +# how many user-assistant turns to keep in context +CHAT_CONTEXT_TURNS = int(os.environ.get("CHAT_CONTEXT_TURNS", "10")) + + +class ChatRequest(BaseModel): + session_id: Optional[str] = None + message: str + backend: Optional[str] = None + + +class ChatResponse(BaseModel): + session_id: str + reply: str + turns: int + + +def _now_iso() -> str: + return datetime.now(timezone.utc).isoformat() + + +def _is_expired(session: Dict) -> bool: + ttl = int(os.environ.get("CHAT_SESSION_TTL_SECONDS", str(DEFAULT_TTL))) + # ttl <= 0 means never expire + if ttl <= 0: + return False + last = session.get("last_active") + if not last: + return True + try: + last_dt = datetime.fromisoformat(last) + except Exception: + return True + age = (datetime.now(timezone.utc) - last_dt).total_seconds() + return age > ttl + + +@router.post("/chat", response_model=ChatResponse) +def chat(req: ChatRequest): + # ensure session id + sid = req.session_id or str(uuid4()) + + # attempt to load persisted session if not in memory + if sid not in SESSIONS: + loaded = persistence.load_session(sid) + if loaded: + SESSIONS[sid] = {"messages": loaded.get("messages", []), "last_active": loaded.get("last_active")} + + # create session structure if missing or expired + if sid in SESSIONS and _is_expired(SESSIONS[sid]): + # remove from memory and persistence + try: + persistence.delete_session(sid) + except Exception: + pass + del SESSIONS[sid] + + if sid not in SESSIONS: + SESSIONS[sid] = {"messages": [], "last_active": _now_iso()} + + session = SESSIONS[sid] + + # append user message + session["messages"].append({"role": "user", "text": req.message}) + + # build a synthetic 'issue' to reuse LLMClient.explain interface + issue = {"type": "chat", "message": req.message, "snippet": "", "line": 0} + + # include conversation history in context (trim to recent turns) + max_msgs = CHAT_CONTEXT_TURNS * 2 + recent = session["messages"][-max_msgs:] + history_text = "\n".join([f"{m['role']}: {m['text']}" for m in recent]) + context = {"history": history_text} + + # initialize LLM client with optional backend override + client = LLMClient(mode=req.backend if req.backend else None) + try: + out = client.explain(issue, context=context) + reply = out.get("explanation") or out.get("fix") or "" + except Exception: + reply = "(LLM unavailable)" + + # append assistant reply and update last_active + session["messages"].append({"role": "assistant", "text": reply}) + session["last_active"] = _now_iso() + + # persist session (best-effort) + try: + persistence.save_session(sid, session["messages"], session["last_active"]) + except Exception: + pass + + return ChatResponse(session_id=sid, reply=reply, turns=len(session["messages"])) + + +class ChatHistoryResponse(BaseModel): + session_id: str + messages: List[Dict] + last_active: Optional[str] + + +@router.get("/chat/{session_id}/history", response_model=ChatHistoryResponse) +def chat_history(session_id: str): + # try in-memory first + if session_id not in SESSIONS: + # try to load from persistence + loaded = persistence.load_session(session_id) + if not loaded: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="session not found") + SESSIONS[session_id] = {"messages": loaded.get("messages", []), "last_active": loaded.get("last_active")} + + session = SESSIONS[session_id] + if _is_expired(session): + # expire and remove from memory and persistence + try: + persistence.delete_session(session_id) + except Exception: + pass + del SESSIONS[session_id] + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="session expired") + + return ChatHistoryResponse(session_id=session_id, messages=session["messages"], last_active=session.get("last_active")) + + +class SessionItem(BaseModel): + session_id: str + last_active: Optional[str] + in_memory: bool + message_count: int + + +class SessionsResponse(BaseModel): + sessions: List[SessionItem] + + +@router.get("/chat/sessions", response_model=SessionsResponse) +def chat_sessions(): + """List chat sessions (in-memory and persisted). + + Returns a merged view: in-memory sessions take precedence for message counts/last_active. + """ + out: Dict[str, SessionItem] = {} + + # in-memory sessions + for sid, s in SESSIONS.items(): + msgs = s.get("messages") or [] + out[sid] = SessionItem(session_id=sid, last_active=s.get("last_active"), in_memory=True, message_count=len(msgs)) + + # persisted sessions + try: + for meta in persistence.list_sessions(): + sid = meta.get("session_id") + if not sid: + continue + if sid in out: + # already present (in-memory), skip or update missing last_active + if not out[sid].last_active and meta.get("last_active"): + out[sid].last_active = meta.get("last_active") + continue + last_active = meta.get("last_active") + out[sid] = SessionItem(session_id=sid, last_active=last_active, in_memory=False, message_count=0) + except Exception: + # best-effort; if persistence fails, return in-memory only + pass + + return SessionsResponse(sessions=list(out.values())) + + +@router.delete("/chat/{session_id}") +def chat_delete(session_id: str): + # remove from memory + if session_id in SESSIONS: + del SESSIONS[session_id] + # remove persisted + try: + persistence.delete_session(session_id) + except Exception: + pass + return {}, 204 + + +def evict_expired_once() -> int: + """Perform a single eviction pass. Returns number of sessions removed.""" + removed = 0 + # check in-memory sessions + for sid in list(SESSIONS.keys()): + session = SESSIONS.get(sid) + if session and _is_expired(session): + try: + persistence.delete_session(sid) + except Exception: + pass + del SESSIONS[sid] + removed += 1 + + # check persisted sessions that might not be in memory + try: + for meta in persistence.list_sessions(): + sid = meta.get("session_id") + if not sid: + continue + last_active = meta.get("last_active") + # construct a small session-like object for expiry check + session_like = {"last_active": last_active} + if _is_expired(session_like): + try: + persistence.delete_session(sid) + removed += 1 + except Exception: + pass + except Exception: + # best-effort; ignore persistence read errors + pass + + return removed + + +async def _evict_loop(interval: int): + while True: + try: + removed = evict_expired_once() + if removed: + # minor logging to stdout for debug in dev (non-blocking) + print(f"chat-evict: removed {removed} expired sessions") + except Exception: + pass + await asyncio.sleep(interval) + + +# Background eviction task handle +_EVICTOR_TASK: Optional[asyncio.Task] = None + + +@router.on_event("startup") +async def _start_evictor(): + global _EVICTOR_TASK + try: + interval = int(os.environ.get("CHAT_EVICT_INTERVAL_SECONDS", "60")) + except Exception: + interval = 60 + if _EVICTOR_TASK is None: + _EVICTOR_TASK = asyncio.create_task(_evict_loop(interval)) + + +@router.on_event("shutdown") +async def _stop_evictor(): + global _EVICTOR_TASK + if _EVICTOR_TASK is not None: + _EVICTOR_TASK.cancel() + try: + await _EVICTOR_TASK + except Exception: + pass + _EVICTOR_TASK = None diff --git a/data/sessions.db b/data/sessions.db new file mode 100644 index 0000000..0d1cbc4 Binary files /dev/null and b/data/sessions.db differ diff --git a/scripts/demo_demo.py b/scripts/demo_demo.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_chat.py b/tests/test_chat.py new file mode 100644 index 0000000..25a5810 --- /dev/null +++ b/tests/test_chat.py @@ -0,0 +1,34 @@ +from fastapi.testclient import TestClient +from unittest.mock import patch + +from app.app import app + + +def test_chat_endpoint_creates_session_and_replies(monkeypatch): + client = TestClient(app) + + # mock LLMClient.explain to return a predictable response + fake = {"explanation": "Hello, I am a mock LLM."} + + with patch("agent.llm_client.LLMClient.explain", return_value=fake) as mock_explain: + r = client.post("/chat", json={"message": "Hi"}) + assert r.status_code == 200 + j = r.json() + assert "session_id" in j + assert j["reply"] == "Hello, I am a mock LLM." + # ensure the LLM was called with an issue-like dict + mock_explain.assert_called() + + +def test_chat_session_continues(monkeypatch): + client = TestClient(app) + fake1 = {"explanation": "First reply"} + fake2 = {"explanation": "Second reply"} + + with patch("agent.llm_client.LLMClient.explain", side_effect=[fake1, fake2]) as mock_explain: + r1 = client.post("/chat", json={"message": "Hello"}) + sid = r1.json()["session_id"] + r2 = client.post("/chat", json={"session_id": sid, "message": "Again"}) + assert r2.status_code == 200 + assert r2.json()["reply"] == "Second reply" + assert mock_explain.call_count == 2 diff --git a/tests/test_chat_admin.py b/tests/test_chat_admin.py new file mode 100644 index 0000000..4d8ceb5 --- /dev/null +++ b/tests/test_chat_admin.py @@ -0,0 +1,42 @@ +import os +from unittest.mock import patch + +from fastapi.testclient import TestClient + +from app.app import app +from agent import persistence + + +def test_chat_sessions_lists_inmemory_and_persisted(tmp_path): + client = TestClient(app) + fake = {"explanation": "admin-list"} + + db_path = str(tmp_path / "sessions_admin.db") + os.environ["CHAT_DB"] = db_path + + # create an in-memory session by posting + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "One"}) + assert r.status_code == 200 + sid1 = r.json()["session_id"] + + # create another and then clear memory to simulate persisted-only + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r2 = client.post("/chat", json={"message": "Two"}) + sid2 = r2.json()["session_id"] + + # ensure both persisted + assert persistence.load_session(sid1, path=db_path) is not None + assert persistence.load_session(sid2, path=db_path) is not None + + # clear in-memory to make sid2 persisted-only + from app import routes_chat + routes_chat.SESSIONS.pop(sid2, None) + + # call admin endpoint + res = client.get("/chat/sessions") + assert res.status_code == 200 + j = res.json() + sids = {s["session_id"] for s in j["sessions"]} + assert sid1 in sids + assert sid2 in sids diff --git a/tests/test_chat_delete.py b/tests/test_chat_delete.py new file mode 100644 index 0000000..0d8ac67 --- /dev/null +++ b/tests/test_chat_delete.py @@ -0,0 +1,58 @@ +import os +from datetime import datetime, timezone, timedelta +from unittest.mock import patch + +from fastapi.testclient import TestClient + +from app.app import app +import app.routes_chat as routes_chat +from agent import persistence + + +def test_chat_delete_endpoint_removes_session(tmp_path): + client = TestClient(app) + fake = {"explanation": "To be deleted"} + + db_path = str(tmp_path / "sessions_del.db") + os.environ["CHAT_DB"] = db_path + + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "Delete me"}) + assert r.status_code == 200 + sid = r.json()["session_id"] + + # ensure persisted + assert persistence.load_session(sid, path=db_path) is not None + + # delete via endpoint + d = client.delete(f"/chat/{sid}") + assert d.status_code in (200, 204) + + # should be removed from persistence + assert persistence.load_session(sid, path=db_path) is None + + +def test_evict_expired_once_removes_persisted(tmp_path): + client = TestClient(app) + fake = {"explanation": "Evict me"} + + db_path = str(tmp_path / "sessions_evict.db") + os.environ["CHAT_DB"] = db_path + + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "Temp"}) + sid = r.json()["session_id"] + + # force last_active to a long time ago in persistence + old = (datetime.now(timezone.utc) - timedelta(days=1)).isoformat() + # load messages to re-save with old timestamp + loaded = persistence.load_session(sid, path=db_path) + assert loaded is not None + persistence.save_session(sid, loaded["messages"], old, path=db_path) + + # call eviction pass + removed = routes_chat.evict_expired_once() + assert removed >= 1 + + # ensure persistence gone + assert persistence.load_session(sid, path=db_path) is None diff --git a/tests/test_chat_history.py b/tests/test_chat_history.py new file mode 100644 index 0000000..5943be5 --- /dev/null +++ b/tests/test_chat_history.py @@ -0,0 +1,44 @@ +from fastapi.testclient import TestClient +from unittest.mock import patch +from datetime import datetime, timezone, timedelta +import os + +from app.app import app +import app.routes_chat as routes_chat + + +def test_chat_history_returns_messages(): + client = TestClient(app) + fake = {"explanation": "History reply"} + + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "Hello history"}) + assert r.status_code == 200 + sid = r.json()["session_id"] + + # fetch history + hr = client.get(f"/chat/{sid}/history") + assert hr.status_code == 200 + data = hr.json() + assert data["session_id"] == sid + # expect at least user and assistant messages + assert len(data["messages"]) >= 2 + + +def test_chat_history_expiry(): + client = TestClient(app) + fake = {"explanation": "Will expire"} + + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "Temp"}) + sid = r.json()["session_id"] + + # force session to appear old + old = (datetime.now(timezone.utc) - timedelta(seconds=3600)).isoformat() + routes_chat.SESSIONS[sid]["last_active"] = old + + # set TTL to 1 second so expiry check will remove it + os.environ["CHAT_SESSION_TTL_SECONDS"] = "1" + + hr = client.get(f"/chat/{sid}/history") + assert hr.status_code == 404 diff --git a/tests/test_chat_persistence.py b/tests/test_chat_persistence.py new file mode 100644 index 0000000..3036740 --- /dev/null +++ b/tests/test_chat_persistence.py @@ -0,0 +1,38 @@ +import os +import json +import tempfile +from fastapi.testclient import TestClient +from unittest.mock import patch + +from app.app import app +import app.routes_chat as routes_chat +from agent import persistence + + +def test_chat_persistence_survives_restart(tmp_path): + client = TestClient(app) + fake = {"explanation": "Persisted reply"} + + # use a temp DB for chat persistence + db_path = str(tmp_path / "sessions_test.db") + os.environ["CHAT_DB"] = db_path + + with patch("agent.llm_client.LLMClient.explain", return_value=fake): + r = client.post("/chat", json={"message": "Persistent"}) + assert r.status_code == 200 + sid = r.json()["session_id"] + + # ensure persistence saved + loaded = persistence.load_session(sid, path=db_path) + assert loaded is not None + assert len(loaded["messages"]) >= 2 + + # simulate restart by clearing in-memory sessions + routes_chat.SESSIONS.clear() + + # fetch history, should load from DB + hr = client.get(f"/chat/{sid}/history") + assert hr.status_code == 200 + data = hr.json() + assert data["session_id"] == sid + assert len(data["messages"]) >= 2 diff --git a/tests/test_history.py b/tests/test_history.py new file mode 100644 index 0000000..8607ebf --- /dev/null +++ b/tests/test_history.py @@ -0,0 +1,37 @@ +import os +import importlib + +from fastapi.testclient import TestClient + +from agent import persistence + + +def test_history_endpoints(tmp_path, monkeypatch): + db = tmp_path / "reports.db" + # point persistence to temp DB via env and reload module + monkeypatch.setenv("CODEGUARDIAN_DB", str(db)) + importlib.reload(persistence) + + # ensure DB empty + assert persistence.list_reports() == [] + + # save a report + rid = persistence.save_report("test.py", {"counts": {}, "risk": "Low"}, {"results": {}}, path=str(db)) + assert isinstance(rid, int) + + # reload app to ensure it uses updated persistence module (app imports persistence earlier) + from app.app import app + + client = TestClient(app) + + r = client.get("/history") + assert r.status_code == 200 + j = r.json() + assert "reports" in j + assert any(rep["filename"] == "test.py" or rep["filename"] == 'test.py' for rep in j["reports"]) or len(j["reports"]) >= 1 + + # get the report by id + r2 = client.get(f"/history/{rid}") + assert r2.status_code == 200 + jr2 = r2.json() + assert jr2.get("report") and jr2["report"]["id"] == rid