Skip to content

test#8

Open
tgensol wants to merge 82 commits into
appchoose:mainfrom
elastic:main
Open

test#8
tgensol wants to merge 82 commits into
appchoose:mainfrom
elastic:main

Conversation

@tgensol
Copy link
Copy Markdown

@tgensol tgensol commented Apr 24, 2026

Closes https://github.com/elastic/connectors-py/issues/###

Checklists

Pre-Review Checklist

  • this PR does NOT contain credentials of any kind, such as API keys or username/passwords (double check config.yml.example)
  • this PR has a meaningful title
  • this PR links to all relevant github issues that it fixes or partially addresses
  • if there is no GH issue, please create it. Each PR should have a link to an issue
  • this PR has a thorough description
  • Covered the changes with automated tests
  • Tested the changes locally
  • Added a label for each target release version (example: v7.13.2, v7.14.0, v8.0.0)
  • For bugfixes: backport safely to all minor branches still receiving patch releases
  • Considered corresponding documentation changes
  • Contributed any configuration settings changes to the configuration reference
  • if you added or changed Rich Configurable Fields for a Native Connector, you made a corresponding PR in Kibana

Changes Requiring Extra Attention

  • Security-related changes (encryption, TLS, SSRF, etc)
  • New external service dependencies added.

Related Pull Requests

Release Note

mattnowzari and others added 30 commits September 16, 2025 11:54
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
The problem was that in bash, local var=$(command) always succeeds
(returns exit code 0) even if command fails. By separating the
declaration (local
tarball_url) from the assignment
(tarball_url=$(get_docker_tarball_url...)), the exit code check $? now
correctly captures the function's return value.


We were seeing log lines like:

```

Attempting to fetch Elasticsearch version: 9.3.0-SNAPSHOT
--
  | ++ get_docker_tarball_name 9.3.0-SNAPSHOT x86_64
  | ++ local version=9.3.0-SNAPSHOT
  | ++ local arch=x86_64
  | ++ case $arch in
  | ++ echo elasticsearch-9.3.0-SNAPSHOT-docker-image-amd64.tar.gz
  | + local tarball_name=elasticsearch-9.3.0-SNAPSHOT-docker-image-amd64.tar.gz
  | + '[' 0 -ne 0 ']'
  | ++ resolve_dra_manifest elasticsearch 9.3.0-SNAPSHOT
  | ++ local dra_artifact=elasticsearch
  | ++ local dra_version=9.3.0-SNAPSHOT
  | curl -sS -f --retry 3 --retry-delay 5 --retry-connrefused https://artifacts-snapshot.elastic.co/elasticsearch/latest/9.3.0-SNAPSHOT.json
  | ++ local 'response=curl: (22) The requested URL returned error: 404'
  | ++ local curl_exit_code=0
  | ++ '[' 0 -ne 0 ']'
  | echo 'curl: (22) The requested URL returned error: 404'
  | jq -r .manifest_url
  | curl -sS --retry 3 --retry-delay 5 --retry-connrefused ''
  | jq -r '.projects.elasticsearch.packages."elasticsearch-9.3.0-SNAPSHOT-docker-image-amd64.tar.gz".url'
  | curl: (3) URL using bad/illegal format or missing URL
  | ++ local tarball_url=
  | ++ '[' -z '' ']'
  | ++ return 1
  | + local tarball_url=
  | + '[' 0 -ne 0 ']'
  | + download_docker_tarball '' elasticsearch-9.3.0-SNAPSHOT-docker-image-amd64.tar.gz
  | + local tar_url=
  | + local tar_file=elasticsearch-9.3.0-SNAPSHOT-docker-image-amd64.tar.gz
  | + echo 'Downloading Docker image tarball from ...'
  | Downloading Docker image tarball from ...
  | + local curl_output
  | ++ curl -v --http1.1 --retry 3 --retry-delay 5 --retry-connrefused -O ''
  | + curl_output='curl: Remote file name has no length!

```

In particular, note:

```
  | ++ '[' -z '' ']'
  | ++ return 1
  | + local tarball_url=
  | + '[' 0 -ne 0 ']'
```

So our tarball URL was failing to be assigned, but we still thought we
were getting a non-0 exit code.



## Checklists



#### Pre-Review Checklist
- [x] this PR has a thorough description
- [ ] Covered the changes with automated tests
- [ ] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)


## Related Pull Requests

bug introduced in #3720

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Relates elastic/search-team#10592

Bump main to 9.3.0 as part of 9.2 release

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Closes #3654 &
#2880

Both related issues are about idle Github connectors eating into too
much of our quota.
There were a few possible codepaths that led into this situation,
depending on the flavor of the configuration (the two `repository_type`
options and access token vs github app).

## Background 

To briefly explain, the `JobSchedulingService` loops over configured
connectors forever, and on each loop instantiates objects
`BaseDataSource` objects using the current connector config, and uses
them to schedule a job for that connector.

This process repeats every (30?) seconds.
As part of this process, it also tries to validate the configuration for
each connector via the instantiated data source by calling `await
data_source.validate_config()`. In the case of the Github datasource,
that validation includes checking configured repositories for whether
they're actually accessible.

Before the changes present in this PR, these codepaths for access check
involved fetching all user repos, all org repos (both can be expensive
to paginate through for lots of repos) OR running separate graphQL
queries for each repo being checked.

The situation is in reality a bit more confusing because the Github data
source class tries to cache this information about all-org-repos and
all-user-repos but because of how we re-instantiate data sources in a
loop, all this information goes away.


## Alternatives considered

I actually set out to try and work around this in a couple of different
ways at first.

--
A) One approach was implemented in
ce6b998
and it involved module-level caching for validation checks.
This approach would allow us, at the cost of ugly python-module level
state, cache validation results for a given configuration for a little
while.

On configuration change, the cache would be invalid and so we would run
all validation logic again. But without configuration changing, we would
cache the results of checks for a configurable-per-data-source amount of
time.

Concretely for something like this data source it could mean - check
repositories for accessibility every 30 secs if configuration changed,
but if it didn't, only check and flag the fact that you, for example,
removed a repo or lost access to it, every 5 minutes.

**Why it didn't make the final PR:** : I'm hesitant to include this
module level state as it makes things harder to understand, and at least
in this connector it seems we can probably get away with refactoring
some code.

B) Another approach was implemented in
9c3a564
and it involved maintaining data source instances in a cached state in
the `JobSchedulingService` - we would keep for a given connector with a
given configuration an entry in a cache instead of re-initializing it
over and over. Since the Github data source maintains cached information
about repos internally, invoking validation again on an existing data
source wouldn't cost.
We would still throw away these instances to force re-validation
occasionally.


**Why it didn't make the final PR:** : I don't understanding the
semantics of all data sources, but they implement a `close` method which
implies that they might be holding resources that we don't want to keep
if work isn't being done. Keeping these instances cached would imply
that we don't call `close` to free resources until the cache entry is to
be removed - I didn't want to make this change without fully grasping
the semantics when there's maybe a good enough way forward for *this*
data source.


## Solution implemented

Changed individual fetches that happen through the validation codepaths
to be batched checks. Also refactored validation codepaths that invoked
get-all-user-repos and get-all-org-repos trying to get invalid repos
(using the formula configured repos minus found-on-org-or-user equals
invalid repos) to instead explicitly look up the configured repos. This
involved changing some graphQL queries and also slightly changing what
errors we consider acceptable as part of handling these graphQL
responses.


<!--Provide a general description of the code changes in your pull
request.
If the change relates to a specific issue, include the link at the top.

If this is an ad-hoc/trivial change and does not have a corresponding
issue, please describe your changes in enough details, so that reviewers
and other team members can understand the reasoning behind the pull
request.-->

## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [ ] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

<!--Please call out any changes that require special attention from the
reviewers and/or increase the risk to availability or security of the
system after deployment. Remove the ones that don't apply.-->

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

## Related Pull Requests

<!--List any relevant PRs here or remove the section if this is a
standalone PR.

* https://github.com/elastic/.../pull/123-->

## Release Note

<!--If you think this enhancement/fix should be included in the release
notes,
please write a concise user-facing description of the change here.
You should also label the PR with `release_note` so the release notes
author(s) can easily look it up.-->

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to c85a849 - abandoned (#3688)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `2b6277f` -> `c85a849` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xNy4wIiwidjguMTguMCIsInY4LjE5LjAiLCJ2OS4wLjAiLCJ2OS4xLjAiLCJ2OS4yLjAiXX0=-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Lorena Balan <lorena.balan@elastic.co>
…3630)

## Closes #3603

The change excludes specific /contentstorage/ urls from the sync in all
API calls to Sharepoint. These URLs should not be attempted to be
accessed as they're created internally by Sharepoint for Teams private
channels, loop components, etc. (it's fairly undocumented what they're
used for to be honest), and have a different permission model that will
cause 401 errors and the connector to stop syncing.


## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] this PR has a thorough description
- [x] Tested the changes locally
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases

## Release Note

Fixes an issue where a Sharepoint Online sync configured to crawl the
entire tenant by selecting * in the site list, might stop with 401
errors when trying to access URLs containing /contentstorage/.

---------

Co-authored-by: Artem Shelkovnikov <artem.shelkovnikov@elastic.co>
Addressing a thread that came up a couple of times in recent releases,
where folks in charge of 8.x releases were unable to retrigger DRAs for
new version for `connectors` repo.

A bit of guessing, added 
*
[enterprise-search](https://buildkite.com/organizations/elastic/teams/enterprise-search/members)
*
[search-inference](https://buildkite.com/organizations/elastic/teams/search-inference-team/members)

Couldn't find bk teams for the other search teams.
## related to elastic/search-team#10592

As reported in `#mission-control`: now that 9.2.0 is released, 9.0 minor
version is unsupported following our new release cadence policy. That
means that we will stop to produce snapshot and staging builds for the
9.0 branch


## Checklists


#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] this PR has a thorough description
- [ ] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
…gest to 15ccd99 (#3783)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `c85a849` -> `15ccd99` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xNy4wIiwidjguMTguMCIsInY4LjE5LjAiLCJ2OS4wLjAiLCJ2OS4xLjAiLCJ2OS4yLjAiLCJ2OS4zLjAiXX0=-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Lorena Bălan <lorena.balan@elastic.co>
## Closes elastic/search-team#10999

Bringing `develop` up to date via
#3823

## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [ ] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [ ] this PR has a meaningful title
- [ ] this PR links to all relevant github issues that it fixes or
partially addresses
- [ ] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [ ] this PR has a thorough description
- [ ] Covered the changes with automated tests
- [ ] Tested the changes locally
- [ ] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [ ] Considered corresponding documentation changes
- [ ] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

<!--Please call out any changes that require special attention from the
reviewers and/or increase the risk to availability or security of the
system after deployment. Remove the ones that don't apply.-->

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

## Release Note

<!--If you think this enhancement/fix should be included in the release
notes,
please write a concise user-facing description of the change here.
You should also label the PR with `release_note` so the release notes
author(s) can easily look it up.-->

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Artem Shelkovnikov <artem.shelkovnikov@elastic.co>
Co-authored-by: Matt Nowzari <matt.nowzari@elastic.co>
Co-authored-by: Sean Story <sean.story@elastic.co>
Fixed linting step.

- For some reason re-exported imports from `graphql` make `pyright`
unhappy. Changed to import from precise packages, rather than from the
root
- `from connectors.sources.dropbox.client import ...
ClientResponseError` is a factual mistake, the error comes from
`aiohttp`

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Noticed some things weren't getting cleaned up.
Should fix `main` builds failures like [this
one](https://buildkite.com/elastic/connectors/builds/20676#019a4904-11aa-4763-acea-dfbbaabcbab5)

> ++
VERSION_PATH=/opt/buildkite-agent/builds/bk-agent-prod-aws-1762162307404853761/elastic/connectors/connectors/VERSION
> ...
> cat:
/opt/buildkite-agent/builds/bk-agent-prod-aws-1762162307404853761/elastic/connectors/connectors/VERSION:
No such file or directory
> ...
>
/opt/buildkite-agent/builds/bk-agent-prod-aws-1762162307404853761/elastic/connectors/.buildkite/publish/publish-common.sh:
line 39: connectors/build.yaml: No such file or directory

~Also should fix backport process, as the GH action was failing to check
for the version in order to work out auto-labelling.. 🤞~
Another minor fix for the automation - fixing the add labels GH workflow
to use the right VERSION file

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to b94c277 (#3827)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `15ccd99` -> `b94c277` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOC4wIiwidjguMTkuMCIsInY5LjEuMCIsInY5LjIuMCIsInY5LjMuMCJdfQ==-->

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Sets OracleDB version for ftest back to `:latest` from `23.8.0.0`

Co-authored-by: Artem Shelkovnikov <artem.shelkovnikov@elastic.co>
## Description
* app/.venv/bin doesn't contain everything installed - we should either
use the proper path (app/connector_service/.venv.bin), or the symlinked
path app/bin we created in
https://github.com/elastic/connectors/blob/main/Dockerfile.wolfi#L6
* `artifact_paths` doesn't support the `matrix` notation, so we need to
upload the artifacts manually (or recreate them in the publish step, but
that'd make CI take longer and do some duplicate work)
* `make zip` was missing from the root-level Makefile, so the
`init_dra_publishing` script was failing

## Testing
https://buildkite.com/elastic/connectors/builds/20728

---------

Co-authored-by: Dennis Tismenko <dennis.tismenko@elastic.co>
Minor fix to unlock Agent DRA: we need to actually zip the whole project
for now.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Did not properly test a couple places 😮‍💨

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to 3b2cbf3 (#3843)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `b94c277` -> `3b2cbf3` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOC4wIiwidjguMTkuMCIsInY5LjEuMCIsInY5LjIuMCIsInY5LjMuMCJdfQ==-->

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
elastic-renovate-prod Bot and others added 30 commits February 16, 2026 12:09
…gest to fdce1eb (#3938)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `29861e7` -> `fdce1eb` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOS4wIiwidjkuMi4wIiwidjkuMy4wIiwidjkuNC4wIl19-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Closes #3939



See issue for details, just implementing suggested fix from over there,
don't mind me!


## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [ ] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [x] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

<!--Please call out any changes that require special attention from the
reviewers and/or increase the risk to availability or security of the
system after deployment. Remove the ones that don't apply.-->

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

## Related Pull Requests

<!--List any relevant PRs here or remove the section if this is a
standalone PR.

* https://github.com/elastic/.../pull/123-->

## Release Note

<!--If you think this enhancement/fix should be included in the release
notes,
please write a concise user-facing description of the change here.
You should also label the PR with `release_note` so the release notes
author(s) can easily look it up.-->

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to 2d8be86 (#3949)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `fdce1eb` -> `2d8be86` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOS4wIiwidjkuMi4wIiwidjkuMy4wIiwidjkuNC4wIl19-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Not related to any specific issue

## Summary

The monorepo restructure in #3721 moved the connector service into
`app/connectors_service/`, but several file path references across
Makefiles and stack scripts were not updated. This caused broken
behavior for users running connectors from source:

- `make run` from the repo root silently ignored the user's
`config.yml`, falling back to `service_cli.py`'s default path inside
`app/connectors_service/`. This produced a confusing `Cannot connect to
host localhost:9200` error even with a valid cloud config at the repo
root.
- The `scripts/stack/` development scripts referenced stale paths for
`VERSION`, `config.yml.example`, and the `connectors` CLI binary — all
of which moved during the restructure.
- `run-stack.sh --no-connectors` still prompted for the connector
configurator.
- The stack scripts themselves were left at the repo root despite being
specific to the connector service.

## Changes

### Makefile wiring for `make run`

- **Root Makefile**: added a `config.yml` target (copies from example if
missing) and updated `run` to pass `CONFIG_FILE=$(CURDIR)/config.yml` to
the inner Makefile.
- **`app/connectors_service/Makefile`**: added `CONFIG_FILE ?=
config.yml` and updated `run` to pass `-c $(CONFIG_FILE)` explicitly.
When called from root, it receives the absolute path; when called
directly, it defaults to the local `config.yml`.

### Move `scripts/stack/` into `app/connectors_service/scripts/stack/`

Per review feedback, relocated the stack scripts to live alongside the
service they belong to. This simplifies all internal path references
because `PROJECT_ROOT` (computed as two directories up from the script
location) now naturally resolves to `app/connectors_service/` —
eliminating the need for `app/connectors_service/` prefixes throughout.

### Script fixes

- **`copy-config.sh`**: removed the intermediary `cp` that created a
ghost `config.yml` at `PROJECT_ROOT`; now points directly at
`config.yml.example`.
- **`configure-connectors.sh`**: fixed the `connectors` CLI path
(`bin/connectors` → `.venv/bin/connectors`).
- **`run-stack.sh`**: moved config copy, configurator prompt, and
connector startup inside the `no_connectors == false` block.

### Reference updates

- `.gitignore`: updated `connectors-config` path; added root
`config.yml` to ignore list.
- `README.md`, `docs/CLI.md`, stack `README.md`: updated all
`scripts/stack/` links and command examples to the new location.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [ ] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [ ] Covered the changes with automated tests
- [x] Tested the changes locally
- [ ] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

N/A — no security changes, no new dependencies.

## Related Pull Requests

* #3721 — Restructure Connectors project (introduced the monorepo
layout)
* Kibana-side instructions may also need updating to reference
`app/connectors_service/config.yml` for the "run from source" path

## Release Note

Fixed broken file path references in Makefiles and stack scripts that
were not updated during the monorepo restructure (#3721). Users running
connectors from source who were experiencing `Cannot connect to host
localhost:9200` errors (despite having a valid `config.yml` at the repo
root) will find that `make run` now correctly picks up their
configuration. The `scripts/stack/` development scripts have also been
relocated to `app/connectors_service/scripts/stack/` and fixed to
reference correct post-restructure paths. These fixes will take effect
after merging to the corresponding branches and are not strictly tied to
a specific release.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Summary

Adds a `check-versions` target to the Makefile that verifies both
VERSION files have matching content:
- `app/connectors_service/connectors/VERSION`
- `libs/connectors_sdk/connectors_sdk/VERSION`

This runs as part of `make lint` to catch version mismatches early in
the PR process rather than waiting for DRA publishing to fail.

## Context

Following the discussion in #search-extract-and-transform about the 9.3
DRA publishing failure caused by mismatched VERSION files (see
#3956), this adds an early
check to prevent similar issues.

## Testing

```bash
# When versions match:
$ make check-versions
VERSION files match: 9.4.0

# When versions don't match:
$ make check-versions
ERROR: VERSION files do not match!
  app/connectors_service/connectors/VERSION: 9.4.0
  libs/connectors_sdk/connectors_sdk/VERSION: 9.9.9
make: *** [check-versions] Error 1
```

Made with [Cursor](https://cursor.com)
## Closes #3922 

This PR adds FIPS 140-2/140-3 compliance support. When enabled, the
service validates that OpenSSL is running in FIPS mode and automatically
disables connectors that rely on non-FIPS-compliant protocols (NTLM).

## Changes

All changes were tested locally for postgresql, mongodb, and dir
connectors.

### Core FIPS Module

- New `connectors/fips.py` module providing:
- FIPS mode detection via environment variable
(ELASTICSEARCH_CONNECTORS_FIPS_MODE) or config
  - OpenSSL FIPS mode validation (tests by attempting to use RC4 cipher)
  - Automatic filtering of non-FIPS-compliant connectors
  - FIPSModeError exception for validation failures

### FIPS Docker Image (TESTING ONLY)

- New `Dockerfile.fips` that builds a FIPS-enabled container:
  - Compiles OpenSSL 3.0.9 FIPS provider from source
  - Compiles OpenSSL 3.5.2 with FIPS support
  - Builds Python 3.11 linked against FIPS OpenSSL
  - Validates FIPS mode during image build

### Configuration

- New `service.fips_mode` config option in config.yml
- Environment variable support:
`ELASTICSEARCH_CONNECTORS_FIPS_MODE=true`

### CI Pipeline

- Added FIPS unit tests step that runs make fips-test in CI
- New `run_fips_unit_tests.sh` script

### Makefile Targets

- `fips-build-base` - Build FIPS base Docker image
- `fips-build-test` - Build FIPS functional test image
- `fips-test` - Run unit tests in FIPS container
- `fips-ftest` - Run functional/smoke tests in FIPS container
- `ftest` now runs both non-FIPS and FIPS functional tests

### Functional Tests

- Updated `ftest.sh` to support FIPS mode execution
- Connector runs inside FIPS container when FIPS_MODE=true
- Container monitoring via `fixture.py` --container flag

### Documentation

- New `docs/FIPS.md` with:
  - How to enable FIPS mode
  - Explanation of library FIPS compliance (delegated to system OpenSSL)
  - Known limitations (NTLM-based connectors)
  - Full connector compatibility matrix

### Non-FIPS-Compliant Connectors

The following connectors are automatically disabled in FIPS mode due to
NTLM protocol requirements:

| Connector | Reason |
|-------------------|-------------------------------------|
| Network Drive       | NTLM authentication (SMB/WinRM)  |
| SharePoint Server | NTLM authentication                          |

NTLM fundamentally requires MD4, MD5, and RC4 which are not
FIPS-approved algorithms.

## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### FIPS

- [ ] `make fips-test` - Run unit tests in FIPS container
- [ ] `make fips-ftest` NAME=dir - Run smoke test in FIPS container
- [ ] `make ftest` - Run both non-FIPS and FIPS functional tests
- [ ] Verify non-FIPS connectors are filtered when FIPS mode enabled
- [ ] Verify startup fails gracefully if FIPS mode enabled but OpenSSL
not in FIPS mode

#### Pre-Review Checklist
- [X] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [X] this PR has a meaningful title
- [X] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [X] this PR has a thorough description
- [X] Covered the changes with automated tests
- [X] Tested the changes locally
- [ ] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] Considered corresponding documentation changes
- [X] Contributed any configuration settings changes to the
configuration reference

#### Changes Requiring Extra Attention

<!--Please call out any changes that require special attention from the
reviewers and/or increase the risk to availability or security of the
system after deployment. Remove the ones that don't apply.-->

- [x] Security-related changes (encryption, TLS, SSRF, etc)
- Adds FIPS 140-2/140-3 compliance mode that validates OpenSSL FIPS
configuration
- Automatically disables connectors using non-FIPS-compliant protocols
(NTLM)
- New `Dockerfile.fips` compiles OpenSSL and Python from source with
FIPS support
## Closes #3957

As of now we treat `noop` status coming from Elasticsearch `bulk`
request as a **failure**. This means, that if multiple noops happen
consecutively the connector can stop the job and mark it as failed.

In practice it only happened for access control syncs as only they used
`OP_UPDATE` operation:
https://github.com/elastic/connectors/blob/main/app/connectors_service/connectors/es/sink.py#L783

This started happening since [Error Monitor
change](#2671) has been merged
- which is 9.0.X.

## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [ ] Considered corresponding documentation changes
- [ ] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)
## Release Note

Fix a problem with access control syncs crashing due to `noop` returned
from `bulk` API was treated as a failure.
…ransformation (#3885)

## Closes #3884

This PR fixes a case sensitivity bug in the PostgreSQL and MSSQL
connectors when using `id_columns` in advanced sync rules:
- **PostgreSQL**: Added `.lower()` to the `id_columns` transformation
- **MSSQL**: Added `.lower()` and `sorted()` to match
`map_column_names()` behaviour

<!--Provide a general description of the code changes in your pull
request.
If the change relates to a specific issue, include the link at the top.

If this is an ad-hoc/trivial change and does not have a corresponding
issue, please describe your changes in enough details, so that reviewers
and other team members can understand the reasoning behind the pull
request.-->

### Testing (MSSQL)

#### 1. Start MSSQL
```bash
docker run -d --name mssql-test --net elastic \
  -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD='Password_123' \
  -p 1433:1433 mcr.microsoft.com/azure-sql-edge:latest
```

#### 2. Create test data
```
docker run --rm --net elastic mcr.microsoft.com/mssql-tools:latest \
  /opt/mssql-tools/bin/sqlcmd -S mssql-test -U sa -P 'Password_123' -Q "
CREATE DATABASE xe;
GO
USE xe;
CREATE LOGIN admin WITH PASSWORD = 'Password_123';
ALTER SERVER ROLE [sysadmin] ADD MEMBER [admin];
GO
USE xe;
CREATE TABLE COAXIS_RV_CALL (
    Call_No INT PRIMARY KEY,
    Call_Date DATETIME,
    Call_Description VARCHAR(255)
);
INSERT INTO COAXIS_RV_CALL (Call_No, Call_Date, Call_Description) VALUES
    (1001, '2025-01-15', 'Server maintenance request'),
    (1002, '2025-01-16', 'Network connectivity issue'),
    (1003, '2025-01-17', 'Database backup failure'),
    (1004, '2025-01-18', 'Application deployment'),
    (1005, '2025-01-19', 'Security patch update');
GO
"
```

#### 3. Create connector in Kibana

| Field | Value |
|-------|-------|
| Host | `host.docker.internal` (or `localhost` if running from source)
|
| Port | `1433` |
| Username | `admin` |
| Password | `Password_123` |
| Database | `xe` |
| Schema | `dbo` |

#### 4. Set advanced sync rule
```json
[
  {
    "tables": ["COAXIS_RV_CALL"],
    "query": "SELECT * FROM COAXIS_RV_CALL",
    "id_columns": ["Call_No"]
  }
]
```

#### 5. Run a __Full content sync__
Result: __5__ docs upserted (previously 1).
<img width="2450" height="1308" alt="Screenshot 2026-03-09 at 17 25
54@2x"
src="https://github.com/user-attachments/assets/ca1790ca-f4c1-4d9c-a323-1f079fafe052"
/>



## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [x] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)
— N/A

## Release Note

**PostgreSQL/MSSQL connectors**: Fixed a bug where using `id_columns` in
advanced sync rules with mixed-case table or column names caused all
documents to receive the same `_id`, resulting in document overwrites
and only 1 document being indexed instead of the expected count.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to fc2f07e (#3960)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `2d8be86` -> `fc2f07e` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOS4wIiwidjkuMi4wIiwidjkuMy4wIiwidjkuNC4wIl19-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…tifier (#3973)

## Closes #3972

From Claude:
> **The one assumption the fix relies on**
It assumes the SID string format from PowerShell WinRM (Get-LocalGroup,
Get-LocalGroupMember) and from smbprotocol's DACL parsing both produce
the same canonical S-1-5-21-... representation. They do in practice —
both sources use the standard Windows SID string format. But if they
ever diverged (different casing, whitespace, etc.) the group lookup
would silently fail and the group ACE would be treated as a user SID.
With RIDs that risk was smaller since you were only comparing a single
integer. This is the one genuine trade-off, but it's a theoretical
concern rather than a practical one.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] Covered the changes with automated tests
- [ ] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases

## Release Note

Fixed a bug in Network Drive connector where users from different
domains with the same RID could inherit each other's document
permissions.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…gest to cc3bb21 (#3975)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `fc2f07e` -> `cc3bb21` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [x] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOS4wIiwidjkuMi4wIiwidjkuMy4wIiwidjkuNC4wIl19-->

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
## Summary
- Replace the bare `elasticsearch-connectors-sdk` package name in
`app/connectors_service/pyproject.toml` with an explicit `file:` path
reference to `libs/connectors_sdk`
- Functionally nothing changes: all build paths (Docker, Makefile, DRA)
already install the SDK from local source before the service. This just
makes the local resolution explicit so the bare name no longer looks
like a dependency confusion risk.

## Why the extra changes

The `file:` relative path resolves from pip's current working directory,
not from the pyproject.toml location. This means any `pip install` of
the connectors service needs to run from `app/connectors_service/` for
the path to resolve correctly.

Two install paths were running from the repo root:

- **FIPS test** (`Makefile` `fips-test` target): Changed to `cd
app/connectors_service && pip install -e .[tests]` instead of `pip
install -e app/connectors_service[tests]`. Also split the single pip
install into two (SDK first, service second) and added `pip install
--upgrade pip` because pip 24.0 in the FIPS image cannot parse relative
`file:` URLs.
- **Package test** (`.buildkite/test_python_packages.sh`): Changed to
`cd "$PACKAGE_PATH" && pip install dist/*.whl` instead of `pip install
"$PACKAGE_PATH"/dist/*.whl`.

## Context
- Security issue: elastic/security#9273
- [Analysis
comment](elastic/security#9273 (comment))

## Test plan
- [x] `make clean install install-agent` succeeds
- [x] `make fips-test` passes (2122 tests, 92% coverage)
- [x] CI passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…nch (#3990)

This PR adds the 9.4 branch to the buildkite `pipeline.yml` and removes
`9.2`. Thus, only `9.4` and `9.3` will be built from version `9.x`

[Part of `9.4` release
activities](elastic/search-team#12738)

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
Bump `main` to version `9.5.0`
Includes and builds on #3951. Replaces the block step with automated
version bump logic.

The centralized release-eng pipeline triggers `connectors-version-bump`
with `NEW_VERSION`, `BRANCH`, and `WORKFLOW`. For `patch`, the script
opens an auto-merging PR bumping both VERSION files on the release
branch. For `minor`, it updates `pipeline.yml`'s DRA branch list,
creates the new release branch, and bumps main to the next minor -- each
step idempotent. The merged commits trigger existing CI which publishes
DRA artifacts, and the json-watcher steps confirm completion.

Requires elastic/terrazzo#1190 for `pull_requests: write` permission.
Set `DRY_RUN=true` to preview without side effects.

> **Note to reviewer**: we should port this to 9.2, 9.1, and 8.19 unless
we explicitly decide to only do this for 9.3 onwards. Those branches
have a single VERSION file (pre-monorepo layout) so this can't be
backported as-is -- I'll work on bringing a separate PR to 9.2 to be
backported.

## Test plan

- [x] Local: shell syntax, pipeline YAML, Python branch-insertion cases,
env var validation, DRY_RUN for both workflows
- [ ] Buildkite: DRY_RUN trigger, patch PR (close without merging),
minor flow with fake branch, end-to-end with @ninalee12

---------

Co-authored-by: Nina Lee <nina.lee@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary

Adds support for pre-9.3 release branches (8.19, 9.0, 9.1, 9.2) in the
version-bump script introduced in #3986.

The original PR's description noted that pre-monorepo branches (single
`connectors/VERSION` file at a different path) couldn't be supported
as-is and would need a separate backport. That turns out not to be
necessary: the script always runs from `main`'s checkout (the
`connectors-version-bump` Buildkite pipeline uploads
`version-bump-pipeline.yml` from `main`, regardless of the target
release branch), so a single `case` on `${BRANCH}` in the on-`main`
script is sufficient. No backport, no per-branch script copies.

I had originally assumed the script ran from each release branch's
checkout, which is why #3986 left this as a follow-up. After verifying
how CI actually invokes the script, this turned out to be a one-file
change.

## Changes

In `.buildkite/publish/version-bump.sh`, replace the hardcoded
`VERSION_FILES` array with a `case` on `${BRANCH}`:

- `8.*`, `9.0`, `9.1`, `9.2` → `connectors/VERSION` (pre-monorepo
single-file layout)
- everything else → the two post-monorepo paths (current behavior,
unchanged for 9.3+/main)

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Summary

Adds `release-eng: BUILD_AND_READ` to the `connectors` pipeline's teams
block so release-eng team members can trigger builds.

## Why

The `connectors-version-bump` pipeline (introduced in #3986) executes a
`trigger:` step that starts a DRA build on the target release branch on
the main `connectors` pipeline. Buildkite propagates the original
triggering user's identity through trigger chains, so the downstream
build on `connectors` is created as that user -- and the user needs
Build access on `connectors` for the trigger to succeed.

We already granted release-eng `BUILD_AND_READ` on
`connectors-version-bump` (so they can trigger our pipeline at all), but
missed adding it on the main `connectors` pipeline. This caused failures
in [build
#3](https://buildkite.com/elastic/connectors-version-bump/builds/3)
(9.3.5) and [build
#4](https://buildkite.com/elastic/connectors-version-bump/builds/4)
(8.19.16) when triggered by Nina Lee, while [build
#2](https://buildkite.com/elastic/connectors-version-bump/builds/2)
(9.4.1) triggered by Julien Mailleret succeeded -- presumably via
individual grants.

This grants team-level access so any release-eng member can complete the
version bump end-to-end.

## Test plan

- [ ] After merge and Backstage sync (~few minutes), re-trigger build #3
or #4 from the centralized pipeline and confirm the `Trigger DRA build
on ${BRANCH}` step succeeds

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Summary

- Fix DLS query template to use `_allow_access_control.keyword` instead
of `_allow_access_control.enum`
- Update corresponding test assertion

The `.enum` sub-field was created by the custom dynamic mapping template
in `settings.py`, which was removed in PR #3013 (v9.0.0). Under
Elasticsearch's default dynamic mapping, string fields get a `.keyword`
sub-field instead.

This caused DLS-protected documents to be silently filtered out for any
content index created on 9.0+.

Closes #4005

## Test plan

- [ ] Existing unit test updated and passes
- [ ] Set up a connector with DLS on 9.0+, run content + access control
sync, verify DLS queries return expected results

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…ject.toml (#4015)

- Bump versions for `idna` from 3.13 to 3.15, `propcache` from 0.4.1 to
0.5.2, and `python-tds` from 1.12.0 to 1.15.0 in NOTICE.txt.
- Update `python-tds` dependency version from 1.12.0 to 1.15.0 in
pyproject.toml.

## Closes #4014

Bump `python-tds` from `1.12.0` to `1.15.0` so it no longer imports the
now-removed `pkg_resources` module at module load time.

Since 8.17.2 the official
`docker.elastic.co/integrations/elastic-connectors` image is built on
`cgr.dev/chainguard/wolfi-base`, which does not ship `setuptools` in the
runtime venv. `python-tds==1.12.0` does `import pkg_resources`
unconditionally in `pytds/__init__.py`, which means any sync against a
SQL Server data source fails on the first
`create_engine("mssql+pytds://...")` call with:

```
ModuleNotFoundError: No module named 'pkg_resources'
```

This affects every published image from `8.17.2` through `9.4.1` and
breaks the Microsoft SQL Server connector entirely, plus any other
connector that resolves the `mssql+pytds` SQLAlchemy dialect. Dev/CI did
not catch it because we install via `pip install -e .`, which pulls
`setuptools` into the venv, so `pkg_resources` is always available
locally.

Upstream removed the `pkg_resources` import in
[denisenkom/pytds#157](denisenkom/pytds#157),
released as `python-tds==1.15.0`.

### Verification

Reproduced the customer's failure locally by blocking `pkg_resources` on
`sys.meta_path` (simulating the Wolfi runtime):

- With `python-tds==1.12.0`: `import pytds` raises `ModuleNotFoundError:
No module named 'pkg_resources'`.
- With `python-tds==1.15.0`: `import pytds`, `import sqlalchemy_pytds`,
`from connectors.sources.mssql.client import MSSQLClient`, and
`create_engine("mssql+pytds://...")` all succeed.

All 27 existing tests in
`app/connectors_service/tests/sources/test_mssql.py` pass on `1.15.0`.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] this PR has a thorough description
- [x] Tested the changes locally
- [x] Added a label for each target release version (`v8.19.0`,
`v9.1.0`, `v9.2.0`, `v9.3.0`, `v9.4.0`, `v9.5.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases

## Release Note

Fix Microsoft SQL Server (and any other `mssql+pytds` SQLAlchemy)
connector failing to start a sync on the official docker image with
`ModuleNotFoundError: No module named 'pkg_resources'`. The bundled
`python-tds` dependency has been upgraded from `1.12.0` to `1.15.0`,
which no longer requires `pkg_resources` (and therefore `setuptools`) at
runtime.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Closes elastic/search-team#14508
Fix the manual release pipeline (`connectors-docker-build-publish` /
`.buildkite/release-pipeline.yml`) so it can actually be triggered
against `main`, `9.4`, or `9.3`. Today it fails on the very first step
("Set build metadata") because the `VERSION` file path was never updated
after the monorepo restructure.

### What was broken

The monorepo move (#3819, Oct 2025) relocated the connectors `VERSION`
file:

```
connectors/VERSION  →  app/connectors_service/connectors/VERSION
```

A follow-up (#3829) updated `publish-common.sh` to point at the new
path, which unblocked DRA builds, but the same fix was never applied to
the three other files that are *only* exercised by manual in-between
releases. As a result, on `main`/`9.4`/`9.3` they reference paths that
no longer exist:

| File | Broken reference | Effect |
|---|---|---|
| `.buildkite/release-pipeline.yml` (line 23) | `cat
app/connectors/VERSION` | "Set build metadata" step exits non-zero →
`orig_version` meta-data never set → entire pipeline aborts |
| `.buildkite/publish/manual-release/update-release-version.sh` |
`$PROJECT_ROOT/app/connectors/VERSION` (×3) | Even if the previous step
were patched, this would write the bumped version to a path the build
process and tag step don't read from |
| `.buildkite/publish/manual-release/restore-stack-version.sh` |
`$PROJECT_ROOT/connectors/VERSION` (×3) | The cleanup step would
silently restore the wrong file, leaving the real `VERSION` file
containing the timestamp suffix on the branch |

The bug was latent because the last in-between release
(`v8.17.4+build202504152041`) was cut in April 2025, well before the
restructure. Nobody triggered this pipeline against a post-monorepo
branch until now.

### What this PR changes

Aligns all three files with the path already used by
`publish-common.sh`:

```
$PROJECT_ROOT/app/connectors_service/connectors/VERSION
```

7 line replacements across 3 files, no logic changes.

### Why it is *not* backported below 9.3

The pre-monorepo branches (`9.2`, `9.1`, `8.19`) still keep `VERSION` at
`connectors/VERSION` and their pipeline scripts are internally
consistent at that path. Backporting this PR there would *break* their
manual release pipeline. Backport labels are intentionally limited to
`v9.4.0` and `v9.3.0`.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR has a thorough description
- [x] Tested the changes locally (simulated `$PROJECT_ROOT` resolution
and the file IO performed by both manual-release scripts; confirmed the
new path resolves to the actual `VERSION` file from the directory the
scripts run in)
- [x] Added a label for each target release version: `v9.4.0`, `v9.3.0`
*(intentionally NOT `v9.2.0` / `v9.1.0` / `v8.19.0` — see "Why it is not
backported below 9.3" above)*
- [x] For bugfixes: backport safely to all minor branches **still on the
post-monorepo layout**

## Related Pull Requests

* #3819 — monorepo restructure
that introduced the path change
* #3829 — partial fix that
updated `publish-common.sh` only
* #4015 — `python-tds` 1.15.0
bump that this in-between release will ship

## Release Note

_None — internal CI/release-pipeline fix, no user-visible behavior
change._

A few things to know before you paste it:

- I left the issue link as plain text rather than a fake URL. If you
want the line to render as the standard "Closes #" link on GitHub,
either create a tracking issue first and put its number there, or just
replace the whole `## Closes ...` line with `## SDH:
https://elastic.my.salesforce.com/500Vv00000sm2emIAA` so reviewers still
have one click into the context.
- I dropped the checklist items that don't apply (automated tests, docs,
config reference, Kibana mirror PR, security/external-services callout)
so the description doesn't read as "lots of unchecked boxes that are
actually fine". Add them back if your team prefers the full template.
- The `Related Pull Requests` section is genuinely useful for the
reviewer here because the chain of three PRs is what makes the
partial-fix story make sense.

Co-authored-by: Cursor <cursoragent@cursor.com>
## Closes elastic/search-team#14289
## Closes elastic/search-team#14452

The original ask was to add Agentless-specific Elasticsearch defaults so
content-heavy connectors (e.g. GMail) wouldn't lose data to bulk
timeouts. Performance testing showed the new values are at least as good
as the old ones for non-Agentless deployments, so this PR moves the
tuning into the global `_default_config` instead of wrapping it inside
`ConnectorsAgentConfigurationWrapper` following the agreement reached in
https://elastic.slack.com/archives/C01795T48LQ/p1778690756537569
discussion. Self-managed, agent-managed, and Agentless deployments all
get the same baseline.

The second issue (#14452) covers the same coupling from a different
angle: `queue_refresh_timeout` was previously short enough that the
mem-queue circuit breaker could fire before the bulk retry layer
(`TransientElasticsearchRetrier.execute_with_retry`, called from
`ESManagementClient.bulk_insert`) had finished its retry budget. The new
default of 1300s comfortably outlasts the worst-case retry budget under
default settings, and the comment / docs / sanity tests make the
coupling explicit so future changes don't silently re-introduce the bug.
Originally was supposed to be fixed in a **[separate
PR](#4011, but with this PR
now covering general defaults, it was decided to cover both issues with
single PR.

### New defaults

| Setting | Old | New |
|---|---|---|
| `elasticsearch.request_timeout` | 120 | **240** |
| `elasticsearch.max_wait_duration` | 120 | **240** |
| `elasticsearch.bulk.queue_refresh_timeout` | 600 | **1300** |
| `elasticsearch.bulk.chunk_size` | 1000 | **500** |
| `elasticsearch.bulk.chunk_max_mem_size` | 5 | **3** |

`queue_refresh_timeout = 1300` is sized for 5 attempts × 240s
`request_timeout` + linear backoff (10 + 20 + 30 + 40s) = 1300s. If any
of those upstream values change, `queue_refresh_timeout` must change
with them; this is now documented in `config.yml.example` and on the
`DEFAULT_BULK_QUEUE_REFRESH_TIMEOUT` constant.

### Changes

- `connectors/config.py`
  - Updated five values in `_default_config()` (table above).
- Added `DEFAULT_BULK_QUEUE_REFRESH_TIMEOUT = 1300` with a comment
explaining how it's derived and why it must move together with
`request_timeout` / `max_retries` / `retry_interval`.
- `connectors/es/sink.py`
- Bulk fallback `queue_refresh_timeout` 60 → 1300 (matches the new
default).
#4011 (comment)
- `connectors/agent/config.py`
- Removed the now-redundant Agentless-only `elasticsearch` block from
`_default_config` — the global `_default_config` now provides those
values.
- Removed the partial-update guard in `_elasticsearch_config_changed()`;
it was only needed to avoid spurious diffs against the wrapper-side ES
defaults, which no longer exist.
- `config.yml.example`
  - Updated the commented example values to match the new defaults.
- Added a note under `queue_refresh_timeout` calling out that it must be
raised together with `request_timeout` / `max_retries` /
`retry_interval` if a user overrides those.
- `tests/test_config.py`
- Replaced the Agentless-specific assertions with property-based sanity
tests that lock in invariants of the new defaults:
- `queue_refresh_timeout` outlives the worst-case
`TransientElasticsearchRetrier` budget.
    - Bulk chunk / queue / concurrency knobs stay in a sane range.
    - No single retried operation can stall for more than an hour.
- The error-monitor sliding window can actually observe the
consecutive-error threshold.
- Service polling / heartbeat / cleanup intervals respect their natural
ordering.

## Performance Testing

Testing performed on MEDIUM dataset (elasticsearch repo) on local
machine with ElasticSearch being set to `ES_JAVA_OPTS=-Xms1g -Xmx1g`
(default is `ES_JAVA_OPTS=-Xms1g -Xmx1g`)
>DATA_SIZE=medium MAX_DURATION=1800 REFRESH_RATE=2 make -C
app/connectors_service ftest NAME=dir PERF8=yes

BASELINE VS TARGET

Memory Usage
<img width="140" height="100" alt="rss"
src="https://github.com/user-attachments/assets/dbd399cf-2179-4c8c-95c4-d8edf835075f"
/> <img width="140" height="100" alt="rss"
src="https://github.com/user-attachments/assets/d09b5449-679c-42f4-ae51-1cac2bf21d9d"
/>

CPU
<img width="140" height="100" alt="cpu"
src="https://github.com/user-attachments/assets/7bc35bc3-60b1-4a71-aeeb-d65fe2136b39"
/> <img width="140" height="100" alt="cpu"
src="https://github.com/user-attachments/assets/46a1caa0-fc23-4362-b357-ff5e18b72287"
/>

Threads
<img width="140" height="100" alt="threads"
src="https://github.com/user-attachments/assets/696149f7-70c9-478f-b6d3-7df1f3fe166a"
/> <img width="140" height="100" alt="threads"
src="https://github.com/user-attachments/assets/755a506a-064d-4dfd-9f05-17f843ce330f"
/>

Disk I/O
<img width="140" height="100" alt="disk_io"
src="https://github.com/user-attachments/assets/4e11d00a-ad0c-4ea4-b110-de513511714d"
/> <img width="140" height="100" alt="disk_io"
src="https://github.com/user-attachments/assets/6b0c8c66-f0c6-4cff-9d2d-46d1558c1e00"
/>

Disk Usage
<img width="140" height="100" alt="disk"
src="https://github.com/user-attachments/assets/e8ccecb8-217c-41f6-8484-d0b2cbfc6d06"
/> <img width="140" height="100" alt="disk"
src="https://github.com/user-attachments/assets/aa2c24b6-15cf-43aa-8f11-ae43a3f1049c"
/>

Event Loop Lag
<img width="140" height="100" alt="loop_lag"
src="https://github.com/user-attachments/assets/20094e4b-f670-4732-8203-825307ab433b"
/> <img width="140" height="100" alt="loop_lag"
src="https://github.com/user-attachments/assets/cabca8d2-1811-44a2-90af-edccff18e43e"
/>

Task Concurrency
<img width="140" height="100" alt="loop_coro"
src="https://github.com/user-attachments/assets/bddda5c3-67b9-4a33-9807-4b736bb065d6"
/> <img width="140" height="100" alt="loop_coro"
src="https://github.com/user-attachments/assets/91a84e4a-4605-44d1-a882-e7c2e7083d6b"
/>

TARGET shows overall better performance than BASELINE across the
measured metrics, which is the basis for promoting these values from an
Agentless-only override to the global default — they are safe (and
beneficial) for self-managed and agent-managed deployments too.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

## Release Note

Tune Elasticsearch ingestion defaults to better protect content-heavy
connectors against bulk timeouts: increase
`elasticsearch.request_timeout` and `elasticsearch.max_wait_duration` to
240s, raise `elasticsearch.bulk.queue_refresh_timeout` to 1300s so the
mem-queue circuit breaker outlasts the bulk retry budget, and reduce
`elasticsearch.bulk.chunk_size` /
`elasticsearch.bulk.chunk_max_mem_size` for steadier per-request memory
use. Applies to all deployments (self-managed, agent-managed, and
Agentless).

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…max_mem_size and perform pre-append flush (#4012)

## Closes elastic/search-team#14453

`Sink._run` previously checked the batch thresholds **after** appending
each
new doc, meaning a batch could be dispatched only once it had *already*
exceeded
`chunk_mem_size`. For workloads with docs near the limit (e.g. five 1–2
MiB docs
against a 5 MiB ceiling) this produced bulk requests larger than
configured,
risking `413`/OOM errors downstream.

This PR moves the threshold check to fire **pre-emptively**: before
adding a
doc, if the prospective batch size (`bulk_size + doc_size`) would exceed
`chunk_mem_size` — or the batch would exceed `chunk_size` entries — the
current
batch is flushed first, then the new doc starts a fresh batch. An `if
batch`
guard ensures an oversized single doc is still dispatched on its own
rather
than producing an empty flush.

### Changes
- `connectors/es/sink.py`: relocate and tighten the flush condition in
  `Sink._run` so dispatched bulks stay at or below `chunk_mem_size`.
- `tests/test_sink.py`: add four async tests covering
- the bug-report scenario (1,1,1,1,2 MiB vs. 5 MiB ceiling → two
batches, never oversized),
  - `chunk_size` boundary flushing,
  - oversized single doc handled without an empty pre-flush,
  - trailing flush behavior unchanged when no in-loop flush triggers.
- `NOTICE.txt`: refresh `idna` (3.13 → 3.14) and `propcache` (0.4.1 →
0.5.2)
  entries to match current pinned dependencies.

## Testing

Testing was performed by running functional tests 2 times, one without
fix (on main) and one with the fix. The only change is replacement of
`get_mib_size` with `get_size` for more accurate values in the logs.

config.yml has chunk_max_mem_size: 1 #MiB 

Command:
>DATA_SIZE=medium MAX_DURATION=1800 REFRESH_RATE=2 make -C
app/connectors_service ftest NAME=dir 2>&1 | tee ftest-dir.log

Before fix:
There are **three** batches dispatched above `1.0 MiB`, and **none** of
them are single-doc batches — proving the size cap is being violated by
the multi-doc batching path itself.

```6371:6371:ftest-dir.log
[FMWK][17:20:30][DEBUG] [...] Task 3 - Sending a batch of 110 ops -- 1.1570510864MiB
```

```6884:6884:ftest-dir.log
[FMWK][17:20:33][DEBUG] [...] Task 1 - Sending a batch of 262 ops -- 1.1061477661MiB
```

```6938:6938:ftest-dir.log
[FMWK][17:20:33][DEBUG] [...] Task 1 - Sending a batch of 84 ops -- 17.8958511353MiB
```

- 110 ops = **55 docs** packed into a 1.16 MiB bulk.
- 262 ops = **131 docs** packed into a 1.11 MiB bulk.
- 84 ops = **42 docs** packed into a **17.9 MiB** bulk — almost 18× the
configured limit, with plenty of room to have split the batch before the
offending doc landed in it.

No such cases in fixed version:

There is **exactly one** batch dispatched above `1.0 MiB`, and it is a
single-document batch — the unavoidable case the new code explicitly
preserves via the `if batch:` guard.

```6687:6687:ftest-dir-fixed.log
[FMWK][17:03:31][DEBUG] [...] Task 2 - Sending a batch of 2 ops -- 17.4230194092MiB
```

- 2 ops = **1 doc**. A single 17.4 MiB document cannot be split, so it
must be sent on its own; the fixed code correctly flushes the previously
accumulated batch first (see line 6683 immediately before it, which
dispatches the queued 88 ops at 0.53 MiB) and then sends the oversized
doc by itself.

Every other batch in the fixed log stays at or below ~1.0 MiB — the
largest non-single-doc batches are values like `0.9718 MiB`, `0.9711
MiB`, `0.9125 MiB`, etc., all comfortably under the ceiling.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [ ] Added a label for each target release version
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [ ] Considered corresponding documentation changes

## Release Note

[Optional] Fix Elasticsearch sink occasionally dispatching bulk requests
larger than the
configured `chunk_mem_size`, which could trigger `413 Request Entity Too
Large`
or memory pressure on the cluster. Batches are now flushed pre-emptively
so any
single bulk stays within the configured size and memory limits.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…ep big documents from being ingested (#4013)

## Closes elastic/search-team#14454

Introduces a hard per-document size cap for the Elasticsearch bulk sink
so that
clusters are not overwhelmed by oversized **text** documents — for
example,
docs whose `body` was inflated by the Data Extraction Service (which
bypasses
`service.max_file_download_size`) or structured-only docs from API
connectors
with very long fields.

The cap is **scoped to non-binary documents**: docs that carry an
`_attachment`
key (the binary path) remain governed by
`service.max_file_download_size`, and
are never affected by this cap. The intent is to give operators one knob
for
the text/structured path without changing how binary attachments flow.

### What changed

- New config option **`elasticsearch.bulk.max_text_document_size`**
(MiB,
  default `3`, `0` disables, must be `>= 0`).
- `Sink._run`: every non-DELETE bulk op whose `doc` body has **no
`_attachment`
key** is measured against the cap; oversized docs are **skipped, logged
at
  `WARNING`, and counted** as `docs_dropped_too_large`.
- Size measurement matches the actual **wire bytes** the ES client
sends,
  mirroring `elastic_transport._serializer.JsonSerializer`:
`len(json.dumps(op, ensure_ascii=False, separators=(",",
":")).encode("utf-8", "surrogatepass"))`.
This avoids over-counting i18n / emoji content (default `json.dumps`
uses
`ensure_ascii=True`, escaping each non-ASCII character into 6+ ASCII
bytes —
  e.g. `é` → `\u00e9` measured as 6 bytes vs 2 UTF-8 bytes on the wire).
- `_attachment` gate uses **key presence**, not value, so docs that pass
an
empty/None/falsy `_attachment` are still treated as binary path and
exempted.
- `Sink.__init__` rejects negative `max_text_document_size` with a clear
`ValueError` at construction. Without this guard, a negative cap would
be
  truthy and silently drop every non-attachment doc.
- `DELETE` ops are exempt (no body).
- Wired through `SyncOrchestrator.async_bulk` via
  `options["max_text_document_size"]`, defaulting to
`DEFAULT_MAX_TEXT_DOCUMENT_SIZE` from `connectors.config`, and threaded
into
  `_default_config()`.
- Added a commented entry + upgrade-warning paragraph in
`config.yml.example`.

### Behavior

Default: documents whose serialized bulk-op JSON exceeds **3 MiB**
(UTF-8 wire
bytes), and that have no `_attachment` key, are dropped with a log line:

```
Dropping doc id=<id> index=<index> op=<op>: serialized text size <N>B exceeds elasticsearch.bulk.max_text_document_size (<M>B)
```

Set `elasticsearch.bulk.max_text_document_size: 0` to disable the cap
entirely
and restore previous behavior.

### Out of scope (deferred to follow-ups)

This PR fixes the **DES-on text path** specifically. Known related
issues that
are **not** addressed here and need separate PRs:

- Removing the `use_text_extraction_service` short-circuit in
`is_file_size_within_limit` so DES-extracted file size is also bounded.
- Fixing connectors (e.g. GitLab) that pass `file_size=0` and bypass the
  metadata-based file-size check.
- Adding a streaming byte counter in `download_to_temp_file` so the
actual
  download is bounded even when metadata is missing/wrong.
- Switching `bulk_size` / `chunk_mem_size` accounting from
`pympler.asizeof`
  to exact serialized bytes (currently the cap and the chunk flush use
  different units).
- Feeding pre-serialized bytes to `client.bulk(...)` to skip
transport-side
re-serialization (this PR does serialize twice for non-`_attachment`
docs:
  once to measure, once on the wire).

## Testing

### Unit tests

`tests/test_sink.py` (cap-specific):

- `test_sink_drops_doc_exceeding_max_text_document_size` — oversized
text doc
  is dropped, warning string and counter pinned exactly.
- `test_sink_does_not_drop_doc_within_max_text_document_size` — small
text doc
  passes through.
- `test_sink_max_text_document_size_disabled[None, 0]` — falsy cap
disables.
- `test_sink_does_not_drop_delete_op_even_if_oversized` — DELETE exempt.
- `test_sink_drops_only_oversized_doc_in_mixed_batch` — only the
oversized
  doc is dropped from a mixed batch; the rest are sent.
- `test_sink_does_not_drop_doc_with_attachment_even_if_oversized` —
binary
  path exemption.
- `test_sink_attachment_gate_uses_key_presence_not_value[None, "", 0,
False, []]`
  — gate is key-presence, not value-truthiness.
- `test_sink_drops_oversized_doc_when_attachment_key_absent` — explicit
  key-absent sanity.
- `test_sink_drops_doc_with_body_only_when_oversized` — DES-text shape
(`body`,
  no `_attachment`).
- `test_sink_drops_structured_only_doc_when_oversized` — structured-only
doc
  shape (no `body`, no `_attachment`).
- `test_sink_measures_serialized_size_in_wire_utf8_bytes` — regression
for
the i18n/emoji over-count: 200 000 × `é` body fits the 1 MiB cap on the
wire (~0.4 MiB UTF-8) but would have been over the cap (~1.15 MiB) under
  the old `json.dumps` default measurement.
- `test_sink_rejects_negative_max_text_document_size[-1, -3, -1024]` —
negative
  cap is rejected at construction with `ValueError`.

`tests/test_config.py`:

- `test_default_max_text_document_size` asserts the default is `3`.

All 119 cap+config tests pass.

### Functional smoke

The `dir` source ftest still completes end-to-end with the cap enabled:

```
DATA_SIZE=medium MAX_DURATION=1800 REFRESH_RATE=2 \
  make -C app/connectors_service ftest NAME=dir
```

(Earlier runs in this PR exercised the older `pympler.asizeof`
measurement
path; the current measurement is wire-byte and the log format is the new
`serialized text size ...` form.)

## Checklists

#### Pre-Review Checklist

- [x] this PR does NOT contain credentials of any kind
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference

#### Changes Requiring Extra Attention

- **Behavior change (default-on):** by default, non-binary docs whose
serialized bulk-op JSON exceeds 3 MiB will be dropped (with a warning +
`docs_dropped_too_large` counter) instead of being sent. Operators
relying
  on ingesting very large structured/text docs must set
  `elasticsearch.bulk.max_text_document_size: 0` or raise the threshold.
  Binary attachments (`_attachment` present) are unchanged.

## Release Note

Add `elasticsearch.bulk.max_text_document_size` (MiB, default `3`, `0`
disables)
to drop oversized **text** documents (docs without an `_attachment` key)
before
they hit the Elasticsearch bulk API, protecting clusters from being
overwhelmed
by huge extracted/structured documents. The size is measured against the
actual
UTF-8 wire bytes the ES client sends. Dropped docs are logged at
`WARNING` and
counted as `docs_dropped_too_large`. Binary attachments remain governed
by
`service.max_file_download_size`.

**Upgrade note:** earlier connectors versions had no per-document text
cap, so
a sync that previously succeeded with multi-MiB structured/text docs may
begin
reporting `docs_dropped_too_large` after upgrade. Set
`elasticsearch.bulk.max_text_document_size: 0` to preserve previous
behavior,
or raise the value to fit your largest legitimate doc.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ng for iss claim (#4027)

## Closes elastic/sdh-search#1881

The GitHub connector was passing `app_id` as an integer into
`gidgethub`'s JWT construction. This caused PyJWT ≥ 2.11.0 to raise
`TypeError: Issuer (iss) must be a string.` when generating
authentication tokens for GitHub App connections, making the connector
completely unable to sync.

**Root cause:** The `app_id` config field is declared as `"type":
"int"`, so it is coerced to an integer by the configuration layer. PyJWT
2.11.0 (released late 2024) began enforcing RFC 7519 §4.1.1, which
requires the `iss` (issuer) JWT claim to be a string. Versions of PyJWT
before 2.11.0 silently accepted integers, so this went undetected.

**Fix:** Cast `app_id` to `str` at the point it is stored in
`GitHubClient.__init__`. This is the correct boundary — the conversion
is co-located with the code that uses the value for JWT construction,
and is safe regardless of PyJWT version (older versions accepted both,
newer versions require a string).

No dependency version changes are needed. A regression test is included
to pin the type contract.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes or
partially addresses
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [ ] Considered corresponding documentation changes
- [ ] Contributed any configuration settings changes to the
configuration reference

#### Changes Requiring Extra Attention

None — this is a one-line type coercion at initialisation with no
behavioural change for valid inputs. `str(str_value)` is a no-op, so the
fix is fully backward-compatible with environments running older PyJWT.

## Related Pull Requests

None — standalone fix.

## Release Note

Fixed a `TypeError: Issuer (iss) must be a string` crash that prevented
GitHub App authentication from working in connector environments running
PyJWT ≥ 2.11.0. The GitHub App ID is now correctly passed as a string in
the JWT `iss` claim, as required by RFC 7519.

Co-authored-by: Cursor <cursoragent@cursor.com>
… scheduled syncs (#3032) (#3997)

## Closes #3032

## Problem

`time.time()` in Python returns a float with decimal places (e.g.
`1745123456.561659`).
These float timestamps are passed directly to the Slack
`conversations.history` API
as `oldest` and `latest` parameters.

The Slack API inconsistently rejects decimal timestamps — returning no
messages when
decimals are present, despite the docs showing decimal format in
examples. This causes
the connector to successfully sync all messages on the first manual full
sync, but all
subsequent scheduled syncs return no messages and only sync users,
permanently deleting
all previously indexed messages until another manual full sync is
triggered.

- Run 1 (manual full sync) → ~4,750 documents (messages + users) ✅
- Run 2 (scheduled sync) → 613 documents (users only, ~4,137 messages
deleted) ❌
- All subsequent scheduled syncs → 613 documents only ❌

This issue was first reported in December 2024. As of April 2026, 16
months later,
Slack has not resolved the inconsistent API behavior, making this
connector-side
fix necessary to unblock users. While the root cause may lie in
inconsistent Slack
API behavior, this defensive fix on the connector side ensures reliable
syncing
regardless of whether Slack resolves the inconsistency on their end.

## Fix

Truncate float timestamps to `int` before passing to the Slack API:

```python
current_unix_timestamp = int(time.time())
past_unix_timestamp = int(current_unix_timestamp - self.n_days_to_fetch * 24 * 3600)

```

## Testing

Applied this fix to the `v9.1.4` tag and tested against Elasticsearch
9.1.4:

- Run 1 (manual full sync) → ~4,750 documents (messages + users) ✅
- Run 2 (scheduled sync) → ~4,750 documents retained ✅
- Run 3 (scheduled sync) → ~4,750 documents retained ✅

Messages are no longer deleted on scheduled syncs confirming the fix
works as expected.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind
- [x] this PR has a meaningful title
- [x] this PR links to all relevant github issues that it fixes
- [x] this PR has a thorough description
- [x] All 9 Slack unit tests pass including
`test_channels_and_messages_uses_integer_timestamps` which directly
validates the fix
- [x] Tested the fix locally on connector v9.1.4 tag against
Elasticsearch 9.1.4 — messages retained across multiple scheduled syncs
…efore indexing (#4031)

## Closes #1369

The Gmail connector currently ships the entire raw RFC 822 message in
`_attachment` — every routing/auth header, both `text/plain` and
`text/html` alternatives, and every binary part (inline images, PDFs,
etc.). This is wasteful on bandwidth, storage, and Tika cycles, and it
produces noisy indexed text in `attachment.content` whenever Tika's RFC
822 detection falls back to its `TextParser` (which dumps the raw bytes
verbatim — this is the failure mode in the reported issue's screenshot).

This PR trims the message in the connector, before it ever reaches
Elasticsearch. Using Python's stdlib `email` module we parse the raw
Gmail payload, rebuild a minimal `.eml` containing only the headers and
the body part we actually want indexed, and forward that as
`_attachment`.

**Kept headers** (matches Tika's default `RFC822Parser` content output,
plus `Message-ID` for dedup): `Subject`, `From`, `Reply-To`, `To`, `Cc`,
`Bcc`, `Date`, `Message-ID`. Everything else (`Received`, `ARC-*`,
`DKIM-Signature`, `Return-Path`, `Authentication-Results`, `List-*`,
`X-*`, …) is dropped.

**Body selection**: `text/plain` preferred over `text/html` via
`EmailMessage.get_body(preferencelist=("plain", "html"))`. All binary
parts (inline images, attachments, signed/encrypted blobs) are dropped —
Tika would not produce useful indexed text from them anyway, and the ES
attachment processor doesn't run OCR by default.

**New toggle** `include_full_raw_message` (default `False`, order 5)
restores the previous full-raw passthrough for edge cases where body
extraction misses content.

**Safety**: any exception inside the trim helper returns `None` and the
caller falls back to the legacy `base64url_to_base64` raw passthrough
with a logged warning. No path can drop a message because of parse
failure.

## Smoke testing

Validated against a real Gmail message (`/tmp/sample.eml`, 695 KB — a
Google Groups welcome email with two inline PNGs) via two ad-hoc scripts
(`scripts/smoke_gmail_trim.py` and `scripts/smoke_gmail_tika.sh`).

**Wire payload (`_attachment`)** — what the connector ships to
Elasticsearch:

| | `before.eml` (legacy) | `after.eml` (this branch) |
|---|---:|---:|
| size | 695,427 B | 2,722 B |
| reduction | — | **99.61 %** |

Bytes dropped by the trim, by MIME part:

| part | size | kept? |
|---|---:|:---:|
| `text/plain` (body) | 2,267 B | yes |
| `text/html` (same body, marked-up) | 6,961 B | no |
| `image/png` inline (logo) | 1,434 B | no |
| `image/png` inline (photo) | 488,143 B | no |
| routing/auth/`X-*`/`List-*` headers | ~196 KB | no |

**Tika output (`attachment.content`)** — what ends up in the indexed
text after the ES attachment processor runs (apache/tika:latest,
content-type auto-detected as `message/rfc822` in both cases here):

- `before.txt`: 2,293 B — HTML-derived flattened text. Loses sender's
email address, stripped because it was inside an HTML anchor), collapses
paragraph breaks, mangles signature spacing.
- `after.txt`: 2,313 B — proper plain-text rendering. Email addresses
preserved inline, line breaks intact, signature block readable.

The bytes are similar because this email happens to hit Tika's happy
path; the qualitative formatting win is what's visible in the diff. On
emails where Tika misdetects (the reported issue's screenshot is the
canonical example), trimming reduces `attachment.content` from tens of
KB of `Received:`/`ARC-Seal:`/base64 image blobs down to the body only.

Also covered by unit tests in `tests/sources/test_gmail.py` (44
passing): 7 parametrized fixtures (plain-only, multipart/alternative,
html-only, multipart/mixed with PDF attachment, multipart/related with
inline image, RFC 2047 encoded subject, Windows-1252 body), DSN with no
textual body, malformed-base64 garbage, fallback when extraction returns
`None`, toggle-on legacy passthrough, empty/`None` input.

## Checklists

#### Pre-Review Checklist
- [x] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [x] this PR has a meaningful title
- [X] this PR links to all relevant github issues that it fixes or
partially addresses
- [X] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [x] this PR has a thorough description
- [x] Covered the changes with automated tests
- [x] Tested the changes locally
- [x] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [x] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [x] Considered corresponding documentation changes
- [x] Contributed any configuration settings changes to the
configuration reference
- [x] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

**Behavior change**: existing Gmail indices will start receiving
smaller, body-only `_attachment` payloads after upgrade. Routing/auth
headers and binary parts that were previously visible in
`attachment.content` will no longer appear. Users who depended on that
content can restore it by enabling `include_full_raw_message`.

## Related Pull Requests

<!-- Kibana Rich Configurable Fields PR for the new
`include_full_raw_message` toggle, if applicable. -->

## Release Note

Gmail connector: by default, only the email body (preferring
`text/plain` over `text/html`) and a small set of headers (`Subject`,
`From`, `Reply-To`, `To`, `Cc`, `Bcc`, `Date`, `Message-ID`) are
indexed; routing/authentication headers and binary attachments are
dropped. Reduces `_attachment` payload size by ~90 %+ on typical mail
and produces cleaner indexed text. Set the new **Index full raw email
(including headers)** toggle in the connector configuration to restore
the previous behavior.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…4035)

## Summary

- Fixed `docker-compose.yml`: replaced invalid `network_mode:
\"elastic\"` with `networks: - elastic` so the connectors container
actually joins the shared Docker network and can reach the
`elasticsearch` container by hostname.
- Fixed `connectors-config/config.yml`: changed `elasticsearch.host`
from `http://localhost:9200` to `http://elasticsearch:9200` —
`localhost` inside a container resolves to itself, not to the ES
container.

## References

No related issue.
…gest to 56b0d1a (#3983)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker.elastic.co/wolfi/python](https://images.chainguard.dev/directory/image/python/overview)
([source](https://redirect.github.com/chainguard-images/images-private/tree/HEAD/images/python))
| final | digest | `cc3bb21` -> `56b0d1a` |

---

### Configuration

📅 **Schedule**: Branch creation - "* * * * 0,6" (UTC), Automerge - At
any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJhdXRvLWJhY2twb3J0IiwicmVub3ZhdGUiLCJ2OC4xOS4wIiwidjkuMi4wIiwidjkuMy4wIiwidjkuNC4wIl19-->

---------

Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Artem Shelkovnikov <artem.shelkovnikov@elastic.co>
## Description
Hello Team,

Our org went through a re-org. I opened this PR to change the team name
for the version bump pipeline


<!--Provide a general description of the code changes in your pull
request.
If the change relates to a specific issue, include the link at the top.

If this is an ad-hoc/trivial change and does not have a corresponding
issue, please describe your changes in enough details, so that reviewers
and other team members can understand the reasoning behind the pull
request.-->

## Checklists

<!--You can remove unrelated items from checklists below and/or add new
items that may help during the review.-->

#### Pre-Review Checklist
- [ ] this PR does NOT contain credentials of any kind, such as API keys
or username/passwords (double check `config.yml.example`)
- [ ] this PR has a meaningful title
- [ ] this PR links to all relevant github issues that it fixes or
partially addresses
- [ ] if there is no GH issue, please create it. Each PR should have a
link to an issue
- [ ] this PR has a thorough description
- [ ] Covered the changes with automated tests
- [ ] Tested the changes locally
- [ ] Added a label for each target release version (example: `v7.13.2`,
`v7.14.0`, `v8.0.0`)
- [ ] For bugfixes: backport safely to all minor branches still
receiving patch releases
- [ ] Considered corresponding documentation changes
- [ ] Contributed any configuration settings changes to the
configuration reference
- [ ] if you added or changed Rich Configurable Fields for a Native
Connector, you made a corresponding PR in
[Kibana](https://github.com/elastic/kibana/blob/main/packages/kbn-search-connectors/types/native_connectors.ts)

#### Changes Requiring Extra Attention

<!--Please call out any changes that require special attention from the
reviewers and/or increase the risk to availability or security of the
system after deployment. Remove the ones that don't apply.-->

- [ ] Security-related changes (encryption, TLS, SSRF, etc)
- [ ] New external service dependencies added.

## Related Pull Requests

<!--List any relevant PRs here or remove the section if this is a
standalone PR.

* https://github.com/elastic/.../pull/123-->

## Release Note

<!--If you think this enhancement/fix should be included in the release
notes,
please write a concise user-facing description of the change here.
You should also label the PR with `release_note` so the release notes
author(s) can easily look it up.-->

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Backporting to 9.4.0 did not work because of `branchLabelMapping`
counting `main` as `v9.4.0`.

This fixes it, we'll need to re-backport stuff after this is merged.
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.