diff --git a/.github/workflows/sca-scan.yml b/.github/workflows/sca-scan.yml index 85ca00e8..21e97963 100644 --- a/.github/workflows/sca-scan.yml +++ b/.github/workflows/sca-scan.yml @@ -2,25 +2,33 @@ name: Source Composition Analysis Scan on: pull_request: types: [opened, synchronize, reopened] + jobs: security-sca: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@master + - name: Setup .NET Core @ Latest uses: actions/setup-dotnet@v1 with: dotnet-version: "7.0.x" + - name: Run Dotnet Restore - run: | - dotnet restore + run: dotnet restore + + - name: Setup Snyk + uses: snyk/actions/setup@master # just installs Snyk CLI, no deprecated dotnet action + - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/dotnet@master + run: | + snyk test \ + --file=Contentstack.Core/obj/project.assets.json \ + --fail-on=all \ + --json-file-output=snyk.json # ← writes snyk.json to disk env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - with: - args: --file=Contentstack.Core/obj/project.assets.json --fail-on=all - json: true - continue-on-error: true + continue-on-error: true # ← let pipeline continue even if vulns found + - uses: contentstack/sca-policy@main diff --git a/.gitignore b/.gitignore index 52c1b1e8..152183fd 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,5 @@ packages/ *.userosscache *.sln.docstates +# Python +Scripts/venv/ \ No newline at end of file diff --git a/Contentstack.Core.Tests/Contentstack.Core.Tests.csproj b/Contentstack.Core.Tests/Contentstack.Core.Tests.csproj index 42960a42..85968f71 100644 --- a/Contentstack.Core.Tests/Contentstack.Core.Tests.csproj +++ b/Contentstack.Core.Tests/Contentstack.Core.Tests.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -27,6 +27,8 @@ + + diff --git a/Contentstack.Core.Tests/Helpers/TestDataHelper.cs b/Contentstack.Core.Tests/Helpers/TestDataHelper.cs index 0813ebca..9499df51 100644 --- a/Contentstack.Core.Tests/Helpers/TestDataHelper.cs +++ b/Contentstack.Core.Tests/Helpers/TestDataHelper.cs @@ -187,16 +187,16 @@ static TestDataHelper() /// /// Gets a required configuration value and throws if not found /// - /// Configuration key + /// Configuration key name /// Configuration value /// Thrown when configuration is missing - private static string GetRequiredConfig(string key) + private static string GetRequiredConfig(string configKey) { - var value = ConfigurationManager.AppSettings[key]; + var value = ConfigurationManager.AppSettings[configKey]; if (string.IsNullOrEmpty(value)) { throw new InvalidOperationException( - $"Required configuration '{key}' is missing from app.config. " + + $"Required configuration '{configKey}' is missing from app.config. " + $"Please ensure all required keys are present in the section."); } return value; @@ -205,12 +205,12 @@ private static string GetRequiredConfig(string key) /// /// Gets an optional configuration value with a default /// - /// Configuration key + /// Configuration key name /// Default value if not found /// Configuration value or default - private static string GetOptionalConfig(string key, string defaultValue = null) + private static string GetOptionalConfig(string configKey, string defaultValue = null) { - return ConfigurationManager.AppSettings[key] ?? defaultValue; + return ConfigurationManager.AppSettings[configKey] ?? defaultValue; } /// diff --git a/Contentstack.Core.Unit.Tests/Contentstack.Core.Unit.Tests.csproj b/Contentstack.Core.Unit.Tests/Contentstack.Core.Unit.Tests.csproj index bb1056f5..a4138b9d 100644 --- a/Contentstack.Core.Unit.Tests/Contentstack.Core.Unit.Tests.csproj +++ b/Contentstack.Core.Unit.Tests/Contentstack.Core.Unit.Tests.csproj @@ -18,6 +18,8 @@ + + diff --git a/Scripts/generate_enhanced_html_report.py b/Scripts/generate_enhanced_html_report.py index 8367b648..d8a3e7d1 100644 --- a/Scripts/generate_enhanced_html_report.py +++ b/Scripts/generate_enhanced_html_report.py @@ -5,10 +5,10 @@ - Expected vs Actual values - HTTP Request details (including cURL) - Response details -No external dependencies - uses only Python standard library +Uses defusedxml for secure XML parsing (XXE/DDoS-safe). """ -import xml.etree.ElementTree as ET +import defusedxml.ElementTree as ET import os import sys import re @@ -158,9 +158,9 @@ def parse_trx(self): test_output = stdout_elem.text structured_output = self.parse_structured_output(test_output) - # Get test category + # Get test category (find by id without dynamic XPath to avoid CWE-643) test_def_id = test_result.get('testId', '') - test_def = root.find(f".//UnitTest[@id='{test_def_id}']", ns) + test_def = next((el for el in root.findall('.//UnitTest', ns) if el.get('id') == test_def_id), None) category = 'General' if test_def is not None: test_method = test_def.find('.//TestMethod', ns) diff --git a/Scripts/generate_html_report.py b/Scripts/generate_html_report.py index ca84a439..de116b13 100644 --- a/Scripts/generate_html_report.py +++ b/Scripts/generate_html_report.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 """ HTML Test Report Generator for .NET Test Results -Converts .trx files to beautiful HTML reports -No external dependencies - uses only Python standard library +Converts .trx files to beautiful HTML reports. +Uses defusedxml for secure XML parsing (XXE/DDoS-safe). """ -import xml.etree.ElementTree as ET +import defusedxml.ElementTree as ET import os import sys from datetime import datetime @@ -78,9 +78,9 @@ def parse_trx(self): if stacktrace_elem is not None: error_stacktrace = stacktrace_elem.text - # Get test category + # Get test category (find by id without dynamic XPath to avoid CWE-643) test_def_id = test_result.get('testId', '') - test_def = root.find(f".//UnitTest[@id='{test_def_id}']", ns) + test_def = next((el for el in root.findall('.//UnitTest', ns) if el.get('id') == test_def_id), None) category = 'General' if test_def is not None: test_method = test_def.find('.//TestMethod', ns) diff --git a/Scripts/requirements.txt b/Scripts/requirements.txt new file mode 100644 index 00000000..377b0d3e --- /dev/null +++ b/Scripts/requirements.txt @@ -0,0 +1,2 @@ +# Secure XML parsing (fixes Snyk CWE-611 Insecure Xml Parser / XXE) +defusedxml>=0.7.1