INFRA-3304 | Dhruv | Uploads aws policy file to a channel and uses the permaLink for jit

This commit is contained in:
dhruvjoshi
2024-07-31 17:26:50 +05:30
parent b5d956e229
commit d30b7d2e42
8 changed files with 102 additions and 49 deletions

View File

@@ -130,6 +130,10 @@
"name": "JIT_COMMON_CHANNEL", "name": "JIT_COMMON_CHANNEL",
"value": "$JIT_COMMON_CHANNEL" "value": "$JIT_COMMON_CHANNEL"
}, },
{
"name": "JIT_POLICY_UPLOAD_CHANNEL",
"value": "$JIT_POLICY_UPLOAD_CHANNEL"
},
{ {
"name": "GITHUB_CLOUD_OAUTH_TOKEN", "name": "GITHUB_CLOUD_OAUTH_TOKEN",
"value": "$GITHUB_CLOUD_OAUTH_TOKEN" "value": "$GITHUB_CLOUD_OAUTH_TOKEN"

View File

@@ -100,6 +100,10 @@
{ {
"name": "JIT_COMMON_CHANNEL", "name": "JIT_COMMON_CHANNEL",
"value": "$JIT_COMMON_CHANNEL" "value": "$JIT_COMMON_CHANNEL"
},
{
"name": "JIT_POLICY_UPLOAD_CHANNEL",
"value": "$JIT_POLICY_UPLOAD_CHANNEL"
} }
], ],
"namespace": "$NAMESPACE", "namespace": "$NAMESPACE",

View File

@@ -142,12 +142,15 @@ class JitServiceImpl implements JitService {
private void postReviewerDmOnSlack( private void postReviewerDmOnSlack(
User reviewer, User reviewer,
String policyPermaLink,
JitApproval jitApproval, JitApproval jitApproval,
SlackBotAttachment reviewMessage SlackBotAttachment reviewMessage
) throws IOException { ) throws IOException {
var result = slackBotClient.postMessage(userService.getUsersSlackId(reviewer), var channelId = userService.getUsersSlackId(reviewer);
reviewMessage); var result = slackBotClient.postMessage(channelId, reviewMessage);
if (policyPermaLink != null) {
slackBotClient.postPermaLinkMessage(channelId, policyPermaLink);
}
jitApproval.setReviewerSlackMessageTimestamp(result.getTs()); jitApproval.setReviewerSlackMessageTimestamp(result.getTs());
jitApproval.setBotChannelId(result.getChannel()); jitApproval.setBotChannelId(result.getChannel());
jitApprovalsRepository.save(jitApproval); jitApprovalsRepository.save(jitApproval);
@@ -163,11 +166,14 @@ class JitServiceImpl implements JitService {
private void postRequestorDmOnSlack( private void postRequestorDmOnSlack(
JitRequest jitRequest, JitRequest jitRequest,
String policyPermaLink,
SlackBotAttachment personalMessage SlackBotAttachment personalMessage
) throws IOException { ) throws IOException {
var result = slackBotClient.postMessage( var channelId = userService.getUsersSlackId(jitRequest.getRequestedFor());
userService.getUsersSlackId(jitRequest.getRequestedFor()), personalMessage); var result = slackBotClient.postMessage(channelId, personalMessage);
if (policyPermaLink != null) {
slackBotClient.postPermaLinkMessage(channelId, policyPermaLink);
}
jitRequest.setRequestorSlackMessageTimestamp(result.getTs()); jitRequest.setRequestorSlackMessageTimestamp(result.getTs());
jitRequest.setBotChannelId(result.getChannel()); jitRequest.setBotChannelId(result.getChannel());
} }
@@ -198,9 +204,13 @@ class JitServiceImpl implements JitService {
private void postChannelOnSlack( private void postChannelOnSlack(
JitRequest jitRequest, JitRequest jitRequest,
String policyPermaLink,
SlackBotAttachment commonChannelMessage SlackBotAttachment commonChannelMessage
) throws IOException { ) throws IOException {
var result = slackBotClient.postMessage(commonChannelId, commonChannelMessage); var result = slackBotClient.postMessage(commonChannelId, commonChannelMessage);
if (policyPermaLink != null) {
slackBotClient.postPermaLinkMessage(commonChannelId, policyPermaLink);
}
jitRequest.setChannelSlackMessageTimestamp(result.getTs()); jitRequest.setChannelSlackMessageTimestamp(result.getTs());
} }
@@ -359,13 +369,13 @@ class JitServiceImpl implements JitService {
actionEnabled = false; actionEnabled = false;
} }
if (reviewerEmail.equals(onCallApproverEmail)) { if (reviewerEmail.equals(onCallApproverEmail)) {
postRequestorDmOnSlack(jitRequest, postRequestorDmOnSlack(jitRequest, null,
slackBotUtil.getRequestorDm(jitRequest, false, Collections.emptyList(), slackBotUtil.getRequestorDm(jitRequest, false, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
SlackColor.APPROVED)); SlackColor.APPROVED));
postChannelOnSlack(jitRequest, postChannelOnSlack(jitRequest, null,
slackBotUtil.getChannelMessage(jitRequest, Collections.emptyList(), slackBotUtil.getChannelMessage(jitRequest, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
@@ -616,15 +626,19 @@ class JitServiceImpl implements JitService {
}); });
pendingTeams.sort(String::compareTo); pendingTeams.sort(String::compareTo);
final String uploadedPolicyPermaLink = jitRequest.getAwsPolicy() != null
? slackBotClient.sendAwsPolicyDocumentToCommonChannel(
objectMapper.writeValueAsString(jitRequest.getAwsPolicy()))
: null;
// send personal message to user with details on pending and approved reviewers // send personal message to user with details on pending and approved reviewers
JitRequest jitRequestWithId = jitRequestRepository.save(jitRequest); JitRequest jitRequestWithId = jitRequestRepository.save(jitRequest);
postRequestorDmOnSlack(jitRequestWithId, postRequestorDmOnSlack(jitRequestWithId, uploadedPolicyPermaLink,
slackBotUtil.getRequestorDm(jitRequestWithId, true, pendingTeams, slackBotUtil.getRequestorDm(jitRequestWithId, true, pendingTeams,
new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
SlackColor.INFO)); SlackColor.INFO));
// send group message to common channel with details on pending and approved reviewers // send group message to common channel with details on pending and approved reviewers
postChannelOnSlack(jitRequest, postChannelOnSlack(jitRequest, uploadedPolicyPermaLink,
slackBotUtil.getChannelMessage(jitRequest, pendingTeams, new ArrayList<>(), slackBotUtil.getChannelMessage(jitRequest, pendingTeams, new ArrayList<>(),
new ArrayList<>(), new ArrayList<>(),
new ArrayList<>(), new ArrayList<>(), SlackColor.INFO)); new ArrayList<>(), new ArrayList<>(), SlackColor.INFO));
@@ -633,8 +647,8 @@ class JitServiceImpl implements JitService {
JitRequest finalJitRequest = jitRequest; JitRequest finalJitRequest = jitRequest;
jitApprovalsWithId.stream().forEach(jitApproval -> { jitApprovalsWithId.stream().forEach(jitApproval -> {
try { try {
postReviewerDmOnSlack(jitApproval.getReviewer(), jitApproval, postReviewerDmOnSlack(jitApproval.getReviewer(), uploadedPolicyPermaLink,
slackBotUtil.getReviewerDm(finalJitRequest.getRequestedFor().getEmail(), jitApproval, slackBotUtil.getReviewerDm(finalJitRequest.getRequestedFor().getEmail(),
finalJitRequest, jitApproval, true, SlackColor.INFO)); finalJitRequest, jitApproval, true, SlackColor.INFO));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@@ -20,4 +20,5 @@ public class JitUtil {
jitRequestDto.setTeam(jitTeamOverrideMap.get(team)); jitRequestDto.setTeam(jitTeamOverrideMap.get(team));
} }
} }
} }

View File

@@ -22,23 +22,6 @@ import org.springframework.stereotype.Component;
@Component @Component
public class SlackBotUtil { public class SlackBotUtil {
private final ObjectMapper objectMapper = new ObjectMapper();
private String prettyPrintJson(Map<String, Object> json) {
try {
ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter();
return writer.writeValueAsString(json);
} catch (Exception e) {
return json.toString();
}
}
private SlackMessageText createJsonTextBoxField(String title, Map<String, Object> json) {
String formattedJson = prettyPrintJson(json);
String formattedText = String.format("*%s*\n```%s```", title, formattedJson);
return new SlackMessageText(SlackMessageTextType.MARKDOWN, formattedText);
}
private SlackMessageText createTextBoxField(String title, String text) { private SlackMessageText createTextBoxField(String title, String text) {
return new SlackMessageText(SlackMessageTextType.MARKDOWN, return new SlackMessageText(SlackMessageTextType.MARKDOWN,
@@ -180,12 +163,6 @@ public class SlackBotUtil {
style, value, actionId); style, value, actionId);
} }
SlackBotMessageBlock generateAwsPolicyBlocks(Map<String, Object> awsPolicy) {
SlackMessageText awsPolicyText = createJsonTextBoxField("POLICY", awsPolicy);
return new SlackBotMessageBlock(
SlackMessageBlockType.SECTION, awsPolicyText, null, null);
}
public SlackBotAttachment getReviewerDm( public SlackBotAttachment getReviewerDm(
String userEmail, JitRequest jitRequest, JitApproval jitApproval, String userEmail, JitRequest jitRequest, JitApproval jitApproval,
boolean actionEnabled, SlackColor color boolean actionEnabled, SlackColor color
@@ -204,9 +181,6 @@ public class SlackBotUtil {
ArrayList<SlackBotMessageBlock> blocks = new ArrayList<>(); ArrayList<SlackBotMessageBlock> blocks = new ArrayList<>();
blocks.add(reviewRequestSection); blocks.add(reviewRequestSection);
if (jitRequest.getAwsPolicy() != null) {
blocks.add(generateAwsPolicyBlocks(jitRequest.getAwsPolicy()));
}
if (reviewRequestAction != null) { if (reviewRequestAction != null) {
blocks.add(reviewRequestAction); blocks.add(reviewRequestAction);
} }
@@ -242,9 +216,6 @@ public class SlackBotUtil {
blocks.add(reviewRequestSection); blocks.add(reviewRequestSection);
blocks.add(dividerSection); blocks.add(dividerSection);
blocks.add(requestDetailSection); blocks.add(requestDetailSection);
if (jitRequest.getAwsPolicy() != null) {
blocks.add(generateAwsPolicyBlocks(jitRequest.getAwsPolicy()));
}
if (actionEnabled) { if (actionEnabled) {
ArrayList<SlackMessageElement> elements = new ArrayList<>(); ArrayList<SlackMessageElement> elements = new ArrayList<>();
@@ -325,9 +296,6 @@ public class SlackBotUtil {
blocks.add(infoSection); blocks.add(infoSection);
blocks.add(dividerSection); blocks.add(dividerSection);
blocks.add(reviewRequestSection); blocks.add(reviewRequestSection);
if (jitRequest.getAwsPolicy() != null) {
blocks.add(generateAwsPolicyBlocks(jitRequest.getAwsPolicy()));
}
return new SlackBotAttachment(color.color, blocks); return new SlackBotAttachment(color.color, blocks);
} }
} }

View File

@@ -5,14 +5,18 @@ import com.slack.api.methods.MethodsClient;
import com.slack.api.methods.SlackApiException; import com.slack.api.methods.SlackApiException;
import com.slack.api.methods.response.chat.ChatPostMessageResponse; import com.slack.api.methods.response.chat.ChatPostMessageResponse;
import com.slack.api.methods.response.files.FilesUploadResponse; import com.slack.api.methods.response.files.FilesUploadResponse;
import com.slack.api.model.File; import com.slack.api.methods.response.files.FilesUploadV2Response;
import com.slack.api.model.Attachment;
import com.slack.api.model.User; import com.slack.api.model.User;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,9 +29,10 @@ public class SlackBotClient {
private static final String SLACK_API_URL = "https://api.slack.com/methods/"; private static final String SLACK_API_URL = "https://api.slack.com/methods/";
private static final String postMessage = "chat.postMessage"; private static final String postMessage = "chat.postMessage";
@Value("${jit.slack.policy.upload.channel.id}") String policyUploadChannelId;
@Value("${slackbot.token}") @Value("${slackbot.token}")
private String slackBotToken; private String slackBotToken;
@Autowired @Autowired
private MethodsClient client; private MethodsClient client;
@@ -53,6 +58,38 @@ public class SlackBotClient {
return userSlackIdMap; return userSlackIdMap;
} }
public String sendAwsPolicyDocumentToCommonChannel(
String awsPolicyDocument
) throws IOException {
FilesUploadResponse uploadResponse = null;
try {
uploadResponse = client.filesUpload(req -> req
.token(slackBotToken)
.content(awsPolicyDocument)
.channels(List.of(policyUploadChannelId))
.filename("AwsPolicyDocument.json")
.filetype("json")
);
var policyPermaLink = uploadResponse.getFile().getPermalink();
var result = client.chatPostMessage(r -> r
.token(slackBotToken)
.channel(policyUploadChannelId)
.attachments(List.of(
Attachment.builder()
.title("AWS Policy Document")
.titleLink(policyPermaLink)
.build()
))
);
if (!result.isOk()) {
throw new IOException("Unable to send policy document : " + result.getError());
}
return policyPermaLink;
} catch (Exception e) {
throw new IOException("Unable to upload policy document : " + e.getMessage());
}
}
public ChatPostMessageResponse postMessage( public ChatPostMessageResponse postMessage(
String channelId, String channelId,
SlackBotAttachment slackBotAttachment SlackBotAttachment slackBotAttachment
@@ -70,14 +107,37 @@ public class SlackBotClient {
.attachmentsAsString(textJson) .attachmentsAsString(textJson)
); );
if (!result.isOk()) { if (!result.isOk()) {
log.error("Unable to process Slack API request: {}", result.getError()); throw new IOException("Unable to process Slack API request: " + result.getError());
} }
} catch (IOException | SlackApiException e) { } catch (Exception e) {
log.error("error: {}", e.getMessage(), e); throw new IOException("Unable to process Slack API request: " + e.getMessage());
} }
return result; return result;
} }
public ChatPostMessageResponse postPermaLinkMessage(
String channelId,
String policyPermaLink
) throws IOException {
try {
var result = client.chatPostMessage(r -> r
.token(slackBotToken)
.channel(channelId)
.attachments(List.of(
Attachment.builder().title("AWS Policy Document").titleLink(policyPermaLink)
.build()
))
);
if (!result.isOk()) {
throw new IOException("Unable to process Slack API request: " + result.getError());
}
return result;
} catch (Exception e) {
throw new IOException("Unable to process Slack API request: " + e.getMessage());
}
}
public void updateMessage(String channelId, SlackBotAttachment slackBotAttachment, String ts) public void updateMessage(String channelId, SlackBotAttachment slackBotAttachment, String ts)
throws IOException { throws IOException {
try { try {

View File

@@ -36,6 +36,7 @@ slackbot.token=${SLACK_BOT_TOKEN:xoxb-format-12345}
jit.dag.id=${JIT_DAG_ID:jit_dag} jit.dag.id=${JIT_DAG_ID:jit_dag}
jit.oncall-approver.email=jit-slackbot@jit.com jit.oncall-approver.email=jit-slackbot@jit.com
jit.slack.common.channel.id=${JIT_COMMON_CHANNEL:C06NDTBFA1G} jit.slack.common.channel.id=${JIT_COMMON_CHANNEL:C06NDTBFA1G}
jit.slack.policy.upload.channel.id=${JIT_POLICY_UPLOAD_CHANNEL:C0000000000}
jit.request.config.path=classpath:jit jit.request.config.path=classpath:jit
jit.team-override.map={'Kubernetes Platform': 'Infra'} jit.team-override.map={'Kubernetes Platform': 'Infra'}
#pipeline creation #pipeline creation

View File

@@ -80,6 +80,7 @@ jit.dag.id=${JIT_DAG_ID:jit_dag}
jit.gocd.dag.id=${JIT_GOCD_DAG_ID:jit_gocd_dag} jit.gocd.dag.id=${JIT_GOCD_DAG_ID:jit_gocd_dag}
jit.oncall-approver.email=jit-slackbot@jit.com jit.oncall-approver.email=jit-slackbot@jit.com
jit.slack.common.channel.id=${JIT_COMMON_CHANNEL:C0000000000} jit.slack.common.channel.id=${JIT_COMMON_CHANNEL:C0000000000}
jit.slack.policy.upload.channel.id=${JIT_POLICY_UPLOAD_CHANNEL:C0000000000}
github.token=${GITHUB_CLOUD_OAUTH_TOKEN} github.token=${GITHUB_CLOUD_OAUTH_TOKEN}
gocd.pipelines.config=${GOCD_PIPELINES_CONFIG} gocd.pipelines.config=${GOCD_PIPELINES_CONFIG}
vertical.owner.map={'lending':{'navi-data-science':'navi-data-science','default':'navi-medici'},'insurance':{'default':'navi-gi'},'sa':{'default':'navi-sa'},'amc':{'default':'navi-amc'},'navi-pay':{'default':'navi-pay'},'navi-ppl':{'default':'navi-ppl'}} vertical.owner.map={'lending':{'navi-data-science':'navi-data-science','default':'navi-medici'},'insurance':{'default':'navi-gi'},'sa':{'default':'navi-sa'},'amc':{'default':'navi-amc'},'navi-pay':{'default':'navi-pay'},'navi-ppl':{'default':'navi-ppl'}}