1818import com .jayway .jsonpath .JsonPath ;
1919import io .openaev .IntegrationTest ;
2020import io .openaev .database .model .*;
21+ import io .openaev .database .model .Tag ;
2122import io .openaev .database .repository .InjectRepository ;
2223import io .openaev .database .repository .ScenarioRepository ;
2324import io .openaev .database .repository .SecurityCoverageRepository ;
25+ import io .openaev .database .repository .TagRepository ;
26+ import io .openaev .service .AssetGroupService ;
2427import io .openaev .utils .fixtures .*;
2528import io .openaev .utils .fixtures .composers .*;
2629import io .openaev .utils .fixtures .files .AttackPatternFixture ;
@@ -56,19 +59,23 @@ class StixApiTest extends IntegrationTest {
5659
5760 @ Autowired private ScenarioRepository scenarioRepository ;
5861 @ Autowired private InjectRepository injectRepository ;
62+ @ Autowired private TagRepository tagRepository ;
5963 @ Autowired private SecurityCoverageRepository securityCoverageRepository ;
64+ @ Autowired private AssetGroupService assetGroupService ;
6065
6166 @ Autowired private AttackPatternComposer attackPatternComposer ;
6267 @ Autowired private VulnerabilityComposer vulnerabilityComposer ;
6368 @ Autowired private TagRuleComposer tagRuleComposer ;
6469 @ Autowired private AssetGroupComposer assetGroupComposer ;
6570 @ Autowired private EndpointComposer endpointComposer ;
71+ @ Autowired private PayloadComposer payloadComposer ;
6672 @ Autowired private InjectorContractComposer injectorContractComposer ;
6773 @ Autowired private TagComposer tagComposer ;
6874
6975 @ Autowired private InjectorFixture injectorFixture ;
7076
7177 private String stixSecurityCoverage ;
78+ private String stixSecurityCoverageNoLabels ;
7279 private String stixSecurityCoverageWithoutTtps ;
7380 private String stixSecurityCoverageWithoutVulns ;
7481 private String stixSecurityCoverageWithoutObjects ;
@@ -79,9 +86,21 @@ class StixApiTest extends IntegrationTest {
7986 @ BeforeEach
8087 void setUp () throws Exception {
8188 attackPatternComposer .reset ();
89+ vulnerabilityComposer .reset ();
90+ tagRuleComposer .reset ();
91+ endpointComposer .reset ();
92+ assetGroupComposer .reset ();
93+ payloadComposer .reset ();
94+ injectorContractComposer .reset ();
95+ tagComposer .reset ();
96+
8297 stixSecurityCoverage =
8398 loadJsonWithStixObjectsAsText ("src/test/resources/stix-bundles/security-coverage.json" );
8499
100+ stixSecurityCoverageNoLabels =
101+ loadJsonWithStixObjectsAsText (
102+ "src/test/resources/stix-bundles/security-coverage-no-labels.json" );
103+
85104 stixSecurityCoverageWithoutTtps =
86105 loadJsonWithStixObjectsAsText (
87106 "src/test/resources/stix-bundles/security-coverage-without-ttps.json" );
@@ -98,9 +117,6 @@ void setUp() throws Exception {
98117 loadJsonWithStixObjectsAsText (
99118 "src/test/resources/stix-bundles/security-coverage-only-vulns.json" );
100119
101- attackPatternComposer
102- .forAttackPattern (AttackPatternFixture .createAttackPatternsWithExternalId (T_1531 ))
103- .persist ();
104120 attackPatternComposer
105121 .forAttackPattern (AttackPatternFixture .createAttackPatternsWithExternalId (T_1003 ))
106122 .persist ();
@@ -170,16 +186,125 @@ void setUp() throws Exception {
170186 .persist ();
171187 }
172188
173- @ AfterEach
174- void afterEach () {
175- attackPatternComposer .reset ();
176- vulnerabilityComposer .reset ();
177- }
178-
179189 @ Nested
180190 @ DisplayName ("Import STIX Bundles" )
181191 class ImportStixBundles {
182192
193+ @ Test
194+ @ DisplayName (
195+ "When Security Coverage SDO has no labels property, should force adding opencti tag to scenario" )
196+ void whenSecurityCoverageSDOHasNoLabelsProperty_shouldForceAddingOpenctiTagToScenario ()
197+ throws Exception {
198+ String response =
199+ mvc .perform (
200+ post (STIX_URI + "/process-bundle" )
201+ .contentType (MediaType .APPLICATION_JSON )
202+ .content (stixSecurityCoverageNoLabels ))
203+ .andExpect (status ().isOk ())
204+ .andReturn ()
205+ .getResponse ()
206+ .getContentAsString ();
207+
208+ assertThat (response ).isNotBlank ();
209+ String scenarioId = JsonPath .read (response , "$.scenarioId" );
210+ Scenario createdScenario = scenarioRepository .findById (scenarioId ).orElseThrow ();
211+ Tag openctiTag = tagRepository .findByName (OPENCTI_TAG_NAME ).get ();
212+
213+ assertThat (createdScenario .getTags ()).contains (openctiTag );
214+ }
215+
216+ @ Test
217+ @ DisplayName (
218+ "When Security Coverage SDO has labels property but not the opencti value, should force adding opencti tag to scenario" )
219+ void
220+ whenSecurityCoverageSDOHasLabelsPropertyButNotTheOpenctiValue_shouldForceAddingOpenctiTagToScenario ()
221+ throws Exception {
222+ String bundleWithoutOpenctiLabel = stixSecurityCoverage .replace ("opencti" , "some-label" );
223+
224+ String response =
225+ mvc .perform (
226+ post (STIX_URI + "/process-bundle" )
227+ .contentType (MediaType .APPLICATION_JSON )
228+ .content (bundleWithoutOpenctiLabel ))
229+ .andExpect (status ().isOk ())
230+ .andReturn ()
231+ .getResponse ()
232+ .getContentAsString ();
233+
234+ assertThat (response ).isNotBlank ();
235+ String scenarioId = JsonPath .read (response , "$.scenarioId" );
236+ Scenario createdScenario = scenarioRepository .findById (scenarioId ).orElseThrow ();
237+ Tag openctiTag = tagRepository .findByName (OPENCTI_TAG_NAME ).get ();
238+
239+ assertThat (createdScenario .getTags ()).contains (openctiTag );
240+ }
241+
242+ @ Test
243+ @ DisplayName ("Eligible asset groups are assigned by tag rule" )
244+ void eligibleAssetGroupsAreAssignedByTagRule () throws Exception {
245+ String label = "custom-label" ;
246+ tagRuleComposer
247+ .forTagRule (TagRuleFixture .createDefaultTagRule ())
248+ .withTag (tagComposer .forTag (TagFixture .getTagWithText (label )))
249+ .withAssetGroup (
250+ assetGroupComposer
251+ .forAssetGroup (
252+ AssetGroupFixture .createDefaultAssetGroup ("%s asset group" .formatted (label )))
253+ .withAsset (endpointComposer .forEndpoint (EndpointFixture .createEndpoint ())))
254+ .persist ();
255+
256+ AttackPatternComposer .Composer attackPatternWrapper =
257+ attackPatternComposer .forAttackPattern (
258+ AttackPatternFixture .createAttackPatternsWithExternalId (T_1531 ));
259+ injectorContractComposer
260+ .forInjectorContract (
261+ InjectorContractFixture .createInjectorContractWithPlatforms (
262+ List .of (Endpoint .PLATFORM_TYPE .Windows ).toArray (Endpoint .PLATFORM_TYPE []::new )))
263+ .withAttackPattern (attackPatternWrapper )
264+ .withPayload (
265+ payloadComposer
266+ .forPayload (PayloadFixture .createDefaultCommand ())
267+ .withAttackPattern (attackPatternWrapper ))
268+ .persist ();
269+
270+ String bundleWithCustomLabel = stixSecurityCoverage .replace (OPENCTI_TAG_NAME , label );
271+
272+ entityManager .flush ();
273+ entityManager .clear ();
274+
275+ String response =
276+ mvc .perform (
277+ post (STIX_URI + "/process-bundle" )
278+ .contentType (MediaType .APPLICATION_JSON )
279+ .content (bundleWithCustomLabel ))
280+ .andExpect (status ().isOk ())
281+ .andReturn ()
282+ .getResponse ()
283+ .getContentAsString ();
284+
285+ entityManager .flush ();
286+ entityManager .clear ();
287+
288+ assertThat (response ).isNotBlank ();
289+ String scenarioId = JsonPath .read (response , "$.scenarioId" );
290+ Scenario createdScenario = scenarioRepository .findById (scenarioId ).orElseThrow ();
291+ Tag customTag = tagRepository .findByName (label ).get ();
292+
293+ assertThat (createdScenario .getTags ()).contains (customTag );
294+
295+ List <Inject > injects =
296+ createdScenario .getInjects ().stream ()
297+ .filter (i -> i .getInjectorContract ().get ().getPayload () != null )
298+ .toList ();
299+ assertThat (injects .size ()).isEqualTo (1 );
300+
301+ Inject inject = injects .getFirst ();
302+ Set <AssetGroup > desiredAssetGroups =
303+ assetGroupService .fetchAssetGroupsFromScenarioTagRules (createdScenario );
304+ assertThat (inject .getAssetGroups ())
305+ .containsExactlyInAnyOrderElementsOf (desiredAssetGroups .stream ().toList ());
306+ }
307+
183308 @ Test
184309 @ DisplayName ("Should return 400 when STIX bundle has no security coverage" )
185310 void shouldReturnBadRequestWhenNoSecurityCoverage () throws Exception {
0 commit comments