Skip to content

fix: add None safety for optional fields in GitLab webhook handlers#2276

Open
wishhyt wants to merge 1 commit intoqodo-ai:mainfrom
wishhyt:fix/gitlab-webhook-none-safety
Open

fix: add None safety for optional fields in GitLab webhook handlers#2276
wishhyt wants to merge 1 commit intoqodo-ai:mainfrom
wishhyt:fix/gitlab-webhook-none-safety

Conversation

@wishhyt
Copy link
Copy Markdown

@wishhyt wishhyt commented Mar 18, 2026

Summary

  • is_draft() calls 'Draft:' in .get('title') which raises TypeError when title is absent from the webhook payload (.get() returns None)
  • should_process_pr_logic() passes potentially None values from .get('source_branch'), .get('target_branch'), and .get('title') into re.search(), which raises TypeError on None input
  • Although outer try/except blocks catch these errors, they cause incorrect fallback behavior: is_draft returns False (processing draft MRs) and should_process_pr_logic returns True (processing MRs that should be ignored)

Changes

pr_agent/servers/gitlab_webhook.py: Added empty string defaults to all .get() calls for optional fields and added truthiness guards before re.search calls

Test plan

  • Verify GitLab webhook handling works correctly when title, source_branch, or target_branch fields are missing from the payload
  • Verify that MR filtering by branch name and title patterns still works with complete payloads

`is_draft` calls `'Draft:' in .get('title')` which raises TypeError
when 'title' is absent (returns None). Similarly, `should_process_pr_logic`
passes potentially None values from `.get('source_branch')`,
`.get('target_branch')`, and `.get('title')` into `re.search()`, which
raises TypeError on None input.

Add empty string defaults to all `.get()` calls for these optional fields
and guard `re.search` calls with truthiness checks.

Made-with: Cursor
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Add None safety for optional fields in GitLab webhook handlers

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add None safety for optional fields in GitLab webhook handlers
• Provide empty string defaults to .get() calls for title, source_branch, and target_branch
• Guard re.search() calls with truthiness checks to prevent TypeError
• Prevent incorrect fallback behavior when optional fields are missing from payload
Diagram
flowchart LR
  A["GitLab Webhook Payload"] -->|Missing optional fields| B["is_draft & should_process_pr_logic"]
  B -->|Before: TypeError| C["Incorrect fallback behavior"]
  B -->|After: Empty string defaults| D["Safe field access"]
  D -->|Truthiness guards| E["Correct processing logic"]
Loading

Grey Divider

File Changes

1. pr_agent/servers/gitlab_webhook.py 🐞 Bug fix +6/-6

Add None safety guards for optional webhook fields

• Added empty string default to .get('title', '') in is_draft() function to handle missing title
 field
• Added empty string defaults to .get('title', ''), .get('source_branch', ''), and
 .get('target_branch', '') in should_process_pr_logic() function
• Added truthiness checks (if source_branch and and if target_branch and) before re.search()
 calls to prevent TypeError on None/empty values
• Prevents incorrect fallback behavior when optional webhook payload fields are absent

pr_agent/servers/gitlab_webhook.py


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Mar 18, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. should_process_pr_logic() title None 📘 Rule violation ⛯ Reliability
Description
The updated title = ...get('title', '') assignment still allows title to be None when the
payload explicitly provides null, and later re.search(regex, title) will raise TypeError. The
exception handler then returns True, potentially processing MRs that should be ignored.
Code

pr_agent/servers/gitlab_webhook.py[115]

+        title = data['object_attributes'].get('title', '')
Evidence
The compliance checklist requires defensive access/validation of optional payload fields; title
can still become None and is later passed into re.search, which expects a string/bytes.

Rule 3: Robust Error Handling
pr_agent/servers/gitlab_webhook.py[115-115]
pr_agent/servers/gitlab_webhook.py[161-167]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`should_process_pr_logic()` still allows `title` to be `None` when the payload includes an explicit null, which can trigger `TypeError` inside `re.search()`.

## Issue Context
The PR intent is None-safety for optional webhook fields; `.get(key, '')` does not protect against `key` being present with a `None` value.

## Fix Focus Areas
- pr_agent/servers/gitlab_webhook.py[111-167]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. None-safety lacks pytest coverage 📘 Rule violation ⛯ Reliability
Description
This PR changes GitLab webhook logic to handle missing title/branch fields, but existing pytest
coverage does not validate behavior when these fields are absent/None under the ignore-pattern
settings. Without targeted tests, regressions in MR filtering behavior are likely to go unnoticed.
Code

pr_agent/servers/gitlab_webhook.py[R141-150]

+            source_branch = data['object_attributes'].get('source_branch', '')
+            if source_branch and any(re.search(regex, source_branch) for regex in ignore_mr_source_branches):
                get_logger().info(
                    f"Ignoring MR with source branch '{source_branch}' due to gitlab.ignore_mr_source_branches settings")
                return False

        if ignore_mr_target_branches:
-            target_branch = data['object_attributes'].get('target_branch')
-            if any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
+            target_branch = data['object_attributes'].get('target_branch', '')
+            if target_branch and any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
                get_logger().info(
Evidence
Compliance requires behavior changes to be accompanied by appropriate pytest tests; the changed
webhook filtering logic is not covered by tests that exercise missing/None title and branch fields
with ignore settings enabled.

AGENTS.md
pr_agent/servers/gitlab_webhook.py[141-150]
tests/unittest/test_ignore_repositories.py[31-35]
tests/unittest/test_ignore_repositories.py[43-57]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The GitLab webhook filtering logic was changed for None/missing safety, but there are no targeted pytest tests that exercise these new edge cases.

## Issue Context
Current tests for GitLab webhook processing focus on repository ignore behavior and use a payload that always includes a non-empty `title`, so regressions for missing/None fields can slip through.

## Fix Focus Areas
- tests/unittest/test_ignore_repositories.py[31-81]
- pr_agent/servers/gitlab_webhook.py[75-167]ర్వ

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Empty-branch ignores bypassed 🐞 Bug ✓ Correctness
Description
In should_process_pr_logic(), the new truthiness guards skip applying
CONFIG.IGNORE_PR_SOURCE_BRANCHES / CONFIG.IGNORE_PR_TARGET_BRANCHES when GitLab payloads omit branch
fields (now defaulting to ''). This prevents regex-based ignore rules from matching empty strings
(e.g., '^$' or '.*'), so MRs that should be filtered by configuration can still be processed.
Code

pr_agent/servers/gitlab_webhook.py[R141-149]

+            source_branch = data['object_attributes'].get('source_branch', '')
+            if source_branch and any(re.search(regex, source_branch) for regex in ignore_mr_source_branches):
                get_logger().info(
                    f"Ignoring MR with source branch '{source_branch}' due to gitlab.ignore_mr_source_branches settings")
                return False

        if ignore_mr_target_branches:
-            target_branch = data['object_attributes'].get('target_branch')
-            if any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
+            target_branch = data['object_attributes'].get('target_branch', '')
+            if target_branch and any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
Evidence
The PR already makes branches None-safe by defaulting missing values to '', but additionally adds
if source_branch / if target_branch guards, which prevents any regex evaluation when the branch
is an empty string. The docs describe these settings as regex patterns matched against branch names
(no exclusion for empty strings), and other webhook providers in this repo apply the regexes
directly even when the extracted branch defaults to ''.

pr_agent/servers/gitlab_webhook.py[132-152]
docs/docs/usage-guide/additional_configurations.md[188-199]
pr_agent/servers/bitbucket_server_webhook.py[90-100]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`should_process_pr_logic()` now defaults missing `source_branch`/`target_branch` to `''` (good for None-safety), but it also adds `if source_branch` / `if target_branch` guards that skip the regex matching entirely when the branch is empty. This makes `CONFIG.IGNORE_PR_SOURCE_BRANCHES` / `CONFIG.IGNORE_PR_TARGET_BRANCHES` unable to match empty strings (e.g. `'^$'`, `'.*'`) and diverges from the documented “regex patterns to match branch names” behavior.

### Issue Context
None-safety is already achieved via `.get(..., '')`, so the additional truthiness guards are not needed for crash prevention.

### Fix
- Always evaluate the regexes on the string value (including `''`).
- Keep the `.get(..., '')` default (or alternatively use `.get(...)` and coerce via `or ''`) to avoid `re.search(..., None)`.

### Fix Focus Areas
- pr_agent/servers/gitlab_webhook.py[140-152]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

if not data.get('object_attributes', {}):
return False
title = data['object_attributes'].get('title')
title = data['object_attributes'].get('title', '')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. should_process_pr_logic() title none 📘 Rule violation ⛯ Reliability

The updated title = ...get('title', '') assignment still allows title to be None when the
payload explicitly provides null, and later re.search(regex, title) will raise TypeError. The
exception handler then returns True, potentially processing MRs that should be ignored.
Agent Prompt
## Issue description
`should_process_pr_logic()` still allows `title` to be `None` when the payload includes an explicit null, which can trigger `TypeError` inside `re.search()`.

## Issue Context
The PR intent is None-safety for optional webhook fields; `.get(key, '')` does not protect against `key` being present with a `None` value.

## Fix Focus Areas
- pr_agent/servers/gitlab_webhook.py[111-167]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +141 to 150
source_branch = data['object_attributes'].get('source_branch', '')
if source_branch and any(re.search(regex, source_branch) for regex in ignore_mr_source_branches):
get_logger().info(
f"Ignoring MR with source branch '{source_branch}' due to gitlab.ignore_mr_source_branches settings")
return False

if ignore_mr_target_branches:
target_branch = data['object_attributes'].get('target_branch')
if any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
target_branch = data['object_attributes'].get('target_branch', '')
if target_branch and any(re.search(regex, target_branch) for regex in ignore_mr_target_branches):
get_logger().info(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

2. None-safety lacks pytest coverage 📘 Rule violation ⛯ Reliability

This PR changes GitLab webhook logic to handle missing title/branch fields, but existing pytest
coverage does not validate behavior when these fields are absent/None under the ignore-pattern
settings. Without targeted tests, regressions in MR filtering behavior are likely to go unnoticed.
Agent Prompt
## Issue description
The GitLab webhook filtering logic was changed for None/missing safety, but there are no targeted pytest tests that exercise these new edge cases.

## Issue Context
Current tests for GitLab webhook processing focus on repository ignore behavior and use a payload that always includes a non-empty `title`, so regressions for missing/None fields can slip through.

## Fix Focus Areas
- tests/unittest/test_ignore_repositories.py[31-81]
- pr_agent/servers/gitlab_webhook.py[75-167]ర్వ

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant