[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[grid] Dynamic Grid group dynamic containers in compose stack - #16620

Merged
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack
Nov 20, 2025
Merged

[grid] Dynamic Grid group dynamic containers in compose stack#16620
VietND96 merged 2 commits into
trunkfrom
dynamic-grid-compose-stack

Conversation

@VietND96

@VietND96VietND96 commented Nov 20, 2025

Copy link
Copy Markdown
Member

User description

🔗 Related Issues

💥 What does this PR do?

Continue of #16599, #16613 - manage and group dynamic containers in Dynamic Grid under a compose stack (compatible when running with Docker Compose, Podman, or other platforms based on grouping labels defined by the user).

Enhanced filtering to support multiple orchestration systems:

  • Docker Compose: com.docker.compose.project
  • Podman Compose: io.podman.compose.project
  • User-defined grouping labels via CLI --docker-grouping-labels or TOML config key grouping-labels

✅ Platform agnostic - Works with any container orchestration system
✅ User configurable - No code changes needed for new platforms
✅ Backward compatible - Existing setups continue to work
✅ Flexible - Supports multiple custom labels simultaneously
✅ Safe - Only project labels are copied, service labels are excluded

Makes the Dynamic Grid Docker integration truly platform-independent and ready for any container orchestration system.

🔧 Implementation Notes

💡 Additional Considerations

🔄 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)

PR Type

Enhancement


Description

  • Add configurable grouping labels for Docker containers

  • Support multiple orchestration systems (Docker Compose, Podman Compose)

  • Allow user-defined custom labels via CLI and TOML config

  • Filter and apply only project-level labels to containers


Diagram Walkthrough

flowchart LR
A["DockerFlags"] -->|"adds grouping-labels parameter"| B["DockerOptions"]
B -->|"reads custom labels from config"| C["getGroupingLabels"]
C -->|"filters Docker/Podman/custom labels"| D["DockerSessionFactory"]
D -->|"applies labels to containers"| E["Browser & Video Containers"]
Loading

File Walkthrough

Relevant files
Configuration changes
DockerFlags.java
Add CLI parameter for custom grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java

  • Add new --docker-grouping-labels CLI parameter
  • Support TOML config key grouping-labels
  • Allow users to specify custom labels for container grouping
  • Example labels: azure.container.group, aws.ecs.cluster
+11/-0
Enhancement
DockerOptions.java
Enhance label filtering for multiple orchestration systems

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java

  • Rename getComposeLabels() to getGroupingLabels() for clarity
  • Enhance filtering to support Docker Compose, Podman Compose, and
    custom labels
  • Read custom label keys from configuration
  • Filter labels to include only project identifiers, excluding
    service-specific labels
  • Update method calls to use new naming convention
+21/-5
DockerSessionFactory.java
Refactor to use generic grouping labels

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java

  • Rename composeLabels field to groupingLabels throughout class
  • Remove hardcoded com.docker.compose.oneoff=False label logic
  • Simplify label handling to use filtered grouping labels directly
  • Update constructor and container creation methods
+5/-9

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@selenium-ciselenium-ci added B-grid Everything grid and server related C-java Java Bindings labels Nov 20, 2025
@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Label injection risk

Description: User-supplied label keys from configuration are copied directly to container labels, which
could enable label injection to unintentionally join containers to existing compose/podman
projects or leak sensitive grouping metadata; consider validating/whitelisting allowed
keys or scoping with a Selenium-specific prefix.
DockerOptions.java [270-289]

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Ticket Compliance
🟡
🎫 #1234
🔴Investigate and resolve why click() does not trigger JavaScript in an anchor href in
Selenium 2.48.x (works in 2.47.1) on Firefox 42.
Provide a fix or regression handling specific to Firefox driver behavior so that alert is
triggered as in 2.47.1.
Verify behavior with the provided test case/videos.
🟡
🎫 #5678
🔴Diagnose "Error: ConnectFailure (Connection refused)" when instantiating multiple
ChromeDriver instances on Ubuntu 16.04, Chrome 65, ChromeDriver 2.35, Selenium 3.9.0.
Implement a fix or provide configuration/workaround to prevent connection failures on
subsequent ChromeDriver instantiations.
Validate that subsequent driver instances start without console errors.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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: Secure Error Handling

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

Status: Passed

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: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Missing auditing: New logic that reads and applies container grouping labels is not accompanied by any
logging to audit which labels were used or applied, which could hinder reconstructing
actions.

Referred Code
// Get custom grouping labels from configurationList<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

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:
Input validation: The code consumes user-provided grouping label keys from configuration without validating
for emptiness, duplicates, or malformed values, and proceeds silently with an empty set if
absent.

Referred Code
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems// Keep only project identifiers, exclude service-specific labels to prevent// exit monitoring in Docker Compose, Podman Compose, etc.returnallLabels.entrySet().stream()
.filter(
entry -> {
Stringkey = entry.getKey();
// Docker Compose project labelif (key.equals("com.docker.compose.project")) returntrue;
// Podman Compose project labelif (key.equals("io.podman.compose.project")) returntrue;
// Custom user-defined grouping labelsif (customLabelKeys.contains(key)) returntrue;
returnfalse;

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:
Unvalidated labels: User-configurable grouping labels from configuration are passed directly to container
label sets without normalization or validation, which could allow unintended or
conflicting labels.

Referred Code
ContainerConfigcontainerConfig =
image(browserImage)
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys)
.labels(groupingLabels)
.name(containerName);

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

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

@qodo-code-review

qodo-code-reviewBot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion Impact
General
Improve filtering logic for performance
Suggestion Impact:The commit introduced a HashSet of grouping keys and replaced the multi-branch filter logic with a contains check against the Set, matching the suggested optimization.

code diff:

@@ -270,22 +272,14 @@
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
+ Set<String> groupingKeys = new HashSet<>(customLabelKeys);+ groupingKeys.add("com.docker.compose.project");+ groupingKeys.add("io.podman.compose.project");+
Map<String, String> allLabels = info.get().getLabels();
- // Filter for project/grouping labels that work across orchestration systems- // Keep only project identifiers, exclude service-specific labels to prevent- // exit monitoring in Docker Compose, Podman Compose, etc.+ // Filter for grouping labels that work across orchestration systems
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Refactor the label filtering logic to use a Set for grouping keys instead of a
List and multiple if conditions, improving lookup performance and code clarity.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [269-289]

 // Get custom grouping labels from configuration
List<String> customLabelKeys =
config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);
++Set<String> groupingKeys = new HashSet<>(customLabelKeys);+groupingKeys.add("com.docker.compose.project");+groupingKeys.add("io.podman.compose.project");
Map<String, String> allLabels = info.get().getLabels();
// Filter for project/grouping labels that work across orchestration systems
// Keep only project identifiers, exclude service-specific labels to prevent
// exit monitoring in Docker Compose, Podman Compose, etc.
return allLabels.entrySet().stream()
- .filter(- entry -> {- String key = entry.getKey();- // Docker Compose project label- if (key.equals("com.docker.compose.project")) return true;- // Podman Compose project label- if (key.equals("io.podman.compose.project")) return true;- // Custom user-defined grouping labels- if (customLabelKeys.contains(key)) return true;- return false;- })+ .filter(entry -> groupingKeys.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using a Set for more efficient lookups, which improves performance and code readability, aligning with best practices.

Low
Learned
best practice
Validate custom grouping labels

Validate that configured grouping-labels are non-empty strings and reject
invalid entries with a clear message to avoid silent misconfiguration.

java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java [270-271]

 List<String> customLabelKeys =
- config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList);+ config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList)+ .stream()+ .map(String::trim)+ .filter(s -> !s.isEmpty())+ .collect(Collectors.toList());+if (!config.getAll(DOCKER_SECTION, "grouping-labels").orElseGet(Collections::emptyList).isEmpty()+ && customLabelKeys.isEmpty()) {+ throw new IllegalArgumentException("Invalid docker grouping-labels: only blank values provided");+}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Guard external configuration values with validation and clear errors before use.

Low
Clarify groupingLabels purpose

Add a concise field-level comment clarifying that groupingLabels are
non-service-specific labels used to group dynamic containers across
orchestrators.

java/src/org/openqa/selenium/grid/node/docker/DockerSessionFactory.java [108]

+// Labels that identify a project/group across orchestrators (e.g., Docker/Podman Compose, custom),+// excluding service-specific labels. Used to group dynamic containers for lifecycle handling.
private final Map<String, String> groupingLabels;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Enforce accurate and consistent naming/documentation to match behavior and aid maintainability.

Low
  • Update

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@VietND96
VietND96 merged commit 32dc667 into trunkNov 20, 2025
46 checks passed
@VietND96
VietND96 deleted the dynamic-grid-compose-stack branch November 20, 2025 17:26
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-gridEverything grid and server relatedC-javaJava BindingsReview effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VietND96@selenium-ci