-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[backend] Fix strict_dynamic_mapping_exception exceptions thrown in fileIndexManager (#14665) #14655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[backend] Fix strict_dynamic_mapping_exception exceptions thrown in fileIndexManager (#14665) #14655
Changes from all commits
d7e0fac
4e3a37f
ad0a325
eba4579
960fd39
0cc6780
c67d22e
bf5d902
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| FROM opensearchproject/opensearch:3.5.0 | ||
| RUN /usr/share/opensearch/bin/opensearch-plugin install --batch ingest-attachment |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import type { Mutable } from '../utils/type-utils'; | ||
|
|
||
| // List of fields extracted by the attachment ingest processor. | ||
| // The full list is available in the Elasticsearch docs: | ||
| // (https://www.elastic.co/guide/en/elasticsearch/reference/8.19/attachment.html#attachment-fields). | ||
| export const ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_ELASTICSEARCH = [ | ||
| 'content', | ||
| 'title', | ||
| 'author', | ||
| 'keywords', | ||
| 'date', | ||
| 'content_type', | ||
| 'content_length', | ||
| 'language', | ||
| 'modified', | ||
| 'format', | ||
| // identifier, NOT EXTRACTED | ||
| // contributor, NOT EXTRACTED | ||
| // coverage, NOT EXTRACTED | ||
| 'modifier', | ||
| 'creator_tool', | ||
| // publisher, NOT EXTRACTED | ||
| // relation, NOT EXTRACTED | ||
| // rights, NOT EXTRACTED | ||
| // source, NOT EXTRACTED | ||
| // type, NOT EXTRACTED | ||
| 'description', | ||
| 'print_date', | ||
| 'metadata_date', | ||
| // latitude, NOT EXTRACTED | ||
| // longitude, NOT EXTRACTED | ||
| // altitude, NOT EXTRACTED | ||
| // rating, NOT EXTRACTED | ||
| 'comments', | ||
| ] as const; | ||
|
|
||
| // List of fields extracted by the attachment ingest processor, for OpenSearch. | ||
| // The full list is available in the OS docs: | ||
| // (https://docs.opensearch.org/latest/install-and-configure/additional-plugins/ingest-attachment-plugin/#extracted-information), | ||
| // and code shows the check rejects unknown fields with an exception: | ||
| // https://github.com/opensearch-project/OpenSearch/blob/315481148edaa43410e2e9f1801ec903fd62ec20/plugins/ingest-attachment/src/main/java/org/opensearch/ingest/attachment/AttachmentProcessor.java#L277 | ||
| export const ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_OPENSEARCH = [ | ||
| 'content', | ||
| 'title', | ||
| 'author', | ||
| 'keywords', | ||
| 'date', | ||
| 'content_type', | ||
| 'content_length', | ||
| 'language', | ||
| ] as const; | ||
|
|
||
| // Union type of all properties extracted by the ES or OS attachment processor | ||
| export type AttachmentProcessorExtractedProp = Mutable<typeof ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_ELASTICSEARCH>[number] | ||
| | Mutable<typeof ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_OPENSEARCH>[number]; | ||
|
Comment on lines
+53
to
+55
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -176,6 +176,7 @@ import { DRAFT_OPERATION_CREATE, DRAFT_OPERATION_DELETE, DRAFT_OPERATION_DELETE_ | |
| import { RELATION_SAMPLE } from '../modules/malwareAnalysis/malwareAnalysis-types'; | ||
| import { asyncMap } from '../utils/data-processing'; | ||
| import { doYield } from '../utils/eventloop-utils'; | ||
| import type { Mutable } from '../utils/type-utils'; | ||
| import { RELATION_COVERED } from '../modules/securityCoverage/securityCoverage-types'; | ||
| import type { AuthContext, AuthUser } from '../types/user'; | ||
| import type { | ||
|
|
@@ -197,6 +198,7 @@ import { IDS_ATTRIBUTES } from '../domain/attribute-utils'; | |
| import { schemaRelationsRefDefinition } from '../schema/schema-relationsRef'; | ||
| import type { FiltersWithNested } from './middleware-loader'; | ||
| import { pushAll, unshiftAll } from '../utils/arrayUtil'; | ||
| import { ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_ELASTICSEARCH, ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_OPENSEARCH } from './attachment-processor-props'; | ||
|
|
||
| const ELK_ENGINE = 'elk'; | ||
| const OPENSEARCH_ENGINE = 'opensearch'; | ||
|
|
@@ -309,6 +311,7 @@ export const elConfigureAttachmentProcessor = async (): Promise<boolean> => { | |
| attachment: { | ||
| field: 'file_data', | ||
| remove_binary: true, | ||
| properties: ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_ELASTICSEARCH as Mutable<typeof ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_ELASTICSEARCH>, | ||
| }, | ||
|
Comment on lines
313
to
315
|
||
| }, | ||
| ], | ||
|
|
@@ -325,6 +328,7 @@ export const elConfigureAttachmentProcessor = async (): Promise<boolean> => { | |
| { | ||
| attachment: { | ||
| field: 'file_data', | ||
| properties: ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_OPENSEARCH as Mutable<typeof ATTACHMENT_PROCESSOR_EXTRACTED_PROPS_OPENSEARCH>, | ||
| }, | ||
| }, | ||
| { | ||
|
|
@@ -2717,11 +2721,11 @@ const buildSubQueryForFilterGroup = ( | |
|
|
||
| const currentSubQuery = localMustFilters.length > 0 | ||
| ? { | ||
| bool: { | ||
| should: localMustFilters, | ||
| minimum_should_match: mode === 'or' ? 1 : localMustFilters.length, | ||
| }, | ||
| } | ||
| bool: { | ||
| should: localMustFilters, | ||
| minimum_should_match: mode === 'or' ? 1 : localMustFilters.length, | ||
| }, | ||
| } | ||
| : null; | ||
| return { subQuery: currentSubQuery, postFiltersTags: localPostFilterTags, resultSaltCount: localSaltCount }; | ||
| }; | ||
|
|
@@ -3094,12 +3098,12 @@ const tagFiltersForPostFiltering = ( | |
| ) => { | ||
| const taggedFilters: (Filter & { postFilteringTag: string })[] = filters | ||
| ? extractFiltersFromGroup(filters, [INSTANCE_REGARDING_OF, INSTANCE_DYNAMIC_REGARDING_OF]) | ||
| .filter((filter) => isEmptyField(filter.operator) || filter.operator === 'eq') | ||
| .map((filter, i) => { | ||
| const taggedFilter = filter as Filter & { postFilteringTag: string }; | ||
| taggedFilter.postFilteringTag = `${i}`; | ||
| return taggedFilter; | ||
| }) | ||
| .filter((filter) => isEmptyField(filter.operator) || filter.operator === 'eq') | ||
| .map((filter, i) => { | ||
| const taggedFilter = filter as Filter & { postFilteringTag: string }; | ||
| taggedFilter.postFilteringTag = `${i}`; | ||
| return taggedFilter; | ||
| }) | ||
| : []; | ||
|
|
||
| if (taggedFilters.length > 0) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,13 @@ | ||||||||||||||||||||||
| import { assertType } from '../../../utils/type-utils'; | ||||||||||||||||||||||
| import type { AttachmentProcessorExtractedProp } from '../../../database/attachment-processor-props'; | ||||||||||||||||||||||
| import { ENTITY_TYPE_INTERNAL_FILE } from '../../../schema/internalObject'; | ||||||||||||||||||||||
| import { schemaAttributesDefinition } from '../../../schema/schema-attributes'; | ||||||||||||||||||||||
| import { type AttributeDefinition, createdAt, creators, entityType, id, internalId, parentTypes, refreshedAt, standardId, updatedAt } from '../../../schema/attribute-definition'; | ||||||||||||||||||||||
| import { ENTITY_TYPE_MARKING_DEFINITION } from '../../../schema/stixMetaObject'; | ||||||||||||||||||||||
| import { ABSTRACT_STIX_CORE_OBJECT } from '../../../schema/general'; | ||||||||||||||||||||||
| import { UPLOAD_STATUS_VALUES } from './document-domain'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const attributes: Array<AttributeDefinition> = [ | ||||||||||||||||||||||
| const attributes = [ | ||||||||||||||||||||||
| id, | ||||||||||||||||||||||
| internalId, | ||||||||||||||||||||||
| standardId, | ||||||||||||||||||||||
|
|
@@ -93,6 +95,17 @@ const attributes: Array<AttributeDefinition> = [ | |||||||||||||||||||||
| { name: 'file_id', label: 'File identifier', type: 'string', format: 'short', mandatoryType: 'internal', editDefault: false, multiple: false, upsert: false, isFilterable: false }, | ||||||||||||||||||||||
| { name: 'entity_id', label: 'Related entity', type: 'string', format: 'id', entityTypes: [ABSTRACT_STIX_CORE_OBJECT], mandatoryType: 'internal', editDefault: false, multiple: false, upsert: false, isFilterable: false }, | ||||||||||||||||||||||
| { name: 'removed', label: 'Removed', type: 'boolean', mandatoryType: 'no', editDefault: false, multiple: false, upsert: false, isFilterable: false }, | ||||||||||||||||||||||
| ]; | ||||||||||||||||||||||
| ] as const satisfies Array<AttributeDefinition>; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const attachmentAttributes = attributes[18]; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| type AttachmentAttributeMappingNames = typeof attachmentAttributes.mappings[number]['name'][]; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
+100
to
+103
|
||||||||||||||||||||||
| const attachmentAttributes = attributes[18]; | |
| type AttachmentAttributeMappingNames = typeof attachmentAttributes.mappings[number]['name'][]; | |
| const attachmentAttributes = attributes.find((attribute) => attribute.name === 'attachment'); | |
| if (!attachmentAttributes || !attachmentAttributes.mappings) { | |
| throw new Error('Attachment attribute definition with mappings not found in internal file attributes'); | |
| } | |
| type AttachmentAttributeMappingNames = (typeof attachmentAttributes.mappings)[number]['name'][]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /** | ||
| * Inverse operation of the built-in Readonly<T> utility type: | ||
| * makes all records of an object mutable. | ||
| */ | ||
| export type Mutable<T> = { -readonly [P in keyof T]: T[P]; }; | ||
|
|
||
| type AssertEqual<T, TExpected> = [T] extends [TExpected] | ||
| ? [TExpected] extends [T] | ||
| ? T | ||
| : never | ||
| : never; | ||
|
|
||
| /** | ||
| * Compile-time type assertion utility checking that a type T | ||
| * is exactly of type TExpected. | ||
| * | ||
| * @example | ||
| * ``` | ||
| * type Fruit = 'banana' | 'strawberry' | 'pineapple'; | ||
| * const allFruits = ['banana' as const, 'strawberry' as const, 'pineapple' as const]; | ||
| * // Checks for exhaustiveness | ||
| * assertType<typeof allFruits[number][], Fruit[]>(allFruits); | ||
| * ``` | ||
| */ | ||
| export const assertType = <T, TExpected>(_x: AssertEqual<T, TExpected>) => { | ||
| // noop | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usage hint here was changed to
podman compose, but the rest of this file still documentsdocker composefor other profiles. If Podman is not required, keepdocker compose(or mention both) to avoid confusing contributors following the dev setup instructions.