Skip to content

Commit 994b193

Browse files
feat: add linked datasets default security update on scenario default security update
1 parent 4d77881 commit 994b193

File tree

4 files changed

+166
-5
lines changed

4 files changed

+166
-5
lines changed

runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import com.redis.testcontainers.RedisStackContainer
4242
import io.mockk.every
4343
import io.mockk.junit5.MockKExtension
4444
import io.mockk.mockkStatic
45+
import io.mockk.verify
4546
import java.time.Instant
4647
import java.util.*
4748
import kotlin.test.*
@@ -1095,6 +1096,56 @@ class RunnerServiceIntegrationTest : CsmRedisTestBase() {
10951096
}
10961097
}
10971098

1099+
@Test
1100+
fun `when sharing a runner, the linked dataset default security should be set to at least viewer if the dataset isn't main`() {
1101+
runnerSaved.datasetList!!.removeLast()
1102+
listOf(ROLE_NONE, ROLE_VIEWER, ROLE_USER, ROLE_EDITOR, ROLE_ADMIN).forEach { role ->
1103+
var linkedDataset =
1104+
datasetApiService.createDataset(
1105+
organizationSaved.id!!, makeDataset(isMain = false, default = role))
1106+
runnerSaved.datasetList!!.add(linkedDataset.id!!)
1107+
linkedDataset =
1108+
datasetApiService.createDataset(
1109+
organizationSaved.id!!, makeDataset(isMain = true, default = role))
1110+
runnerSaved.datasetList!!.add(linkedDataset.id!!)
1111+
}
1112+
runnerSaved =
1113+
runnerApiService.updateRunner(
1114+
organizationSaved.id!!, workspaceSaved.id!!, runnerSaved.id!!, runnerSaved)
1115+
1116+
runnerApiService.setRunnerDefaultSecurity(
1117+
organizationSaved.id!!, workspaceSaved.id!!, runnerSaved.id!!, RunnerRole(ROLE_EDITOR))
1118+
1119+
verify(exactly = 1) {
1120+
datasetApiService.setDatasetDefaultSecurity(any(), any(), DatasetRole(ROLE_VIEWER))
1121+
}
1122+
}
1123+
1124+
@Test
1125+
fun `when stopping sharing a scenario, the dataset default security should be set to none it's not higher than viewer and the dataset isn't main`() {
1126+
runnerSaved.datasetList!!.removeLast()
1127+
listOf(ROLE_NONE, ROLE_VIEWER, ROLE_USER, ROLE_EDITOR, ROLE_ADMIN).forEach { role ->
1128+
var linkedDataset =
1129+
datasetApiService.createDataset(
1130+
organizationSaved.id!!, makeDataset(isMain = false, default = role))
1131+
runnerSaved.datasetList!!.add(linkedDataset.id!!)
1132+
linkedDataset =
1133+
datasetApiService.createDataset(
1134+
organizationSaved.id!!, makeDataset(isMain = true, default = role))
1135+
runnerSaved.datasetList!!.add(linkedDataset.id!!)
1136+
}
1137+
runnerSaved =
1138+
runnerApiService.updateRunner(
1139+
organizationSaved.id!!, workspaceSaved.id!!, runnerSaved.id!!, runnerSaved)
1140+
1141+
runnerApiService.setRunnerDefaultSecurity(
1142+
organizationSaved.id!!, workspaceSaved.id!!, runnerSaved.id!!, RunnerRole(ROLE_NONE))
1143+
1144+
verify(exactly = 1) {
1145+
datasetApiService.setDatasetDefaultSecurity(any(), any(), DatasetRole(ROLE_NONE))
1146+
}
1147+
}
1148+
10981149
private fun makeConnector(name: String = "name"): Connector {
10991150
return Connector(
11001151
key = UUID.randomUUID().toString(),
@@ -1107,7 +1158,9 @@ class RunnerServiceIntegrationTest : CsmRedisTestBase() {
11071158
fun makeDataset(
11081159
organizationId: String = organizationSaved.id!!,
11091160
name: String = "name",
1110-
connector: Connector = connectorSaved
1161+
connector: Connector = connectorSaved,
1162+
isMain: Boolean = true,
1163+
default: String = ROLE_NONE
11111164
): Dataset {
11121165
return Dataset(
11131166
name = name,
@@ -1120,9 +1173,10 @@ class RunnerServiceIntegrationTest : CsmRedisTestBase() {
11201173
name = connector.name,
11211174
version = connector.version,
11221175
),
1176+
main = isMain,
11231177
security =
11241178
DatasetSecurity(
1125-
default = ROLE_NONE,
1179+
default = default,
11261180
accessControlList =
11271181
mutableListOf(
11281182
DatasetAccessControl(id = CONNECTED_ADMIN_USER, role = ROLE_ADMIN),

runner/src/main/kotlin/com/cosmotech/runner/service/RunnerService.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.cosmotech.api.rbac.PERMISSION_READ_SECURITY
1515
import com.cosmotech.api.rbac.ROLE_NONE
1616
import com.cosmotech.api.rbac.ROLE_USER
1717
import com.cosmotech.api.rbac.ROLE_VALIDATOR
18+
import com.cosmotech.api.rbac.ROLE_VIEWER
1819
import com.cosmotech.api.rbac.RolesDefinition
1920
import com.cosmotech.api.rbac.getScenarioRolesDefinition
2021
import com.cosmotech.api.rbac.model.RbacAccessControl
@@ -26,6 +27,7 @@ import com.cosmotech.api.utils.getCurrentAuthenticatedRoles
2627
import com.cosmotech.api.utils.getCurrentAuthenticatedUserName
2728
import com.cosmotech.dataset.DatasetApiServiceInterface
2829
import com.cosmotech.dataset.domain.Dataset
30+
import com.cosmotech.dataset.domain.DatasetRole
2931
import com.cosmotech.dataset.service.getRbac
3032
import com.cosmotech.organization.OrganizationApiServiceInterface
3133
import com.cosmotech.organization.domain.Organization
@@ -506,6 +508,34 @@ class RunnerService(
506508
// create a rbacSecurity object from runner Rbac by changing default value
507509
val rbacSecurity = csmRbac.setDefault(this.getRbacSecurity(), role, this.roleDefinition)
508510
this.setRbacSecurity(rbacSecurity)
511+
// this.runner.datasetList!!
512+
// .mapNotNull {
513+
// datasetApiService.findByOrganizationIdAndDatasetId(this.runner.organizationId!!,
514+
// it)
515+
// }
516+
// .forEach { dataset ->
517+
updateLinkedDatasetDefaultSecurity(role)
518+
// }
519+
}
520+
521+
private fun updateLinkedDatasetDefaultSecurity(role: String) {
522+
var datasetRole = ROLE_NONE
523+
if (role != ROLE_NONE) datasetRole = ROLE_VIEWER
524+
this.runner.datasetList!!.forEach { datasetId ->
525+
val linkedDataset =
526+
datasetApiService.findDatasetById(this.runner.organizationId!!, datasetId)
527+
// We do not want to lower the default security if it's higher than viewer
528+
if (linkedDataset.security!!.default != ROLE_NONE && datasetRole == ROLE_VIEWER)
529+
return@forEach Unit
530+
if (linkedDataset.security!!.default != ROLE_NONE && datasetRole == ROLE_NONE)
531+
return@forEach Unit
532+
// Filter on dataset copy (because we do not want to update main dataset as it can be shared
533+
// between scenarios)
534+
if (linkedDataset.main != true) {
535+
datasetApiService.setDatasetDefaultSecurity(
536+
this.runner.organizationId!!, datasetId, DatasetRole(datasetRole))
537+
}
538+
}
509539
}
510540
}
511541

scenario/src/integrationTest/kotlin/com/cosmotech/scenario/service/ScenarioServiceIntegrationTest.kt

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import io.mockk.every
5454
import io.mockk.impl.annotations.MockK
5555
import io.mockk.junit5.MockKExtension
5656
import io.mockk.mockkStatic
57+
import io.mockk.verify
5758
import java.time.Instant
5859
import java.util.*
5960
import kotlin.test.assertEquals
@@ -1257,6 +1258,56 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
12571258
}
12581259
}
12591260

1261+
@Test
1262+
fun `when sharing a scenario, the linked dataset default security should be set to at least viewer if the dataset isn't main`() {
1263+
scenarioSaved.datasetList!!.removeLast()
1264+
listOf(ROLE_NONE, ROLE_VIEWER, ROLE_USER, ROLE_EDITOR, ROLE_ADMIN).forEach { role ->
1265+
var linkedDataset =
1266+
datasetApiService.createDataset(
1267+
organizationSaved.id!!, makeDataset(isMain = false, default = role))
1268+
scenarioSaved.datasetList!!.add(linkedDataset.id!!)
1269+
linkedDataset =
1270+
datasetApiService.createDataset(
1271+
organizationSaved.id!!, makeDataset(isMain = true, default = role))
1272+
scenarioSaved.datasetList!!.add(linkedDataset.id!!)
1273+
}
1274+
scenarioSaved =
1275+
scenarioApiService.updateScenario(
1276+
organizationSaved.id!!, workspaceSaved.id!!, scenarioSaved.id!!, scenarioSaved)
1277+
1278+
scenarioApiService.setScenarioDefaultSecurity(
1279+
organizationSaved.id!!, workspaceSaved.id!!, scenarioSaved.id!!, ScenarioRole(ROLE_EDITOR))
1280+
1281+
verify(exactly = 1) {
1282+
datasetApiService.setDatasetDefaultSecurity(any(), any(), DatasetRole(ROLE_VIEWER))
1283+
}
1284+
}
1285+
1286+
@Test
1287+
fun `when stopping sharing a scenario, the dataset default security should be set to none it's not higher than viewer and the dataset isn't main`() {
1288+
scenarioSaved.datasetList!!.removeLast()
1289+
listOf(ROLE_NONE, ROLE_VIEWER, ROLE_USER, ROLE_EDITOR, ROLE_ADMIN).forEach { role ->
1290+
var linkedDataset =
1291+
datasetApiService.createDataset(
1292+
organizationSaved.id!!, makeDataset(isMain = false, default = role))
1293+
scenarioSaved.datasetList!!.add(linkedDataset.id!!)
1294+
linkedDataset =
1295+
datasetApiService.createDataset(
1296+
organizationSaved.id!!, makeDataset(isMain = true, default = role))
1297+
scenarioSaved.datasetList!!.add(linkedDataset.id!!)
1298+
}
1299+
scenarioSaved =
1300+
scenarioApiService.updateScenario(
1301+
organizationSaved.id!!, workspaceSaved.id!!, scenarioSaved.id!!, scenarioSaved)
1302+
1303+
scenarioApiService.setScenarioDefaultSecurity(
1304+
organizationSaved.id!!, workspaceSaved.id!!, scenarioSaved.id!!, ScenarioRole(ROLE_NONE))
1305+
1306+
verify(exactly = 1) {
1307+
datasetApiService.setDatasetDefaultSecurity(any(), any(), DatasetRole(ROLE_NONE))
1308+
}
1309+
}
1310+
12601311
private fun makeWorkspaceEventHubInfo(eventHubAvailable: Boolean): WorkspaceEventHubInfo {
12611312
return WorkspaceEventHubInfo(
12621313
eventHubNamespace = "eventHubNamespace",
@@ -1284,7 +1335,8 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
12841335
name: String = "name",
12851336
connector: Connector = connectorSaved,
12861337
sourceType: DatasetSourceType = DatasetSourceType.Twincache,
1287-
isMain: Boolean = true
1338+
isMain: Boolean = true,
1339+
default: String = ROLE_NONE
12881340
): Dataset {
12891341
return Dataset(
12901342
name = name,
@@ -1301,7 +1353,7 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
13011353
main = isMain,
13021354
security =
13031355
DatasetSecurity(
1304-
default = ROLE_NONE,
1356+
default = default,
13051357
accessControlList =
13061358
mutableListOf(
13071359
DatasetAccessControl(id = CONNECTED_ADMIN_USER, role = ROLE_ADMIN))))
@@ -1397,6 +1449,7 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
13971449
name: String = "name",
13981450
datasetList: MutableList<String>? = mutableListOf(),
13991451
parentId: String? = null,
1452+
defaultSecurity: String = ROLE_NONE,
14001453
userName: String = "roleName",
14011454
role: String = ROLE_USER,
14021455
validationStatus: ScenarioValidationStatus = ScenarioValidationStatus.Draft,
@@ -1416,7 +1469,7 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
14161469
parametersValues = parametersValues,
14171470
security =
14181471
ScenarioSecurity(
1419-
ROLE_NONE,
1472+
defaultSecurity,
14201473
mutableListOf(
14211474
ScenarioAccessControl(CONNECTED_ADMIN_USER, ROLE_ADMIN),
14221475
ScenarioAccessControl(userName, role))))

scenario/src/main/kotlin/com/cosmotech/scenario/service/ScenarioServiceImpl.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.cosmotech.api.rbac.PERMISSION_DELETE
2727
import com.cosmotech.api.rbac.PERMISSION_READ_SECURITY
2828
import com.cosmotech.api.rbac.PERMISSION_WRITE
2929
import com.cosmotech.api.rbac.PERMISSION_WRITE_SECURITY
30+
import com.cosmotech.api.rbac.ROLE_NONE
3031
import com.cosmotech.api.rbac.ROLE_USER
3132
import com.cosmotech.api.rbac.ROLE_VALIDATOR
3233
import com.cosmotech.api.rbac.ROLE_VIEWER
@@ -40,6 +41,7 @@ import com.cosmotech.api.utils.findAllPaginated
4041
import com.cosmotech.api.utils.getCurrentAccountIdentifier
4142
import com.cosmotech.api.utils.getCurrentAuthenticatedUserName
4243
import com.cosmotech.dataset.DatasetApiServiceInterface
44+
import com.cosmotech.dataset.domain.DatasetRole
4345
import com.cosmotech.dataset.domain.IngestionStatusEnum
4446
import com.cosmotech.dataset.domain.SubDatasetGraphQuery
4547
import com.cosmotech.dataset.service.getRbac
@@ -996,6 +998,7 @@ internal class ScenarioServiceImpl(
996998
csmRbac.setDefault(scenario.getRbac(), scenarioRole.role, scenarioPermissions)
997999
scenario.setRbac(rbacSecurity)
9981000
upsertScenarioData(scenario)
1001+
setLinkedDatasetDefaultSecurity(organizationId, scenario, scenarioRole.role)
9991002
return scenario.security as ScenarioSecurity
10001003
}
10011004

@@ -1158,6 +1161,27 @@ internal class ScenarioServiceImpl(
11581161
}
11591162
}
11601163

1164+
fun setLinkedDatasetDefaultSecurity(
1165+
organizationId: String,
1166+
scenario: Scenario,
1167+
scenarioRole: String
1168+
) {
1169+
var datasetRole = ROLE_NONE
1170+
if (scenarioRole != ROLE_NONE) datasetRole = ROLE_VIEWER
1171+
scenario.datasetList!!.forEach { datasetId ->
1172+
val dataset = datasetService.findDatasetById(organizationId, datasetId)
1173+
// We do not want to lower the default security if it's higher than viewer
1174+
if (dataset.security!!.default != ROLE_NONE && datasetRole == ROLE_VIEWER) return Unit
1175+
if (dataset.security!!.default != ROLE_NONE && datasetRole == ROLE_NONE) return Unit
1176+
// Filter on dataset copy (because we do not want to update main dataset as it can be shared
1177+
// between scenarios)
1178+
if (dataset.main != true) {
1179+
datasetService.setDatasetDefaultSecurity(
1180+
organizationId, datasetId, DatasetRole(datasetRole))
1181+
}
1182+
}
1183+
}
1184+
11611185
override fun getScenarioSecurityUsers(
11621186
organizationId: String,
11631187
workspaceId: String,

0 commit comments

Comments
 (0)