Skip to content

Conversation

@nvborisenko
Copy link
Member

Now we are forcing user to construct command options object and never change it. So everything in Bidi world now is immutable!

🔗 Related Issues

Contributes to #16095

💥 What does this PR do?

This pull request makes broad improvements to the BiDi WebDriver codebase by refactoring option types from classes to records and switching property setters to initializers. These changes enhance immutability, simplify object construction, and align with modern C# practices. The refactor affects command option types across browser and browsing context modules, as well as related value types and utility structs.

These changes collectively modernize the codebase, making it safer and easier to work with, especially when constructing and passing command options.

🔄 Types of changes

  • Cleanup (formatting, renaming)
  • Bug fix (backwards compatible)
  • New feature (non-breaking change which adds functionality and tests!)
  • Breaking change (fix or feature that would cause existing functionality to change)

Copilot AI review requested due to automatic review settings February 10, 2026 23:14
@selenium-ci selenium-ci added the C-dotnet .NET Bindings label Feb 10, 2026
@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #16095
🟢 Make command option types immutable so callers construct them once and cannot mutate state
afterward (e.g., records with get; init;).
🔴 Move/land driver.AsBiDiAsync() as a final public API on AnyDriver (or possibly
IWebDriver), ensuring the AnyDriver/driver owns the BiDi instance and disposes it with the
driver.
Expose previously hidden/internal methods (e.g., make AddIntercept() public) so users can
call them directly.
Use `EmptyResult` as the standard return type instead of `void` across methods.
Use normal types as event args (address inheritance/topic around event-args types).
Remove overkill syntax sugar where Result implements IReadOnlyList and remove strange JSON
converters for those types.
Ensure commands return the exact types (e.g., Task) instead of wrapper Result objects.
Remove stateful JSON converters that depend on the BiDi object, keeping AOT trimming
friendliness while still allowing extensibility.
Decide on scoped event handlers (remove or keep) and implement accordingly.
Revisit InterceptRequestAsync() (and related response/auth helpers) so these convenience
APIs are implemented as extensions on top of already-public APIs, potentially moved into a
dedicated namespace.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Stack trace exposure: The PR adds/keeps support for attaching StackTrace data to log/event objects which may be
surfaced to consumers and could leak sensitive internals depending on how these entries
are exposed.

Referred Code
public abstract record LogEntry(Level Level, Script.Source Source, string? Text, DateTimeOffset Timestamp)
    : EventArgs
{
    public Script.StackTrace? StackTrace { get; init; }
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive data in logs: The PR includes StackTrace on Initiator (and similarly on log entry types) which can
contain URLs/paths or other sensitive runtime details and should be reviewed to ensure it
is not logged or exposed inappropriately.

Referred Code
public sealed record Initiator(InitiatorType Type)
{
    public long? ColumnNumber { get; init; }

    public long? LineNumber { get; init; }

    public Script.StackTrace? StackTrace { get; init; }

    public Request? Request { get; init; }
}

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

No code suggestions found for the PR.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the .NET BiDi binding’s command option types (and many related value/event types) to be immutable-at-the-API-surface by converting classes to records and replacing property setters with init accessors.

Changes:

  • Convert CommandOptions and most *Options types from classes to records, switching { get; set; } to { get; init; }.
  • Update various BiDi value/event model types (cookies, script values, proxy config, locators, etc.) to use init-only properties.
  • Adjust a few call sites to use object initializers (e.g., ContextTarget sandbox assignment) to comply with init usage.

Reviewed changes

Copilot reviewed 85 out of 85 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs Convert UninstallOptions to a record for immutability.
dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs Convert InstallOptions to a record for immutability.
dotnet/src/webdriver/BiDi/Subscription.cs Convert subscription option types to records and make properties init-only.
dotnet/src/webdriver/BiDi/Storage/SetCookieCommand.cs Make cookie/options properties init-only; convert option types to records.
dotnet/src/webdriver/BiDi/Storage/PartitionKey.cs Make partition key properties init-only.
dotnet/src/webdriver/BiDi/Storage/GetCookiesCommand.cs Convert options to records; make filter/partition properties init-only.
dotnet/src/webdriver/BiDi/Storage/DeleteCookiesCommand.cs Convert options to records; make filter/partition properties init-only.
dotnet/src/webdriver/BiDi/Session/UserPromptHandler.cs Make handler properties init-only.
dotnet/src/webdriver/BiDi/Session/UnsubscribeCommand.cs Convert UnsubscribeByIdOptions to a record.
dotnet/src/webdriver/BiDi/Session/SubscribeCommand.cs Convert SubscribeOptions to a record and make properties init-only.
dotnet/src/webdriver/BiDi/Session/StatusCommand.cs Convert StatusOptions to a record.
dotnet/src/webdriver/BiDi/Session/ProxyConfiguration.cs Make proxy configuration properties init-only; update interface accordingly.
dotnet/src/webdriver/BiDi/Session/NewCommand.cs Convert NewOptions to a record; make capability properties init-only.
dotnet/src/webdriver/BiDi/Session/EndCommand.cs Convert EndOptions to a record.
dotnet/src/webdriver/BiDi/Session/CapabilityRequest.cs Make capability request properties init-only.
dotnet/src/webdriver/BiDi/Session/CapabilitiesRequest.cs Make capabilities request properties init-only.
dotnet/src/webdriver/BiDi/Script/Target.cs Make ContextTarget.Sandbox init-only.
dotnet/src/webdriver/BiDi/Script/Source.cs Make Source.Context init-only.
dotnet/src/webdriver/BiDi/Script/SerializationOptions.cs Convert to record; make serialization settings init-only.
dotnet/src/webdriver/BiDi/Script/RemovePreloadScriptCommand.cs Convert RemovePreloadScriptOptions to a record.
dotnet/src/webdriver/BiDi/Script/RemoteValue.cs Make remote value properties init-only across many variants.
dotnet/src/webdriver/BiDi/Script/RegExpValue.cs Make Flags init-only.
dotnet/src/webdriver/BiDi/Script/RealmInfo.cs Make Sandbox init-only.
dotnet/src/webdriver/BiDi/Script/LocalValue.cs Make remote-reference local value properties init-only.
dotnet/src/webdriver/BiDi/Script/IRemoteReference.cs Make reference interface properties init-only; align implementers.
dotnet/src/webdriver/BiDi/Script/GetRealmsCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs Convert EvaluateOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Script/DisownCommand.cs Convert DisownOptions to a record.
dotnet/src/webdriver/BiDi/Script/ChannelProperties.cs Make channel properties init-only.
dotnet/src/webdriver/BiDi/Script/CallFunctionCommand.cs Convert CallFunctionOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Permissions/SetPermissionCommand.cs Convert SetPermissionOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/UrlPattern.cs Make URL pattern properties init-only.
dotnet/src/webdriver/BiDi/Network/SetExtraHeadersCommand.cs Convert SetExtraHeadersOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/SetCookieHeader.cs Make set-cookie header properties init-only.
dotnet/src/webdriver/BiDi/Network/SetCacheBehaviorCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Network/RemoveInterceptCommand.cs Convert RemoveInterceptOptions to a record.
dotnet/src/webdriver/BiDi/Network/RemoveDataCollectorCommand.cs Convert RemoveDataCollectorOptions to a record.
dotnet/src/webdriver/BiDi/Network/ProvideResponseCommand.cs Convert ProvideResponseOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/NetworkModule.HighLevel.cs Convert interception option marker types to records.
dotnet/src/webdriver/BiDi/Network/Initiator.cs Make initiator properties init-only.
dotnet/src/webdriver/BiDi/Network/GetDataCommand.cs Convert GetDataOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/FailRequestCommand.cs Convert FailRequestOptions to a record.
dotnet/src/webdriver/BiDi/Network/ContinueWithAuthCommand.cs Convert auth continuation option hierarchy to records.
dotnet/src/webdriver/BiDi/Network/ContinueResponseCommand.cs Convert ContinueResponseOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/ContinueRequestCommand.cs Convert ContinueRequestOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs Convert intercept options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Log/LogEntry.cs Make StackTrace init-only.
dotnet/src/webdriver/BiDi/Input/SourceActions.cs Make various input action properties init-only; adjust action container property to init-only.
dotnet/src/webdriver/BiDi/Input/SetFilesCommand.cs Convert SetFilesOptions to a record.
dotnet/src/webdriver/BiDi/Input/ReleaseActionsCommand.cs Convert ReleaseActionsOptions to a record.
dotnet/src/webdriver/BiDi/Input/PerformActionsCommand.cs Convert PerformActionsOptions to a record.
dotnet/src/webdriver/BiDi/Emulation/SetUserAgentOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetTouchOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetTimezoneOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetScriptingEnabledCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetScreenSettingsOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetScreenOrientationOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetNetworkConditionsCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetLocaleOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetGeolocationOverrideCommand.cs Convert geolocation option hierarchy to records; make properties init-only.
dotnet/src/webdriver/BiDi/Emulation/SetForcedColorsModeThemeOverrideCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/CommandOptions.cs Convert base options type to abstract record; make Timeout init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/TraverseHistoryCommand.cs Convert TraverseHistoryOptions to a record.
dotnet/src/webdriver/BiDi/BrowsingContext/SetViewportCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/ReloadCommand.cs Convert ReloadOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/PrintCommand.cs Convert PrintOptions to a record; make print settings init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/NavigateCommand.cs Convert NavigateOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/Locator.cs Make locator/accessibility value properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/LocateNodesCommand.cs Convert LocateNodesOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/HandleUserPromptCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs Convert CreateOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/CloseCommand.cs Convert CloseOptions to a record; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/CaptureScreenshotCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextScriptModule.cs Update sandbox assignment to use object initializer (init-only compliance).
dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs Convert interception option marker types to records.
dotnet/src/webdriver/BiDi/BrowsingContext/ActivateCommand.cs Convert ActivateOptions to a record.
dotnet/src/webdriver/BiDi/Browser/SetDownloadBehaviorCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Browser/RemoveUserContextCommand.cs Convert RemoveUserContextOptions to a record.
dotnet/src/webdriver/BiDi/Browser/GetUserContextsCommand.cs Convert GetUserContextsOptions to a record.
dotnet/src/webdriver/BiDi/Browser/GetClientWindowsCommand.cs Convert GetClientWindowsOptions to a record.
dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs Convert options to records; make properties init-only.
dotnet/src/webdriver/BiDi/Browser/CloseCommand.cs Convert CloseOptions to a record.
Comments suppressed due to low confidence (1)

dotnet/src/webdriver/BiDi/Input/SourceActions.cs:42

  • This PR description states “everything in BiDi world now is immutable”, but SourceActions still exposes a mutable IList and an Add() method that mutates the instance after construction. If the intent is deep immutability, consider switching Actions to an immutable/read-only collection and making mutation APIs return a new instance (or adjust the PR description/scope to clarify that input actions remain mutable builders).

@nvborisenko nvborisenko merged commit 7d7ceae into SeleniumHQ:trunk Feb 11, 2026
32 of 34 checks passed
@nvborisenko nvborisenko deleted the bidi-immutable-commands branch February 11, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants