From 2b20a723b9bcaf5adc81e06052ef9af7c05f0722 Mon Sep 17 00:00:00 2001 From: Cesare de Cal Date: Mon, 23 Mar 2026 17:09:12 +0100 Subject: [PATCH] [Osquery] Fix pack and saved query APIs returning 500 instead of 404 for "not found" errors (#258883) I noticed while working on Scout API tests (https://github.com/elastic/kibana/pull/258534) that the GET endpoints for packs and saved queries return a `500` Internal Server Error when the resource doesn't exist, rather than the usual `404`. This PR fixes it. Worth mentioning that the issue occurs in all surfaces (stateful deployment, ECH, MKI). Some FTR API integration tests were added to ensure coverage. (cherry picked from commit 4301849b361347096590df70c0229d63f63dc932) # Conflicts: # x-pack/platform/plugins/shared/osquery/server/routes/pack/delete_pack_route.ts # x-pack/platform/plugins/shared/osquery/server/routes/pack/update_pack_route.ts # x-pack/platform/plugins/shared/osquery/server/routes/saved_query/update_saved_query_route.ts # x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts --- .../server/routes/pack/delete_pack_route.ts | 21 ++++++-- .../server/routes/pack/read_pack_route.ts | 21 ++++++-- .../server/routes/pack/update_pack_route.ts | 21 ++++++-- .../saved_query/delete_saved_query_route.ts | 18 +++++-- .../saved_query/read_saved_query_route.ts | 21 ++++++-- .../saved_query/update_saved_query_route.ts | 53 +++++++++++-------- .../api_integration/apis/osquery/packs.ts | 29 ++++++++++ 7 files changed, 141 insertions(+), 43 deletions(-) diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/pack/delete_pack_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/pack/delete_pack_route.ts index 2892795e18a48..4dd2a81b1e472 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/pack/delete_pack_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/pack/delete_pack_route.ts @@ -8,7 +8,7 @@ import { has, filter, unset } from 'lodash'; import { produce } from 'immer'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { DeletePacksRequestParamsSchema } from '../../../common/api'; import { buildRouteValidation } from '../../utils/build_validation/route_validation'; @@ -54,10 +54,21 @@ export const deletePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte const packagePolicyService = osqueryContext.service.getPackagePolicyService(); - const currentPackSO = await spaceScopedClient.get<{ name: string }>( - packSavedObjectType, - request.params.id - ); + let currentPackSO; + try { + currentPackSO = await spaceScopedClient.get<{ name: string }>( + packSavedObjectType, + request.params.id + ); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Pack ${request.params.id} not found` }, + }); + } + + throw err; + } await spaceScopedClient.delete(packSavedObjectType, request.params.id, { refresh: 'wait_for', diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/pack/read_pack_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/pack/read_pack_route.ts index 0e542bb0dd1fb..fd052c930e466 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/pack/read_pack_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/pack/read_pack_route.ts @@ -7,7 +7,7 @@ import { filter, map } from 'lodash'; import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { createInternalSavedObjectsClientForSpaceId } from '../../utils/get_internal_saved_object_client'; import type { ReadPacksRequestParamsSchema } from '../../../common/api'; @@ -52,8 +52,23 @@ export const readPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext request ); - const { attributes, references, id, ...rest } = - await spaceScopedClient.get(packSavedObjectType, request.params.id); + let packSO; + try { + packSO = await spaceScopedClient.get( + packSavedObjectType, + request.params.id + ); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Pack ${request.params.id} not found` }, + }); + } + + throw err; + } + + const { attributes, references, id, ...rest } = packSO; const policyIds = map( filter(references, ['type', LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE]), diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/pack/update_pack_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/pack/update_pack_route.ts index 225e098407542..5c631959aeb94 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/pack/update_pack_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/pack/update_pack_route.ts @@ -14,7 +14,7 @@ import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '@kbn/fleet-plugin/common'; -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { createInternalSavedObjectsClientForSpaceId } from '../../utils/get_internal_saved_object_client'; import type { @@ -89,10 +89,21 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte const { name, description, queries, enabled, policy_ids, shards = {} } = request.body; - const currentPackSO = await spaceScopedClient.get<{ name: string; enabled: boolean }>( - packSavedObjectType, - request.params.id - ); + let currentPackSO; + try { + currentPackSO = await spaceScopedClient.get( + packSavedObjectType, + request.params.id + ); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Pack ${request.params.id} not found` }, + }); + } + + throw err; + } if (name) { const conflictingEntries = await spaceScopedClient.find({ diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/delete_saved_query_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/delete_saved_query_route.ts index 5965eacb63f77..1ca31f1b3511e 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/delete_saved_query_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/delete_saved_query_route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-utils'; import { createInternalSavedObjectsClientForSpaceId } from '../../utils/get_internal_saved_object_client'; import { buildRouteValidation } from '../../utils/build_validation/route_validation'; @@ -59,9 +59,19 @@ export const deleteSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAp return response.conflict({ body: `Elastic prebuilt Saved query cannot be deleted.` }); } - await spaceScopedClient.delete(savedQuerySavedObjectType, request.params.id, { - refresh: 'wait_for', - }); + try { + await spaceScopedClient.delete(savedQuerySavedObjectType, request.params.id, { + refresh: 'wait_for', + }); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Saved query ${request.params.id} not found` }, + }); + } + + throw err; + } return response.ok({ body: {}, diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/read_saved_query_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/read_saved_query_route.ts index 66607a5e08e12..bf6e32d5e2ef4 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/read_saved_query_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/read_saved_query_route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-utils'; import { createInternalSavedObjectsClientForSpaceId } from '../../utils/get_internal_saved_object_client'; import { buildRouteValidation } from '../../utils/build_validation/route_validation'; @@ -52,10 +52,21 @@ export const readSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC const space = await osqueryContext.service.getActiveSpace(request); const spaceId = space?.id ?? DEFAULT_SPACE_ID; - const savedQuery = await spaceScopedClient.get( - savedQuerySavedObjectType, - request.params.id - ); + let savedQuery; + try { + savedQuery = await spaceScopedClient.get( + savedQuerySavedObjectType, + request.params.id + ); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Saved query ${request.params.id} not found` }, + }); + } + + throw err; + } if (savedQuery.attributes.ecs_mapping) { // @ts-expect-error update types diff --git a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/update_saved_query_route.ts b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/update_saved_query_route.ts index 61d7a33c1d9c4..edf40c1ff9bc5 100644 --- a/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/update_saved_query_route.ts +++ b/x-pack/platform/plugins/shared/osquery/server/routes/saved_query/update_saved_query_route.ts @@ -7,7 +7,7 @@ import { filter, some } from 'lodash'; -import type { IRouter } from '@kbn/core/server'; +import { type IRouter, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-utils'; import { createInternalSavedObjectsClientForSpaceId } from '../../utils/get_internal_saved_object_client'; import { buildRouteValidation } from '../../utils/build_validation/route_validation'; @@ -112,27 +112,38 @@ export const updateSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAp return response.conflict({ body: `Saved query with id "${id}" already exists.` }); } - const updatedSavedQuerySO = await spaceScopedClient.update( - savedQuerySavedObjectType, - request.params.id, - { - id, - description: description || '', - platform, - query, - version, - interval, - timeout, - snapshot, - removed, - ecs_mapping: convertECSMappingToArray(ecs_mapping), - updated_by: username, - updated_at: new Date().toISOString(), - }, - { - refresh: 'wait_for', + let updatedSavedQuerySO; + try { + updatedSavedQuerySO = await spaceScopedClient.update( + savedQuerySavedObjectType, + request.params.id, + { + id, + description: description || '', + platform, + query, + version, + interval, + timeout, + snapshot, + removed, + ecs_mapping: convertECSMappingToArray(ecs_mapping), + updated_by: username, + updated_at: new Date().toISOString(), + }, + { + refresh: 'wait_for', + } + ); + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return response.notFound({ + body: { message: `Saved query ${request.params.id} not found` }, + }); } - ); + + throw err; + } if (ecs_mapping || updatedSavedQuerySO.attributes.ecs_mapping) { // @ts-expect-error update types diff --git a/x-pack/platform/test/api_integration/apis/osquery/packs.ts b/x-pack/platform/test/api_integration/apis/osquery/packs.ts index bf9f9eeccff0c..f8cc47ccb57e6 100644 --- a/x-pack/platform/test/api_integration/apis/osquery/packs.ts +++ b/x-pack/platform/test/api_integration/apis/osquery/packs.ts @@ -151,5 +151,34 @@ export default function ({ getService }: FtrProviderContext) { singleLineQuery ); }); + + describe('404 for non-existent resources', () => { + it('returns 404 when reading a non-existent pack', async () => { + await supertest + .get('/api/osquery/packs/non-existent-id') + .set('kbn-xsrf', 'true') + .expect(404); + }); + + it('returns 404 when updating a non-existent pack', async () => { + await supertest + .put('/api/osquery/packs/non-existent-id') + .set('kbn-xsrf', 'true') + .send({ + name: 'Updated Pack', + description: 'Updated', + enabled: true, + queries: { q1: { query: 'select 1;', interval: 3600 } }, + }) + .expect(404); + }); + + it('returns 404 when deleting a non-existent pack', async () => { + await supertest + .delete('/api/osquery/packs/non-existent-id') + .set('kbn-xsrf', 'true') + .expect(404); + }); + }); }); }