2424#import " Source/common/SNTFileInfo.h"
2525#import " Source/common/SNTStoredExecutionEvent.h"
2626#import " Source/common/SNTStoredFileAccessEvent.h"
27+ #include " Source/common/TestUtils.h"
2728
2829NSString *GenerateRandomHexStringWithSHA256Length () {
2930 // Create an array to hold random bytes
4849
4950@interface SNTEventTable (Testing)
5051- (SNTStoredEvent *)eventFromResultSet : (FMResultSet *)rs ;
52+ @property NSTimeInterval unactionableEventCacheTimeSeconds;
5153@end
5254
5355// / This test case actually tests SNTEventTable and SNTStoredEvent.
@@ -82,7 +84,7 @@ - (SNTStoredExecutionEvent *)createTestEvent {
8284 event.executingUser = @" nobody" ;
8385 event.loggedInUsers = @[ @" nobody" ];
8486 event.currentSessions = @[ @" nobody@ttys000" , @" nobody@console" ];
85- event.decision = SNTEventStateAllowBinary ;
87+ event.decision = SNTEventStateBlockBinary ;
8688 return event;
8789}
8890
@@ -100,6 +102,7 @@ - (SNTStoredFileAccessEvent *)createTestFileAccessEvent {
100102 event.process .pid = @(1234 );
101103 event.process .parent = [[SNTStoredFileAccessProcess alloc ] init ];
102104 event.process .parent .pid = @(4567 );
105+ event.decision = FileAccessPolicyDecision::kDenied ;
103106 return event;
104107}
105108
@@ -111,7 +114,7 @@ - (void)testAddEvent {
111114 XCTAssertEqual (self.sut .pendingEventsCount , 2 );
112115}
113116
114- - (void )testUniqueIndex {
117+ - (void )testUniqueIndexActionable {
115118 XCTAssertEqual (self.sut .pendingEventsCount , 0 );
116119
117120 SNTStoredExecutionEvent *event = [self createTestEvent ];
@@ -157,6 +160,94 @@ - (void)testUniqueIndex {
157160 XCTAssertEqual (self.sut .pendingEventsCount , 4 );
158161}
159162
163+ - (void )testUniqueIndexUnactionable {
164+ XCTAssertEqual (self.sut .pendingEventsCount , 0 );
165+
166+ SNTStoredExecutionEvent *event = [self createTestEvent ];
167+ // Make this an "unactionable" event
168+ event.decision = SNTEventStateAllowBinary;
169+ XCTAssertTrue ([self .sut addStoredEvent: event]);
170+ XCTAssertEqual (self.sut .pendingEventsCount , 1 );
171+
172+ // Attempt to add an event with the same file hash will fail because
173+ // no insert will be attempted
174+ event.idx = @(arc4random ());
175+ XCTAssertFalse ([self .sut addStoredEvent: event]);
176+ XCTAssertEqual (self.sut .pendingEventsCount , 1 );
177+
178+ // Create a new hash and re-insert
179+ event.idx = @(arc4random ());
180+ event.fileSHA256 = GenerateRandomHexStringWithSHA256Length ();
181+ XCTAssertTrue ([self .sut addStoredEvent: event]);
182+ XCTAssertEqual (self.sut .pendingEventsCount , 2 );
183+
184+ // Attempting to add an event with a non-unique idx fails
185+ event.fileSHA256 = GenerateRandomHexStringWithSHA256Length ();
186+ XCTAssertFalse ([self .sut addStoredEvent: event]);
187+ XCTAssertEqual (self.sut .pendingEventsCount , 2 );
188+
189+ // Now for FAA Events...
190+ SNTStoredFileAccessEvent *faaEvent = [self createTestFileAccessEvent ];
191+ // Make this an "unactionable" event
192+ faaEvent.decision = FileAccessPolicyDecision::kAllowedAuditOnly ;
193+ XCTAssertTrue ([self .sut addStoredEvent: faaEvent]);
194+ XCTAssertEqual (self.sut .pendingEventsCount , 3 );
195+
196+ // Attempt to add an event with the same file hash will fail because
197+ // no insert will be attempted
198+ faaEvent.idx = @(arc4random ());
199+ XCTAssertFalse ([self .sut addStoredEvent: faaEvent]);
200+ XCTAssertEqual (self.sut .pendingEventsCount , 3 );
201+
202+ // Create a new hash and re-insert
203+ faaEvent.process .fileSHA256 = GenerateRandomHexStringWithSHA256Length ();
204+ XCTAssertTrue ([self .sut addStoredEvent: faaEvent]);
205+ XCTAssertEqual (self.sut .pendingEventsCount , 4 );
206+
207+ // Attempting to add an event with a non-unique idx fails
208+ faaEvent.process .fileSHA256 = GenerateRandomHexStringWithSHA256Length ();
209+ XCTAssertFalse ([self .sut addStoredEvent: faaEvent]);
210+ XCTAssertEqual (self.sut .pendingEventsCount , 4 );
211+ }
212+
213+ - (void )testBackoff {
214+ XCTAssertEqual (self.sut .pendingEventsCount , 0 );
215+
216+ // Set the backoff time to 3 seconds
217+ self.sut .unactionableEventCacheTimeSeconds = 3 ;
218+
219+ SNTStoredExecutionEvent *event = [self createTestEvent ];
220+ // Make this an "unactionable" event
221+ event.decision = SNTEventStateAllowBinary;
222+ NSNumber *origId = event.idx ;
223+ XCTAssertTrue ([self .sut addStoredEvent: event]);
224+ XCTAssertEqual (self.sut .pendingEventsCount , 1 );
225+
226+ // Attempt to add an event with the same file hash will fail because
227+ // no insert will be attempted
228+ event.idx = @(arc4random ());
229+ XCTAssertFalse ([self .sut addStoredEvent: event]);
230+ XCTAssertEqual (self.sut .pendingEventsCount , 1 );
231+
232+ // Delete everything
233+ [self .sut deleteEventWithId: origId];
234+ XCTAssertEqual (self.sut .pendingEventsCount , 0 );
235+
236+ // Attempt to reinsert an unactionable event before the backoff time
237+ // This should still fail, even though it wouldn't conflict in the DB
238+ event.idx = @(arc4random ());
239+ XCTAssertFalse ([self .sut addStoredEvent: event]);
240+ XCTAssertEqual (self.sut .pendingEventsCount , 0 );
241+
242+ // Sleep for the backoff time
243+ SleepMS (3000 );
244+
245+ // Now re-add the stored event, all should be well
246+ event.idx = @(arc4random ());
247+ XCTAssertTrue ([self .sut addStoredEvent: event]);
248+ XCTAssertEqual (self.sut .pendingEventsCount , 1 );
249+ }
250+
160251- (void )testRetrieveExecutionEvent {
161252 SNTStoredExecutionEvent *event = [self createTestEvent ];
162253 [self .sut addStoredEvent: event];
0 commit comments