Skip to content

Commit

Permalink
Grant/Revoke workspace definition grants (#11338)
Browse files Browse the repository at this point in the history
* writeActorDefinitionWorkspaceGrant

* add workspaceId to definition handler tests

* method to check whether a grant exists

given an actor definition id and workspace id

* deleteActorDefinitionWorkspaceGrant

* grantSourceDefinitionToWorkspace

* grantDestinationDefinitionToWorkspace

* revokeSourceDefinitionFromWorkspace

* revokeDestinationDefinitionFromWorkspace

* use jooq fetchCount
  • Loading branch information
git-phu authored Mar 24, 2022
1 parent 3dc83ad commit 05b816d
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,21 @@ public void writeActorDefinitionWorkspaceGrant(final UUID actorDefinitionId, fin
.execute());
}

public boolean actorDefinitionWorkspaceGrantExists(final UUID actorDefinitionId, final UUID workspaceId) throws IOException {
final Integer count = database.query(ctx -> ctx.fetchCount(
DSL.selectFrom(ACTOR_DEFINITION_WORKSPACE_GRANT)
.where(ACTOR_DEFINITION_WORKSPACE_GRANT.ACTOR_DEFINITION_ID.eq(actorDefinitionId))
.and(ACTOR_DEFINITION_WORKSPACE_GRANT.WORKSPACE_ID.eq(workspaceId))));
return count == 1;
}

public void deleteActorDefinitionWorkspaceGrant(final UUID actorDefinitionId, final UUID workspaceId) throws IOException {
database.query(ctx -> ctx.deleteFrom(ACTOR_DEFINITION_WORKSPACE_GRANT)
.where(ACTOR_DEFINITION_WORKSPACE_GRANT.ACTOR_DEFINITION_ID.eq(actorDefinitionId))
.and(ACTOR_DEFINITION_WORKSPACE_GRANT.WORKSPACE_ID.eq(workspaceId))
.execute());
}

private <T> List<T> listStandardActorDefinitions(final ActorType actorType,
final Function<Record, T> recordToActorDefinition,
final Condition... conditions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,20 @@ private Set<UUID> fetchOperationIdsForConnectionId(final UUID connectionId) thro
.fetchSet(CONNECTION_OPERATION.OPERATION_ID));
}

@Test
public void testActorDefinitionWorkspaceGrantExists() throws IOException {
final UUID workspaceId = MockData.standardWorkspaces().get(0).getWorkspaceId();
final UUID definitionId = MockData.standardSourceDefinitions().get(0).getSourceDefinitionId();

assertFalse(configRepository.actorDefinitionWorkspaceGrantExists(definitionId, workspaceId));

configRepository.writeActorDefinitionWorkspaceGrant(definitionId, workspaceId);
assertTrue(configRepository.actorDefinitionWorkspaceGrantExists(definitionId, workspaceId));

configRepository.deleteActorDefinitionWorkspaceGrant(definitionId, workspaceId);
assertFalse(configRepository.actorDefinitionWorkspaceGrantExists(definitionId, workspaceId));
}

@Test
public void testListPublicSourceDefinitions() throws IOException {
final List<StandardSourceDefinition> actualDefinitions = configRepository.listPublicSourceDefinitions(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,15 @@ public void deleteCustomSourceDefinition(final SourceDefinitionIdWithWorkspaceId

@Override
public PrivateSourceDefinitionRead grantSourceDefinitionToWorkspace(final SourceDefinitionIdWithWorkspaceId sourceDefinitionIdWithWorkspaceId) {
return null;
return execute(() -> sourceDefinitionsHandler.grantSourceDefinitionToWorkspace(sourceDefinitionIdWithWorkspaceId));
}

@Override
public void revokeSourceDefinitionFromWorkspace(final SourceDefinitionIdWithWorkspaceId sourceDefinitionIdWithWorkspaceId) {

execute(() -> {
sourceDefinitionsHandler.revokeSourceDefinitionFromWorkspace(sourceDefinitionIdWithWorkspaceId);
return null;
});
}

// SOURCE SPECIFICATION
Expand Down Expand Up @@ -568,12 +571,15 @@ public void deleteCustomDestinationDefinition(final DestinationDefinitionIdWithW
@Override
public PrivateDestinationDefinitionRead grantDestinationDefinitionToWorkspace(
final DestinationDefinitionIdWithWorkspaceId destinationDefinitionIdWithWorkspaceId) {
return null;
return execute(() -> destinationDefinitionsHandler.grantDestinationDefinitionToWorkspace(destinationDefinitionIdWithWorkspaceId));
}

@Override
public void revokeDestinationDefinitionFromWorkspace(final DestinationDefinitionIdWithWorkspaceId destinationDefinitionIdWithWorkspaceId) {

execute(() -> {
destinationDefinitionsHandler.revokeDestinationDefinitionFromWorkspace(destinationDefinitionIdWithWorkspaceId);
return null;
});
}

// DESTINATION SPECIFICATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import com.google.common.annotations.VisibleForTesting;
import io.airbyte.api.model.DestinationDefinitionCreate;
import io.airbyte.api.model.DestinationDefinitionIdRequestBody;
import io.airbyte.api.model.DestinationDefinitionIdWithWorkspaceId;
import io.airbyte.api.model.DestinationDefinitionRead;
import io.airbyte.api.model.DestinationDefinitionReadList;
import io.airbyte.api.model.DestinationDefinitionUpdate;
import io.airbyte.api.model.DestinationRead;
import io.airbyte.api.model.PrivateDestinationDefinitionRead;
import io.airbyte.api.model.ReleaseStage;
import io.airbyte.api.model.WorkspaceIdRequestBody;
import io.airbyte.commons.docker.DockerUtils;
Expand Down Expand Up @@ -228,4 +230,24 @@ public static String loadIcon(final String name) {
}
}

public PrivateDestinationDefinitionRead grantDestinationDefinitionToWorkspace(
final DestinationDefinitionIdWithWorkspaceId destinationDefinitionIdWithWorkspaceId)
throws JsonValidationException, ConfigNotFoundException, IOException {
final StandardDestinationDefinition standardDestinationDefinition =
configRepository.getStandardDestinationDefinition(destinationDefinitionIdWithWorkspaceId.getDestinationDefinitionId());
configRepository.writeActorDefinitionWorkspaceGrant(
destinationDefinitionIdWithWorkspaceId.getDestinationDefinitionId(),
destinationDefinitionIdWithWorkspaceId.getWorkspaceId());
return new PrivateDestinationDefinitionRead()
.destinationDefinition(buildDestinationDefinitionRead(standardDestinationDefinition))
.granted(true);
}

public void revokeDestinationDefinitionFromWorkspace(final DestinationDefinitionIdWithWorkspaceId destinationDefinitionIdWithWorkspaceId)
throws IOException {
configRepository.deleteActorDefinitionWorkspaceGrant(
destinationDefinitionIdWithWorkspaceId.getDestinationDefinitionId(),
destinationDefinitionIdWithWorkspaceId.getWorkspaceId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import static io.airbyte.server.ServerConstants.DEV_IMAGE_TAG;

import com.google.common.annotations.VisibleForTesting;
import io.airbyte.api.model.PrivateSourceDefinitionRead;
import io.airbyte.api.model.ReleaseStage;
import io.airbyte.api.model.SourceDefinitionCreate;
import io.airbyte.api.model.SourceDefinitionIdRequestBody;
import io.airbyte.api.model.SourceDefinitionIdWithWorkspaceId;
import io.airbyte.api.model.SourceDefinitionRead;
import io.airbyte.api.model.SourceDefinitionReadList;
import io.airbyte.api.model.SourceDefinitionUpdate;
Expand Down Expand Up @@ -220,4 +222,24 @@ public static String loadIcon(final String name) {
}
}

public PrivateSourceDefinitionRead grantSourceDefinitionToWorkspace(
final SourceDefinitionIdWithWorkspaceId sourceDefinitionIdWithWorkspaceId)
throws JsonValidationException, ConfigNotFoundException, IOException {
final StandardSourceDefinition standardSourceDefinition =
configRepository.getStandardSourceDefinition(sourceDefinitionIdWithWorkspaceId.getSourceDefinitionId());
configRepository.writeActorDefinitionWorkspaceGrant(
sourceDefinitionIdWithWorkspaceId.getSourceDefinitionId(),
sourceDefinitionIdWithWorkspaceId.getWorkspaceId());
return new PrivateSourceDefinitionRead()
.sourceDefinition(buildSourceDefinitionRead(standardSourceDefinition))
.granted(true);
}

public void revokeSourceDefinitionFromWorkspace(final SourceDefinitionIdWithWorkspaceId sourceDefinitionIdWithWorkspaceId)
throws IOException {
configRepository.deleteActorDefinitionWorkspaceGrant(
sourceDefinitionIdWithWorkspaceId.getSourceDefinitionId(),
sourceDefinitionIdWithWorkspaceId.getWorkspaceId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
import com.google.common.collect.Lists;
import io.airbyte.api.model.DestinationDefinitionCreate;
import io.airbyte.api.model.DestinationDefinitionIdRequestBody;
import io.airbyte.api.model.DestinationDefinitionIdWithWorkspaceId;
import io.airbyte.api.model.DestinationDefinitionRead;
import io.airbyte.api.model.DestinationDefinitionReadList;
import io.airbyte.api.model.DestinationDefinitionUpdate;
import io.airbyte.api.model.DestinationRead;
import io.airbyte.api.model.DestinationReadList;
import io.airbyte.api.model.PrivateDestinationDefinitionRead;
import io.airbyte.api.model.ReleaseStage;
import io.airbyte.api.model.WorkspaceIdRequestBody;
import io.airbyte.commons.docker.DockerUtils;
Expand Down Expand Up @@ -303,6 +305,51 @@ void testDeleteDestinationDefinition() throws ConfigNotFoundException, IOExcepti
verify(configRepository).writeStandardDestinationDefinition(updatedDestinationDefinition);
}

@Test
@DisplayName("grantDestinationDefinitionToWorkspace should correctly create a workspace grant")
void testGrantDestinationDefinitionToWorkspace() throws JsonValidationException, ConfigNotFoundException, IOException, URISyntaxException {
when(configRepository.getStandardDestinationDefinition(destinationDefinition.getDestinationDefinitionId()))
.thenReturn(destinationDefinition);

final DestinationDefinitionRead expectedDestinationDefinitionRead = new DestinationDefinitionRead()
.destinationDefinitionId(destinationDefinition.getDestinationDefinitionId())
.name(destinationDefinition.getName())
.dockerRepository(destinationDefinition.getDockerRepository())
.dockerImageTag(destinationDefinition.getDockerImageTag())
.documentationUrl(new URI(destinationDefinition.getDocumentationUrl()))
.icon(DestinationDefinitionsHandler.loadIcon(destinationDefinition.getIcon()))
.releaseStage(ReleaseStage.fromValue(destinationDefinition.getReleaseStage().value()))
.releaseDate(LocalDate.parse(destinationDefinition.getReleaseDate()))
.resourceRequirements(new io.airbyte.api.model.ActorDefinitionResourceRequirements()
._default(new io.airbyte.api.model.ResourceRequirements()
.cpuRequest(destinationDefinition.getResourceRequirements().getDefault().getCpuRequest())));

final PrivateDestinationDefinitionRead expectedPrivateDestinationDefinitionRead =
new PrivateDestinationDefinitionRead().destinationDefinition(expectedDestinationDefinitionRead).granted(true);

final PrivateDestinationDefinitionRead actualPrivateDestinationDefinitionRead =
destinationDefinitionsHandler.grantDestinationDefinitionToWorkspace(
new DestinationDefinitionIdWithWorkspaceId()
.destinationDefinitionId(destinationDefinition.getDestinationDefinitionId())
.workspaceId(workspaceId));

assertEquals(expectedPrivateDestinationDefinitionRead, actualPrivateDestinationDefinitionRead);
verify(configRepository).writeActorDefinitionWorkspaceGrant(
destinationDefinition.getDestinationDefinitionId(),
workspaceId);
}

@Test
@DisplayName("revokeDestinationDefinitionFromWorkspace should correctly delete a workspace grant")
void testRevokeDestinationDefinitionFromWorkspace() throws IOException {
destinationDefinitionsHandler.revokeDestinationDefinitionFromWorkspace(new DestinationDefinitionIdWithWorkspaceId()
.destinationDefinitionId(destinationDefinition.getDestinationDefinitionId())
.workspaceId(workspaceId));
verify(configRepository).deleteActorDefinitionWorkspaceGrant(
destinationDefinition.getDestinationDefinitionId(),
workspaceId);
}

@Nested
@DisplayName("listLatest")
class listLatest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import io.airbyte.api.model.PrivateSourceDefinitionRead;
import io.airbyte.api.model.ReleaseStage;
import io.airbyte.api.model.SourceDefinitionCreate;
import io.airbyte.api.model.SourceDefinitionIdRequestBody;
import io.airbyte.api.model.SourceDefinitionIdWithWorkspaceId;
import io.airbyte.api.model.SourceDefinitionRead;
import io.airbyte.api.model.SourceDefinitionReadList;
import io.airbyte.api.model.SourceDefinitionUpdate;
Expand Down Expand Up @@ -298,6 +300,51 @@ void testDeleteSourceDefinition() throws ConfigNotFoundException, IOException, J
verify(configRepository).writeStandardSourceDefinition(updatedSourceDefinition);
}

@Test
@DisplayName("grantSourceDefinitionToWorkspace should correctly create a workspace grant")
void testGrantSourceDefinitionToWorkspace() throws JsonValidationException, ConfigNotFoundException, IOException, URISyntaxException {
when(configRepository.getStandardSourceDefinition(sourceDefinition.getSourceDefinitionId()))
.thenReturn(sourceDefinition);

final SourceDefinitionRead expectedSourceDefinitionRead = new SourceDefinitionRead()
.sourceDefinitionId(sourceDefinition.getSourceDefinitionId())
.name(sourceDefinition.getName())
.dockerRepository(sourceDefinition.getDockerRepository())
.dockerImageTag(sourceDefinition.getDockerImageTag())
.documentationUrl(new URI(sourceDefinition.getDocumentationUrl()))
.icon(SourceDefinitionsHandler.loadIcon(sourceDefinition.getIcon()))
.releaseStage(ReleaseStage.fromValue(sourceDefinition.getReleaseStage().value()))
.releaseDate(LocalDate.parse(sourceDefinition.getReleaseDate()))
.resourceRequirements(new io.airbyte.api.model.ActorDefinitionResourceRequirements()
._default(new io.airbyte.api.model.ResourceRequirements()
.cpuRequest(sourceDefinition.getResourceRequirements().getDefault().getCpuRequest())));

final PrivateSourceDefinitionRead expectedPrivateSourceDefinitionRead =
new PrivateSourceDefinitionRead().sourceDefinition(expectedSourceDefinitionRead).granted(true);

final PrivateSourceDefinitionRead actualPrivateSourceDefinitionRead =
sourceDefinitionsHandler.grantSourceDefinitionToWorkspace(
new SourceDefinitionIdWithWorkspaceId()
.sourceDefinitionId(sourceDefinition.getSourceDefinitionId())
.workspaceId(workspaceId));

assertEquals(expectedPrivateSourceDefinitionRead, actualPrivateSourceDefinitionRead);
verify(configRepository).writeActorDefinitionWorkspaceGrant(
sourceDefinition.getSourceDefinitionId(),
workspaceId);
}

@Test
@DisplayName("revokeSourceDefinitionFromWorkspace should correctly delete a workspace grant")
void testRevokeSourceDefinitionFromWorkspace() throws IOException {
sourceDefinitionsHandler.revokeSourceDefinitionFromWorkspace(new SourceDefinitionIdWithWorkspaceId()
.sourceDefinitionId(sourceDefinition.getSourceDefinitionId())
.workspaceId(workspaceId));
verify(configRepository).deleteActorDefinitionWorkspaceGrant(
sourceDefinition.getSourceDefinitionId(),
workspaceId);
}

@Nested
@DisplayName("listLatest")
class listLatest {
Expand Down

0 comments on commit 05b816d

Please sign in to comment.