diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 217723d72a..e564e38672 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -94538,6 +94538,222 @@ components: example: "report_id" type: string type: object + STIXBundleRequest: + additionalProperties: {} + description: A STIX 2.1 bundle containing threat intelligence indicator objects. + properties: + id: + description: The STIX bundle identifier. + example: bundle--11111111-1111-4111-8111-111111111111 + type: string + objects: + description: >- + The STIX objects included in the bundle. Indicator objects are processed and ingested; all other STIX object types are ignored and are not included in the response counters. + example: + - created: "2026-07-22T12:00:00Z" + id: indicator--22222222-2222-4222-8222-222222222222 + modified: "2026-07-22T12:00:00Z" + pattern: "[ipv4-addr:value = '198.51.100.42']" + pattern_type: stix + spec_version: "2.1" + type: indicator + valid_from: "2026-07-22T12:00:00Z" + items: + $ref: "#/components/schemas/STIXObject" + type: array + spec_version: + $ref: "#/components/schemas/STIXSpecVersion" + type: + $ref: "#/components/schemas/STIXBundleType" + required: + - type + - id + - objects + type: object + STIXBundleType: + description: The STIX object type for a bundle. + enum: + - bundle + example: bundle + type: string + x-enum-varnames: + - BUNDLE + STIXContentEncoding: + description: The content encoding applied to the request body. + enum: + - gzip + example: gzip + type: string + x-enum-varnames: + - GZIP + STIXIngestResponse: + description: The response from a completed STIX ingestion request. + properties: + data: + $ref: "#/components/schemas/STIXIngestResponseData" + required: + - data + type: object + STIXIngestResponseAttributes: + description: Counters describing the result of the STIX ingestion request. + properties: + accepted: + description: The number of supported indicators accepted. + example: 1 + format: int64 + minimum: 0 + type: integer + invalid: + description: The number of indicators with patterns that could not be parsed. + example: 0 + format: int64 + minimum: 0 + type: integer + unsupported: + description: >- + The number of indicator objects with an unsupported STIX version or a pattern that produced no supported observable values. + example: 0 + format: int64 + minimum: 0 + type: integer + required: + - accepted + - unsupported + - invalid + type: object + STIXIngestResponseData: + description: The JSON:API resource describing the completed STIX ingestion request. + properties: + attributes: + $ref: "#/components/schemas/STIXIngestResponseAttributes" + id: + description: The normalized vendor identifier. + example: acme + type: string + type: + $ref: "#/components/schemas/STIXIngestResponseType" + required: + - type + - id + - attributes + type: object + STIXIngestResponseType: + description: The STIX ingestion resource type. + enum: + - threat-intel-stix-ingest + example: threat-intel-stix-ingest + type: string + x-enum-varnames: + - THREAT_INTEL_STIX_INGEST + STIXMetadataObject: + additionalProperties: {} + description: An opaque STIX metadata object. + type: object + STIXObject: + additionalProperties: {} + description: >- + A STIX 2.1 object. Indicator objects are processed and ingested; all other STIX object types are ignored and are not included in the response counters. + properties: + confidence: + description: The confidence in the correctness of the indicator, from 0 through 100. + example: 80 + format: int32 + maximum: 100 + minimum: 0 + type: integer + created: + description: The time when the object was created. + example: "2026-07-22T12:00:00Z" + format: date-time + type: string + external_references: + description: Optional external reference metadata preserved with the indicator but not interpreted during ingestion. + items: + $ref: "#/components/schemas/STIXMetadataObject" + type: array + id: + description: The STIX object identifier. + example: indicator--22222222-2222-4222-8222-222222222222 + type: string + indicator_types: + description: The open vocabulary terms that categorize the indicator. + example: + - malicious-activity + items: + type: string + type: array + kill_chain_phases: + description: Optional kill chain metadata preserved with the indicator but not interpreted during ingestion. + items: + $ref: "#/components/schemas/STIXMetadataObject" + type: array + labels: + description: Labels associated with the indicator. + example: + - synthetic + items: + type: string + type: array + modified: + description: The time when the object was last modified. + example: "2026-07-22T12:00:00Z" + format: date-time + type: string + object_marking_refs: + description: References to marking definition objects that apply to the indicator. + example: + - marking-definition--33333333-3333-4333-8333-333333333333 + items: + type: string + type: array + pattern: + description: The STIX pattern that identifies the observable. Present on indicator objects. + example: "[ipv4-addr:value = '198.51.100.42']" + type: string + pattern_type: + $ref: "#/components/schemas/STIXPatternType" + revoked: + description: Whether the indicator has been revoked. + example: false + type: boolean + spec_version: + description: The STIX specification version declared on the object. Objects with an unsupported version are accepted and counted in the `unsupported` response counter. + example: "2.1" + type: string + type: + description: The STIX object type. + example: indicator + type: string + valid_from: + description: The time from which the indicator is considered valid. Present on indicator objects. + example: "2026-07-22T12:00:00Z" + format: date-time + type: string + valid_until: + description: The time until which the indicator is considered valid. + example: "2027-07-22T12:00:00Z" + format: date-time + type: string + required: + - type + - id + type: object + STIXPatternType: + description: The supported STIX pattern language. + enum: + - stix + example: stix + type: string + x-enum-varnames: + - STIX + STIXSpecVersion: + description: The supported STIX specification version. + enum: + - "2.1" + example: "2.1" + type: string + x-enum-varnames: + - VERSION_2_1 SalesforceIncidentsOrganizationResponseAttributes: description: Attributes of a Salesforce organization connected to the Datadog Salesforce integration. properties: @@ -198089,6 +198305,120 @@ paths: operator: OR permissions: - security_monitoring_notification_profiles_write + /api/v2/security/threat-intel/stix: + post: + description: |- + Ingest a STIX 2.1 bundle containing threat intelligence indicators. Only indicator objects are processed. Supported indicator patterns contain IPv4 addresses, IPv6 addresses, domain names, or SHA-256 file hashes. + + Non-indicator objects are ignored and are not included in the response counters. Indicator objects with unsupported STIX versions or patterns that produce no supported observable values increment the `unsupported` counter. Patterns that cannot be parsed increment the `invalid` counter. Processing is best effort, so valid supported indicators in the same bundle are still added. + + A successful response means ingestion has completed. Reference-table materialization and enrichment happen asynchronously. Requests are limited to 50 MB as received, 100 MB after decompression, and 10 requests per second per API key. Gzip-compressed request bodies are supported. + operationId: AddSTIXThreatIntel + parameters: + - description: >- + Vendor identifier for the feed. The value must not exceed 10 characters. Datadog normalizes the accepted value to lowercase, converts non-alphanumeric characters to underscores, and trims leading and trailing underscores. + example: acme + in: header + name: ti_vendor + required: true + schema: + maxLength: 10 + minLength: 1 + type: string + - description: Content encoding for the request body. Use gzip for a compressed STIX bundle. + in: header + name: Content-Encoding + required: false + schema: + $ref: "#/components/schemas/STIXContentEncoding" + requestBody: + content: + application/json: + examples: + default: + value: + id: bundle--11111111-1111-4111-8111-111111111111 + objects: + - created: "2026-07-22T12:00:00Z" + id: indicator--22222222-2222-4222-8222-222222222222 + modified: "2026-07-22T12:00:00Z" + pattern: "[ipv4-addr:value = '198.51.100.42']" + pattern_type: stix + spec_version: "2.1" + type: indicator + valid_from: "2026-07-22T12:00:00Z" + spec_version: "2.1" + type: bundle + schema: + $ref: "#/components/schemas/STIXBundleRequest" + description: >- + A STIX 2.1 bundle containing indicator objects. The request body must not exceed 50 MB as received or 100 MB after decompression. + required: true + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + accepted: 1 + invalid: 0 + unsupported: 0 + id: acme + type: threat-intel-stix-ingest + schema: + $ref: "#/components/schemas/STIXIngestResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "401": + $ref: "#/components/responses/UnauthorizedResponse" + "403": + $ref: "#/components/responses/ForbiddenResponse" + "413": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: The request body exceeds 50 MB as received or 100 MB after decompression. + "429": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Too many requests + "502": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: The STIX ingestion service returned an error while processing the request. + "503": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: The STIX ingestion service is temporarily unavailable. + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Ingest STIX threat intelligence + tags: + - Threat Intelligence + x-codegen-request-body-name: body + x-permission: + operator: OR + permissions: + - reference_tables_write + x-unstable: |- + **Note**: This endpoint is in preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). /api/v2/security/vulnerabilities: get: deprecated: true @@ -221364,6 +221694,8 @@ tags: - description: |- Search and manage flaky tests through Test Optimization. See the [Test Optimization page](https://docs.datadoghq.com/tests/) for more information. name: Test Optimization + - description: Ingest and manage threat intelligence data for security enrichment and investigation. + name: Threat Intelligence - description: |- Manage your Datadog Twilio integration accounts directly through the Datadog API. Create, update, and delete accounts, configure authentication and settings, and diff --git a/examples/v2/threat-intelligence/AddSTIXThreatIntel.py b/examples/v2/threat-intelligence/AddSTIXThreatIntel.py new file mode 100644 index 0000000000..9d8107263a --- /dev/null +++ b/examples/v2/threat-intelligence/AddSTIXThreatIntel.py @@ -0,0 +1,39 @@ +""" +Ingest STIX threat intelligence returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.threat_intelligence_api import ThreatIntelligenceApi +from datadog_api_client.v2.model.stix_bundle_request import STIXBundleRequest +from datadog_api_client.v2.model.stix_bundle_type import STIXBundleType +from datadog_api_client.v2.model.stix_object import STIXObject +from datadog_api_client.v2.model.stix_pattern_type import STIXPatternType +from datadog_api_client.v2.model.stix_spec_version import STIXSpecVersion +from datetime import datetime +from dateutil.tz import tzutc + +body = STIXBundleRequest( + id="bundle--44444444-4444-4444-8444-444444444444", + objects=[ + STIXObject( + created=datetime(2026, 7, 22, 12, 0, tzinfo=tzutc()), + id="indicator--55555555-5555-4555-8555-555555555555", + modified=datetime(2026, 7, 22, 12, 0, tzinfo=tzutc()), + pattern="[ipv4-addr:value = '198.51.100.42']", + pattern_type=STIXPatternType.STIX, + spec_version="2.1", + type="indicator", + valid_from=datetime(2026, 7, 22, 12, 0, tzinfo=tzutc()), + ), + ], + spec_version=STIXSpecVersion.VERSION_2_1, + type=STIXBundleType.BUNDLE, +) + +configuration = Configuration() +configuration.unstable_operations["add_stix_threat_intel"] = True +with ApiClient(configuration) as api_client: + api_instance = ThreatIntelligenceApi(api_client) + response = api_instance.add_stix_threat_intel(ti_vendor="Acme-Inc", body=body) + + print(response) diff --git a/src/datadog_api_client/configuration.py b/src/datadog_api_client/configuration.py index 3d8e652708..6d4971595e 100644 --- a/src/datadog_api_client/configuration.py +++ b/src/datadog_api_client/configuration.py @@ -799,6 +799,7 @@ def __init__( "v2.create_scorecard_outcomes_batch": False, "v2.get_entity_risk_score": False, "v2.list_entity_risk_scores": False, + "v2.add_stix_threat_intel": False, "v2.create_slo_report_job": False, "v2.get_slo_report": False, "v2.get_slo_report_job_status": False, diff --git a/src/datadog_api_client/v2/api/threat_intelligence_api.py b/src/datadog_api_client/v2/api/threat_intelligence_api.py new file mode 100644 index 0000000000..f045732ca2 --- /dev/null +++ b/src/datadog_api_client/v2/api/threat_intelligence_api.py @@ -0,0 +1,95 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import Any, Dict, Union + +from datadog_api_client.api_client import ApiClient, Endpoint as _Endpoint +from datadog_api_client.configuration import Configuration +from datadog_api_client.model_utils import ( + UnsetType, + unset, +) +from datadog_api_client.v2.model.stix_ingest_response import STIXIngestResponse +from datadog_api_client.v2.model.stix_content_encoding import STIXContentEncoding +from datadog_api_client.v2.model.stix_bundle_request import STIXBundleRequest + + +class ThreatIntelligenceApi: + """ + Ingest and manage threat intelligence data for security enrichment and investigation. + """ + + def __init__(self, api_client=None): + if api_client is None: + api_client = ApiClient(Configuration()) + self.api_client = api_client + + self._add_stix_threat_intel_endpoint = _Endpoint( + settings={ + "response_type": (STIXIngestResponse,), + "auth": ["apiKeyAuth", "appKeyAuth"], + "endpoint_path": "/api/v2/security/threat-intel/stix", + "operation_id": "add_stix_threat_intel", + "http_method": "POST", + "version": "v2", + }, + params_map={ + "ti_vendor": { + "required": True, + "validation": { + "max_length": 10, + "min_length": 1, + }, + "openapi_types": (str,), + "attribute": "ti_vendor", + "location": "header", + }, + "content_encoding": { + "openapi_types": (STIXContentEncoding,), + "attribute": "Content-Encoding", + "location": "header", + }, + "body": { + "required": True, + "openapi_types": (STIXBundleRequest,), + "location": "body", + }, + }, + headers_map={"accept": ["application/json"], "content_type": ["application/json"]}, + api_client=api_client, + ) + + def add_stix_threat_intel( + self, + ti_vendor: str, + body: STIXBundleRequest, + *, + content_encoding: Union[STIXContentEncoding, UnsetType] = unset, + ) -> STIXIngestResponse: + """Ingest STIX threat intelligence. + + Ingest a STIX 2.1 bundle containing threat intelligence indicators. Only indicator objects are processed. Supported indicator patterns contain IPv4 addresses, IPv6 addresses, domain names, or SHA-256 file hashes. + + Non-indicator objects are ignored and are not included in the response counters. Indicator objects with unsupported STIX versions or patterns that produce no supported observable values increment the ``unsupported`` counter. Patterns that cannot be parsed increment the ``invalid`` counter. Processing is best effort, so valid supported indicators in the same bundle are still added. + + A successful response means ingestion has completed. Reference-table materialization and enrichment happen asynchronously. Requests are limited to 50 MB as received, 100 MB after decompression, and 10 requests per second per API key. Gzip-compressed request bodies are supported. + + :param ti_vendor: Vendor identifier for the feed. The value must not exceed 10 characters. Datadog normalizes the accepted value to lowercase, converts non-alphanumeric characters to underscores, and trims leading and trailing underscores. + :type ti_vendor: str + :param body: A STIX 2.1 bundle containing indicator objects. The request body must not exceed 50 MB as received or 100 MB after decompression. + :type body: STIXBundleRequest + :param content_encoding: Content encoding for the request body. Use gzip for a compressed STIX bundle. + :type content_encoding: STIXContentEncoding, optional + :rtype: STIXIngestResponse + """ + kwargs: Dict[str, Any] = {} + kwargs["ti_vendor"] = ti_vendor + + if content_encoding is not unset: + kwargs["content_encoding"] = content_encoding + + kwargs["body"] = body + + return self._add_stix_threat_intel_endpoint.call_with_http_info(**kwargs) diff --git a/src/datadog_api_client/v2/apis/__init__.py b/src/datadog_api_client/v2/apis/__init__.py index e486f90f67..597ce512c6 100644 --- a/src/datadog_api_client/v2/apis/__init__.py +++ b/src/datadog_api_client/v2/apis/__init__.py @@ -135,6 +135,7 @@ from datadog_api_client.v2.api.tag_rules_api import TagRulesApi from datadog_api_client.v2.api.teams_api import TeamsApi from datadog_api_client.v2.api.test_optimization_api import TestOptimizationApi +from datadog_api_client.v2.api.threat_intelligence_api import ThreatIntelligenceApi from datadog_api_client.v2.api.twilio_integration_accounts_api import TwilioIntegrationAccountsApi from datadog_api_client.v2.api.usage_metering_api import UsageMeteringApi from datadog_api_client.v2.api.user_authorized_clients_api import UserAuthorizedClientsApi @@ -283,6 +284,7 @@ "TagRulesApi", "TeamsApi", "TestOptimizationApi", + "ThreatIntelligenceApi", "TwilioIntegrationAccountsApi", "UsageMeteringApi", "UserAuthorizedClientsApi", diff --git a/src/datadog_api_client/v2/model/stix_bundle_request.py b/src/datadog_api_client/v2/model/stix_bundle_request.py new file mode 100644 index 0000000000..437244a8eb --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_bundle_request.py @@ -0,0 +1,72 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.stix_object import STIXObject + from datadog_api_client.v2.model.stix_spec_version import STIXSpecVersion + from datadog_api_client.v2.model.stix_bundle_type import STIXBundleType + + +class STIXBundleRequest(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.stix_object import STIXObject + from datadog_api_client.v2.model.stix_spec_version import STIXSpecVersion + from datadog_api_client.v2.model.stix_bundle_type import STIXBundleType + + return { + "id": (str,), + "objects": ([STIXObject],), + "spec_version": (STIXSpecVersion,), + "type": (STIXBundleType,), + } + + attribute_map = { + "id": "id", + "objects": "objects", + "spec_version": "spec_version", + "type": "type", + } + + def __init__( + self_, + id: str, + objects: List[STIXObject], + type: STIXBundleType, + spec_version: Union[STIXSpecVersion, UnsetType] = unset, + **kwargs, + ): + """ + A STIX 2.1 bundle containing threat intelligence indicator objects. + + :param id: The STIX bundle identifier. + :type id: str + + :param objects: The STIX objects included in the bundle. Indicator objects are processed and ingested; all other STIX object types are ignored and are not included in the response counters. + :type objects: [STIXObject] + + :param spec_version: The supported STIX specification version. + :type spec_version: STIXSpecVersion, optional + + :param type: The STIX object type for a bundle. + :type type: STIXBundleType + """ + if spec_version is not unset: + kwargs["spec_version"] = spec_version + super().__init__(kwargs) + + self_.id = id + self_.objects = objects + self_.type = type diff --git a/src/datadog_api_client/v2/model/stix_bundle_type.py b/src/datadog_api_client/v2/model/stix_bundle_type.py new file mode 100644 index 0000000000..e5faafce7c --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_bundle_type.py @@ -0,0 +1,35 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class STIXBundleType(ModelSimple): + """ + The STIX object type for a bundle. + + :param value: If omitted defaults to "bundle". Must be one of ["bundle"]. + :type value: str + """ + + allowed_values = { + "bundle", + } + BUNDLE: ClassVar["STIXBundleType"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +STIXBundleType.BUNDLE = STIXBundleType("bundle") diff --git a/src/datadog_api_client/v2/model/stix_content_encoding.py b/src/datadog_api_client/v2/model/stix_content_encoding.py new file mode 100644 index 0000000000..31f35eec05 --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_content_encoding.py @@ -0,0 +1,35 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class STIXContentEncoding(ModelSimple): + """ + The content encoding applied to the request body. + + :param value: If omitted defaults to "gzip". Must be one of ["gzip"]. + :type value: str + """ + + allowed_values = { + "gzip", + } + GZIP: ClassVar["STIXContentEncoding"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +STIXContentEncoding.GZIP = STIXContentEncoding("gzip") diff --git a/src/datadog_api_client/v2/model/stix_ingest_response.py b/src/datadog_api_client/v2/model/stix_ingest_response.py new file mode 100644 index 0000000000..118d01418c --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_ingest_response.py @@ -0,0 +1,40 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.stix_ingest_response_data import STIXIngestResponseData + + +class STIXIngestResponse(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.stix_ingest_response_data import STIXIngestResponseData + + return { + "data": (STIXIngestResponseData,), + } + + attribute_map = { + "data": "data", + } + + def __init__(self_, data: STIXIngestResponseData, **kwargs): + """ + The response from a completed STIX ingestion request. + + :param data: The JSON:API resource describing the completed STIX ingestion request. + :type data: STIXIngestResponseData + """ + super().__init__(kwargs) + + self_.data = data diff --git a/src/datadog_api_client/v2/model/stix_ingest_response_attributes.py b/src/datadog_api_client/v2/model/stix_ingest_response_attributes.py new file mode 100644 index 0000000000..145e8be5e7 --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_ingest_response_attributes.py @@ -0,0 +1,57 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class STIXIngestResponseAttributes(ModelNormal): + validations = { + "accepted": { + "inclusive_minimum": 0, + }, + "invalid": { + "inclusive_minimum": 0, + }, + "unsupported": { + "inclusive_minimum": 0, + }, + } + + @cached_property + def openapi_types(_): + return { + "accepted": (int,), + "invalid": (int,), + "unsupported": (int,), + } + + attribute_map = { + "accepted": "accepted", + "invalid": "invalid", + "unsupported": "unsupported", + } + + def __init__(self_, accepted: int, invalid: int, unsupported: int, **kwargs): + """ + Counters describing the result of the STIX ingestion request. + + :param accepted: The number of supported indicators accepted. + :type accepted: int + + :param invalid: The number of indicators with patterns that could not be parsed. + :type invalid: int + + :param unsupported: The number of indicator objects with an unsupported STIX version or a pattern that produced no supported observable values. + :type unsupported: int + """ + super().__init__(kwargs) + + self_.accepted = accepted + self_.invalid = invalid + self_.unsupported = unsupported diff --git a/src/datadog_api_client/v2/model/stix_ingest_response_data.py b/src/datadog_api_client/v2/model/stix_ingest_response_data.py new file mode 100644 index 0000000000..bb56e09dbe --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_ingest_response_data.py @@ -0,0 +1,54 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.stix_ingest_response_attributes import STIXIngestResponseAttributes + from datadog_api_client.v2.model.stix_ingest_response_type import STIXIngestResponseType + + +class STIXIngestResponseData(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.stix_ingest_response_attributes import STIXIngestResponseAttributes + from datadog_api_client.v2.model.stix_ingest_response_type import STIXIngestResponseType + + return { + "attributes": (STIXIngestResponseAttributes,), + "id": (str,), + "type": (STIXIngestResponseType,), + } + + attribute_map = { + "attributes": "attributes", + "id": "id", + "type": "type", + } + + def __init__(self_, attributes: STIXIngestResponseAttributes, id: str, type: STIXIngestResponseType, **kwargs): + """ + The JSON:API resource describing the completed STIX ingestion request. + + :param attributes: Counters describing the result of the STIX ingestion request. + :type attributes: STIXIngestResponseAttributes + + :param id: The normalized vendor identifier. + :type id: str + + :param type: The STIX ingestion resource type. + :type type: STIXIngestResponseType + """ + super().__init__(kwargs) + + self_.attributes = attributes + self_.id = id + self_.type = type diff --git a/src/datadog_api_client/v2/model/stix_ingest_response_type.py b/src/datadog_api_client/v2/model/stix_ingest_response_type.py new file mode 100644 index 0000000000..5499c7003d --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_ingest_response_type.py @@ -0,0 +1,35 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class STIXIngestResponseType(ModelSimple): + """ + The STIX ingestion resource type. + + :param value: If omitted defaults to "threat-intel-stix-ingest". Must be one of ["threat-intel-stix-ingest"]. + :type value: str + """ + + allowed_values = { + "threat-intel-stix-ingest", + } + THREAT_INTEL_STIX_INGEST: ClassVar["STIXIngestResponseType"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +STIXIngestResponseType.THREAT_INTEL_STIX_INGEST = STIXIngestResponseType("threat-intel-stix-ingest") diff --git a/src/datadog_api_client/v2/model/stix_metadata_object.py b/src/datadog_api_client/v2/model/stix_metadata_object.py new file mode 100644 index 0000000000..aa7971f220 --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_metadata_object.py @@ -0,0 +1,17 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, +) + + +class STIXMetadataObject(ModelNormal): + def __init__(self_, **kwargs): + """ + An opaque STIX metadata object. + """ + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/stix_object.py b/src/datadog_api_client/v2/model/stix_object.py new file mode 100644 index 0000000000..eadb639d74 --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_object.py @@ -0,0 +1,175 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + datetime, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.stix_metadata_object import STIXMetadataObject + from datadog_api_client.v2.model.stix_pattern_type import STIXPatternType + + +class STIXObject(ModelNormal): + validations = { + "confidence": { + "inclusive_maximum": 100, + "inclusive_minimum": 0, + }, + } + + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.stix_metadata_object import STIXMetadataObject + from datadog_api_client.v2.model.stix_pattern_type import STIXPatternType + + return { + "confidence": (int,), + "created": (datetime,), + "external_references": ([STIXMetadataObject],), + "id": (str,), + "indicator_types": ([str],), + "kill_chain_phases": ([STIXMetadataObject],), + "labels": ([str],), + "modified": (datetime,), + "object_marking_refs": ([str],), + "pattern": (str,), + "pattern_type": (STIXPatternType,), + "revoked": (bool,), + "spec_version": (str,), + "type": (str,), + "valid_from": (datetime,), + "valid_until": (datetime,), + } + + attribute_map = { + "confidence": "confidence", + "created": "created", + "external_references": "external_references", + "id": "id", + "indicator_types": "indicator_types", + "kill_chain_phases": "kill_chain_phases", + "labels": "labels", + "modified": "modified", + "object_marking_refs": "object_marking_refs", + "pattern": "pattern", + "pattern_type": "pattern_type", + "revoked": "revoked", + "spec_version": "spec_version", + "type": "type", + "valid_from": "valid_from", + "valid_until": "valid_until", + } + + def __init__( + self_, + id: str, + type: str, + confidence: Union[int, UnsetType] = unset, + created: Union[datetime, UnsetType] = unset, + external_references: Union[List[STIXMetadataObject], UnsetType] = unset, + indicator_types: Union[List[str], UnsetType] = unset, + kill_chain_phases: Union[List[STIXMetadataObject], UnsetType] = unset, + labels: Union[List[str], UnsetType] = unset, + modified: Union[datetime, UnsetType] = unset, + object_marking_refs: Union[List[str], UnsetType] = unset, + pattern: Union[str, UnsetType] = unset, + pattern_type: Union[STIXPatternType, UnsetType] = unset, + revoked: Union[bool, UnsetType] = unset, + spec_version: Union[str, UnsetType] = unset, + valid_from: Union[datetime, UnsetType] = unset, + valid_until: Union[datetime, UnsetType] = unset, + **kwargs, + ): + """ + A STIX 2.1 object. Indicator objects are processed and ingested; all other STIX object types are ignored and are not included in the response counters. + + :param confidence: The confidence in the correctness of the indicator, from 0 through 100. + :type confidence: int, optional + + :param created: The time when the object was created. + :type created: datetime, optional + + :param external_references: Optional external reference metadata preserved with the indicator but not interpreted during ingestion. + :type external_references: [STIXMetadataObject], optional + + :param id: The STIX object identifier. + :type id: str + + :param indicator_types: The open vocabulary terms that categorize the indicator. + :type indicator_types: [str], optional + + :param kill_chain_phases: Optional kill chain metadata preserved with the indicator but not interpreted during ingestion. + :type kill_chain_phases: [STIXMetadataObject], optional + + :param labels: Labels associated with the indicator. + :type labels: [str], optional + + :param modified: The time when the object was last modified. + :type modified: datetime, optional + + :param object_marking_refs: References to marking definition objects that apply to the indicator. + :type object_marking_refs: [str], optional + + :param pattern: The STIX pattern that identifies the observable. Present on indicator objects. + :type pattern: str, optional + + :param pattern_type: The supported STIX pattern language. + :type pattern_type: STIXPatternType, optional + + :param revoked: Whether the indicator has been revoked. + :type revoked: bool, optional + + :param spec_version: The STIX specification version declared on the object. Objects with an unsupported version are accepted and counted in the ``unsupported`` response counter. + :type spec_version: str, optional + + :param type: The STIX object type. + :type type: str + + :param valid_from: The time from which the indicator is considered valid. Present on indicator objects. + :type valid_from: datetime, optional + + :param valid_until: The time until which the indicator is considered valid. + :type valid_until: datetime, optional + """ + if confidence is not unset: + kwargs["confidence"] = confidence + if created is not unset: + kwargs["created"] = created + if external_references is not unset: + kwargs["external_references"] = external_references + if indicator_types is not unset: + kwargs["indicator_types"] = indicator_types + if kill_chain_phases is not unset: + kwargs["kill_chain_phases"] = kill_chain_phases + if labels is not unset: + kwargs["labels"] = labels + if modified is not unset: + kwargs["modified"] = modified + if object_marking_refs is not unset: + kwargs["object_marking_refs"] = object_marking_refs + if pattern is not unset: + kwargs["pattern"] = pattern + if pattern_type is not unset: + kwargs["pattern_type"] = pattern_type + if revoked is not unset: + kwargs["revoked"] = revoked + if spec_version is not unset: + kwargs["spec_version"] = spec_version + if valid_from is not unset: + kwargs["valid_from"] = valid_from + if valid_until is not unset: + kwargs["valid_until"] = valid_until + super().__init__(kwargs) + + self_.id = id + self_.type = type diff --git a/src/datadog_api_client/v2/model/stix_pattern_type.py b/src/datadog_api_client/v2/model/stix_pattern_type.py new file mode 100644 index 0000000000..89432a19df --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_pattern_type.py @@ -0,0 +1,35 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class STIXPatternType(ModelSimple): + """ + The supported STIX pattern language. + + :param value: If omitted defaults to "stix". Must be one of ["stix"]. + :type value: str + """ + + allowed_values = { + "stix", + } + STIX: ClassVar["STIXPatternType"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +STIXPatternType.STIX = STIXPatternType("stix") diff --git a/src/datadog_api_client/v2/model/stix_spec_version.py b/src/datadog_api_client/v2/model/stix_spec_version.py new file mode 100644 index 0000000000..ab02ca16f7 --- /dev/null +++ b/src/datadog_api_client/v2/model/stix_spec_version.py @@ -0,0 +1,35 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class STIXSpecVersion(ModelSimple): + """ + The supported STIX specification version. + + :param value: If omitted defaults to "2.1". Must be one of ["2.1"]. + :type value: str + """ + + allowed_values = { + "2.1", + } + VERSION_2_1: ClassVar["STIXSpecVersion"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +STIXSpecVersion.VERSION_2_1 = STIXSpecVersion("2.1") diff --git a/src/datadog_api_client/v2/models/__init__.py b/src/datadog_api_client/v2/models/__init__.py index f88afdca91..fdfe5fd89c 100644 --- a/src/datadog_api_client/v2/models/__init__.py +++ b/src/datadog_api_client/v2/models/__init__.py @@ -8309,6 +8309,17 @@ from datadog_api_client.v2.model.slo_report_status_get_response import SLOReportStatusGetResponse from datadog_api_client.v2.model.slo_report_status_get_response_attributes import SLOReportStatusGetResponseAttributes from datadog_api_client.v2.model.slo_report_status_get_response_data import SLOReportStatusGetResponseData +from datadog_api_client.v2.model.stix_bundle_request import STIXBundleRequest +from datadog_api_client.v2.model.stix_bundle_type import STIXBundleType +from datadog_api_client.v2.model.stix_content_encoding import STIXContentEncoding +from datadog_api_client.v2.model.stix_ingest_response import STIXIngestResponse +from datadog_api_client.v2.model.stix_ingest_response_attributes import STIXIngestResponseAttributes +from datadog_api_client.v2.model.stix_ingest_response_data import STIXIngestResponseData +from datadog_api_client.v2.model.stix_ingest_response_type import STIXIngestResponseType +from datadog_api_client.v2.model.stix_metadata_object import STIXMetadataObject +from datadog_api_client.v2.model.stix_object import STIXObject +from datadog_api_client.v2.model.stix_pattern_type import STIXPatternType +from datadog_api_client.v2.model.stix_spec_version import STIXSpecVersion from datadog_api_client.v2.model.salesforce_incidents_organization_response_attributes import ( SalesforceIncidentsOrganizationResponseAttributes, ) @@ -17038,6 +17049,17 @@ "SLOReportStatusGetResponse", "SLOReportStatusGetResponseAttributes", "SLOReportStatusGetResponseData", + "STIXBundleRequest", + "STIXBundleType", + "STIXContentEncoding", + "STIXIngestResponse", + "STIXIngestResponseAttributes", + "STIXIngestResponseData", + "STIXIngestResponseType", + "STIXMetadataObject", + "STIXObject", + "STIXPatternType", + "STIXSpecVersion", "SalesforceIncidentsOrganizationResponseAttributes", "SalesforceIncidentsOrganizationResponseData", "SalesforceIncidentsOrganizationType", diff --git a/tests/generated-test/test-runner-data/manifest.json b/tests/generated-test/test-runner-data/manifest.json index 6adae37efa..c71715538f 100644 --- a/tests/generated-test/test-runner-data/manifest.json +++ b/tests/generated-test/test-runner-data/manifest.json @@ -11480,6 +11480,13 @@ "scenario": "Update team notification rule returns \"OK\" response", "version": "v2" }, + { + "feature": "Threat Intelligence", + "feature_file": "../../v2/features/threat_intelligence.feature", + "file": "v2/threat-intelligence/ingest-stix-threat-intelligence-returns-ok-response.json", + "scenario": "Ingest STIX threat intelligence returns \"OK\" response", + "version": "v2" + }, { "feature": "Usage Metering", "feature_file": "../../v2/features/usage_metering.feature", diff --git a/tests/generated-test/test-runner-data/v2/threat-intelligence/ingest-stix-threat-intelligence-returns-ok-response.json b/tests/generated-test/test-runner-data/v2/threat-intelligence/ingest-stix-threat-intelligence-returns-ok-response.json new file mode 100644 index 0000000000..e38a0c9de2 --- /dev/null +++ b/tests/generated-test/test-runner-data/v2/threat-intelligence/ingest-stix-threat-intelligence-returns-ok-response.json @@ -0,0 +1,59 @@ +{ + "api": "ThreatIntelligence", + "expected_status": 200, + "feature": "Threat Intelligence", + "id": "v2/Threat Intelligence/Ingest STIX threat intelligence returns \"OK\" response", + "operation_id": "AddSTIXThreatIntel", + "request": { + "body": { + "schema": { + "format": null, + "ref": "STIXBundleRequest", + "type": "object" + }, + "source": "inline", + "value": { + "id": "bundle--44444444-4444-4444-8444-444444444444", + "objects": [ + { + "created": "2026-07-22T12:00:00Z", + "id": "indicator--55555555-5555-4555-8555-555555555555", + "modified": "2026-07-22T12:00:00Z", + "pattern": "[ipv4-addr:value = '198.51.100.42']", + "pattern_type": "stix", + "spec_version": "2.1", + "type": "indicator", + "valid_from": "2026-07-22T12:00:00Z" + } + ], + "spec_version": "2.1", + "type": "bundle" + } + }, + "content_type": "application/json", + "method": "POST", + "pagination": false, + "parameters": [ + { + "explode": null, + "in": "header", + "name": "ti_vendor", + "required": true, + "schema": { + "format": null, + "ref": null, + "type": "string" + }, + "source": { + "type": "literal", + "value": "Acme-Inc" + }, + "style": null + } + ], + "path": "/api/v2/security/threat-intel/stix" + }, + "scenario": "Ingest STIX threat intelligence returns \"OK\" response", + "schema_version": 1, + "version": "v2" +} diff --git a/tests/generated-test/test-server-data/manifest.json b/tests/generated-test/test-server-data/manifest.json index a5bd4bc09a..77fd3c6d42 100644 --- a/tests/generated-test/test-server-data/manifest.json +++ b/tests/generated-test/test-server-data/manifest.json @@ -535,6 +535,11 @@ "file": "v2/teams.json", "version": "v2" }, + { + "feature": "Threat Intelligence", + "file": "v2/threat-intelligence.json", + "version": "v2" + }, { "feature": "Usage Metering", "file": "v2/usage-metering.json", diff --git a/tests/generated-test/test-server-data/v2/threat-intelligence.json b/tests/generated-test/test-server-data/v2/threat-intelligence.json new file mode 100644 index 0000000000..945a6d693d --- /dev/null +++ b/tests/generated-test/test-server-data/v2/threat-intelligence.json @@ -0,0 +1,54 @@ +{ + "feature": "Threat Intelligence", + "recordings": [ + { + "feature": "Threat Intelligence", + "frozen_at": "2026-07-24T13:40:34.989Z", + "interactions": [ + { + "request": { + "body": { + "type": "json", + "value": { + "id": "bundle--44444444-4444-4444-8444-444444444444", + "objects": [ + { + "created": "2026-07-22T12:00:00Z", + "id": "indicator--55555555-5555-4555-8555-555555555555", + "modified": "2026-07-22T12:00:00Z", + "pattern": "[ipv4-addr:value = '198.51.100.42']", + "pattern_type": "stix", + "spec_version": "2.1", + "type": "indicator", + "valid_from": "2026-07-22T12:00:00Z" + } + ], + "spec_version": "2.1", + "type": "bundle" + } + }, + "content_type": "application/json", + "method": "POST", + "path": "/api/v2/security/threat-intel/stix", + "query": [] + }, + "response": { + "body": { + "encoding": "text", + "value": "{\"data\":{\"id\":\"acme_inc\",\"type\":\"threat-intel-stix-ingest\",\"attributes\":{\"accepted\":1,\"invalid\":0,\"unsupported\":0}}}" + }, + "headers": { + "content-type": "application/vnd.api+json" + }, + "reason": "OK", + "status": 200 + } + } + ], + "scenario": "Ingest STIX threat intelligence returns \"OK\" response", + "version": "v2" + } + ], + "schema_version": 1, + "version": "v2" +} diff --git a/tests/v2/features/threat_intelligence.feature b/tests/v2/features/threat_intelligence.feature new file mode 100644 index 0000000000..62542a9cea --- /dev/null +++ b/tests/v2/features/threat_intelligence.feature @@ -0,0 +1,37 @@ +@endpoint(threat-intelligence) @endpoint(threat-intelligence-v2) +Feature: Threat Intelligence + Ingest and manage threat intelligence data for security enrichment and + investigation. + + Background: + Given a valid "apiKeyAuth" key in the system + And a valid "appKeyAuth" key in the system + And an instance of "ThreatIntelligence" API + And operation "AddSTIXThreatIntel" enabled + And new "AddSTIXThreatIntel" request + + @generated @skip @team:DataDog/cloud-siem + Scenario: Ingest STIX threat intelligence returns "Bad Request" response + Given body with value {"id": "bundle--11111111-1111-4111-8111-111111111111", "objects": [{"created": "2026-07-22T12:00:00Z", "id": "indicator--22222222-2222-4222-8222-222222222222", "modified": "2026-07-22T12:00:00Z", "pattern": "[ipv4-addr:value = '198.51.100.42']", "pattern_type": "stix", "spec_version": "2.1", "type": "indicator", "valid_from": "2026-07-22T12:00:00Z"}], "spec_version": "2.1", "type": "bundle"} + And request contains "ti_vendor" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @replay-only @skip-validation @team:DataDog/cloud-siem + Scenario: Ingest STIX threat intelligence returns "OK" response + Given request contains "ti_vendor" parameter with value "Acme-Inc" + And body with value {"id": "bundle--44444444-4444-4444-8444-444444444444", "objects": [{"created": "2026-07-22T12:00:00Z", "id": "indicator--55555555-5555-4555-8555-555555555555", "modified": "2026-07-22T12:00:00Z", "pattern": "[ipv4-addr:value = '198.51.100.42']", "pattern_type": "stix", "spec_version": "2.1", "type": "indicator", "valid_from": "2026-07-22T12:00:00Z"}], "spec_version": "2.1", "type": "bundle"} + When the request is sent + Then the response status is 200 OK + And the response "data.type" is equal to "threat-intel-stix-ingest" + And the response "data.id" is equal to "acme_inc" + And the response "data.attributes.accepted" is equal to 1 + And the response "data.attributes.unsupported" is equal to 0 + And the response "data.attributes.invalid" is equal to 0 + + @generated @skip @team:DataDog/cloud-siem + Scenario: Ingest STIX threat intelligence returns "The request body exceeds 50 MB as received or 100 MB after decompression." response + Given body with value {"id": "bundle--11111111-1111-4111-8111-111111111111", "objects": [{"created": "2026-07-22T12:00:00Z", "id": "indicator--22222222-2222-4222-8222-222222222222", "modified": "2026-07-22T12:00:00Z", "pattern": "[ipv4-addr:value = '198.51.100.42']", "pattern_type": "stix", "spec_version": "2.1", "type": "indicator", "valid_from": "2026-07-22T12:00:00Z"}], "spec_version": "2.1", "type": "bundle"} + And request contains "ti_vendor" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 413 The request body exceeds 50 MB as received or 100 MB after decompression. diff --git a/tests/v2/features/undo.json b/tests/v2/features/undo.json index 16e0df0b38..c0d502c15f 100644 --- a/tests/v2/features/undo.json +++ b/tests/v2/features/undo.json @@ -8065,6 +8065,12 @@ "type": "idempotent" } }, + "AddSTIXThreatIntel": { + "tag": "Threat Intelligence", + "undo": { + "type": "safe" + } + }, "ListVulnerabilities": { "tag": "Security Monitoring", "undo": {