Skip to content

fix(call_rate): honor trailing slashes in HttpRequestMatcher and HttpRequestRegexMatcher path matching - #1158

Draft
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1789429746-call-rate-trailing-slash
Draft

devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1789429746-call-rate-trailing-slash

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Overview

👉 TL;DR: Rate-limit request matchers whose URL or regex ends in a trailing slash could never match any request, so the affected API budget policies were silently skipped. This fixes the matchers so trailing slashes on either side are handled consistently.

Specifically, HttpRequestMatcher.__init__ now strips the trailing slash from its literal path and appends a (?=/|$) path boundary, and HttpRequestRegexMatcher.__call__ matches url_path_pattern against both the slash-stripped and the original request path.

Resolves https://github.com/airbytehq/airbyte-internal-issues/issues/17248:

Changes

  • HttpRequestRegexMatcher.__call__: previously request_path = path.rstrip("/") was the only value the regex was applied to, so a pattern like ^/users/$ (or the re.escaped literal /users/) could never match. Now:
    request_path = str(parsed_url.path)
    normalized_path = request_path.rstrip("/")
    matched = pattern.search(normalized_path) or (
        request_path != normalized_path and pattern.search(request_path)
    )
  • HttpRequestMatcher.__init__: url_path = parsed_url.path.rstrip("/") or None and url_path_pattern = re.escape(url_path) + r"(?=/|$)", so url="https://example.com/users/" matches GET /users, GET /users/ and GET /users/123 but not GET /users-other; the root-URL special case (/ → no path constraint) is preserved.
  • Docstring for url_path_pattern updated to describe the matching semantics.
  • Regression tests in unit_tests/sources/streams/test_call_rate.py: both matcher classes with/without trailing slash on pattern and request, the literal path boundary, plus APIBudget.get_matching_policy / acquire_call selection for a trailing-slash request.

Design notes: why keep stripping the request path

Show/Hide Content

Applying the regex only to the raw path would have been the "honor regexes literally" option, but many connector manifests in airbytehq/airbyte rely on the current stripping behavior with patterns such as ^groups$ (source-gitlab), ^/api/lists$ (source-klaviyo), reports/2021-06-30/reports$ (source-amazon-seller-partner) and expect them to match /foo/ requests too. Matching against the stripped path first keeps all of those working unchanged, and additionally trying the original path fixes the previously-impossible slash-requiring patterns.

Risks

  • Patterns that previously matched nothing (because they required a trailing slash) will now match and rate-limit requests — the intended fix, but it could newly throttle a connector that had a dormant policy.
  • HttpRequestMatcher literals without a trailing slash (e.g. url=".../users") previously also matched sibling paths like /users-other via unanchored re.search; with the (?=/|$) boundary they no longer do.

Test plan

  • poetry run pytest unit_tests/sources/streams/test_call_rate.py -q (52 passed; the new trailing-slash cases fail on main without the source change)
  • poetry run ruff check ., poetry run ruff format .
  • poetry run mypy --config-file mypy.ini airbyte_cdk/sources/streams/call_rate.py

Requested via /ai-fix on the linked issue (triage session: https://app.devin.ai/sessions/7ae5f89db63d417d92c2f6a058c46eab).

Link to Devin session: https://app.devin.ai/sessions/56f24b43ca1d43ab91527d2ee0c9db30
Open in Devin Desktop: https://app.devin.ai/desktop/session/56f24b43ca1d43ab91527d2ee0c9db30?variant=devin

…cher path matching

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This CDK Version

You can test this version of the CDK using the following:

# Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1789429746-call-rate-trailing-slash#egg=airbyte-python-cdk[dev]' --help

# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1789429746-call-rate-trailing-slash

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /autofix - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test - Runs connector tests with the updated CDK
  • /prerelease - Triggers a prerelease publish with default arguments
  • /poe build - Regenerate git-committed build artifacts, such as the pydantic models which are generated from the manifest JSON schema in YAML.
  • /poe <command> - Runs any poe command in the CDK environment
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Literal matching can incorrectly match sibling endpoints such as /users-other; a path boundary must be preserved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Updates HTTP request rate-limit matchers to handle trailing slashes consistently and adds regression coverage.

Changes:

  • Normalizes literal matcher paths.
  • Supports regex matching against normalized and original paths.
  • Adds matcher and API budget tests.
File summaries
File Summary
unit_tests/sources/streams/test_call_rate.py Adds trailing-slash matcher and budget regression tests.
airbyte_cdk/sources/streams/call_rate.py Updates HTTP path matching behavior.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread airbyte_cdk/sources/streams/call_rate.py
@github-actions

Copy link
Copy Markdown

PyTest Results (Fast)

4 402 tests  +14   4 390 ✅ +14   7m 47s ⏱️ - 1m 51s
    1 suites ± 0      12 💤 ± 0 
    1 files   ± 0       0 ❌ ± 0 

Results for commit 9c46891. ± Comparison against base commit 96a7c0a.

@github-actions

Copy link
Copy Markdown

PyTest Results (Full)

4 405 tests  +14   4 393 ✅ +14   14m 11s ⏱️ +10s
    1 suites ± 0      12 💤 ± 0 
    1 files   ± 0       0 ❌ ± 0 

Results for commit 9c46891. ± Comparison against base commit 96a7c0a.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant