Skip to content

Commit

Permalink
[8.18] [Search] Don't error out on missing connectors permissions (#2…
Browse files Browse the repository at this point in the history
…12622) (#213085)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[Search] Don't error out on missing connectors permissions
(#212622)](#212622)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Sander
Philipse","email":"94373878+sphilipse@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-02-28T12:36:37Z","message":"[Search]
Don't error out on missing connectors permissions (#212622)\n\n##
Summary\n\nThis stops errors on missing connectors permissions when
fetching\nindices, which was preventing users without connectors
permissions but\nwith listing and write permissions to indices generally
from seeing\nindices in the Search UI.\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"7590205f9a9dd79c8a204eb75b69782503d30937","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:version","v8.18.0","v9.1.0","v8.19.0","v8.17.3"],"title":"[Search]
Don't error out on missing connectors
permissions","number":212622,"url":"https://github.com/elastic/kibana/pull/212622","mergeCommit":{"message":"[Search]
Don't error out on missing connectors permissions (#212622)\n\n##
Summary\n\nThis stops errors on missing connectors permissions when
fetching\nindices, which was preventing users without connectors
permissions but\nwith listing and write permissions to indices generally
from seeing\nindices in the Search UI.\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"7590205f9a9dd79c8a204eb75b69782503d30937"}},"sourceBranch":"main","suggestedTargetBranches":["8.18","8.x","8.17"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/212763","number":212763,"state":"MERGED","mergeCommit":{"sha":"e32f93a3f59c104f0f658ba4d5a7fc6431cb5096","message":"[9.0]
[Search] Don't error out on missing connectors permissions (#212622)
(#212763)\n\n# Backport\n\nThis will backport the following commits from
`main` to `9.0`:\n- [[Search] Don't error out on missing connectors
permissions\n(#212622)](https://github.com/elastic/kibana/pull/212622)\n\n\n\n###
Questions ?\nPlease refer to the [Backport
tool\ndocumentation](https://github.com/sorenlouv/backport)\n\n\n\nCo-authored-by:
Sander Philipse
<94373878+sphilipse@users.noreply.github.com>"}},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212622","number":212622,"mergeCommit":{"message":"[Search]
Don't error out on missing connectors permissions (#212622)\n\n##
Summary\n\nThis stops errors on missing connectors permissions when
fetching\nindices, which was preventing users without connectors
permissions but\nwith listing and write permissions to indices generally
from seeing\nindices in the Search UI.\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"7590205f9a9dd79c8a204eb75b69782503d30937"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.17","label":"v8.17.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
  • Loading branch information
sphilipse authored Mar 4, 2025
1 parent b07584e commit 5bb5384
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { ByteSizeValue } from '@kbn/config-schema';
import { IScopedClusterClient } from '@kbn/core/server';
import { IScopedClusterClient, Logger } from '@kbn/core/server';

import { fetchConnectorByIndexName } from '@kbn/search-connectors';

Expand Down Expand Up @@ -55,6 +55,10 @@ describe('fetchIndex lib function', () => {
jest.clearAllMocks();
});

const logger = {
error: jest.fn(),
} as any as Logger;

const statsResponse = {
indices: {
index_name: {
Expand Down Expand Up @@ -110,7 +114,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve(statsResponse));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).resolves.toEqual(result);
});

Expand All @@ -134,7 +138,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve(statsResponse));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).resolves.toEqual({
...result,
connector: { doc: 'doc', service_type: 'some-service-type' },
Expand All @@ -159,7 +163,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve(statsResponse));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).resolves.toEqual({
...result,
crawler: {
Expand Down Expand Up @@ -194,7 +198,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve(statsResponse));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).resolves.toEqual({
...result,
connector: { doc: 'doc', service_type: ENTERPRISE_SEARCH_CONNECTOR_CRAWLER_SERVICE_TYPE },
Expand All @@ -213,7 +217,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve(statsResponse));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).rejects.toEqual(new Error('404'));
});
it('should throw a 404 error if the indexStats cannot be fonud', async () => {
Expand All @@ -230,7 +234,7 @@ describe('fetchIndex lib function', () => {
);

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).rejects.toEqual(new Error('404'));
});
it('should throw a 404 error if the index stats indices cannot be fonud', async () => {
Expand All @@ -245,7 +249,7 @@ describe('fetchIndex lib function', () => {
mockClient.asCurrentUser.indices.stats.mockImplementation(() => Promise.resolve({}));

await expect(
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name')
fetchIndex(mockClient as unknown as IScopedClusterClient, 'index_name', logger)
).rejects.toEqual(new Error('404'));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
* 2.0.
*/

import { IScopedClusterClient } from '@kbn/core/server';

import {} from '../..';
import { IScopedClusterClient, Logger } from '@kbn/core/server';

import {
Connector,
CONNECTORS_JOBS_INDEX,
ConnectorSyncJobDocument,
fetchConnectorByIndexName,
Expand Down Expand Up @@ -61,7 +60,8 @@ const hasInProgressSyncs = async (

export const fetchIndex = async (
client: IScopedClusterClient,
index: string
index: string,
logger: Logger
): Promise<ElasticsearchIndexWithIngestion> => {
const indexDataResult = await client.asCurrentUser.indices.get({ index });
const indexData = indexDataResult[index];
Expand All @@ -73,8 +73,12 @@ export const fetchIndex = async (
throw new Error('404');
}
const indexStats = indices[index];

const connector = await fetchConnectorByIndexName(client.asCurrentUser, index);
let connector: Connector | undefined;
try {
connector = await fetchConnectorByIndexName(client.asCurrentUser, index);
} catch (error) {
logger.error(`Error fetching connector for index ${index}: ${error}`);
}
const hasInProgressSyncsResult = connector
? await hasInProgressSyncs(client, connector.id)
: { inProgress: false, pending: false };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
*/

import { IScopedClusterClient } from '@kbn/core/server';
import { fetchConnectors } from '@kbn/search-connectors';

import { Connector, fetchConnectors } from '@kbn/search-connectors';

import { Crawler } from '../../../common/types/crawler';

import { isNotNullish } from '../../../common/utils/is_not_nullish';
import { fetchCrawlers } from '../crawler/fetch_crawlers';
Expand All @@ -23,8 +26,16 @@ export const fetchUnattachedIndices = async (
totalResults: number;
}> => {
const { indexNames } = await getUnattachedIndexData(client, searchQuery);
const connectors = await fetchConnectors(client.asCurrentUser, indexNames);
const crawlers = await fetchCrawlers(client, indexNames);

let connectors: Connector[] = [];
let crawlers: Crawler[] = [];
try {
crawlers = await fetchCrawlers(client, indexNames);
connectors = await fetchConnectors(client.asCurrentUser, indexNames);
} catch (error) {
connectors = [];
crawlers = [];
}

const connectedIndexNames = [
...connectors.map((con) => con.index_name).filter(isNotNullish),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const getIndexPipelineParameters = async (
// we want to throw the error if getDefaultPipeline() fails so we're not catching it on purpose
const [defaultPipeline, connector, customPipelineResp] = await Promise.all([
getDefaultPipeline(client),
fetchConnectorByIndexName(client.asCurrentUser, indexName),
fetchConnectorByIndexName(client.asCurrentUser, indexName).catch(() => null),
client.asCurrentUser.ingest
.getPipeline({
id: `${indexName}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import {
deleteConnectorSecret,
deleteConnectorById,
updateConnectorIndexName,
Connector,
} from '@kbn/search-connectors';
import {
fetchConnectorByIndexName,
fetchConnectors,
} from '@kbn/search-connectors/lib/fetch_connectors';

import { DEFAULT_PIPELINE_NAME } from '../../../common/constants';
import { Crawler } from '../../../common/types/crawler';
import { ErrorCode } from '../../../common/types/error_codes';
import { AlwaysShowPattern } from '../../../common/types/indices';

Expand Down Expand Up @@ -126,8 +128,15 @@ export function registerIndexRoutes({
from,
size
);
const connectors = await fetchConnectors(client.asCurrentUser, indexNames);
const crawlers = await fetchCrawlers(client, indexNames);
let crawlers: Crawler[] = [];
let connectors: Connector[] = [];
// If the user doesn't have permissions, fetchConnectors will error out. We still want to return indices in that case.
try {
connectors = await fetchConnectors(client.asCurrentUser, indexNames);
crawlers = await fetchCrawlers(client, indexNames);
} catch {
connectors = [];
}
const enrichedIndices = indices.map((index) => ({
...index,
connector: connectors.find((connector) => connector.index_name === index.name),
Expand Down Expand Up @@ -164,7 +173,7 @@ export function registerIndexRoutes({
const { client } = (await context.core).elasticsearch;

try {
const index = await fetchIndex(client, indexName);
const index = await fetchIndex(client, indexName, log);
return response.ok({
body: index,
headers: { 'content-type': 'application/json' },
Expand Down Expand Up @@ -198,8 +207,15 @@ export function registerIndexRoutes({
const { client } = (await context.core).elasticsearch;

try {
const crawler = await fetchCrawlerByIndexName(client, indexName);
const connector = await fetchConnectorByIndexName(client.asCurrentUser, indexName);
let crawler: Crawler | undefined;
let connector: Connector | undefined;
// users without permissions to fetch connectors should still see a result
try {
connector = await fetchConnectorByIndexName(client.asCurrentUser, indexName);
crawler = await fetchCrawlerByIndexName(client, indexName);
} catch (error) {
log.error(`Error fetching connector for index ${indexName}: ${error}`);
}

if (crawler) {
const crawlerRes = await enterpriseSearchRequestHandler.createRequest({
Expand Down Expand Up @@ -588,7 +604,15 @@ export function registerIndexRoutes({
});
}

const crawler = await fetchCrawlerByIndexName(client, request.body.index_name);
let connector: Connector | undefined;
let crawler: Crawler | undefined;
// users without permissions to fetch connectors should still be able to create an index
try {
connector = await fetchConnectorByIndexName(client.asCurrentUser, indexName);
crawler = await fetchCrawlerByIndexName(client, request.body.index_name);
} catch (error) {
log.error(`Error fetching connector for index ${indexName}: ${error}`);
}

if (crawler) {
return createError({
Expand All @@ -604,11 +628,6 @@ export function registerIndexRoutes({
});
}

const connector = await fetchConnectorByIndexName(
client.asCurrentUser,
request.body.index_name
);

if (connector) {
return createError({
errorCode: ErrorCode.CONNECTOR_DOCUMENT_ALREADY_EXISTS,
Expand Down

0 comments on commit 5bb5384

Please sign in to comment.