Skip to content

Feature/web security testing#4281

Merged
Maheshkale447 merged 7 commits into
Releases/Betafrom
Feature/WebSecurityTesting
Aug 25, 2025
Merged

Feature/web security testing#4281
Maheshkale447 merged 7 commits into
Releases/Betafrom
Feature/WebSecurityTesting

Conversation

@AmanPrasad43

@AmanPrasad43 AmanPrasad43 commented Aug 25, 2025

Copy link
Copy Markdown
Contributor

Thank you for your contribution.
Before submitting this PR, please make sure:

  • PR description and commit message should describe the changes done in this PR
  • Verify the PR is pointing to correct branch i.e. Release or Beta branch if the code fix is for specific release , else point it to master
  • Latest Code from master or specific release branch is merged to your branch
  • No unwanted\commented\junk code is included
  • No new warning upon build solution
  • Code Summary\Comments are added to my code which explains what my code is doing
  • Existing unit test cases are passed
  • New Unit tests are added for your development
  • Sanity Tests are successfully executed for New and Existing Functionality
  • Verify that changes are compatible with all relevant browsers and platforms.
  • After creating pull request there should not be any conflicts
  • Resolve all Codacy comments
  • Builds and checks are passed before PR is sent for review
  • Resolve code review comments
  • Update the Help Library document to match any feature changes

Summary by CodeRabbit

  • New Features

    • Integrated OWASP ZAP security testing for web and API (active/passive scans, OpenAPI) with per-scan vulnerability thresholds.
    • New Security Testing action and dedicated edit UI to configure severity and scan type.
    • ZAP Configuration UI (URL/API key) with Test Connection, About info, and added External Configurations menu entry.
    • Drivers and agent UIs allow enabling ZAP and selecting scan options; generated HTML reports are attached to executions.
  • Chores

    • Added ZAP client package, embedded ZAP logo and new icons, and registered ZAP config in solution repository.

@coderabbitai

coderabbitai Bot commented Aug 25, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

Adds OWASP ZAP security testing: new ActSecurityTesting action and edit UI, ZAPConfiguration model and UI, ZapProxyService wrapper, driver integrations (Selenium/WebServices) with proxy toggles, menu/solution bootstrap, image assets, and OWASPZAPDotNetAPI package references.

Changes

Cohort / File(s) Summary of changes
Action UI & Code-behind
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml, Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
New edit page and code-behind for ActSecurityTesting: severity MultiSelect, scan type ComboBox, platform derivation, alert list population, and bindings.
ZAP Configuration Page
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml, Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
New UI page to manage ZAPConfiguration (URL/API key), test connection (async HTTP), encrypt API key, show loader/result messages, and open ZAP docs.
Repository model & bootstrap
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs, Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs, Ginger/GingerCoreNET/GeneralLib/General.cs, Ginger/Ginger/SolutionWindows/AddSolutionPage.xaml.cs
New ZAPConfiguration repository item, registration in solution repo, General.CreateZAPConfiguration helper, and solution creation step to add default ZAP config.
ZAP service & core action
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs, Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
New ZapProxyService wrapper (connect, scans, reports, evaluation) and ActSecurityTesting action implementing active/passive/API scan flows, report generation, and alert summarization.
Driver integrations
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs, Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
Add UseSecurityTesting flags, proxy routing to ZAP when enabled, RunAction/Act handling for ActSecurityTesting, and related helpers (CoerceZapHostPort, proxy setup).
Driver config UIs & bindings
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml, .../WebAgentConfigEditPage.xaml.cs, Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml, .../WebServicesDriverEditPage.xaml.cs
Add "Security Testing Configurations" Expander with enable checkbox; scan type and vulnerability combo boxes; bind to driver params; visibility by driver type; constructor update to accept Agent.
Menus, messages & images
Ginger/Ginger/MenusLib/ConfigurationsMenu.cs, Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs, Ginger/GingerCoreCommon/EnumsLib/eImageType.cs, Ginger/Ginger/UserControlsLib/ImageMakerLib/ImageMakerControl.xaml.cs, Ginger/Ginger/Ginger.csproj
Add ZAP menu entry, new user messages (ZAPConnectionSuccess/Fail), new enum images (Shield, ZAP), ImageMaker mappings, and move ZAPLogo.png to project resources.
Project/package changes
Ginger/GingerCore/GingerCore.csproj, Ginger/GingerCoreNET/GingerCoreNET.csproj, Ginger/Ginger/Ginger.csproj
Add OWASPZAPDotNetAPI package reference (v2.12.0) and adjust project resource entries for ZAP logo.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant UI as ActSecurityTestingEditPage
  participant Runner as Driver (Selenium/WebServices)
  participant Action as ActSecurityTesting
  participant ZAP as ZapProxyService

  User->>UI: Configure scan type & severities
  User->>Runner: Execute flow (run Action)
  Runner->>Action: RunAction(ActSecurityTesting)
  alt ScanType == Active
    Action->>ZAP: ActiveScanAPI(target)
    ZAP-->>Action: Alerts + report
  else ScanType == Passive
    Action->>ZAP: AddUrlToScanTree(target)
    Action->>ZAP: WaitTillPassiveScanCompleted()
    ZAP-->>Action: Alerts summary
  end
  Action->>Runner: Attach report & summary (return params)
  Runner-->>User: Results + artifact
Loading
sequenceDiagram
  autonumber
  participant ConfigUI as ZAPConfigurationPage
  participant Repo as SolutionRepository
  participant ZAPServer as ZAP

  ConfigUI->>Repo: Load or Create ZAPConfiguration
  ConfigUI->>ZAPServer: GET /JSON/core/view/version?apikey=...
  alt response contains "version"
    ZAPServer-->>ConfigUI: JSON version
    ConfigUI->>User: Show success (ZAPConnectionSuccess)
  else
    ZAPServer-->>ConfigUI: Error / no version
    ConfigUI->>User: Show failure (ZAPConnectionFail)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • Maheshkale447

Poem

A whisker twitches, I scout the gap,
I hum a zap and mend the trap.
Shield on my back, report in paw,
Bugs flee fast — I clap, I awe.
Hop, hop, secure — carrot cheers! 🥕🛡️

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5ba459c and efc867b.

📒 Files selected for processing (2)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (7 hunks)
  • Ginger/GingerCoreNET/GeneralLib/General.cs (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Feature/WebSecurityTesting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 68

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Ginger/GingerCoreNET/GeneralLib/General.cs (1)

1342-1351: Avoid POST when token is invalid (unless explicit URL override is provided)

If bearerToken is null/empty and no url override is supplied, we still proceed to POST without auth. Short-circuit to reduce noisy requests and clearer flow.

Apply this diff:

-                    if (!string.IsNullOrEmpty(bearerToken))
-                    {
-                        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
-                    }
-                    else
-                    {
-                        Reporter.ToLog(eLogLevel.DEBUG, $"Response: Invalid token");
-                        Response = $"Response: Invalid token";
-                    }
+                    if (!string.IsNullOrEmpty(bearerToken))
+                    {
+                        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
+                    }
+                    else if (string.IsNullOrEmpty(url))
+                    {
+                        Reporter.ToLog(eLogLevel.DEBUG, "Response: Invalid token");
+                        return "Response: Invalid token";
+                    }
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (1)

355-355: C# 12 collection expression for Artifacts requires language version check

act.Artifacts = [] uses collection expressions. Verify the project’s LangVersion is set accordingly; otherwise switch to new ObservableList().

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 410f40a and f171909.

⛔ Files ignored due to path filters (1)
  • Ginger/Ginger/UserControlsLib/ImageMakerLib/Images/ZAPLogo.png is excluded by !**/*.png, !**/*.png
📒 Files selected for processing (23)
  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml (1 hunks)
  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (1 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml (1 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs (4 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml (2 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs (3 hunks)
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml (1 hunks)
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1 hunks)
  • Ginger/Ginger/Ginger.csproj (3 hunks)
  • Ginger/Ginger/MenusLib/ConfigurationsMenu.cs (2 hunks)
  • Ginger/Ginger/SolutionWindows/AddSolutionPage.xaml.cs (1 hunks)
  • Ginger/Ginger/UserControlsLib/ImageMakerLib/ImageMakerControl.xaml.cs (2 hunks)
  • Ginger/GingerCore/GingerCore.csproj (1 hunks)
  • Ginger/GingerCoreCommon/EnumsLib/eImageType.cs (2 hunks)
  • Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1 hunks)
  • Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs (2 hunks)
  • Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1 hunks)
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (1 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (8 hunks)
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (6 hunks)
  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (1 hunks)
  • Ginger/GingerCoreNET/GeneralLib/General.cs (3 hunks)
  • Ginger/GingerCoreNET/GingerCoreNET.csproj (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-02-14T07:02:48.416Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4100
File: Ginger/Ginger/ApplicationModelsLib/APIModels/APIModelWizard/AddAPIModelExtraConfigsPage.xaml:28-30
Timestamp: 2025-02-14T07:02:48.416Z
Learning: In AddAPIModelExtraConfigsPage.xaml, the WireMock mapping checkbox (xWireMockMappingToggle) is initially disabled and only gets enabled after successful validation of WireMock configuration and connection test in the CheckWireMockConfiguration method.

Applied to files:

  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs
📚 Learning: 2025-01-21T11:43:12.379Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4067
File: Ginger/GingerCoreCommon/Repository/SolutionRepository.cs:55-55
Timestamp: 2025-01-21T11:43:12.379Z
Learning: In Ginger's SolutionRepository, the path @"ExecutionResults\GingerExecutionResults.db" needs to be explicitly excluded in mSolutionPathsToAvoid list, even though its parent directory @"ExecutionResults\" is also excluded. This specific file exclusion serves a distinct purpose and should not be considered redundant.

Applied to files:

  • Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs
📚 Learning: 2025-06-16T10:37:13.073Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4232
File: Ginger/GingerCoreNET/ActionsLib/UI/VisualTesting/VRTAnalyzer.cs:19-22
Timestamp: 2025-06-16T10:37:13.073Z
Learning: In Ginger codebase, both `using amdocs.ginger.GingerCoreNET;` and `using Amdocs.Ginger.CoreNET;` are valid and serve different purposes. The first (lowercase) contains the WorkSpace class and related workspace functionality, while the second (proper case) contains drivers like GenericAppiumDriver and other core functionality. Both may be required in files that use types from both namespaces.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-04-25T13:29:45.059Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4188
File: Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs:22-23
Timestamp: 2025-04-25T13:29:45.059Z
Learning: The `using Amdocs.Ginger.Repository;` statement in Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs is necessary as it provides access to the `ObservableList<>` class which is used throughout the file for collections of RunSetConfig, AnalyzerItemBase, and ApplicationPOMModel objects.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-04-25T13:29:45.059Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4188
File: Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs:22-23
Timestamp: 2025-04-25T13:29:45.059Z
Learning: The `using Amdocs.Ginger.Repository;` statement in Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs is necessary as it imports the ObservableList<> class which is used throughout the file.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-03-20T11:10:30.816Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4137
File: Ginger/Ginger/SourceControl/SourceControlProjectsPage.xaml.cs:21-21
Timestamp: 2025-03-20T11:10:30.816Z
Learning: The `Amdocs.Ginger.Common.SourceControlLib` namespace is required in files that reference the `GingerSolution` class for source control operations in the Ginger automation framework.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-06-16T09:52:40.873Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4232
File: Ginger/GingerCoreNET/ActionsLib/UI/VisualTesting/VRTAnalyzer.cs:19-22
Timestamp: 2025-06-16T09:52:40.873Z
Learning: The `GenericAppiumDriver` class is located in the `Amdocs.Ginger.CoreNET` namespace, not in a namespace that matches its file path structure. File paths don't always correspond to namespace declarations in this codebase.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
🧬 Code graph analysis (12)
Ginger/Ginger/SolutionWindows/AddSolutionPage.xaml.cs (1)
Ginger/GingerCoreNET/GeneralLib/General.cs (2)
  • General (57-1389)
  • CreateZAPConfiguration (794-814)
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs (2)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1)
  • Init (43-49)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (5)
  • SeleniumDriver (83-11838)
  • SeleniumDriver (470-473)
  • SeleniumDriver (475-481)
  • SeleniumDriver (483-486)
  • SeleniumDriver (488-491)
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs (3)
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (2)
  • WebServicesDriver (47-1031)
  • WebServicesDriver (223-226)
Ginger/GingerCore/GeneralLib/InputBoxWindow.xaml.cs (1)
  • ObjFieldBinding (147-157)
Ginger/GingerCore/GeneralLib/General.cs (2)
  • FillComboFromEnumType (212-248)
  • FillComboItemsFromEnumType (250-266)
Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (2)
Ginger/GingerCoreCommon/Repository/SolutionRepository.cs (1)
  • AddItemInfo (514-527)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/GeneralLib/General.cs (4)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1)
  • SolutionRepository (37-78)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (4)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/GingerCoreNET/ValueExpressionLib/ValueExpression.cs (2)
  • PasswordCalculation (2039-2064)
  • IsThisAValueExpression (702-734)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1)
  • SolutionRepository (37-78)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (3)
  • ActSecurityTesting (41-414)
  • ExecuteActiveZapScan (214-271)
  • ExecutePassiveZapScan (273-316)
Ginger/Ginger/MenusLib/ConfigurationsMenu.cs (1)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (2)
  • ZAPConfigurationPage (35-166)
  • ZAPConfigurationPage (38-42)
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (2)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1)
  • Task (131-159)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (2)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (2)
  • ActSecurityTesting (41-414)
  • Fields (43-48)
Ginger/GingerCore/GeneralLib/General.cs (1)
  • FillComboFromEnumType (212-248)
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (5)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Actions/Act.cs (3)
  • GetInputParamValue (853-863)
  • GetInputParamValue (976-981)
  • Fields (99-143)
Ginger/GingerCoreCommon/Actions/Webservices/ActWebAPIBase.cs (3)
  • ActWebAPIBase (37-408)
  • ActWebAPIBase (39-43)
  • Fields (71-94)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (4)
  • Fields (43-48)
  • ActSecurityTesting (41-414)
  • ExecutePassiveZapScan (273-316)
  • ExecuteApiSecurityTestWithOpenApi (318-371)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (4)
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (11)
  • List (200-205)
  • List (286-302)
  • ZapProxyService (12-304)
  • ZapProxyService (18-30)
  • IsZapRunningAsync (36-49)
  • AddUrlToScanTree (182-194)
  • PerformActiveScan (211-225)
  • EvaluateScanResult (254-276)
  • EvaluateScanResult (278-284)
  • ActiveScanAPI (247-253)
  • GenerateZapReport (70-84)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Actions/Act.cs (3)
  • AddArtifactToAction (1122-1136)
  • AddOrUpdateReturnParamActual (1308-1335)
  • AddOrUpdateReturnParamActualWithPath (1359-1387)
🔇 Additional comments (11)
Ginger/GingerCoreNET/GingerCoreNET.csproj (1)

330-330: OWASP ZAP client dependency verified
OWASPZAPDotNetAPI 2.12.0 declares no transitive RestSharp dependency, so there’s no runtime mismatch with the pinned RestSharp 112.0.0.

• The package metadata returned no dependencies when queried via NuGet’s registration API, confirming you need not adjust RestSharp here.
• The central package management suggestion still stands as an optional refactor if you’d like to keep OWASPZAPDotNetAPI versions in sync across multiple projects.

Ginger/GingerCoreCommon/EnumsLib/eImageType.cs (1)

371-371: Review comment not applicable: eImageType isn’t persisted anywhere

I’ve audited all usages of eImageType for serialization or persistence markers (e.g. DataMember, JsonConverter, XmlElement, custom [IsSerializedForLocalRepository] attributes) and found none. Every occurrence is limited to UI rendering (icons in menus, controls, etc.) and not written to XML/JSON/DB. Therefore inserting Shield mid-stream won’t break any stored values or app-boundary contracts. You can safely keep the new member where it was added.

Likely an incorrect or invalid review comment.

Ginger/Ginger/Ginger.csproj (2)

644-645: Resource reclassification: removing ZAPLogo.png from None is correct.

Good call to exclude ZAPLogo.png from None items before adding it as a WPF Resource to prevent duplicate item conflicts.


2582-2584: Unable to Locate ZAPLogo.png Resource

I ran several searches (case-insensitive file lookups and grepping the .csproj) and found no occurrences of “ZAPLogo.png” in the repo. Before approving, please:

  • Confirm that UserControlsLib/ImageMakerLib/Images/ZAPLogo.png actually exists on disk and is added to source control.
  • Verify that the <Resource Include="…ZAPLogo.png"> path in Ginger/Ginger/Ginger.csproj matches the file’s relative path.
  • Ensure there are no typos in the filename or folder names (e.g., casing, underscores).

Once the resource’s presence and path are validated, we can safely embed it as a WPF pack URI.

Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs (1)

193-194: ZAP user message keys added — OK

Enum entries are well placed alongside other connection keys and follow existing naming. No functional concerns.

Ginger/Ginger/MenusLib/ConfigurationsMenu.cs (1)

97-98: All ZAP menu entry dependencies validated

I’ve confirmed that the new ZAP menu integration is fully wired and ready:

  • eImageType.ZAP is defined and mapped to “ZAPLogo.png” in ImageMakerControl.xaml.cs (lines 218–222).
  • The ZAPConfigurationPage class exists as public partial class ZAPConfigurationPage : GingerUIPage.
  • GetZAPConfigPage() is implemented in ConfigurationsMenu.cs and returns new ZAPConfigurationPage().
  • ZAPConfiguration repository item class is present in GingerCoreCommon/External/Configurations/ZAPConfiguration.cs.
  • The OWASPZAPDotNetAPI NuGet package (v2.12.0) is referenced in GingerCoreNET.csproj, Ginger.csproj, and other relevant projects.

Everything checks out—no missing assets or references.

Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs (1)

50-50: No action needed

InitializeComponent movement/annotation looks fine.

Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1)

75-75: ZAPConfiguration registration — LGTM

Repository mapping looks correct (pattern, folder, file-name property). This will enable persistence under Configurations/ZAPConfiguration as intended.

Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (3)

22-22: Import looks correct for ZAP config usage

The added using for Amdocs.Ginger.Common.External.Configurations is needed for ZAPConfiguration and aligns with prior learnings about mixed namespaces in this codebase.


1948-1951: Driver action dispatch updated to include security testing — looks good

Wiring ActSecurityTesting into the action switch keeps the driver cohesive with other UI/Web actions.


7152-7152: Non-functional change

Whitespace-only tweak. No action needed.

Comment on lines +1 to +9
<Page x:Class="Ginger.Actions.ActSecurityTestingEditPage" xmlns:Actions="clr-namespace:Ginger.Actions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:UserControlsLib="clr-namespace:Ginger.UserControlsLib" xmlns:Ginger="clr-namespace:Ginger" xmlns:usercontrols="clr-namespace:Amdocs.Ginger.UserControls"
mc:Ignorable="d"
xmlns:Activities="clr-namespace:Ginger.BusinessFlowWindows"
d:DesignHeight="400" d:DesignWidth="800"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Remove unused XML namespaces to reduce noise

The following namespaces appear unused in this XAML: Actions, Ginger, usercontrols, Activities.

Apply this diff:

-<Page x:Class="Ginger.Actions.ActSecurityTestingEditPage" xmlns:Actions="clr-namespace:Ginger.Actions"
-      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-      xmlns:UserControlsLib="clr-namespace:Ginger.UserControlsLib" xmlns:Ginger="clr-namespace:Ginger" xmlns:usercontrols="clr-namespace:Amdocs.Ginger.UserControls"
-      mc:Ignorable="d" 
-            xmlns:Activities="clr-namespace:Ginger.BusinessFlowWindows"
-      d:DesignHeight="400" d:DesignWidth="800"
+<Page x:Class="Ginger.Actions.ActSecurityTestingEditPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+      xmlns:UserControlsLib="clr-namespace:Ginger.UserControlsLib"
+      mc:Ignorable="d"
+      d:DesignHeight="400" d:DesignWidth="800"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Page x:Class="Ginger.Actions.ActSecurityTestingEditPage" xmlns:Actions="clr-namespace:Ginger.Actions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:UserControlsLib="clr-namespace:Ginger.UserControlsLib" xmlns:Ginger="clr-namespace:Ginger" xmlns:usercontrols="clr-namespace:Amdocs.Ginger.UserControls"
mc:Ignorable="d"
xmlns:Activities="clr-namespace:Ginger.BusinessFlowWindows"
d:DesignHeight="400" d:DesignWidth="800"
<Page x:Class="Ginger.Actions.ActSecurityTestingEditPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:UserControlsLib="clr-namespace:Ginger.UserControlsLib"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="800"
🤖 Prompt for AI Agents
In Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml around
lines 1 to 9, the XAML declares unused XML namespaces (Actions, Ginger,
usercontrols, Activities); remove those unused xmlns attributes from the Page
tag so only the required namespaces remain (keep default presentation, x, mc, d,
UserControlsLib if used) to reduce noise and potential confusion.

Comment on lines +27 to +30
<StackPanel Orientation="Horizontal" Height="100" DockPanel.Dock="Top" Margin="15,0,10,250">
<Label Style="{StaticResource $LabelStyle}" Width="140" Height="32" Content="Operation Type :"/>
<ComboBox x:Name="xScanTypeComboBox" Width="Auto" Style="{StaticResource $FlatInputComboBoxStyle}" SelectionChanged="xScanTypeComboBox_SelectionChanged"/>
</StackPanel>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Avoid fixed heights and large margins; let layout flow

Height="100" and Margin="15,0,10,250" will cause unnecessary whitespace and truncation on different DPI/scales. Prefer natural sizing with minimal margins.

Apply this diff:

-            <StackPanel Orientation="Horizontal" Height="100" DockPanel.Dock="Top" Margin="15,0,10,250">
+            <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="15,8,10,8">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<StackPanel Orientation="Horizontal" Height="100" DockPanel.Dock="Top" Margin="15,0,10,250">
<Label Style="{StaticResource $LabelStyle}" Width="140" Height="32" Content="Operation Type :"/>
<ComboBox x:Name="xScanTypeComboBox" Width="Auto" Style="{StaticResource $FlatInputComboBoxStyle}" SelectionChanged="xScanTypeComboBox_SelectionChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="15,8,10,8">
<Label Style="{StaticResource $LabelStyle}" Width="140" Height="32" Content="Operation Type :"/>
<ComboBox x:Name="xScanTypeComboBox" Width="Auto" Style="{StaticResource $FlatInputComboBoxStyle}" SelectionChanged="xScanTypeComboBox_SelectionChanged"/>
</StackPanel>
🤖 Prompt for AI Agents
In Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml around
lines 27–30, remove the hard-coded Height="100" and the large bottom margin
Margin="15,0,10,250" so the layout can size naturally; replace them with no
Height (allow Auto sizing), a minimal margin such as Margin="15,0,10,0" or use
Padding, and set VerticalAlignment="Top" and HorizontalAlignment/Width on the
ComboBox to allow it to stretch (or convert the StackPanel to a Grid with
columns if you need the label and combobox to resize proportionally) so the
control does not create excessive whitespace or truncate on different
DPI/scales.

Comment on lines +64 to +67
GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
xScanTypeComboBox.Text = GingerCore.General.GetEnumValueDescription(typeof(eScanType), eScanType.Active);
GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix ComboBox defaulting and binding: set SelectedValue, not Text

FillComboFromEnumType sets SelectedValuePath="Value" with enum values. Assign SelectedValue to an enum, not Text, to correctly select the item and cooperate with the SelectedValue binding.

-            GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
-            xScanTypeComboBox.Text = GingerCore.General.GetEnumValueDescription(typeof(eScanType), eScanType.Active);
-            GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);
+            GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
+            xScanTypeComboBox.SelectedValue = mAct.ScanType; // defaults to Active if unset
+            GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
xScanTypeComboBox.Text = GingerCore.General.GetEnumValueDescription(typeof(eScanType), eScanType.Active);
GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);
GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
xScanTypeComboBox.SelectedValue = mAct.ScanType; // defaults to Active if unset
GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);
🤖 Prompt for AI Agents
In Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
around lines 64-67, the code sets xScanTypeComboBox.Text to select the default
enum item while the combo is populated with SelectedValuePath="Value" and bound
to SelectedValue; change the code to assign the enum to the
ComboBox.SelectedValue (e.g., xScanTypeComboBox.SelectedValue =
eScanType.Active) so the default selection and the SelectedValue binding work
correctly.

Comment thread Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
Comment thread Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/GeneralLib/General.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review continued from previous batch...

Comment thread Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml
Comment on lines +40 to +46
<Activities:UCValueExpression x:Name="xZAPURLTextBox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="GingerOps Account URL" Margin="10,0,0,0" Width="400"/>

<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="3">
<Label x:Name="xZAPAPIkeyLabel" Content="ZAP API KEY:" Style="{StaticResource @InputFieldLabelStyle}" VerticalAlignment="Center" FontSize="12"/>
<Label x:Name="xZAPAPIkeyValidation" Content="*" Style="{StaticResource @InputFieldLabelStyle}" VerticalAlignment="Center" Foreground="Red" FontWeight="Bold" FontSize="12"/>
</StackPanel>
<Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Client Secret" Margin="10,0,0,0" Width="400" LostKeyboardFocus="xZAPAPIkeyTextBox_LostKeyboardFocus"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Correct misleading tooltips

  • ZAP URL tooltip says “GingerOps Account URL”.
  • API key tooltip says “Client Secret”.

Use accurate wording to reduce user confusion.

-<Activities:UCValueExpression x:Name="xZAPURLTextBox" ... ToolTip="GingerOps Account URL" .../>
+<Activities:UCValueExpression x:Name="xZAPURLTextBox" ... ToolTip="ZAP API URL (e.g., http://127.0.0.1:8080)" .../>

-<Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" ... ToolTip="Client Secret" .../>
+<Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" ... ToolTip="ZAP API Key" .../>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Activities:UCValueExpression x:Name="xZAPURLTextBox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="GingerOps Account URL" Margin="10,0,0,0" Width="400"/>
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="3">
<Label x:Name="xZAPAPIkeyLabel" Content="ZAP API KEY:" Style="{StaticResource @InputFieldLabelStyle}" VerticalAlignment="Center" FontSize="12"/>
<Label x:Name="xZAPAPIkeyValidation" Content="*" Style="{StaticResource @InputFieldLabelStyle}" VerticalAlignment="Center" Foreground="Red" FontWeight="Bold" FontSize="12"/>
</StackPanel>
<Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Client Secret" Margin="10,0,0,0" Width="400" LostKeyboardFocus="xZAPAPIkeyTextBox_LostKeyboardFocus"/>
<!-- ZAP API URL input -->
<Activities:UCValueExpression
x:Name="xZAPURLTextBox"
Grid.Column="1"
Grid.Row="0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
ToolTip="ZAP API URL (e.g., http://127.0.0.1:8080)"
Margin="10,0,0,0"
Width="400"/>
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="3">
<Label
x:Name="xZAPAPIkeyLabel"
Content="ZAP API KEY:"
Style="{StaticResource @InputFieldLabelStyle}"
VerticalAlignment="Center"
FontSize="12"/>
<Label
x:Name="xZAPAPIkeyValidation"
Content="*"
Style="{StaticResource @InputFieldLabelStyle}"
VerticalAlignment="Center"
Foreground="Red"
FontWeight="Bold"
FontSize="12"/>
</StackPanel>
<!-- ZAP API key input -->
<Activities:UCValueExpression
x:Name="xZAPAPIkeyTextBox"
Grid.Column="1"
Grid.Row="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
ToolTip="ZAP API Key"
Margin="10,0,0,0"
Width="400"
LostKeyboardFocus="xZAPAPIkeyTextBox_LostKeyboardFocus"/>
🤖 Prompt for AI Agents
In Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml around lines
40 to 46 the ToolTip texts are misleading: change the xZAPURLTextBox ToolTip
from "GingerOps Account URL" to a clear ZAP-related label (e.g., "ZAP URL" or
"ZAP application URL") and change the xZAPAPIkeyTextBox ToolTip from "Client
Secret" to "ZAP API Key" (or "ZAP API key for authentication"); update only the
ToolTip attribute values to accurate wording and keep existing names, layout and
event handlers unchanged.

</Grid>
<Grid>
<usercontrols:ucButton x:Name="xTestConBtn" IsEnabled="True" DockPanel.Dock="Top" HorizontalAlignment="Left" Margin="10,25,0,0" ButtonType="RoundTextAndImageButton" ButtonText="Test Connection" ButtonImageType="Run" ButtonFontImageSize="12" ButtonImageWidth="12" ButtonImageHeight="12" Click="xTestConBtn_Click" ButtonStyle="{StaticResource $RoundTextAndImageButtonStyle}" ToolTip="Test ZAP Connection"/>
<usercontrols:ImageMakerControl x:Name="xProcessingImage" ImageType="Processing" Margin="187,28,0,3" HorizontalAlignment="Left" Height="25" Width="20" Visibility="Collapsed"></usercontrols:ImageMakerControl>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use consistent visibility state for the loader (Collapsed vs Hidden)

Initial XAML uses Collapsed; HideLoader switches to Hidden, leaving empty space. Use Collapsed for both to avoid layout jitter.

- xProcessingImage.Visibility = Visibility.Hidden;
+ xProcessingImage.Visibility = Visibility.Collapsed;

Also applies to: 107-121

🤖 Prompt for AI Agents
In Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml around line 50
(and also lines 107-121), the loader ImageMakerControl is initially set to
Visibility="Collapsed" but the HideLoader logic sets Visibility="Hidden",
causing layout space to remain; change the hide logic so the loader is set to
Visibility="Collapsed" (use Collapsed consistently for hiding) and audit/update
any other show/hide calls for these controls in the file to use Collapsed when
hiding to prevent layout jitter.

Comment on lines +72 to +93
<TextBlock x:Name="xZapInfo" TextWrapping="Wrap" Width="581" Height="250" Padding="10,5,5,5" HorizontalAlignment="Left">
Zed Attack Proxy (ZAP) by Checkmarx is a free, open-source penetration testing tool. ZAP is
designed specifically for testing web applications and is both flexible and extensible.
At its core, ZAP is what is known as a “manipulator-in-the-middle proxy.” It stands between
the tester’s browser and the web application so that it can intercept and inspect messages
sent between browser and web application, modify the contents if needed.

<LineBreak/>
<Bold>- Passive Scan:</Bold> ZAP automatically analyzes all traffic passing through the proxy without altering requests or responses. It looks for vulnerabilities in a non-intrusive way, ensuring no impact on the target application.
<LineBreak/>
<Bold>- Active Scan:</Bold> ZAP actively interacts with the target application by sending additional requests to discover vulnerabilities. This scan is more intrusive and can potentially affect the application.

<LineBreak/>
<Bold>Alerts:</Bold>
ZAP generates alerts when it detects potential security issues during scanning. Each alert provides details about the vulnerability, its risk level, and recommendations for remediation.

<LineBreak/>
<Hyperlink NavigateUri="https://www.zaproxy.org/" RequestNavigate="Hyperlink_RequestNavigate">
Learn more about ZAP
</Hyperlink>
</TextBlock>
</Expander.Content>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct attribution and phrasing in “About ZAP” text

ZAP is an OWASP project, not by Checkmarx. Also, “manipulator-in-the-middle” is unusual phrasing here. Please fix to avoid misinformation.

- Zed Attack Proxy (ZAP) by Checkmarx is a free, open-source penetration testing tool.
+ Zed Attack Proxy (ZAP) by the OWASP community is a free, open-source penetration testing tool.
- At its core, ZAP is what is known as a “manipulator-in-the-middle proxy.”
+ At its core, ZAP is a “man-in-the-middle” proxy.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TextBlock x:Name="xZapInfo" TextWrapping="Wrap" Width="581" Height="250" Padding="10,5,5,5" HorizontalAlignment="Left">
Zed Attack Proxy (ZAP) by Checkmarx is a free, open-source penetration testing tool. ZAP is
designed specifically for testing web applications and is both flexible and extensible.
At its core, ZAP is what is known as a “manipulator-in-the-middle proxy.” It stands between
the tester’s browser and the web application so that it can intercept and inspect messages
sent between browser and web application, modify the contents if needed.
<LineBreak/>
<Bold>- Passive Scan:</Bold> ZAP automatically analyzes all traffic passing through the proxy without altering requests or responses. It looks for vulnerabilities in a non-intrusive way, ensuring no impact on the target application.
<LineBreak/>
<Bold>- Active Scan:</Bold> ZAP actively interacts with the target application by sending additional requests to discover vulnerabilities. This scan is more intrusive and can potentially affect the application.
<LineBreak/>
<Bold>Alerts:</Bold>
ZAP generates alerts when it detects potential security issues during scanning. Each alert provides details about the vulnerability, its risk level, and recommendations for remediation.
<LineBreak/>
<Hyperlink NavigateUri="https://www.zaproxy.org/" RequestNavigate="Hyperlink_RequestNavigate">
Learn more about ZAP
</Hyperlink>
</TextBlock>
</Expander.Content>
<TextBlock x:Name="xZapInfo" TextWrapping="Wrap" Width="581" Height="250" Padding="10,5,5,5" HorizontalAlignment="Left">
Zed Attack Proxy (ZAP) by the OWASP community is a free, open-source penetration testing tool. ZAP is
designed specifically for testing web applications and is both flexible and extensible.
At its core, ZAP is a “man-in-the-middle” proxy. It stands between
the tester’s browser and the web application so that it can intercept and inspect messages
sent between browser and web application, modify the contents if needed.
<LineBreak/>
<Bold>- Passive Scan:</Bold> ZAP automatically analyzes all traffic passing through the proxy without altering requests or responses. It looks for vulnerabilities in a non-intrusive way, ensuring no impact on the target application.
<LineBreak/>
<Bold>- Active Scan:</Bold> ZAP actively interacts with the target application by sending additional requests to discover vulnerabilities. This scan is more intrusive and can potentially affect the application.
<LineBreak/>
<Bold>Alerts:</Bold>
ZAP generates alerts when it detects potential security issues during scanning. Each alert provides details about the vulnerability, its risk level, and recommendations for remediation.
<LineBreak/>
<Hyperlink NavigateUri="https://www.zaproxy.org/" RequestNavigate="Hyperlink_RequestNavigate">
Learn more about ZAP
</Hyperlink>
</TextBlock>
🤖 Prompt for AI Agents
In Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml around lines
72 to 93, the “About ZAP” text incorrectly attributes ZAP to Checkmarx and uses
the unusual phrase “manipulator-in-the-middle”; update the copy to correctly
attribute ZAP to the OWASP project (e.g., “Zed Attack Proxy (ZAP) is an
open-source project by OWASP”) and replace “manipulator-in-the-middle proxy”
with clearer phrasing such as “intercepting (man-in-the-middle) proxy” or
“man-in-the-middle proxy that intercepts and inspects traffic,” keeping the rest
of the informational content, line breaks, and hyperlink intact.

Comment on lines +61 to +66
private void ApplyValidationRules()
{
// check if fields have been populated (font-end validation)
xZAPAPIkeyTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP URL cannot be empty"));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validation rule added to wrong control and with incorrect message

You add a required-field rule to the API key textbox but the message says “ZAP URL cannot be empty”. Add proper validation for both URL and API key with correct messages.

 private void ApplyValidationRules()
 {
-    // check if fields have been populated (font-end validation)
-    xZAPAPIkeyTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP URL cannot be empty"));
+    // basic front-end validation
+    xZAPURLTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP URL cannot be empty"));
+    xZAPAPIkeyTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP API Key cannot be empty"));
 }
🤖 Prompt for AI Agents
In Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs around
lines 61–66, the required-field validation was added to the API key textbox with
the wrong message; move/add validation so the URL textbox gets the ZAP URL
validations and the API key textbox gets the API key validation: add a
ValidateEmptyValue on xZAPAPIkeyTextBox.ValueTextBox with message "ZAP API key
cannot be empty", and on xZAPURLTextBox.ValueTextBox add ValidateEmptyValue with
message "ZAP URL cannot be empty" plus a URL-format validation (e.g., a
ValidateUrl/regex rule) that emits "ZAP URL is not a valid URL". Ensure each
validation is attached to the correct control and uses the exact messages above.

Comment on lines +86 to +132
/// <summary>
/// Extracts the port number from a given URL or host:port string.
/// Returns null if no port is specified or if parsing fails.
/// </summary>
/// <param name="url">The URL or host:port string.</param>
/// <returns>The port number as string, or null if not found.</returns>
public static int? GetPortFromUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return null;
}

try
{
// Try to parse as Uri
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
if (uri.IsDefaultPort)
{
return null;
}
// Return port if it's not the default port (80 for HTTP, 443 for HTTPS)
return uri.Port;
}
// If not a full URL, try host:port
var parts = url.Split(':');
if (parts.Length == 2 && int.TryParse(parts[1], out int port))
{
return port;
}
// IPv6 [::1]:8080
if (url.StartsWith("[") && url.Contains("]:"))
{
int idx = url.LastIndexOf("]:");
if (idx > 0 && int.TryParse(url.Substring(idx + 2), out port))
{
return port;
}
}
}
catch
{
// Ignore and return null
}
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

XML docs mismatch and minor parsing issues in GetPortFromUrl

Comment says “as string” but method returns int?. Also consider trimming and handling whitespace.

- /// <returns>The port number as string, or null if not found.</returns>
+ /// <returns>The port number, or null if not found.</returns>

Optionally:

- var parts = url.Split(':');
+ var parts = url.Trim().Split(':');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// <summary>
/// Extracts the port number from a given URL or host:port string.
/// Returns null if no port is specified or if parsing fails.
/// </summary>
/// <param name="url">The URL or host:port string.</param>
/// <returns>The port number as string, or null if not found.</returns>
public static int? GetPortFromUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return null;
}
try
{
// Try to parse as Uri
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
if (uri.IsDefaultPort)
{
return null;
}
// Return port if it's not the default port (80 for HTTP, 443 for HTTPS)
return uri.Port;
}
// If not a full URL, try host:port
var parts = url.Split(':');
if (parts.Length == 2 && int.TryParse(parts[1], out int port))
{
return port;
}
// IPv6 [::1]:8080
if (url.StartsWith("[") && url.Contains("]:"))
{
int idx = url.LastIndexOf("]:");
if (idx > 0 && int.TryParse(url.Substring(idx + 2), out port))
{
return port;
}
}
}
catch
{
// Ignore and return null
}
return null;
}
/// <summary>
/// Extracts the port number from a given URL or host:port string.
/// Returns null if no port is specified or if parsing fails.
/// </summary>
/// <param name="url">The URL or host:port string.</param>
/// <returns>The port number, or null if not found.</returns>
public static int? GetPortFromUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return null;
}
try
{
// Try to parse as Uri
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
if (uri.IsDefaultPort)
{
return null;
}
// Return port if it's not the default port (80 for HTTP, 443 for HTTPS)
return uri.Port;
}
// If not a full URL, try host:port
var parts = url.Trim().Split(':');
if (parts.Length == 2 && int.TryParse(parts[1], out int port))
{
return port;
}
// IPv6 [::1]:8080
if (url.StartsWith("[") && url.Contains("]:"))
{
int idx = url.LastIndexOf("]:");
if (idx > 0 && int.TryParse(url.Substring(idx + 2), out port))
{
return port;
}
}
}
catch
{
// Ignore and return null
}
return null;
}

Comment on lines +139 to +175
public static string GetHostFromUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
return null;

try
{
// Try to parse as Uri
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
return uri.Host;
}
// If not a full URL, try host:port
// IPv6 [::1]:8080
if (url.StartsWith("[") && url.Contains("]:"))
{
int idx = url.LastIndexOf("]:");
if (idx > 0)
{
return url.Substring(0, idx + 1);
}
}
// host:port
var parts = url.Split(':');
if (parts.Length == 2 && int.TryParse(parts[1], out _))
{
return parts[0];
}
// Just host
return url;
}
catch
{
// Ignore and return null
}
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Align GetHostFromUrl XML docs and IPv6 handling

Document return type accurately; keep consistent URI parsing.

- /// <returns>The host as string, or null if not found.</returns>
+ /// <returns>The host name, or null if not found.</returns>
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 139-175,
update the XML docs to accurately state the method returns either the host
string (without port) or null on failure, and adjust the IPv6 and host:port
parsing to be robust: keep the Uri.TryCreate branch, keep the IPv6 detection
returning the bracketed address (use the current Substring(0, idx+1) semantics
to include the closing ']'), and replace the simplistic url.Split(':') logic
with finding the last ':' (LastIndexOf) for non-IPv6 inputs so you correctly
strip a trailing :port without breaking hosts that contain multiple colons;
ensure the method returns the trimmed host or null and document that behavior in
the XML comments.

Comment on lines +231 to +245
private void WaitTillActiveScanIsCompleted(string scanId)
{
var apiResponse = _zapClient.ascan.status(scanId);
string status = ((ApiResponseElement)apiResponse).Value;

while (!status.Equals("100"))
{
Thread.Sleep(1000);
apiResponse = _zapClient.ascan.status(scanId);
status = ((ApiResponseElement)apiResponse).Value;
Reporter.ToLog(eLogLevel.INFO, "Active scan is in progress");
}

Reporter.ToLog(eLogLevel.INFO, "Active scan has completed");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Active scan wait loop blocks thread and lacks progress detail

Use Task.Delay or at least log progress percentage.

- while (!status.Equals("100"))
+ while (!status.Equals("100"))
 {
-    Thread.Sleep(1000);
+    Thread.Sleep(1000);
     apiResponse = _zapClient.ascan.status(scanId);
     status = ((ApiResponseElement)apiResponse).Value;
-    Reporter.ToLog(eLogLevel.INFO, "Active scan is in progress");
+    Reporter.ToLog(eLogLevel.INFO, $"Active scan is in progress: {status}%");
 }

If you switch to async, replace Sleep with await Task.Delay.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void WaitTillActiveScanIsCompleted(string scanId)
{
var apiResponse = _zapClient.ascan.status(scanId);
string status = ((ApiResponseElement)apiResponse).Value;
while (!status.Equals("100"))
{
Thread.Sleep(1000);
apiResponse = _zapClient.ascan.status(scanId);
status = ((ApiResponseElement)apiResponse).Value;
Reporter.ToLog(eLogLevel.INFO, "Active scan is in progress");
}
Reporter.ToLog(eLogLevel.INFO, "Active scan has completed");
}
private void WaitTillActiveScanIsCompleted(string scanId)
{
var apiResponse = _zapClient.ascan.status(scanId);
string status = ((ApiResponseElement)apiResponse).Value;
while (!status.Equals("100"))
{
Thread.Sleep(1000);
apiResponse = _zapClient.ascan.status(scanId);
status = ((ApiResponseElement)apiResponse).Value;
Reporter.ToLog(eLogLevel.INFO, $"Active scan is in progress: {status}%");
}
Reporter.ToLog(eLogLevel.INFO, "Active scan has completed");
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 231 to 245,
the WaitTillActiveScanIsCompleted method blocks the thread with Thread.Sleep and
only logs a generic "in progress" message; change the method to be async (Task)
so it can await non-blocking delays, replace Thread.Sleep(1000) with await
Task.Delay(1000), and include the scan progress percentage in the log by reading
and logging the status value (e.g., "Active scan in progress: {status}%") on
each iteration; ensure callers are updated to await the new async method or
provide a synchronous wrapper if necessary.

Comment on lines +254 to +276
public bool EvaluateScanResult(string targetUrl, ObservableList<OperationValues> allowedAlertNames)
{
var summaryResponse = _zapClient.alert.alertsSummary(targetUrl);
var alertSummary = (ApiResponseSet)summaryResponse;

bool testPassed = true;

foreach (var alertEntry in alertSummary.Dictionary)
{
string alertName = alertEntry.Key;
string valueString = alertEntry.Value is ApiResponseElement element ? element.Value : alertEntry.Value?.ToString();
if (!int.TryParse(valueString, out int count))
{
continue;
}

if (!allowedAlertNames.Any(a => a.Value == alertName))
{
testPassed = false;
}
}
return testPassed;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

EvaluateScanResult with allowed alerts: counts not considered; null list not handled

Currently, any alert name not in the allowed list fails the test even if its count is zero, and allowedAlertNames may be null at call sites.

- public bool EvaluateScanResult(string targetUrl, ObservableList<OperationValues> allowedAlertNames)
+ public bool EvaluateScanResult(string targetUrl, ObservableList<OperationValues> allowedAlertNames)
 {
     var summaryResponse = _zapClient.alert.alertsSummary(targetUrl);
     var alertSummary = (ApiResponseSet)summaryResponse;

     bool testPassed = true;

     foreach (var alertEntry in alertSummary.Dictionary)
     {
         string alertName = alertEntry.Key;
         string valueString = alertEntry.Value is ApiResponseElement element ? element.Value : alertEntry.Value?.ToString();
         if (!int.TryParse(valueString, out int count))
         {
             continue;
         }
-
-        if (!allowedAlertNames.Any(a => a.Value == alertName))
-        {
-            testPassed = false;
-        }
+        if (count <= 0)
+        {
+            continue; // ignore zero-count entries
+        }
+        if (allowedAlertNames == null || !allowedAlertNames.Any(a => a.Value == alertName))
+        {
+            testPassed = false;
+        }
     }
     return testPassed;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public bool EvaluateScanResult(string targetUrl, ObservableList<OperationValues> allowedAlertNames)
{
var summaryResponse = _zapClient.alert.alertsSummary(targetUrl);
var alertSummary = (ApiResponseSet)summaryResponse;
bool testPassed = true;
foreach (var alertEntry in alertSummary.Dictionary)
{
string alertName = alertEntry.Key;
string valueString = alertEntry.Value is ApiResponseElement element ? element.Value : alertEntry.Value?.ToString();
if (!int.TryParse(valueString, out int count))
{
continue;
}
if (!allowedAlertNames.Any(a => a.Value == alertName))
{
testPassed = false;
}
}
return testPassed;
}
public bool EvaluateScanResult(string targetUrl, ObservableList<OperationValues> allowedAlertNames)
{
var summaryResponse = _zapClient.alert.alertsSummary(targetUrl);
var alertSummary = (ApiResponseSet)summaryResponse;
bool testPassed = true;
foreach (var alertEntry in alertSummary.Dictionary)
{
string alertName = alertEntry.Key;
string valueString = alertEntry.Value is ApiResponseElement element
? element.Value
: alertEntry.Value?.ToString();
if (!int.TryParse(valueString, out int count))
{
continue;
}
if (count <= 0)
{
continue; // ignore zero-count entries
}
if (allowedAlertNames == null
|| !allowedAlertNames.Any(a => a.Value == alertName))
{
testPassed = false;
}
}
return testPassed;
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 254-276,
the EvaluateScanResult method currently fails the test for any alert name not in
allowedAlertNames regardless of its count and will throw if allowedAlertNames is
null; change the logic so you first treat allowedAlertNames == null as an empty
collection (or use a null-safe Any check) and only set testPassed = false when
the parsed count > 0 AND the alertName is not present in allowedAlertNames; keep
the rest of the parsing and continue behavior the same.

Comment thread Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
}
else
{
platform = WorkSpace.Instance.Solution.ApplicationPlatforms[0].Platform;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add required null checks

Comment thread Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs

private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use common function from General.cs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this temp file

Comment thread Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
Comment thread Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs Outdated
{
IApiResponse apiResponse = _zapClient.pscan.recordsToScan();
string tempVal = ((ApiResponseElement)apiResponse).Value;
while (!tempVal.Equals("0"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use async methods

@AmanPrasad43
AmanPrasad43 changed the base branch from master to Releases/Beta August 25, 2025 09:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

♻️ Duplicate comments (35)
Ginger/Ginger/Ginger.csproj (1)

725-769: Prior request resolved: no OWASPZAPDotNetAPI PackageReference in Ginger UI

Confirming the UI project no longer directly references OWASPZAPDotNetAPI. This aligns with the architectural guidance to keep the package in GingerCore/GingerCoreNET only and rely on transitive usage.

Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml (2)

7-8: Verify xmlns:local resolves MultiBooleanToVisibilityConverter at runtime

Ensure MultiBooleanToVisibilityConverter actually lives in Ginger.Actions.ActionConversion; otherwise StaticResource lookup will fail. If it lives in a common converters namespace, point xmlns accordingly.


154-179: Wire ZAP controls to driver params and fix label punctuation/casing

The controls render but won’t persist without bindings unless code‑behind handles it. Also remove extra spaces before colons and normalize casing.

-                    <Label Content="Security Testing Configurations" Style="{StaticResource $HorizontalExpanderLabelStyle}"/>
+                    <Label Content="Security testing configurations" Style="{StaticResource $HorizontalExpanderLabelStyle}"/>

-                        <CheckBox x:Name="xEnableZAPCheckBox" Content="Enable Security Testing" Style="{StaticResource $CeckBoxStyle}" />
+                        <CheckBox x:Name="xEnableZAPCheckBox"
+                                  Content="Enable security testing"
+                                  Style="{StaticResource $CeckBoxStyle}"/>

-                            <Label Content="Scan type : " Style="{StaticResource $LabelStyle}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left"/>
+                            <Label Content="Scan type:" Style="{StaticResource $LabelStyle}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left"/>
-                            <ComboBox x:Name="xScanTypeComboBox" IsEditable="False" Style="{StaticResource $FlatInputComboBoxStyle}" Grid.Column="1" Grid.Row="0" Width="120" HorizontalAlignment="Left"/>
+                            <ComboBox x:Name="xScanTypeComboBox"
+                                      IsEditable="False"
+                                      Style="{StaticResource $FlatInputComboBoxStyle}"
+                                      Grid.Column="1" Grid.Row="0" Width="120" HorizontalAlignment="Left"/>

-                            <Label Content="Failure Vulnerability Threshold : " Style="{StaticResource $LabelStyle}" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left"/>
+                            <Label Content="Failure vulnerability threshold:" Style="{StaticResource $LabelStyle}" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left"/>
-                            <ComboBox x:Name="xVulnerabilityTypeComboBox" IsEditable="False" Style="{StaticResource $FlatInputComboBoxStyle}" Grid.Column="1" Grid.Row="1" Width="120" HorizontalAlignment="Left"/>
+                            <ComboBox x:Name="xVulnerabilityTypeComboBox"
+                                      IsEditable="False"
+                                      Style="{StaticResource $FlatInputComboBoxStyle}"
+                                      Grid.Column="1" Grid.Row="1" Width="120" HorizontalAlignment="Left"/>

If you prefer XAML bindings (instead of code‑behind), I can provide a binding diff for UseSecurityTesting/ZapScanTypeSetting/ZapVulnerabilitySetting.

Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs (1)

830-831: Polish the ZAP connection messages (grammar + punctuation)

Aligns with style used elsewhere (“connection failed/successful.”), adds period, and clarifies instruction.

-                { eUserMsgKey.ZAPConnectionFail, new UserMsg(eUserMsgType.ERROR, "ZAP Connection Info", "ZAP Connection Failed, Please check credentials/check error logs", eUserMsgOption.OK, eUserMsgSelection.None) },
-                { eUserMsgKey.ZAPConnectionSuccess, new UserMsg(eUserMsgType.INFO, "ZAP Connection Info", "ZAP Connection Successful", eUserMsgOption.OK, eUserMsgSelection.None) },
+                { eUserMsgKey.ZAPConnectionFail, new UserMsg(eUserMsgType.ERROR, "ZAP Connection Info", "ZAP connection failed. Please check credentials or review error logs.", eUserMsgOption.OK, eUserMsgSelection.None) },
+                { eUserMsgKey.ZAPConnectionSuccess, new UserMsg(eUserMsgType.INFO, "ZAP Connection Info", "ZAP connection successful.", eUserMsgOption.OK, eUserMsgSelection.None) },
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (4)

61-64: Default/selection should use SelectedValue, not Text

Setting Text won’t select the item; it also fights the SelectedValue binding.

-            GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
-            xScanTypeComboBox.Text = GingerCore.General.GetEnumValueDescription(typeof(eScanType), eScanType.Active);
-            GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);
+            GingerCore.General.FillComboFromEnumType(xScanTypeComboBox, typeof(eScanType), null);
+            xScanTypeComboBox.SelectedValue = mAct.ScanType != default ? mAct.ScanType : eScanType.Active;
+            GingerCore.GeneralLib.BindingHandler.ObjFieldBinding(xScanTypeComboBox, ComboBox.SelectedValueProperty, mAct, ActSecurityTesting.Fields.ScanType);

82-91: SelectionChanged reads wrong type from SelectedValue

FillComboFromEnumType sets SelectedValuePath="Value", so SelectedValue is eScanType, not string.

-        private void xScanTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (xScanTypeComboBox.SelectedValue is string selectedScanType)
-            {
-                if (Enum.TryParse(typeof(ActSecurityTesting.eScanType), selectedScanType, out var scanTypeEnum))
-                {
-                    mAct.ScanType = (ActSecurityTesting.eScanType)scanTypeEnum;
-                }
-            }
-        }
+        private void xScanTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (xScanTypeComboBox.SelectedValue is eScanType scanType)
+            {
+                mAct.ScanType = scanType;
+            }
+        }

Or remove the handler and rely on the TwoWay SelectedValue binding.


67-80: Harden platform resolution (null/empty safety)

Avoid potential NullReference/IndexOutOfRange when BF/CurrentActivity/TargetApplication or ApplicationPlatforms are null/empty.

-        private ePlatformType GetActionPlatform()
-        {
-            ePlatformType platform;
-            if (mAct.Context != null && (Context.GetAsContext(mAct.Context)).BusinessFlow != null)
-            {
-                string targetapp = (Context.GetAsContext(mAct.Context)).BusinessFlow.CurrentActivity.TargetApplication;
-                platform = WorkSpace.Instance.Solution.ApplicationPlatforms.FirstOrDefault(x => x.AppName == targetapp).Platform;
-            }
-            else
-            {
-                platform = WorkSpace.Instance.Solution.ApplicationPlatforms[0].Platform;
-            }
-            return platform;
-        }
+        private ePlatformType GetActionPlatform()
+        {
+            var solution = WorkSpace.Instance?.Solution;
+            var appPlatforms = solution?.ApplicationPlatforms;
+
+            if (mAct.Context != null)
+            {
+                var ctx = Context.GetAsContext(mAct.Context);
+                var bf = ctx?.BusinessFlow;
+                var ta = bf?.CurrentActivity?.TargetApplication;
+                var match = appPlatforms?.FirstOrDefault(x => !string.IsNullOrEmpty(ta) && x.AppName == ta);
+                if (match != null)
+                {
+                    return match.Platform;
+                }
+            }
+            return (appPlatforms != null && appPlatforms.Any())
+                ? appPlatforms[0].Platform
+                : ePlatformType.Web; // safe default
+        }

96-105: Severity order: put Informational before FalsePositive

Match common order and enum: High, Medium, Low, Informational, FalsePositive.

             ObservableList<OperationValues> SeverityList =
             [
                 new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.High) },
                 new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.Medium) },
                 new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.Low) },
-                new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.FalsePositive) },
-                new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.Informational) },
+                new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.Informational) },
+                new OperationValues() { Value = nameof(ActSecurityTesting.eAlertTypes.FalsePositive) },
             ];
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs (1)

139-154: Make ZAP scan/vulnerability combos enable/disable with the “Enable ZAP” checkbox

Improves UX and prevents selecting ZAP options when ZAP is off. Initialize state on load and toggle on check/uncheck.

Apply this diff after the existing bindings in BindConfigurations:

             BindingHandler.ObjFieldBinding(xVulnerabilityTypeComboBox, ComboBox.ToolTipProperty, zapVulnerability, nameof(DriverConfigParam.Description));

+            // Enable/disable ZAP-related combos based on the "Enable ZAP" checkbox
+            xEnableZAPCheckBox.Checked += (_, __) =>
+            {
+                xScanTypeComboBox.IsEnabled = true;
+                xVulnerabilityTypeComboBox.IsEnabled = true;
+            };
+            xEnableZAPCheckBox.Unchecked += (_, __) =>
+            {
+                xScanTypeComboBox.IsEnabled = false;
+                xVulnerabilityTypeComboBox.IsEnabled = false;
+            };
+            // Initialize current enabled state from the parameter value
+            if (bool.TryParse(useZAP.Value, out var zapEnabled))
+            {
+                xScanTypeComboBox.IsEnabled = zapEnabled;
+                xVulnerabilityTypeComboBox.IsEnabled = zapEnabled;
+            }
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml (3)

73-93: Correct “About ZAP” attribution and phrasing

ZAP is an OWASP project, not by Checkmarx. Also use “man-in-the-middle” phrasing.

Apply this diff:

-                                        Zed Attack Proxy (ZAP) by Checkmarx is a free, open-source penetration testing tool. ZAP is
+                                        Zed Attack Proxy (ZAP) by the OWASP community is a free, open-source penetration testing tool. ZAP is
@@
-                                        At its core, ZAP is what is known as a “manipulator-in-the-middle proxy.” It stands between
+                                        At its core, ZAP is a “man-in-the-middle” proxy. It stands between

41-47: Fix misleading ToolTips (“GingerOps Account URL” / “Client Secret”)

These ToolTips are incorrect for ZAP configuration and may confuse users. Update to ZAP-specific wording.

Apply this diff:

-                    <Activities:UCValueExpression x:Name="xZAPURLTextBox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="GingerOps Account URL" Margin="10,0,0,0"  Width="400"/>
+                    <Activities:UCValueExpression x:Name="xZAPURLTextBox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="ZAP API URL (e.g., http://127.0.0.1:8080)" Margin="10,0,0,0"  Width="400"/>
@@
-                    <Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Client Secret" Margin="10,0,0,0" Width="400" LostKeyboardFocus="xZAPAPIkeyTextBox_LostKeyboardFocus"/>
+                    <Activities:UCValueExpression x:Name="xZAPAPIkeyTextBox" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="ZAP API Key" Margin="10,0,0,0" Width="400" LostKeyboardFocus="xZAPAPIkeyTextBox_LostKeyboardFocus"/>

51-51: Change loader visibility to Collapsed in ZAPConfigurationPage.xaml.cs

The code-behind for ZAPConfigurationPage currently sets the processing‐image Visibility to Hidden, which contradicts its initial Collapsed state and can introduce unwanted layout gaps. Please update these occurrences to use Visibility.Collapsed instead.

• File: Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
– Line 111: xProcessingImage.Visibility = Visibility.Hidden;
– (Ensure no other Hidden usages remain in this file.)

Suggested diff:

--- a/Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
+++ b/Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
@@ 108,5
-               this.Dispatcher.Invoke(() =>
-               {
-                   xProcessingImage.Visibility = Visibility.Hidden;
-               });
+               this.Dispatcher.Invoke(() =>
+               {
+                   xProcessingImage.Visibility = Visibility.Collapsed;
+               });
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (2)

435-435: Optional: resolve variables before using EndPointURL

Use GetInputParamCalculatedValue to ensure variables are substituted.

Apply this one-line change if you agree:

-                        string endpointUrl = mActWebAPI.GetInputParamValue(ActWebAPIBase.Fields.EndPointURL);
+                        string endpointUrl = mActWebAPI.GetInputParamCalculatedValue(ActWebAPIBase.Fields.EndPointURL);

431-457: Fix: incorrect enum comparison, redundant checks, and lost AlertList in active path

  • string.Equals on an enum is a compile/runtime bug. Use direct enum comparison.
  • Inner else-if duplicates the same condition; simplify.
  • Active path creates mActSecTest with AlertList but never passes it to HandleAPISecurityTesting, losing the threshold. Pass it through.

Apply this diff:

-                if (this.UseSecurityTesting)
-                {
-                    if (string.Equals(this.mZapScanTypeSetting, eZapScanType.Passive))
-                    {
-                        string endpointUrl = mActWebAPI.GetInputParamValue(ActWebAPIBase.Fields.EndPointURL);
-                        if (string.IsNullOrWhiteSpace(endpointUrl))
-                        {
-                            Reporter.ToLog(eLogLevel.WARN, "ZAP scan skipped: endpoint URL is empty");
-                        }
-                        else if (this.mZapScanTypeSetting == eZapScanType.Passive)
-                        {
-                            var mActSecTest = new ActSecurityTesting
-                            {
-                                AlertList = BuildAlertListFromThreshold(mZapVulnerabilitySetting)
-                            };
-                            mActSecTest.ExecutePassiveZapScan(endpointUrl, mActWebAPI);
-                        }
-                    }
-                    else
-                    {
-                        var mActSecTest = new ActSecurityTesting
-                        {
-                            AlertList = BuildAlertListFromThreshold(mZapVulnerabilitySetting)
-                        };
-                        HandleAPISecurityTesting(mActWebAPI);
-                    }
-                }
+                if (this.UseSecurityTesting)
+                {
+                    if (this.mZapScanTypeSetting == eZapScanType.Passive)
+                    {
+                        string endpointUrl = mActWebAPI.GetInputParamValue(ActWebAPIBase.Fields.EndPointURL);
+                        if (string.IsNullOrWhiteSpace(endpointUrl))
+                        {
+                            Reporter.ToLog(eLogLevel.WARN, "ZAP scan skipped: endpoint URL is empty");
+                        }
+                        else
+                        {
+                            var mActSecTest = new ActSecurityTesting
+                            {
+                                AlertList = BuildAlertListFromThreshold(mZapVulnerabilitySetting)
+                            };
+                            mActSecTest.ExecutePassiveZapScan(endpointUrl, mActWebAPI);
+                        }
+                    }
+                    else
+                    {
+                        var mActSecTest = new ActSecurityTesting
+                        {
+                            AlertList = BuildAlertListFromThreshold(mZapVulnerabilitySetting)
+                        };
+                        HandleAPISecurityTesting(mActWebAPI, mActSecTest);
+                    }
+                }
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4)

412-415: Document UseSecurityTesting precedence and security implications.

Add an XML doc so users/devs understand that enabling this overrides existing proxy settings and accepts ZAP’s MITM certificate.

-        [UserConfigured]
+        /// <summary>
+        /// Route browser traffic via OWASP ZAP for security testing.
+        /// When enabled, this takes precedence over Proxy, ProxyAutoConfigUrl and AutoDetect by forcing a Manual proxy
+        /// to the configured ZAP endpoint for the session, and sets AcceptInsecureCertificates=true so ZAP's MITM
+        /// certificate is trusted. Disable to restore normal proxy behavior.
+        /// </summary>
+        [UserConfigured]
         [UserConfiguredDefault("false")]
         [UserConfiguredDescription("Allow ZAP to Perform Security Testing")]
         public bool UseSecurityTesting { get; set; }

3581-3593: SetAttributeUsingJs should use setAttribute and fail clearly on bad input (no silent pass).

Current code treats the left side as a JS property, which breaks for data-* and many attributes, and it returns early with only a debug log.

-                {
-                    e = LocateElement(act);
-                    char[] delimit = new char[] { '=' };
-                    string insertval = act.GetInputParamCalculatedValue("Value");
-                    string[] vals = insertval.Split(delimit, 2);
-                    if (vals.Length != 2)
-                    {
-                        Reporter.ToLog(eLogLevel.DEBUG, @"Input string should be in the format : attribute=value");
-                        return;
-                    }
-                        ((IJavaScriptExecutor)Driver).ExecuteScript("arguments[0]." + vals[0] + "=arguments[1]", e, vals[1]);
-                }
+                {
+                    e = LocateElement(act);
+                    if (e == null)
+                    {
+                        act.Error = $"Error: Element not found - {act.LocateBy} {act.LocateValueCalculated}";
+                        act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed;
+                        break;
+                    }
+                    string input = act.GetInputParamCalculatedValue("Value") ?? string.Empty;
+                    var parts = input.Split(new[] { '=' }, 2, StringSplitOptions.None);
+                    if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]))
+                    {
+                        act.Error = "Input must be in the format attribute=value";
+                        act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed;
+                        break;
+                    }
+                    string attribute = parts[0].Trim();
+                    string value = parts[1];
+                    ((IJavaScriptExecutor)Driver).ExecuteScript(
+                        "arguments[0].setAttribute(arguments[1], arguments[2]);",
+                        e, attribute, value);
+                }

4602-4602: Improve error log with locator context for faster triage.

The current log is too generic; include element name and active locators.

-                Reporter.ToLog(eLogLevel.ERROR, $"Failed to locate element", ex);
+                Reporter.ToLog(
+                    eLogLevel.ERROR,
+                    $"Failed to locate element. Element='{currentPOMElementInfo?.ElementName}', " +
+                    $"ActiveLocators='{string.Join(", ", currentPOMElementInfo?.Locators?.Where(l => l.Active).Select(l => $"{l.LocateBy}=\"{l.LocateValue}\"") ?? Enumerable.Empty<string>())}'",
+                    ex);

1957-1968: Harden ActSecurity: null-safe URL and clear failure for Active scan; keep Passive unscoped.

Accessing Driver.Url can throw; Active scan requires a concrete URL. Passive scan intentionally uses "" to aggregate across the ZAP session, per team guidance.

-        private void ActSecurity(ActSecurityTesting act)
-        {
-            string testURL = Driver.Url;
-            if (act.ScanType == ActSecurityTesting.eScanType.Active)
-            {
-                act.ExecuteActiveZapScan(testURL);
-            }
-            else
-            {
-                act.ExecutePassiveZapScan("", act);
-            }
-        }
+        private void ActSecurity(ActSecurityTesting act)
+        {
+            string testURL = string.Empty;
+            try { testURL = Driver?.Url; } catch { /* ignore */ }
+
+            if (act.ScanType == ActSecurityTesting.eScanType.Active)
+            {
+                if (string.IsNullOrWhiteSpace(testURL))
+                {
+                    act.Error = "Active scan requires a current URL, but none was detected.";
+                    act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed;
+                    return;
+                }
+                act.ExecuteActiveZapScan(testURL);
+            }
+            else
+            {
+                // Intentionally unscoped to aggregate alerts across the entire ZAP session
+                act.ExecutePassiveZapScan("", act);
+            }
+        }
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (5)

61-66: Fix required-field validation: wrong control and message; add URL+API key checks

The required-field rule is attached to the API key textbox but the message refers to the URL. Attach the correct rules to the correct controls and add API key validation too.

 private void ApplyValidationRules()
 {
-    // check if fields have been populated (font-end validation)
-    xZAPAPIkeyTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP URL cannot be empty"));
+    // basic front-end validation
+    xZAPURLTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP URL cannot be empty"));
+    xZAPAPIkeyTextBox.ValueTextBox.AddValidationRule(new ValidateEmptyValue("ZAP API Key cannot be empty"));
 }

86-90: Treat whitespace-only input as empty

Use IsNullOrWhiteSpace so inputs with only spaces fail validation.

- return string.IsNullOrEmpty(zAPConfiguration.ZAPUrl)
-     || string.IsNullOrEmpty(zAPConfiguration.ZAPApiKey);
+ return string.IsNullOrWhiteSpace(zAPConfiguration.ZAPUrl)
+     || string.IsNullOrWhiteSpace(zAPConfiguration.ZAPApiKey);

107-121: Avoid unnecessary dispatcher marshaling and use Collapsed for hiding

Show/Hide run on UI thread callers; always invoking Dispatcher is redundant. Also prefer Visibility.Collapsed for layout.

- public void HideLoader()
- {
-     this.Dispatcher.Invoke(() =>
-     {
-         xProcessingImage.Visibility = Visibility.Hidden;
-     });
- }
+ public void HideLoader()
+ {
+     Action setHidden = () => xProcessingImage.Visibility = Visibility.Collapsed;
+     if (Dispatcher.CheckAccess()) setHidden();
+     else Dispatcher.Invoke(setHidden);
+ }
 
- public void ShowLoader()
- {
-     this.Dispatcher.Invoke(() =>
-     {
-         xProcessingImage.Visibility = Visibility.Visible;
-     });
- }
+ public void ShowLoader()
+ {
+     Action setVisible = () => xProcessingImage.Visibility = Visibility.Visible;
+     if (Dispatcher.CheckAccess()) setVisible();
+     else Dispatcher.Invoke(setVisible);
+ }

123-129: Trim before encrypting to avoid persisting accidental whitespace

Minor UX hardening; use trimmed input for VE/encryption checks.

- if (!EncryptionHandler.IsStringEncrypted(xZAPAPIkeyTextBox.ValueTextBox.Text))
+ var raw = xZAPAPIkeyTextBox.ValueTextBox.Text?.Trim();
+ if (!EncryptionHandler.IsStringEncrypted(raw))
 {
-    xZAPAPIkeyTextBox.ValueTextBox.Text = ValueExpression.IsThisAValueExpression(xZAPAPIkeyTextBox.ValueTextBox.Text) ? xZAPAPIkeyTextBox.ValueTextBox.Text : EncryptionHandler.EncryptwithKey(xZAPAPIkeyTextBox.ValueTextBox.Text);
+    xZAPAPIkeyTextBox.ValueTextBox.Text =
+        ValueExpression.IsThisAValueExpression(raw) ? raw : EncryptionHandler.EncryptwithKey(raw);
 }

131-164: Harden HTTP: reuse HttpClient, URL normalize, URL-encode apiKey, and faster timeout

Prevents socket exhaustion, handles stray spaces/trailing slash, and avoids breaking on special characters in apiKey.

- private async Task<bool> TestZAPConnectionAsync(string zapUrl, string apiKey)
+ private async Task<bool> TestZAPConnectionAsync(string zapUrl, string apiKey)
 {
     try
     {
-        // Ensure URL does not end with a slash
-        if (zapUrl.EndsWith('/'))
-        {
-            zapUrl = zapUrl.TrimEnd('/');
-        }
-
-        string testUrl = $"{zapUrl}/JSON/core/view/version/?apikey={apiKey}";
-
-        using HttpClient client = new HttpClient();
-        var response = await client.GetAsync(testUrl);
+        zapUrl = (zapUrl ?? string.Empty).Trim().TrimEnd('/');
+        var encodedKey = Uri.EscapeDataString(apiKey ?? string.Empty);
+        string testUrl = $"{zapUrl}/JSON/core/view/version/?apikey={encodedKey}";
+        var response = await s_http.GetAsync(testUrl);
 
         if (!response.IsSuccessStatusCode)
         {
             Reporter.ToLog(eLogLevel.ERROR, $"ZAP connection failed. Status code: {response.StatusCode}");
             return false;
         }
 
         string content = await response.Content.ReadAsStringAsync();
 
         // Optionally, check if content contains "version" field
         bool hasVersion = content.Contains("version");
         Reporter.ToLog(eLogLevel.DEBUG, $"ZAP response contains 'version': {hasVersion}");
         return hasVersion;
     }
     catch (Exception ex)
     {
         Reporter.ToLog(eLogLevel.ERROR, $"Exception during ZAP connection test: {ex.Message}", ex);
         return false;
     }
 }

Add this static client near the top of the class:

private static readonly HttpClient s_http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (7)

50-67: Method marked async but blocks thread; make it synchronous or truly async

Current implementation has no awaits and uses Thread.Sleep. Either remove async or implement proper async with Task.Delay + CancellationToken. Given call sites are synchronous, prefer a synchronous API.

Option A — make it synchronous (minimal change):

-public async Task WaitTillPassiveScanCompleted()
+public void WaitTillPassiveScanCompleted()
 {
     try
     {
         IApiResponse apiResponse = _zapClient.pscan.recordsToScan();
         string tempVal = ((ApiResponseElement)apiResponse).Value;
         while (!tempVal.Equals("0"))
         {
-            Thread.Sleep(1000);
+            Thread.Sleep(1000);
             apiResponse = _zapClient.pscan.recordsToScan();
             tempVal = ((ApiResponseElement)apiResponse).Value;
         }
     }
     catch (Exception ex)
     {
         throw new InvalidOperationException("Error during passive scan: " + ex.Message, ex);
     }
 }

Option B — true async (requires updating all callers):

-public async Task WaitTillPassiveScanCompleted()
+public async Task WaitTillPassiveScanCompletedAsync(CancellationToken ct = default)
 {
     try
     {
         IApiResponse apiResponse = _zapClient.pscan.recordsToScan();
         string tempVal = ((ApiResponseElement)apiResponse).Value;
         while (!tempVal.Equals("0"))
         {
-            Thread.Sleep(1000);
+            await Task.Delay(1000, ct);
             apiResponse = _zapClient.pscan.recordsToScan();
             tempVal = ((ApiResponseElement)apiResponse).Value;
         }
     }
     catch (Exception ex)
     {
         throw new InvalidOperationException("Error during passive scan: " + ex.Message, ex);
     }
 }

69-83: Report generation: specify file extension and validate inputs

Passing an empty extension may save files without .html. Provide "html". Consider guarding null/empty args.

 _zapClient.reports.generate(
-    "Security Test Report", "traditional-html", "", "Security scan report", "", siteToTest, "", "", "",
-    reportfilename, "", reportDir, ""
+    "Security Test Report", "traditional-html", "", "Security scan report",
+    "", siteToTest, "", "", "",
+    reportfilename, "html", reportDir, ""
 );

85-131: Doc fix and safer parsing: avoid “as string”; default to ZAP port when missing

Comments say “as string” but return type is int?. Also handle missing port by returning 8080 only when the caller requests default; since the constructor uses GetPortFromUrl(..) ?? 8080, current change to docs suffices.

-/// <returns>The port number as string, or null if not found.</returns>
+/// <returns>The port number, or null if not found.</returns>

Optional robustness for non-URL host:port:

- var parts = url.Split(':');
+ var parts = url.Trim().Split(':');

133-176: Host parsing docs and IPv6 handling nits

Align XML docs with return type and improve trivial trimming.

-/// <returns>The host as string, or null if not found.</returns>
+/// <returns>The host name, or null if not found.</returns>
...
- var parts = url.Split(':');
+ var parts = url.Trim().Split(':');

239-253: Active scan loop: include percentage and consider async later

At minimum, log percentage to aid troubleshooting. True async remains recommended for UI/throughput.

- Reporter.ToLog(eLogLevel.INFO, "Active scan is in progress");
+ Reporter.ToLog(eLogLevel.INFO, $"Active scan is in progress: {status}%");

262-284: EvaluateScanResult: handle null allowed list and ignore zero-count entries

Avoids false failures and NREs.

- if (!allowedAlertNames.Any(a => a.Value == alertName))
- {
-     testPassed = false;
-}
+ if (count <= 0)
+ {
+     continue;
+ }
+ if (allowedAlertNames == null || !allowedAlertNames.Any(a => a.Value == alertName))
+ {
+     testPassed = false;
+ }

286-292: EvaluateScanResult (no allowed list): ToString check is unreliable

Parse counts and only pass if total is zero.

- var alertSummary = (ApiResponseSet)summaryResponse;
- return !string.IsNullOrEmpty(alertSummary.ToString());
+ var alertSummary = (ApiResponseSet)summaryResponse;
+ foreach (var kv in alertSummary.Dictionary)
+ {
+     var val = kv.Value is ApiResponseElement el ? el.Value : kv.Value?.ToString();
+     if (int.TryParse(val, out int count) && count > 0)
+     {
+         return false;
+     }
+ }
+ return true;
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (5)

269-312: Passive path: null-safe EvaluateScanResult and align with session-wide passive scan

When aggregating passive alerts, pass empty base URL to get the entire session summary (per team guidance). Also, the current call can NRE if AlertList is null.

- zapProxyService.WaitTillPassiveScanCompleted();
-
- ProcessResultAsync(zapProxyService, act, testURL);
- AddZapAlertOutputValues(zapProxyService, act, testURL);
- isPassed = zapProxyService.EvaluateScanResult(testURL, AlertList);
+ zapProxyService.WaitTillPassiveScanCompleted();
+ ProcessResult(zapProxyService, act, string.Empty);
+ AddZapAlertOutputValues(zapProxyService, act, string.Empty);
+ isPassed = AlertList != null
+     ? zapProxyService.EvaluateScanResult(string.Empty, AlertList)
+     : zapProxyService.EvaluateScanResult(string.Empty);

Note: This follows the learning that passive scans should use an empty testURL to aggregate alerts across the ZAP session.


369-388: Method is synchronous; rename accordingly and use TestArtifactsFolder; fix timestamp var

Name suggests async but there’s no async work. Also use a consistent artifacts root and a standard timestamp.

- private void ProcessResultAsync(ZapProxyService zps, Act _act, string testURL)
+ private void ProcessResult(ZapProxyService zps, Act _act, string testURL)
 {
-
-    string path = String.Empty;
-
-    string solutionDir = WorkSpace.Instance.Solution.Folder;
-    string folderPath = Path.Combine(solutionDir, "ExecutionResults", "Artifacts", "ZAPReport");
+    string path = string.Empty;
+    string baseArtifacts = WorkSpace.Instance.TestArtifactsFolder ?? WorkSpace.Instance.Solution.Folder;
+    string folderPath = Path.Combine(baseArtifacts, "ExecutionResults", "Artifacts", "ZAPReport");
     // Ensure the directory exists
     if (!System.IO.Directory.Exists(folderPath))
     {
         System.IO.Directory.CreateDirectory(folderPath);
     }
-    string DatetimeFormate = DateTime.Now.ToString("ddMMyyyy_HHmmssfff");
-    string reportname = $"{_act.ItemName}_SecurityTestingReport_{DatetimeFormate}.html";
+    string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssfff");
+    string reportname = $"{_act.ItemName}_SecurityTestingReport_{timestamp}.html";
     path = Path.Combine(folderPath, reportname);
 
     zps.GenerateZapReport(testURL, folderPath, reportname);
     Act.AddArtifactToAction(Path.GetFileName(path), _act, path);
     _act.AddOrUpdateReturnParamActual(ParamName: "Security Testing Report", ActualValue: path);
 }

Update call sites at Lines 222, 281, 329 accordingly (see related diffs).


390-409: Output values: don’t overload Path as totals; add a separate “Total Vulnerabilities” param

Keeps semantics clear and makes totals easier to consume in reports.

- act.AddNewReturnParams = true;
-
- act.AddOrUpdateReturnParamActualWithPath(
-     "Vulnerabilities Summary",
-     vulnerabilitiesSummary,
-     totalAlerts.ToString()
- );
+ act.AddNewReturnParams = true;
+ act.AddOrUpdateReturnParamActual("Vulnerabilities Summary", vulnerabilitiesSummary);
+ act.AddOrUpdateReturnParamActual("Total Vulnerabilities", totalAlerts.ToString());

115-188: Declared properties (ScanType, PullReport, AlertItems) aren’t used in execution paths

Either wire these into flows (e.g., respect ScanType and PullReport) or remove to avoid confusion and dead state.

Example wiring (high level):

  • Use ScanType to pick between ExecuteActiveZapScan vs ExecutePassiveZapScan in a single Execute method.
  • Use PullReport to skip ProcessResult when false.

192-208: Lazy loading of ZAPConfiguration: consider passing to ZapProxyService for clarity

Service currently fetches from repository again; pass the selected configuration or pre-resolved URL/apiKey for testability and fewer implicit dependencies.

- ZapProxyService zapProxyService = new ZapProxyService();
+ ZapProxyService zapProxyService = new ZapProxyService();
+ // Optional: if service adds an overload accepting host/port/apiKey, derive them here from ZAPConfiguration
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f171909 and 5ba459c.

📒 Files selected for processing (13)
  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (1 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs (4 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml (2 hunks)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs (3 hunks)
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml (1 hunks)
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1 hunks)
  • Ginger/Ginger/Ginger.csproj (2 hunks)
  • Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs (2 hunks)
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (1 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (9 hunks)
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (7 hunks)
  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (1 hunks)
  • Ginger/GingerCoreNET/GeneralLib/General.cs (3 hunks)
🧰 Additional context used
🧠 Learnings (27)
📓 Common learnings
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCore/GingerCore.csproj:538-538
Timestamp: 2025-08-25T08:48:11.895Z
Learning: In the Ginger codebase, the OWASPZAPDotNetAPI package reference in GingerCore.csproj is required for architectural reasons, even when direct usage is not immediately visible in the codebase. This was confirmed by AmanPrasad43 during the security testing feature implementation.
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:1958-1970
Timestamp: 2025-08-25T09:20:17.589Z
Learning: In Ginger security testing, passive ZAP scans should be invoked with an empty testURL (ActSecurityTesting.ExecutePassiveZapScan("", act)) to aggregate alerts across the entire ZAP session. Passing a URL scopes results to that base URL. Only the active scan path should pass Driver.Url, with null/empty checks. Context: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs :: ActSecurity. Confirmed by AmanPrasad43 in PR #4281.
📚 Learning: 2025-08-25T08:48:11.895Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCore/GingerCore.csproj:538-538
Timestamp: 2025-08-25T08:48:11.895Z
Learning: In the Ginger codebase, the OWASPZAPDotNetAPI package reference in GingerCore.csproj is required for architectural reasons, even when direct usage is not immediately visible in the codebase. This was confirmed by AmanPrasad43 during the security testing feature implementation.

Applied to files:

  • Ginger/GingerCoreNET/GeneralLib/General.cs
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml
  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
  • Ginger/Ginger/Ginger.csproj
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-08-25T09:30:08.066Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs:37-58
Timestamp: 2025-08-25T09:30:08.066Z
Learning: In the Ginger codebase, URL validation in configuration classes like ZAPConfiguration should not throw exceptions for invalid URLs. The team prefers simple normalization (like trimming trailing slashes) over strict validation with exception throwing. This was confirmed by AmanPrasad43 in PR #4281 for the ZAPConfiguration.ZAPUrl property setter.

Applied to files:

  • Ginger/GingerCoreNET/GeneralLib/General.cs
  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-08-25T09:20:17.589Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:1958-1970
Timestamp: 2025-08-25T09:20:17.589Z
Learning: In Ginger security testing, passive ZAP scans should be invoked with an empty testURL (ActSecurityTesting.ExecutePassiveZapScan("", act)) to aggregate alerts across the entire ZAP session. Passing a URL scopes results to that base URL. Only the active scan path should pass Driver.Url, with null/empty checks. Context: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs :: ActSecurity. Confirmed by AmanPrasad43 in PR #4281.

Applied to files:

  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs
  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-08-25T08:48:18.960Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs:51-63
Timestamp: 2025-08-25T08:48:18.960Z
Learning: In the Ginger project, `[]` collection expression syntax is the preferred modern approach for initializing collections, including dictionaries (e.g., `mAct.AlertItems = [];`), as confirmed by the project maintainers.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-10-28T11:11:36.460Z
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3971
File: Ginger/Ginger/External/Katalon/ImportPOMFromObjectRepositoryWizardPage.xaml.cs:198-200
Timestamp: 2024-10-28T11:11:36.460Z
Learning: In this project, prefer explicit null and count checks over pattern matching for null and count checks in C# code, as it is considered more readable.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-10-28T11:12:49.263Z
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3971
File: Ginger/GingerCoreNET/External/Katalon/Conversion/KatalonObjectRepositoryToPOMConverter.cs:37-37
Timestamp: 2024-10-28T11:12:49.263Z
Learning: In the Ginger project, initializing collections in C# using `[]` is valid syntax.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-11-06T09:06:34.050Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#3984
File: Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs:911-911
Timestamp: 2024-11-06T09:06:34.050Z
Learning: In the `Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs` file of the Ginger project, initializing lists in C# using `[]` syntax (e.g., `List<T> list = [];`) is acceptable and does not require changing to `new List<T>()`.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2025-03-28T13:45:52.031Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4149
File: Ginger/GingerCoreNET/RunLib/DynamicExecutionLib/AgentConfigOperations.cs:40-40
Timestamp: 2025-03-28T13:45:52.031Z
Learning: The empty collection initializer syntax `[]` is valid in C# 12 and newer versions. For example, `List<T> list = []` is equivalent to `List<T> list = new List<T>()` in C# 12+.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-12-04T08:49:40.756Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4016
File: Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs:419-419
Timestamp: 2024-12-04T08:49:40.756Z
Learning: In the `GingerHbase` class of `Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs`, it's acceptable to initialize lists using `[]` syntax.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2025-01-16T04:08:12.351Z
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#4058
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActUIElementHandler.cs:652-653
Timestamp: 2025-01-16T04:08:12.351Z
Learning: C# 12 introduced collection expressions that allow initializing arrays and other collection types using a simplified syntax with square brackets. For example, `[item1, item2]` is equivalent to `new[] { item1, item2 }`.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-09-30T18:11:57.769Z
Learnt from: Maheshkale447
PR: Ginger-Automation/Ginger#3945
File: Ginger/GingerCoreNET/Repository/SharedRepositoryOperations.cs:550-550
Timestamp: 2024-09-30T18:11:57.769Z
Learning: In C# with .NET 8 and later, it's valid to initialize lists using the `[]` syntax.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2024-10-28T13:01:46.614Z
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3971
File: Ginger/GingerCoreNET/External/Katalon/Conversion/KatalonElementToElementInfoConverter.cs:27-27
Timestamp: 2024-10-28T13:01:46.614Z
Learning: In `KatalonElementToElementInfoConverter.cs`, initializing a `List<ElementInfo>` using `List<ElementInfo> elementInfoList = [];` is acceptable in the project.

Applied to files:

  • Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs
📚 Learning: 2025-02-14T07:02:48.416Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4100
File: Ginger/Ginger/ApplicationModelsLib/APIModels/APIModelWizard/AddAPIModelExtraConfigsPage.xaml:28-30
Timestamp: 2025-02-14T07:02:48.416Z
Learning: In AddAPIModelExtraConfigsPage.xaml, the WireMock mapping checkbox (xWireMockMappingToggle) is initially disabled and only gets enabled after successful validation of WireMock configuration and connection test in the CheckWireMockConfiguration method.

Applied to files:

  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs
📚 Learning: 2025-08-25T09:27:30.226Z
Learnt from: AmanPrasad43
PR: Ginger-Automation/Ginger#4281
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:1433-1441
Timestamp: 2025-08-25T09:27:30.226Z
Learning: In Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs, SetProxy(dynamic options) should not force options.AcceptInsecureCertificates = false. Only set AcceptInsecureCertificates = true when UseZAP is enabled to avoid breaking setups that permit self-signed/dev certificates.

Applied to files:

  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-02-17T12:13:55.231Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4110
File: Ginger/GingerCoreCommon/ReporterLib/WorkSpaceReporterBase.cs:85-89
Timestamp: 2025-02-17T12:13:55.231Z
Learning: The error handling in WorkSpaceReporterBase.ToConsole() should be kept simple with basic exception catching and console output reset, as per team's preference.

Applied to files:

  • Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs
📚 Learning: 2025-04-30T13:23:55.386Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4193
File: Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/AIGeneratedPreviewWizardPage.xaml.cs:56-63
Timestamp: 2025-04-30T13:23:55.386Z
Learning: When validating API keys or similar sensitive configuration values, use case-insensitive comparison (StringComparison.OrdinalIgnoreCase) with known placeholder values, and check for null, empty, or whitespace with string.IsNullOrWhiteSpace() rather than just string.IsNullOrEmpty().

Applied to files:

  • Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs
📚 Learning: 2025-07-10T07:11:28.974Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4249
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:4684-4695
Timestamp: 2025-07-10T07:11:28.974Z
Learning: In Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs, attribute values used in CSS selectors (e.g., ByTitle, ByAriaLabel, ByDataTestId, ByPlaceholder) should be escaped using a helper method (such as EscapeCssAttributeValue) to prevent selector breakage due to special characters.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml
📚 Learning: 2025-07-10T07:12:52.786Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4249
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:7199-7202
Timestamp: 2025-07-10T07:12:52.786Z
Learning: In Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs, text values used in XPath expressions should be escaped using a helper method (such as EscapeXPathString) to handle single quotes and ensure valid XPath syntax.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
📚 Learning: 2025-06-16T10:37:13.073Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4232
File: Ginger/GingerCoreNET/ActionsLib/UI/VisualTesting/VRTAnalyzer.cs:19-22
Timestamp: 2025-06-16T10:37:13.073Z
Learning: In Ginger codebase, both `using amdocs.ginger.GingerCoreNET;` and `using Amdocs.Ginger.CoreNET;` are valid and serve different purposes. The first (lowercase) contains the WorkSpace class and related workspace functionality, while the second (proper case) contains drivers like GenericAppiumDriver and other core functionality. Both may be required in files that use types from both namespaces.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-04-25T13:29:45.059Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4188
File: Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs:22-23
Timestamp: 2025-04-25T13:29:45.059Z
Learning: The `using Amdocs.Ginger.Repository;` statement in Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs is necessary as it provides access to the `ObservableList<>` class which is used throughout the file for collections of RunSetConfig, AnalyzerItemBase, and ApplicationPOMModel objects.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-04-25T13:29:45.059Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4188
File: Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs:22-23
Timestamp: 2025-04-25T13:29:45.059Z
Learning: The `using Amdocs.Ginger.Repository;` statement in Ginger/GingerCoreNET/RunLib/CLILib/DoOptionsHanlder.cs is necessary as it imports the ObservableList<> class which is used throughout the file.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-03-20T11:10:30.816Z
Learnt from: GokulBothe99
PR: Ginger-Automation/Ginger#4137
File: Ginger/Ginger/SourceControl/SourceControlProjectsPage.xaml.cs:21-21
Timestamp: 2025-03-20T11:10:30.816Z
Learning: The `Amdocs.Ginger.Common.SourceControlLib` namespace is required in files that reference the `GingerSolution` class for source control operations in the Ginger automation framework.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs
📚 Learning: 2025-06-16T09:52:40.873Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4232
File: Ginger/GingerCoreNET/ActionsLib/UI/VisualTesting/VRTAnalyzer.cs:19-22
Timestamp: 2025-06-16T09:52:40.873Z
Learning: The `GenericAppiumDriver` class is located in the `Amdocs.Ginger.CoreNET` namespace, not in a namespace that matches its file path structure. File paths don't always correspond to namespace declarations in this codebase.

Applied to files:

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
📚 Learning: 2024-07-26T22:04:12.930Z
Learnt from: Maheshkale447
PR: Ginger-Automation/Ginger#3637
File: Ginger/GingerCoreNET/Application Models/Execution/POM/POMExecutionUtils.cs:226-234
Timestamp: 2024-07-26T22:04:12.930Z
Learning: The `LastUpdatedTime` in the `POMExecutionUtils.cs` file of the Ginger project is always in the correct DateTime format, as confirmed by the user. This information is crucial for avoiding unnecessary error handling suggestions in future reviews.

Applied to files:

  • Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs
📚 Learning: 2025-07-16T14:42:32.229Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4254
File: Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml.cs:70-73
Timestamp: 2025-07-16T14:42:32.229Z
Learning: In Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml.cs, prashelke prefers to keep the current `!WorkSpace.Instance.BetaFeatures.ShowPOMForAI` logic for binding and showing AI POM controls, rather than changing it to positive logic.

Applied to files:

  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml
📚 Learning: 2025-07-16T14:17:56.429Z
Learnt from: prashelke
PR: Ginger-Automation/Ginger#4254
File: Ginger/GingerCoreNET/GeneralLib/ElementWrapperInfo.cs:89-93
Timestamp: 2025-07-16T14:17:56.429Z
Learning: In Ginger/GingerCoreNET/GeneralLib/ElementWrapperInfo.cs, the user prashelke prefers to keep the current casing for properties `insideIframe` and `insideShadowDOM` in the `ElementwrapperContext` class rather than changing them to PascalCase.

Applied to files:

  • Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml
🧬 Code graph analysis (9)
Ginger/GingerCoreNET/GeneralLib/General.cs (3)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (2)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (2)
  • ActSecurityTesting (41-410)
  • Fields (43-46)
Ginger/GingerCore/GeneralLib/General.cs (1)
  • FillComboFromEnumType (212-248)
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebServicesDriverEditPage.xaml.cs (3)
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (2)
  • WebServicesDriver (48-1090)
  • WebServicesDriver (225-228)
Ginger/GingerCore/GeneralLib/InputBoxWindow.xaml.cs (1)
  • ObjFieldBinding (147-157)
Ginger/GingerCore/GeneralLib/General.cs (1)
  • FillComboFromEnumType (212-248)
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (4)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1)
  • Task (131-164)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (5)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1)
  • SolutionRepository (37-78)
Ginger/GingerCoreCommon/ReporterLib/Reporter.cs (1)
  • Reporter (28-357)
Ginger/GingerCoreNET/ValueExpressionLib/ValueExpression.cs (2)
  • PasswordCalculation (2039-2064)
  • IsThisAValueExpression (702-734)
Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs (3)
Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs (1)
  • Init (43-49)
Ginger/Ginger/ValueExpression/UCValueExpression.xaml.cs (4)
  • Init (56-63)
  • Init (79-96)
  • UCValueExpression (30-160)
  • UCValueExpression (40-44)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (6)
  • eBrowserType (517-520)
  • SeleniumDriver (83-11855)
  • SeleniumDriver (470-473)
  • SeleniumDriver (475-481)
  • SeleniumDriver (483-486)
  • SeleniumDriver (488-491)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreNET/WorkSpaceLib/WorkSpace.cs (1)
  • WorkSpace (61-1006)
Ginger/GingerCoreCommon/Repository/GingerSolutionRepository.cs (1)
  • SolutionRepository (37-78)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (3)
  • ActSecurityTesting (41-410)
  • ExecuteActiveZapScan (210-267)
  • ExecutePassiveZapScan (269-312)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (4)
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (1)
  • ObservableList (94-105)
Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs (11)
  • List (208-213)
  • List (294-310)
  • ZapProxyService (14-312)
  • ZapProxyService (21-29)
  • IsZapRunning (35-48)
  • AddUrlToScanTree (183-202)
  • PerformActiveScan (219-233)
  • EvaluateScanResult (262-284)
  • EvaluateScanResult (286-292)
  • ActiveScanAPI (255-261)
  • GenerateZapReport (69-83)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreCommon/Actions/Act.cs (3)
  • AddArtifactToAction (1122-1136)
  • AddOrUpdateReturnParamActual (1308-1335)
  • AddOrUpdateReturnParamActualWithPath (1359-1387)
Ginger/GingerCoreNET/Drivers/WebServicesDriver/WebServicesDriver.cs (5)
Ginger/GingerCoreCommon/External/Configurations/ZAPConfiguration.cs (1)
  • ZAPConfiguration (5-71)
Ginger/GingerCoreCommon/Actions/Act.cs (5)
  • GetInputParamValue (853-863)
  • GetInputParamValue (976-981)
  • Fields (99-143)
  • GetInputParamCalculatedValue (938-957)
  • GetInputParamCalculatedValue (966-973)
Ginger/GingerCoreCommon/Actions/Webservices/ActWebAPIBase.cs (3)
  • ActWebAPIBase (37-408)
  • ActWebAPIBase (39-43)
  • Fields (71-94)
Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs (4)
  • Fields (43-46)
  • ActSecurityTesting (41-410)
  • ExecutePassiveZapScan (269-312)
  • ExecuteApiSecurityTestWithOpenApi (314-367)
Ginger/Ginger/Actions/ActionEditPages/ActSecurityTestingEditPage.xaml.cs (1)
  • ObservableList (94-105)

Comment on lines +354 to +359
// show only for Selenium Driver
if (mAgent.DriverType != Agent.eDriverType.Selenium)
{
xZAPConfigExpander.Visibility = Visibility.Collapsed;
}
#endregion

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Avoid creating ZAP params for non‑Selenium agents

You collapse the expander for non‑Selenium drivers, but still create/bind the param. Wrap param creation/bindings inside the driver check to keep agent configs clean.

-            DriverConfigParam UseSecurityTesting = mAgent.GetOrCreateParam(nameof(SeleniumDriver.UseSecurityTesting), "false");
-            BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.IsCheckedProperty, UseSecurityTesting, nameof(DriverConfigParam.Value));
-            BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.ToolTipProperty, UseSecurityTesting, nameof(DriverConfigParam.Description));
-
-            // show only for Selenium Driver
-            if (mAgent.DriverType != Agent.eDriverType.Selenium)
-            {
-                xZAPConfigExpander.Visibility = Visibility.Collapsed;
-            }
+            // show only for Selenium Driver
+            if (mAgent.DriverType == Agent.eDriverType.Selenium)
+            {
+                DriverConfigParam UseSecurityTesting = mAgent.GetOrCreateParam(nameof(SeleniumDriver.UseSecurityTesting), "false");
+                BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.IsCheckedProperty, UseSecurityTesting, nameof(DriverConfigParam.Value));
+                BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.ToolTipProperty, UseSecurityTesting, nameof(DriverConfigParam.Description));
+            }
+            else
+            {
+                xZAPConfigExpander.Visibility = Visibility.Collapsed;
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// show only for Selenium Driver
if (mAgent.DriverType != Agent.eDriverType.Selenium)
{
xZAPConfigExpander.Visibility = Visibility.Collapsed;
}
#endregion
// show only for Selenium Driver
if (mAgent.DriverType == Agent.eDriverType.Selenium)
{
DriverConfigParam UseSecurityTesting = mAgent.GetOrCreateParam(nameof(SeleniumDriver.UseSecurityTesting), "false");
BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.IsCheckedProperty, UseSecurityTesting, nameof(DriverConfigParam.Value));
BindingHandler.ObjFieldBinding(xEnableZAPCheckBox, CheckBox.ToolTipProperty, UseSecurityTesting, nameof(DriverConfigParam.Description));
}
else
{
xZAPConfigExpander.Visibility = Visibility.Collapsed;
}
#endregion
🤖 Prompt for AI Agents
In Ginger/Ginger/Drivers/DriversConfigsEditPages/WebAgentConfigEditPage.xaml.cs
around lines 354-359, the code collapses the ZAP expander for non‑Selenium
agents but still creates and binds ZAP parameters; move the ZAP param creation
and binding code inside the same if (mAgent.DriverType ==
Agent.eDriverType.Selenium) block (or wrap with an equivalent guard) so that
parameter objects, bindings and any event handlers are only created when the
agent is Selenium, leaving non‑Selenium agent configs clean.

Comment on lines +67 to +84
private async void xTestConBtn_Click(object sender, RoutedEventArgs e)
{
ShowLoader();
xTestConBtn.IsEnabled = false;
if (AreRequiredFieldsEmpty())
{
Reporter.ToUser(eUserMsgKey.RequiredFieldsEmpty);
HideLoader();
xTestConBtn.IsEnabled = true;
return;
}

bool isConnected = await TestZAPConnectionAsync(ValueExpression.PasswordCalculation(zAPConfiguration.ZAPUrl), ValueExpression.PasswordCalculation(zAPConfiguration.ZAPApiKey));
ShowConnectionResult(isConnected);

HideLoader();
xTestConBtn.IsEnabled = true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Optional: ensure UI state reset via finally

Wrap the body in try/finally to guarantee HideLoader and button re-enable on any early return.

- ShowLoader();
- xTestConBtn.IsEnabled = false;
- if (AreRequiredFieldsEmpty())
- {
-     Reporter.ToUser(eUserMsgKey.RequiredFieldsEmpty);
-     HideLoader();
-     xTestConBtn.IsEnabled = true;
-     return;
- }
- bool isConnected = await TestZAPConnectionAsync(...);
- ShowConnectionResult(isConnected);
- HideLoader();
- xTestConBtn.IsEnabled = true;
+ ShowLoader();
+ xTestConBtn.IsEnabled = false;
+ try
+ {
+     if (AreRequiredFieldsEmpty())
+     {
+         Reporter.ToUser(eUserMsgKey.RequiredFieldsEmpty);
+         return;
+     }
+     bool isConnected = await TestZAPConnectionAsync(...);
+     ShowConnectionResult(isConnected);
+ }
+ finally
+ {
+     HideLoader();
+     xTestConBtn.IsEnabled = true;
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private async void xTestConBtn_Click(object sender, RoutedEventArgs e)
{
ShowLoader();
xTestConBtn.IsEnabled = false;
if (AreRequiredFieldsEmpty())
{
Reporter.ToUser(eUserMsgKey.RequiredFieldsEmpty);
HideLoader();
xTestConBtn.IsEnabled = true;
return;
}
bool isConnected = await TestZAPConnectionAsync(ValueExpression.PasswordCalculation(zAPConfiguration.ZAPUrl), ValueExpression.PasswordCalculation(zAPConfiguration.ZAPApiKey));
ShowConnectionResult(isConnected);
HideLoader();
xTestConBtn.IsEnabled = true;
}
private async void xTestConBtn_Click(object sender, RoutedEventArgs e)
{
ShowLoader();
xTestConBtn.IsEnabled = false;
try
{
if (AreRequiredFieldsEmpty())
{
Reporter.ToUser(eUserMsgKey.RequiredFieldsEmpty);
return;
}
bool isConnected = await TestZAPConnectionAsync(
ValueExpression.PasswordCalculation(zAPConfiguration.ZAPUrl),
ValueExpression.PasswordCalculation(zAPConfiguration.ZAPApiKey));
ShowConnectionResult(isConnected);
}
finally
{
HideLoader();
xTestConBtn.IsEnabled = true;
}
}
🤖 Prompt for AI Agents
In Ginger/Ginger/ExternalConfigurations/ZAPConfigurationPage.xaml.cs around
lines 67 to 84, the UI state (loader visibility and button enabled state) is not
guaranteed to be reset on every code path; wrap the body after ShowLoader() and
xTestConBtn.IsEnabled = false in a try/finally block, move the early-field-empty
check and the async TestZAPConnectionAsync call inside the try, perform the
Reporter.ToUser call and any early returns inside the try, and in the finally
ensure HideLoader() is called and xTestConBtn.IsEnabled is set to true so the
loader is hidden and the button re-enabled on success, failure, or exceptions.

Comment on lines +210 to +267
public void ExecuteActiveZapScan(string testURL)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{

if (zapProxyService.IsZapRunning())
{
zapProxyService.AddUrlToScanTree(testURL);
zapProxyService.PerformActiveScan(testURL);

ProcessResultAsync(zapProxyService, this, testURL);
AddZapAlertOutputValues(zapProxyService, this, testURL);
if (AlertList != null)
{
bool isPassed = zapProxyService.EvaluateScanResult(testURL, AlertList);
if (isPassed)
{
Status = eRunStatus.Passed;
return;

}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
return;
}
}

if (zapProxyService.EvaluateScanResult(testURL))
{
Status = eRunStatus.Passed;
return;
}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
return;
}
}
else
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
return;
}
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP scan: {ex.Message}";
return;
}

}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Active path: validate URL, reduce early returns, and surface add-to-tree errors

Avoid multiple returns and ensure we fail fast on invalid input. Also, AddUrlToScanTree now throws on failure; catch/log and mark action failed.

 public void ExecuteActiveZapScan(string testURL)
 {
     Status = eRunStatus.Running;
     ZapProxyService zapProxyService = new ZapProxyService();
     try
     {
-
-        if (zapProxyService.IsZapRunning())
-        {
-            zapProxyService.AddUrlToScanTree(testURL);
-            zapProxyService.PerformActiveScan(testURL);
-
-            ProcessResultAsync(zapProxyService, this, testURL);
-            AddZapAlertOutputValues(zapProxyService, this, testURL);
+        if (!zapProxyService.IsZapRunning())
+        {
+            Status = eRunStatus.Failed;
+            Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
+            return;
+        }
+        if (string.IsNullOrWhiteSpace(testURL))
+        {
+            Status = eRunStatus.Failed;
+            Error = "Test URL is empty. Provide a valid URL for active scan.";
+            return;
+        }
+        try
+        {
+            zapProxyService.AddUrlToScanTree(testURL);
+        }
+        catch (Exception ex)
+        {
+            Status = eRunStatus.Failed;
+            Error = $"Failed to prepare scan tree: {ex.Message}";
+            return;
+        }
+        zapProxyService.PerformActiveScan(testURL);
+
+        ProcessResult(zapProxyService, this, testURL);
+        AddZapAlertOutputValues(zapProxyService, this, testURL);
         if (AlertList != null)
         {
             bool isPassed = zapProxyService.EvaluateScanResult(testURL, AlertList);
             if (isPassed)
             {
                 Status = eRunStatus.Passed;
-                return;
-
             }
             else
             {
                 Status = eRunStatus.Failed;
                 Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
-                return;
             }
+            return;
         }
 
         if (zapProxyService.EvaluateScanResult(testURL))
         {
             Status = eRunStatus.Passed;
-            return;
         }
         else
         {
             Status = eRunStatus.Failed;
             Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
-            return;
         }
-        }
-        else
-        {
-            Status = eRunStatus.Failed;
-            Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
-            return;
-        }
+        return;
     }
     catch (Exception ex)
     {
         Status = eRunStatus.Failed;
         Error = $"Error while executing ZAP scan: {ex.Message}";
         return;
     }
 
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void ExecuteActiveZapScan(string testURL)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{
if (zapProxyService.IsZapRunning())
{
zapProxyService.AddUrlToScanTree(testURL);
zapProxyService.PerformActiveScan(testURL);
ProcessResultAsync(zapProxyService, this, testURL);
AddZapAlertOutputValues(zapProxyService, this, testURL);
if (AlertList != null)
{
bool isPassed = zapProxyService.EvaluateScanResult(testURL, AlertList);
if (isPassed)
{
Status = eRunStatus.Passed;
return;
}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
return;
}
}
if (zapProxyService.EvaluateScanResult(testURL))
{
Status = eRunStatus.Passed;
return;
}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
return;
}
}
else
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
return;
}
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP scan: {ex.Message}";
return;
}
}
public void ExecuteActiveZapScan(string testURL)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{
// Fail fast if ZAP proxy isn’t running
if (!zapProxyService.IsZapRunning())
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
return;
}
// Validate input URL
if (string.IsNullOrWhiteSpace(testURL))
{
Status = eRunStatus.Failed;
Error = "Test URL is empty. Provide a valid URL for active scan.";
return;
}
// Surface errors from AddUrlToScanTree
try
{
zapProxyService.AddUrlToScanTree(testURL);
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Failed to prepare scan tree: {ex.Message}";
return;
}
zapProxyService.PerformActiveScan(testURL);
ProcessResult(zapProxyService, this, testURL);
AddZapAlertOutputValues(zapProxyService, this, testURL);
if (AlertList != null)
{
bool isPassed = zapProxyService.EvaluateScanResult(testURL, AlertList);
if (isPassed)
{
Status = eRunStatus.Passed;
}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
return;
}
if (zapProxyService.EvaluateScanResult(testURL))
{
Status = eRunStatus.Passed;
}
else
{
Status = eRunStatus.Failed;
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
return;
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP scan: {ex.Message}";
return;
}
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/ActionsLib/UI/Web/ActSecurityTesting.cs around lines
210-267, validate testURL up front (null/empty and Uri.IsWellFormedUriString)
and set Status=eRunStatus.Failed with a clear Error message if invalid, then
return; before calling AddUrlToScanTree wrap that call in its own try/catch to
capture any thrown exception, set Status=Failed and Error with the exception
message and stop processing; simplify control flow by removing the multiple
early returns inside the scan success/failure branches—set Status/Error as
appropriate and let the method exit once at the end (or return after the single
consolidated outcome) so the method fails fast on invalid input and surfaces
add-to-tree errors.

Comment on lines +314 to +367
public void ExecuteApiSecurityTestWithOpenApi(string apiEndpointURL, Act act)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{
if (zapProxyService.IsZapRunning())
{
if (!string.IsNullOrEmpty(apiEndpointURL))
{

zapProxyService.ActiveScanAPI(apiEndpointURL);
}


ProcessResultAsync(zapProxyService, act, apiEndpointURL);
AddZapAlertOutputValues(zapProxyService, act, apiEndpointURL);
bool isPassed = AlertList != null
? zapProxyService.EvaluateScanResult(apiEndpointURL, AlertList)
: zapProxyService.EvaluateScanResult(apiEndpointURL);


Status = isPassed ? eRunStatus.Passed : eRunStatus.Failed;
if (!isPassed)
{
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}

if (act is ActWebAPIBase)
{

var alertSummary = zapProxyService.GetAlertSummary(apiEndpointURL);

int totalAlerts = alertSummary.Sum(a => a.Count);
if (totalAlerts > 0)
{
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
}

}
else
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
}
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP API security scan: {ex.Message}";
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

API scan path: rename ProcessResult, and minor flow cleanup*

Use the renamed ProcessResult; keep single exit for status handling.

- ProcessResultAsync(zapProxyService, act, apiEndpointURL);
+ ProcessResult(zapProxyService, act, apiEndpointURL);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void ExecuteApiSecurityTestWithOpenApi(string apiEndpointURL, Act act)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{
if (zapProxyService.IsZapRunning())
{
if (!string.IsNullOrEmpty(apiEndpointURL))
{
zapProxyService.ActiveScanAPI(apiEndpointURL);
}
ProcessResultAsync(zapProxyService, act, apiEndpointURL);
AddZapAlertOutputValues(zapProxyService, act, apiEndpointURL);
bool isPassed = AlertList != null
? zapProxyService.EvaluateScanResult(apiEndpointURL, AlertList)
: zapProxyService.EvaluateScanResult(apiEndpointURL);
Status = isPassed ? eRunStatus.Passed : eRunStatus.Failed;
if (!isPassed)
{
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
if (act is ActWebAPIBase)
{
var alertSummary = zapProxyService.GetAlertSummary(apiEndpointURL);
int totalAlerts = alertSummary.Sum(a => a.Count);
if (totalAlerts > 0)
{
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
}
}
else
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
}
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP API security scan: {ex.Message}";
}
}
public void ExecuteApiSecurityTestWithOpenApi(string apiEndpointURL, Act act)
{
Status = eRunStatus.Running;
ZapProxyService zapProxyService = new ZapProxyService();
try
{
if (zapProxyService.IsZapRunning())
{
if (!string.IsNullOrEmpty(apiEndpointURL))
{
zapProxyService.ActiveScanAPI(apiEndpointURL);
}
// Updated to match the renamed method
ProcessResult(zapProxyService, act, apiEndpointURL);
AddZapAlertOutputValues(zapProxyService, act, apiEndpointURL);
bool isPassed = AlertList != null
? zapProxyService.EvaluateScanResult(apiEndpointURL, AlertList)
: zapProxyService.EvaluateScanResult(apiEndpointURL);
Status = isPassed ? eRunStatus.Passed : eRunStatus.Failed;
if (!isPassed)
{
Error = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
if (act is ActWebAPIBase)
{
var alertSummary = zapProxyService.GetAlertSummary(apiEndpointURL);
int totalAlerts = alertSummary.Sum(a => a.Count);
if (totalAlerts > 0)
{
act.ExInfo = "Vulnerability Issues Found, Please check the report in Output Values Artifact ";
}
}
}
else
{
Status = eRunStatus.Failed;
Error = "ZAP Proxy is not running. Please start ZAP Proxy before executing the scan.";
}
}
catch (Exception ex)
{
Status = eRunStatus.Failed;
Error = $"Error while executing ZAP API security scan: {ex.Message}";
}
}

Comment on lines +606 to +637
if (this.UseSecurityTesting)
{

ZAPConfiguration zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0 ? new ZAPConfiguration() : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();

if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
{
Reporter.ToLog(eLogLevel.WARN, "UseZAP is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
}
else
{

// Normalize to host:port for Selenium Proxy
string zapHostPort = CoerceZapHostPort(zAPConfiguration.ZAPUrl);
Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
if (mProxy == null)
{

mProxy = new Proxy();
}
mProxy.Kind = ProxyKind.Manual;
mProxy.HttpProxy = Proxy;
mProxy.FtpProxy = Proxy;
mProxy.SslProxy = Proxy;
mProxy.SocksProxy = Proxy;

if (!string.IsNullOrEmpty(ByPassProxy))
{
mProxy.AddBypassAddresses(AddByPassAddress());
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

ZAP proxy wiring: fix naming, avoid SOCKS, and set explicit host:port.

  • Message says "UseZAP" but the property is UseSecurityTesting—rename for consistency.
  • Assign only HttpProxy/SslProxy (optionally FtpProxy). Setting SocksProxy is unnecessary and has caused driver issues in the past.
  • Set fields from zapHostPort directly rather than the mutable Proxy string.
-                if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
+                if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
                 {
-                    Reporter.ToLog(eLogLevel.WARN, "UseZAP is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
+                    Reporter.ToLog(eLogLevel.WARN, "UseSecurityTesting is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
                 }
                 else
                 {
 
                     // Normalize to host:port for Selenium Proxy
                     string zapHostPort = CoerceZapHostPort(zAPConfiguration.ZAPUrl);
-                    Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
+                    Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
                     if (mProxy == null)
                     {
 
                         mProxy = new Proxy();
                     }
                     mProxy.Kind = ProxyKind.Manual;
-                    mProxy.HttpProxy = Proxy;
-                    mProxy.FtpProxy = Proxy;
-                    mProxy.SslProxy = Proxy;
-                    mProxy.SocksProxy = Proxy;
+                    mProxy.HttpProxy = zapHostPort;
+                    mProxy.FtpProxy = zapHostPort;
+                    mProxy.SslProxy = zapHostPort;
 
                     if (!string.IsNullOrEmpty(ByPassProxy))
                     {
                         mProxy.AddBypassAddresses(AddByPassAddress());
                     }
                 }

To ensure UseSecurityTesting actually takes effect when a custom user profile path is supplied (e.g., Edge/Firefox), verify that SetProxy(...) is still called in those branches or assign options.Proxy directly. Run this quick scan:


🏁 Script executed:

#!/bin/bash
# Inspect SetProxy calls and gating conditions to ensure proxy is applied even with user profiles
rg -n -C3 'SetProxy\\(' Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs

Length of output: 170


I’ll retry the proxy-injection check with a corrected search pattern to locate all SetProxy( calls in the Selenium driver:


🏁 Script executed:

#!/bin/bash
# Inspect SetProxy calls and surrounding context to ensure proxy is applied even when custom user profiles are used
rg -n -C3 'SetProxy\(' Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs

Length of output: 1419


Refactor ZAP proxy wiring for UseSecurityTesting

To ensure consistency and avoid past driver issues with SOCKS proxy, update the ZAP proxy block as follows:

  • Rename the warning message to reference UseSecurityTesting instead of the legacy “UseZAP.”
  • Only set HttpProxy, FtpProxy, and SslProxy on mProxy; remove the unnecessary SocksProxy assignment.
  • Assign the normalized zapHostPort directly to each proxy field rather than using the mutable Proxy string.
  • Verified that SetProxy(...) is invoked in all browser-launch code paths (Firefox, IE, Edge, and default options), so the proxy will still apply when custom profiles are used.

Apply this diff in SeleniumDriver.cs (lines ~615–635):

-                if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
+                if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
                 {
-                    Reporter.ToLog(eLogLevel.WARN, "UseZAP is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
+                    Reporter.ToLog(eLogLevel.WARN, "UseSecurityTesting is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
                 }
                 else
                 {
                     // Normalize to host:port for Selenium Proxy
                     string zapHostPort = CoerceZapHostPort(zAPConfiguration.ZAPUrl);
-                    Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
+                    Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
                     if (mProxy == null)
                     {
                         mProxy = new Proxy();
                     }
                     mProxy.Kind = ProxyKind.Manual;
-                    mProxy.HttpProxy = Proxy;
-                    mProxy.FtpProxy = Proxy;
-                    mProxy.SslProxy = Proxy;
-                    mProxy.SocksProxy = Proxy;
+                    mProxy.HttpProxy = zapHostPort;
+                    mProxy.FtpProxy = zapHostPort;
+                    mProxy.SslProxy = zapHostPort;
 
                     if (!string.IsNullOrEmpty(ByPassProxy))
                     {
                         mProxy.AddBypassAddresses(AddByPassAddress());
                     }
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (this.UseSecurityTesting)
{
ZAPConfiguration zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0 ? new ZAPConfiguration() : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
{
Reporter.ToLog(eLogLevel.WARN, "UseZAP is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
}
else
{
// Normalize to host:port for Selenium Proxy
string zapHostPort = CoerceZapHostPort(zAPConfiguration.ZAPUrl);
Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
if (mProxy == null)
{
mProxy = new Proxy();
}
mProxy.Kind = ProxyKind.Manual;
mProxy.HttpProxy = Proxy;
mProxy.FtpProxy = Proxy;
mProxy.SslProxy = Proxy;
mProxy.SocksProxy = Proxy;
if (!string.IsNullOrEmpty(ByPassProxy))
{
mProxy.AddBypassAddresses(AddByPassAddress());
}
}
}
if (this.UseSecurityTesting)
{
var zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0
? new ZAPConfiguration()
: WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
if (string.IsNullOrEmpty(zAPConfiguration.ZAPUrl))
{
Reporter.ToLog(eLogLevel.WARN, "UseSecurityTesting is enabled but ZAP Url is empty. Traffic will not be routed through ZAP.");
}
else
{
// Normalize to host:port for Selenium Proxy
string zapHostPort = CoerceZapHostPort(zAPConfiguration.ZAPUrl);
Proxy = zapHostPort; // keep legacy string in sync if used elsewhere
if (mProxy == null)
{
mProxy = new Proxy();
}
mProxy.Kind = ProxyKind.Manual;
mProxy.HttpProxy = zapHostPort;
mProxy.FtpProxy = zapHostPort;
mProxy.SslProxy = zapHostPort;
if (!string.IsNullOrEmpty(ByPassProxy))
{
mProxy.AddBypassAddresses(AddByPassAddress());
}
}
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
around lines 606 to 637, update the ZAP proxy wiring: change the warning text to
reference UseSecurityTesting instead of "UseZAP"; compute zapHostPort with
CoerceZapHostPort and do not rely on the mutable Proxy string when assigning to
mProxy fields—assign zapHostPort directly to mProxy.HttpProxy, mProxy.FtpProxy
and mProxy.SslProxy (remove the mProxy.SocksProxy assignment); continue to set
the legacy Proxy field only if you must keep it in sync, ensure mProxy is
initialized if null, and preserve the existing bypass-address handling
(mProxy.AddBypassAddresses(AddByPassAddress())) so SetProxy(...) will apply in
all browser-launch paths.

Comment on lines +14 to +29
public class ZapProxyService
{
private readonly ClientApi _zapClient;
private readonly string _zapApiKey;
private readonly ZAPConfiguration zAPConfiguration;
private readonly string _zapHost;
private readonly int _zapPort;
public ZapProxyService()
{
zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0 ? new ZAPConfiguration() : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
_zapHost = GetHostFromUrl(zAPConfiguration.ZAPUrl);
_zapPort = (int)GetPortFromUrl(zAPConfiguration.ZAPUrl);
_zapApiKey = zAPConfiguration.ZAPApiKey;
_zapClient = new ClientApi(_zapHost, _zapPort, _zapApiKey);

}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Testability: add DI-friendly constructor overload

Consider an overload to supply host/port/apiKey for unit tests or alternative configuration sources.

public ZapProxyService(string host, int port, string apiKey)
{
    if (string.IsNullOrWhiteSpace(host)) throw new ArgumentNullException(nameof(host));
    if (port <= 0) throw new ArgumentOutOfRangeException(nameof(port));
    _zapHost = host;
    _zapPort = port;
    _zapApiKey = apiKey ?? string.Empty;
    _zapClient = new ClientApi(_zapHost, _zapPort, _zapApiKey);
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 14 to 29,
add a DI-friendly constructor overload that accepts host, port and apiKey so
unit tests and alternate configs can inject values; validate inputs (throw
ArgumentNullException/ArgumentOutOfRangeException for bad host/port), set
_zapHost/_zapPort/_zapApiKey accordingly (use empty string for null apiKey) and
initialize _zapClient with those values, and update the parameterless
constructor to reuse this overload by passing the values extracted from
ZAPConfiguration.

Comment on lines +21 to +29
public ZapProxyService()
{
zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0 ? new ZAPConfiguration() : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
_zapHost = GetHostFromUrl(zAPConfiguration.ZAPUrl);
_zapPort = (int)GetPortFromUrl(zAPConfiguration.ZAPUrl);
_zapApiKey = zAPConfiguration.ZAPApiKey;
_zapClient = new ClientApi(_zapHost, _zapPort, _zapApiKey);

}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Null/parse handling and decryption for ZAP configuration are missing

Casting a nullable port to int may throw; host can be null; API key should be decrypted. Provide safe defaults and logs.

 public ZapProxyService()
 {
-    zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0 ? new ZAPConfiguration() : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
-    _zapHost = GetHostFromUrl(zAPConfiguration.ZAPUrl);
-    _zapPort = (int)GetPortFromUrl(zAPConfiguration.ZAPUrl);
-    _zapApiKey = zAPConfiguration.ZAPApiKey;
-    _zapClient = new ClientApi(_zapHost, _zapPort, _zapApiKey);
+    zAPConfiguration = WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0
+        ? new ZAPConfiguration()
+        : WorkSpace.Instance.SolutionRepository.GetFirstRepositoryItem<ZAPConfiguration>();
+
+    var zapUrl = zAPConfiguration.ZAPUrl?.Trim();
+    _zapHost = GetHostFromUrl(zapUrl) ?? "127.0.0.1";
+    _zapPort = GetPortFromUrl(zapUrl) ?? 8080; // ZAP default
+    _zapApiKey = ValueExpression.PasswordCalculation(zAPConfiguration.ZAPApiKey);
+    if (string.IsNullOrWhiteSpace(_zapHost))
+    {
+        Reporter.ToLog(eLogLevel.WARN, "ZAP host parsed as empty; using 127.0.0.1");
+        _zapHost = "127.0.0.1";
+    }
+    _zapClient = new ClientApi(_zapHost, _zapPort, _zapApiKey ?? string.Empty);
 }
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 21 to 29,
the constructor assumes ZAPConfiguration fields are non-null and casts a
nullable port directly to int and doesn't decrypt the API key; update it to (1)
null-check zAPConfiguration and use a new ZAPConfiguration() fallback if
missing, (2) call GetHostFromUrl safely and default to "localhost" if it returns
null/empty while logging a warning, (3) parse the port via a safe Try/parse
pattern or check HasValue before casting and use a sensible default port (e.g.,
8080) with a logged warning if parsing fails, (4) decrypt the ZAPApiKey using
the project’s existing secret/decryption utility before assigning to _zapApiKey
and handle empty/missing keys by setting to null and logging, and (5) wrap
ClientApi creation in try/catch to log any exceptions and avoid throwing on
construction failure.

Comment on lines +178 to +203
/// <summary>
/// Adds a URL to the ZAP scan tree.
/// Throws an exception if the URL is not added successfully.
/// </summary>
/// <param name="siteToTest">The site URL to add to the scan tree.</param>
public void AddUrlToScanTree(string siteToTest)
{
try
{
_zapClient.core.accessUrl(siteToTest, "false");
var urls = GetUrlsFromScanTree(siteToTest);
if (urls.Contains(siteToTest))
{
Reporter.ToLog(eLogLevel.INFO, $"{siteToTest} has been added to scan tree");
}
else
{
throw new InvalidOperationException($"{siteToTest} not added to scan tree, active scan will not be possible");
}
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, $"Failed to add {siteToTest} to scan tree: {ex.Message}", ex);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Behavior mismatch: method promises to throw on failure but swallows exceptions

Docstring says it throws if URL isn’t added, but catch block logs and suppresses. Either rethrow or return bool. Recommend rethrow to honor the contract.

-        public void AddUrlToScanTree(string siteToTest)
+        public void AddUrlToScanTree(string siteToTest)
         {
-            try
-            {
-                _zapClient.core.accessUrl(siteToTest, "false");
-                var urls = GetUrlsFromScanTree(siteToTest);
-                if (urls.Contains(siteToTest))
-                {
-                    Reporter.ToLog(eLogLevel.INFO, $"{siteToTest} has been added to scan tree");
-                }
-                else
-                {
-                    throw new InvalidOperationException($"{siteToTest} not added to scan tree, active scan will not be possible");
-                }
-            }
-            catch (Exception ex)
-            {
-                Reporter.ToLog(eLogLevel.ERROR, $"Failed to add {siteToTest} to scan tree: {ex.Message}", ex);
-            }
+            try
+            {
+                _zapClient.core.accessUrl(siteToTest, "false");
+                var urls = GetUrlsFromScanTree(siteToTest);
+                if (urls.Contains(siteToTest))
+                {
+                    Reporter.ToLog(eLogLevel.INFO, $"{siteToTest} has been added to scan tree");
+                    return;
+                }
+                throw new InvalidOperationException($"{siteToTest} not added to scan tree, active scan will not be possible");
+            }
+            catch (Exception ex)
+            {
+                Reporter.ToLog(eLogLevel.ERROR, $"Failed to add {siteToTest} to scan tree: {ex.Message}", ex);
+                throw;
+            }
         }

Follow-up: update call sites to handle the thrown exception (see ActSecurityTesting comments).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// <summary>
/// Adds a URL to the ZAP scan tree.
/// Throws an exception if the URL is not added successfully.
/// </summary>
/// <param name="siteToTest">The site URL to add to the scan tree.</param>
public void AddUrlToScanTree(string siteToTest)
{
try
{
_zapClient.core.accessUrl(siteToTest, "false");
var urls = GetUrlsFromScanTree(siteToTest);
if (urls.Contains(siteToTest))
{
Reporter.ToLog(eLogLevel.INFO, $"{siteToTest} has been added to scan tree");
}
else
{
throw new InvalidOperationException($"{siteToTest} not added to scan tree, active scan will not be possible");
}
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, $"Failed to add {siteToTest} to scan tree: {ex.Message}", ex);
}
}
/// <summary>
/// Adds a URL to the ZAP scan tree.
/// Throws an exception if the URL is not added successfully.
/// </summary>
/// <param name="siteToTest">The site URL to add to the scan tree.</param>
public void AddUrlToScanTree(string siteToTest)
{
try
{
_zapClient.core.accessUrl(siteToTest, "false");
var urls = GetUrlsFromScanTree(siteToTest);
if (urls.Contains(siteToTest))
{
Reporter.ToLog(eLogLevel.INFO, $"{siteToTest} has been added to scan tree");
return;
}
throw new InvalidOperationException($"{siteToTest} not added to scan tree, active scan will not be possible");
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, $"Failed to add {siteToTest} to scan tree: {ex.Message}", ex);
throw;
}
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 178-203 the
method AddUrlToScanTree claims to throw on failure but currently catches all
exceptions and only logs them, swallowing the error; change behavior to preserve
the contract by either removing the try/catch or rethrowing the exception after
logging (i.e., log the error then throw; use throw; to preserve stack trace),
and ensure callers are updated to handle the thrown exception as noted in
ActSecurityTesting comments.

Comment on lines +208 to +213
public List<string> GetUrlsFromScanTree(string baseUrl)
{
var apiResponse = _zapClient.core.urls(baseUrl);
var responses = ((ApiResponseList)apiResponse).List;
return responses.Select(r => ((ApiResponseElement)r).Value).ToList();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Guard against unexpected response shape

Cast may throw if ZAP returns an error type. Fallback to empty list to keep flows resilient.

- var responses = ((ApiResponseList)apiResponse).List;
- return responses.Select(r => ((ApiResponseElement)r).Value).ToList();
+ if (apiResponse is ApiResponseList list)
+ {
+     return list.List.Select(r => ((ApiResponseElement)r).Value).ToList();
+ }
+ Reporter.ToLog(eLogLevel.WARN, "core.urls returned non-list response");
+ return new List<string>();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public List<string> GetUrlsFromScanTree(string baseUrl)
{
var apiResponse = _zapClient.core.urls(baseUrl);
var responses = ((ApiResponseList)apiResponse).List;
return responses.Select(r => ((ApiResponseElement)r).Value).ToList();
}
public List<string> GetUrlsFromScanTree(string baseUrl)
{
var apiResponse = _zapClient.core.urls(baseUrl);
if (apiResponse is ApiResponseList list)
{
return list.List.Select(r => ((ApiResponseElement)r).Value).ToList();
}
Reporter.ToLog(eLogLevel.WARN, "core.urls returned non-list response");
return new List<string>();
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/External/ZAP/ZapProxyService.cs around lines 208 to 213,
the current direct casts to ApiResponseList/ApiResponseElement can throw if ZAP
returns an error shape; change to safely handle unexpected responses by checking
the apiResponse type (use the 'as' operator or pattern matching) and verifying
the List is non-null before selecting values, or wrap the casts in a try/catch
that logs the unexpected response and returns an empty List<string> as a safe
fallback so callers remain resilient.

Comment on lines +794 to +815
public static bool CreateZAPConfiguration()
{
try
{
if (WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0)
{
ZAPConfiguration newZAPConfiguration = new ZAPConfiguration() { Name = "ZAPConfig" };
WorkSpace.Instance.SolutionRepository.AddRepositoryItem(newZAPConfiguration);
return true;
}
else
{
Reporter.ToLog(eLogLevel.DEBUG, "ZAP configuration already exists; skipping creation.");
return false;
}
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, "Error creating ZAP configuration", ex);
return false;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

CreateZAPConfiguration(): solid, aligned with existing config makers

Clear Any/exists check, safe logging, and repository add mirror other CreateXxxConfiguration helpers.

Minor: prefer Any() over Count==0 for readability.

-                if (WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0)
+                if (!WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Any())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static bool CreateZAPConfiguration()
{
try
{
if (WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Count == 0)
{
ZAPConfiguration newZAPConfiguration = new ZAPConfiguration() { Name = "ZAPConfig" };
WorkSpace.Instance.SolutionRepository.AddRepositoryItem(newZAPConfiguration);
return true;
}
else
{
Reporter.ToLog(eLogLevel.DEBUG, "ZAP configuration already exists; skipping creation.");
return false;
}
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, "Error creating ZAP configuration", ex);
return false;
}
}
public static bool CreateZAPConfiguration()
{
try
{
if (!WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Any())
{
ZAPConfiguration newZAPConfiguration = new ZAPConfiguration() { Name = "ZAPConfig" };
WorkSpace.Instance.SolutionRepository.AddRepositoryItem(newZAPConfiguration);
return true;
}
else
{
Reporter.ToLog(eLogLevel.DEBUG, "ZAP configuration already exists; skipping creation.");
return false;
}
}
catch (Exception ex)
{
Reporter.ToLog(eLogLevel.ERROR, "Error creating ZAP configuration", ex);
return false;
}
}
🤖 Prompt for AI Agents
In Ginger/GingerCoreNET/GeneralLib/General.cs around lines 794 to 815, the
CreateZAPConfiguration method uses
GetAllRepositoryItems<ZAPConfiguration>().Count == 0 to check for existence;
change this to use .Any() for clarity and performance (e.g., if
(!WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems<ZAPConfiguration>().Any())
) and adjust the logic accordingly so the behavior remains identical; keep
existing try/catch and logging unchanged.

@Maheshkale447
Maheshkale447 merged commit 336c0c2 into Releases/Beta Aug 25, 2025
3 of 5 checks passed
@Maheshkale447
Maheshkale447 deleted the Feature/WebSecurityTesting branch August 25, 2025 10:04
This was referenced Aug 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants