Skip to content

Commit 208fc9b

Browse files
Merge pull request #727 from akto-api-security/feature/configure_cicd_action
Feature/configure cicd action
2 parents c1d3312 + 8fbb075 commit 208fc9b

File tree

7 files changed

+184
-52
lines changed

7 files changed

+184
-52
lines changed

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
<a href="https://artifacthub.io/packages/search?repo=akto" _target="blank">
2+
<img src="https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/akto"/>
3+
</a>
4+
5+
16
<a href="https://www.akto.io/blog/akto-takes-center-stage-at-black-hat-2023-in-las-vegas" _target="blank">
2-
<img src="https://img.shields.io/badge/Black_Hat_Arsenal-USA_2023-blue?style=flat-square"/>
7+
<img src="https://img.shields.io/badge/Black_Hat_Arsenal-USA_2023-blue?style=square"/>
8+
</a>
9+
10+
11+
<a href="https://www.akto.io/blog/akto-presentation-at-defcon-2023-in-las-vegas" _target="blank">
12+
<img src="https://img.shields.io/badge/Defcon-USA_2023-blue?style=square"/>
313
</a>
414

515
<br/>

apps/dashboard/src/main/java/com/akto/action/testing/StartTestAction.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.mongodb.client.model.Projections;
3333
import com.mongodb.client.model.Sorts;
3434
import com.mongodb.client.model.Updates;
35+
import com.mongodb.client.result.InsertOneResult;
3536
import org.apache.commons.lang3.StringUtils;
3637
import org.bson.conversions.Bson;
3738
import org.bson.types.ObjectId;
@@ -183,27 +184,35 @@ public String startTest() {
183184
TestingRunDao.instance.insertOne(localTestingRun);
184185
testingRunHexId = localTestingRun.getId().toHexString();
185186
}
187+
this.testIdConfig = 0;
186188
} else {
187189
TestingRunDao.instance.updateOne(
188190
Filters.eq(Constants.ID,localTestingRun.getId()),
189191
Updates.combine(
190192
Updates.set(TestingRun.STATE,TestingRun.State.SCHEDULED),
191193
Updates.set(TestingRun.SCHEDULE_TIMESTAMP,scheduleTimestamp)
192194
));
195+
196+
TestingRunConfig testingRunConfig = new TestingRunConfig(Context.now(), null, this.selectedTests, null, this.overriddenTestAppUrl);
197+
this.testIdConfig = testingRunConfig.getId();
198+
TestingRunConfigDao.instance.insertOne(testingRunConfig);
199+
193200
}
194201

195202
Map<String, Object> session = getSession();
196203
String utility = (String) session.get("utility");
197204

198205
if(utility!=null && ( Utility.CICD.toString().equals(utility) || Utility.EXTERNAL_API.toString().equals(utility))){
199206
TestingRunResultSummary summary = new TestingRunResultSummary(scheduleTimestamp, 0, new HashMap<>(),
200-
0, localTestingRun.getId(), localTestingRun.getId().toHexString(), 0);
207+
0, localTestingRun.getId(), localTestingRun.getId().toHexString(), 0, this.testIdConfig);
201208
summary.setState(TestingRun.State.SCHEDULED);
202209
if(metadata!=null){
203210
loggerMaker.infoAndAddToDb("CICD test triggered at " + Context.now(), LogDb.DASHBOARD);
204211
summary.setMetadata(metadata);
205212
}
206-
TestingRunResultSummariesDao.instance.insertOne(summary);
213+
InsertOneResult result = TestingRunResultSummariesDao.instance.insertOne(summary);
214+
this.testingRunResultSummaryHexId = result.getInsertedId().asObjectId().getValue().toHexString();
215+
207216
}
208217

209218
this.startTimestamp = 0;
@@ -385,6 +394,18 @@ public String fetchTestingRunResultSummaries() {
385394
return SUCCESS.toUpperCase();
386395
}
387396

397+
public String fetchTestingRunResultSummary() {
398+
this.testingRunResultSummaries = new ArrayList<>();
399+
this.testingRunResultSummaries.add(TestingRunResultSummariesDao.instance.findOne("_id", new ObjectId(this.testingRunResultSummaryHexId)));
400+
401+
if (this.testingRunResultSummaries.size() == 0) {
402+
addActionError("No test summaries found");
403+
return ERROR.toUpperCase();
404+
} else {
405+
return SUCCESS.toUpperCase();
406+
}
407+
}
408+
388409
String testingRunResultSummaryHexId;
389410
List<TestingRunResult> testingRunResults;
390411
private boolean fetchOnlyVulnerable;
@@ -612,6 +633,10 @@ public List<TestingRunResultSummary> getTestingRunResultSummaries() {
612633
return this.testingRunResultSummaries;
613634
}
614635

636+
public String getTestingRunResultSummaryHexId() {
637+
return this.testingRunResultSummaryHexId;
638+
}
639+
615640
public void setTestingRunResultSummaryHexId(String testingRunResultSummaryHexId) {
616641
this.testingRunResultSummaryHexId = testingRunResultSummaryHexId;
617642
}

apps/dashboard/src/main/resources/struts.xml

+11
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,17 @@
992992
</result>
993993
</action>
994994

995+
<action name="api/fetchTestingRunResultSummary" class="com.akto.action.testing.StartTestAction" method="fetchTestingRunResultSummary">
996+
<interceptor-ref name="json"/>
997+
<interceptor-ref name="defaultStack" />
998+
<result name="SUCCESS" type="json"/>
999+
<result name="ERROR" type="json">
1000+
<param name="statusCode">422</param>
1001+
<param name="ignoreHierarchy">false</param>
1002+
<param name="includeProperties">^actionErrors.*</param>
1003+
</result>
1004+
</action>
1005+
9951006
<action name="api/toggleTestingRunForCollection" class="com.akto.action.testing.StartTestAction" method="toggleTestingRunForCollection">
9961007
<interceptor-ref name="json"/>
9971008
<interceptor-ref name="defaultStack" />

apps/dashboard/src/test/java/com/akto/action/testing/TestStartTestAction.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public void testFetchTestingRunResultSummaries() {
9494
testingRun.setId(testingRunId);
9595
for (int startTimestamp=0; startTimestamp < 30; startTimestamp++) {
9696
TestingRunResultSummary testingRunResultSummary = new TestingRunResultSummary(
97-
startTimestamp, startTimestamp+10, new HashMap<>(), 10, testingRunId, testingRunId.toHexString(), 10
97+
startTimestamp, startTimestamp+10, new HashMap<>(), 10, testingRunId, testingRunId.toHexString(), 10, 0
9898
);
9999

100100
testingRunResultSummaryList.add(testingRunResultSummary);

apps/testing/src/main/java/com/akto/testing/Main.java

+98-47
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private static ObjectId createTRRSummaryIfAbsent(TestingRun testingRun, int star
6262
Updates.set(TestingRunResultSummary.STATE, TestingRun.State.RUNNING));
6363
} catch (Exception e){
6464
TestingRunResultSummary summary = new TestingRunResultSummary(start, 0, new HashMap<>(),
65-
0, testingRun.getId(), testingRun.getId().toHexString(), 0);
65+
0, testingRun.getId(), testingRun.getId().toHexString(), 0, 0);
6666

6767
summaryId = TestingRunResultSummariesDao.instance.insertOne(summary).getInsertedId().asObjectId().getValue();
6868
}
@@ -92,6 +92,73 @@ public void accept(Account t) {
9292

9393
private static final int LAST_TEST_RUN_EXECUTION_DELTA = 5 * 60;
9494

95+
private static TestingRun findPendingTestingRun() {
96+
int delta = Context.now() - 20*60;
97+
98+
Bson filter1 = Filters.and(Filters.eq(TestingRun.STATE, TestingRun.State.SCHEDULED),
99+
Filters.lte(TestingRun.SCHEDULE_TIMESTAMP, Context.now())
100+
);
101+
Bson filter2 = Filters.and(
102+
Filters.eq(TestingRun.STATE, TestingRun.State.RUNNING),
103+
Filters.lte(TestingRun.SCHEDULE_TIMESTAMP, delta)
104+
);
105+
106+
Bson update = Updates.combine(
107+
Updates.set(TestingRun.PICKED_UP_TIMESTAMP, Context.now()),
108+
Updates.set(TestingRun.STATE, TestingRun.State.RUNNING)
109+
);
110+
111+
return TestingRunDao.instance.getMCollection().findOneAndUpdate(
112+
Filters.or(filter1,filter2), update);
113+
}
114+
115+
private static TestingRunResultSummary findPendingTestingRunResultSummary() {
116+
int delta = Context.now() - 20*60;
117+
118+
Bson filter1 = Filters.and(
119+
Filters.eq(TestingRun.STATE, TestingRun.State.SCHEDULED),
120+
Filters.lte(TestingRunResultSummary.START_TIMESTAMP, Context.now()),
121+
Filters.gt(TestingRunResultSummary.START_TIMESTAMP, delta)
122+
);
123+
124+
Bson filter2 = Filters.and(
125+
Filters.eq(TestingRun.STATE, TestingRun.State.RUNNING),
126+
Filters.gt(TestingRunResultSummary.START_TIMESTAMP, delta)
127+
);
128+
129+
Bson update = Updates.set(TestingRun.STATE, TestingRun.State.RUNNING);
130+
131+
TestingRunResultSummary trrs = TestingRunResultSummariesDao.instance.getMCollection().findOneAndUpdate(Filters.or(filter1,filter2), update);
132+
133+
return trrs;
134+
}
135+
136+
private static void setTestingRunConfig(TestingRun testingRun, TestingRunResultSummary trrs) {
137+
long timestamp = testingRun.getId().getTimestamp();
138+
long seconds = Context.now() - timestamp;
139+
loggerMaker.infoAndAddToDb("Found one + " + testingRun.getId().toHexString() + " created: " + seconds + " seconds ago", LogDb.TESTING);
140+
141+
TestingRunConfig configFromTrrs = null;
142+
TestingRunConfig baseConfig = null;
143+
144+
if (trrs != null && trrs.getTestIdConfig() > 1) {
145+
configFromTrrs = TestingRunConfigDao.instance.findOne(Constants.ID, trrs.getTestIdConfig());
146+
loggerMaker.infoAndAddToDb("Found testing run config with id :" + configFromTrrs.getId(), LogDb.TESTING);
147+
}
148+
149+
if (testingRun.getTestIdConfig() > 1) {
150+
baseConfig = TestingRunConfigDao.instance.findOne(Constants.ID, testingRun.getTestIdConfig());
151+
loggerMaker.infoAndAddToDb("Found testing run config with id :" + baseConfig.getId(), LogDb.TESTING);
152+
}
153+
154+
if (configFromTrrs == null) {
155+
testingRun.setTestingRunConfig(baseConfig);
156+
} else {
157+
configFromTrrs.rebaseOn(baseConfig);
158+
testingRun.setTestingRunConfig(configFromTrrs);
159+
}
160+
}
161+
95162
public static void main(String[] args) throws InterruptedException {
96163
String mongoURI = System.getenv("AKTO_MONGO_CONN");;
97164
DaoInit.init(new ConnectionString(mongoURI));
@@ -117,66 +184,50 @@ public static void main(String[] args) throws InterruptedException {
117184

118185
while (true) {
119186
AccountTask.instance.executeTask(account -> {
120-
int delta = Context.now() - 20*60;
121-
122-
Bson filter1 = Filters.and(Filters.eq(TestingRun.STATE, TestingRun.State.SCHEDULED),
123-
Filters.lte(TestingRun.SCHEDULE_TIMESTAMP, Context.now())
124-
);
125-
Bson filter2 = Filters.and(
126-
Filters.eq(TestingRun.STATE, TestingRun.State.RUNNING),
127-
Filters.lte(TestingRun.SCHEDULE_TIMESTAMP, delta)
128-
);
129-
130-
Bson update = Updates.combine(
131-
Updates.set(TestingRun.PICKED_UP_TIMESTAMP, Context.now()),
132-
Updates.set(TestingRun.STATE, TestingRun.State.RUNNING)
133-
);
134187

135188
int start = Context.now();
136189

137-
TestingRun testingRun = TestingRunDao.instance.getMCollection().findOneAndUpdate(
138-
Filters.or(filter1,filter2), update);
190+
TestingRunResultSummary trrs = findPendingTestingRunResultSummary();
191+
TestingRun testingRun;
192+
ObjectId summaryId = null;
193+
if (trrs == null) {
194+
testingRun = findPendingTestingRun();
195+
} else {
196+
summaryId = trrs.getId();
197+
testingRun = TestingRunDao.instance.findOne("_id", trrs.getTestingRunId());
198+
}
139199

140200
if (testingRun == null) {
141201
return;
142202
}
143203

144-
145-
ObjectId summaryId = null;
146204
try {
147-
long timestamp = testingRun.getId().getTimestamp();
148-
long seconds = Context.now() - timestamp;
149-
loggerMaker.infoAndAddToDb("Found one + " + testingRun.getId().toHexString() + " created: " + seconds + " seconds ago", LogDb.TESTING);
150-
if (testingRun.getTestIdConfig() > 1) {
151-
TestingRunConfig testingRunConfig = TestingRunConfigDao.instance.findOne(Constants.ID, testingRun.getTestIdConfig());
152-
if (testingRunConfig != null) {
153-
loggerMaker.infoAndAddToDb("Found testing run config with id :" + testingRunConfig.getId(), LogDb.TESTING);
154-
testingRun.setTestingRunConfig(testingRunConfig);
155-
}else {
156-
loggerMaker.errorAndAddToDb("Couldn't find testing run config id for " + testingRun.getTestIdConfig(), LogDb.TESTING);
157-
}
158-
}
159-
if(testingRun.getState().equals(TestingRun.State.RUNNING)){
160-
Map<ObjectId, TestingRunResultSummary> objectIdTestingRunResultSummaryMap = TestingRunResultSummariesDao.instance.fetchLatestTestingRunResultSummaries(Collections.singletonList(testingRun.getId()));
161-
TestingRunResultSummary testingRunResultSummary = objectIdTestingRunResultSummaryMap.get(testingRun.getId());
162-
List<TestingRunResult> testingRunResults = TestingRunResultDao.instance.fetchLatestTestingRunResult(Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, testingRunResultSummary.getId()), 1);
163-
if(testingRunResults != null && !testingRunResults.isEmpty()){
164-
TestingRunResult testingRunResult = testingRunResults.get(0);
165-
if(Context.now() - testingRunResult.getEndTimestamp() < LAST_TEST_RUN_EXECUTION_DELTA){
166-
loggerMaker.infoAndAddToDb("Skipping test run as it was executed recently, TRR_ID:"
167-
+ testingRunResult.getHexId() + ", TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
168-
return;
205+
setTestingRunConfig(testingRun, trrs);
206+
207+
if (summaryId == null) {
208+
if (testingRun.getState().equals(TestingRun.State.RUNNING)) {
209+
Map<ObjectId, TestingRunResultSummary> objectIdTestingRunResultSummaryMap = TestingRunResultSummariesDao.instance.fetchLatestTestingRunResultSummaries(Collections.singletonList(testingRun.getId()));
210+
TestingRunResultSummary testingRunResultSummary = objectIdTestingRunResultSummaryMap.get(testingRun.getId());
211+
List<TestingRunResult> testingRunResults = TestingRunResultDao.instance.fetchLatestTestingRunResult(Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, testingRunResultSummary.getId()), 1);
212+
if (testingRunResults != null && !testingRunResults.isEmpty()) {
213+
TestingRunResult testingRunResult = testingRunResults.get(0);
214+
if (Context.now() - testingRunResult.getEndTimestamp() < LAST_TEST_RUN_EXECUTION_DELTA) {
215+
loggerMaker.infoAndAddToDb("Skipping test run as it was executed recently, TRR_ID:"
216+
+ testingRunResult.getHexId() + ", TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
217+
return;
218+
} else {
219+
loggerMaker.infoAndAddToDb("Test run was executed long ago, TRR_ID:"
220+
+ testingRunResult.getHexId() + ", TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
221+
TestingRunResultSummariesDao.instance.updateOne(Filters.eq(TestingRunResultSummary.ID, testingRunResultSummary.getId()), Updates.set(TestingRunResultSummary.STATE, TestingRun.State.FAILED));
222+
}
169223
} else {
170-
loggerMaker.infoAndAddToDb("Test run was executed long ago, TRR_ID:"
171-
+ testingRunResult.getHexId() + ", TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
224+
loggerMaker.infoAndAddToDb("No executions made for this test, will need to restart it, TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
172225
TestingRunResultSummariesDao.instance.updateOne(Filters.eq(TestingRunResultSummary.ID, testingRunResultSummary.getId()), Updates.set(TestingRunResultSummary.STATE, TestingRun.State.FAILED));
173226
}
174-
} else {
175-
loggerMaker.infoAndAddToDb("No executions made for this test, will need to restart it, TRRS_ID:" + testingRunResultSummary.getHexId() + " TR_ID:" + testingRun.getHexId(), LogDb.TESTING);
176-
TestingRunResultSummariesDao.instance.updateOne(Filters.eq(TestingRunResultSummary.ID, testingRunResultSummary.getId()), Updates.set(TestingRunResultSummary.STATE, TestingRun.State.FAILED));
177227
}
228+
229+
summaryId = createTRRSummaryIfAbsent(testingRun, start);
178230
}
179-
summaryId = createTRRSummaryIfAbsent(testingRun, start);
180231
TestExecutor testExecutor = new TestExecutor();
181232
testExecutor.init(testingRun, summaryId);
182233
raiseMixpanelEvent(summaryId, testingRun);

libs/dao/src/main/java/com/akto/dto/testing/TestingRunConfig.java

+22
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,26 @@ public String getOverriddenTestAppUrl() {
6868
public void setOverriddenTestAppUrl(String overriddenTestAppUrl) {
6969
this.overriddenTestAppUrl = overriddenTestAppUrl;
7070
}
71+
72+
public void rebaseOn(TestingRunConfig that) {
73+
if (that == null) return;
74+
75+
if (this == that) return;
76+
77+
if (this.collectionWiseApiInfoKey == null) {
78+
this.collectionWiseApiInfoKey = that.collectionWiseApiInfoKey;
79+
}
80+
81+
if (this.testSubCategoryList == null) {
82+
this.testSubCategoryList = that.testSubCategoryList;
83+
}
84+
85+
if (this.authMechanismId == null) {
86+
this.authMechanismId = that.authMechanismId;
87+
}
88+
89+
if (this.overriddenTestAppUrl == null) {
90+
this.overriddenTestAppUrl = that.overriddenTestAppUrl;
91+
}
92+
}
7193
}

libs/dao/src/main/java/com/akto/dto/testing/TestingRunResultSummary.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public class TestingRunResultSummary {
3030
private TestingRun.State state;
3131
private int testResultsCount;
3232

33+
private int testIdConfig;
34+
3335
@BsonIgnore
3436
private String hexId;
3537

@@ -38,7 +40,8 @@ public class TestingRunResultSummary {
3840
public TestingRunResultSummary() {
3941
}
4042

41-
public TestingRunResultSummary(int startTimestamp, int endTimestamp, Map<String,Integer> countIssues, int totalApis, ObjectId testingRunId, String testingRunHexId, int testResultsCount) {
43+
public TestingRunResultSummary(int startTimestamp, int endTimestamp, Map<String,Integer> countIssues, int totalApis,
44+
ObjectId testingRunId, String testingRunHexId, int testResultsCount, int testIdConfig) {
4245
this.startTimestamp = startTimestamp;
4346
this.endTimestamp = endTimestamp;
4447
this.countIssues = countIssues;
@@ -47,6 +50,7 @@ public TestingRunResultSummary(int startTimestamp, int endTimestamp, Map<String,
4750
this.testingRunHexId = testingRunHexId;
4851
this.state = TestingRun.State.RUNNING;
4952
this.testResultsCount = testResultsCount;
53+
this.testIdConfig = testIdConfig;
5054
}
5155

5256
public ObjectId getId() {
@@ -134,13 +138,22 @@ public void setMetadata(Map<String, String> metadata) {
134138
this.metadata = metadata;
135139
}
136140

141+
public int getTestIdConfig() {
142+
return testIdConfig;
143+
}
144+
145+
public void setTestIdConfig(int testIdConfig) {
146+
this.testIdConfig = testIdConfig;
147+
}
148+
137149
@Override
138150
public String toString() {
139151
return "{" +
140152
" startTimestamp='" + getStartTimestamp() + "'" +
141153
", endTimestamp='" + getEndTimestamp() + "'" +
142154
", countIssues='" + getCountIssues() + "'" +
143155
", totalApis='" + getTotalApis() + "'" +
156+
", testIdConfig='" + getTestIdConfig() + "'" +
144157
", testingRunId='" + getTestingRunId() + "'" +
145158
", testingRunHexId='" + getTestingRunHexId() + "'" +
146159
", state='" + getState() + "'" +

0 commit comments

Comments
 (0)