Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into feat/add-required-reason-template
Browse files Browse the repository at this point in the history
  • Loading branch information
wallrony committed Oct 19, 2022
2 parents ab997f9 + f1873f5 commit d349a42
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 12 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/main-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ jobs:
git submodule update
# Adding version
echo __version__=\"$IMAGE_TAG\" > plugins/sdm/_version.py
# Building docker image
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
# Pushing image to ECR
# Authenticating to ECR
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
# Building docker image
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name multiarch --driver docker-container --use
# Building docker image for multiple platforms and pushing to ECR
docker buildx build --push --platform "linux/amd64,linux/arm64" -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker buildx build --push --platform "linux/amd64,linux/arm64" -t $ECR_REGISTRY/$ECR_REPOSITORY:latest .
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM continuumio/miniconda3
FROM python:3.9

ENV ERRBOT_DIR=/errbot
ENV SDM_DOCKERIZED=true
Expand All @@ -7,7 +7,6 @@ RUN mkdir -p $ERRBOT_DIR
WORKDIR $ERRBOT_DIR

COPY requirements/common.txt ./requirements.txt
RUN apt update -y && apt install -y gcc
RUN pip install \
--no-cache-dir \
--disable-pip-version-check \
Expand Down
1 change: 1 addition & 0 deletions docs/configure_accessbot/CONFIGURE_ACCESSBOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ You just need to remove the "SDM_" prefix when configuring them. Here's a usage
* **SDM_ENABLE_BOT_STATE_HANDLING**. Boolean flag to enable persistent grant requests. When enabled, all grant requests will be synced in a local file, that way if AccessBot goes down, all ongoing requests will be restored. Default = false
* **SDM_ENABLE_RESOURCES_FUZZY_MATCHING**. Flag to enable fuzzy matching for resources when a perfect match is not found. Default = true
* **SDM_GRANT_TIMEOUT**. Timeout in minutes for an access grant. Default = 60 min
* **SDM_GRANT_TIMEOUT_LIMIT**. Timeout limit in minutes for an access grant when using the `--duration` flag. Disabled by default
* **SDM_GROUPS_TAG**. User tag to be used for specifying the groups a user belongs to. Disabled by default ([see below](#user-groups) for more info about using tags)
* **SDM_HIDE_RESOURCE_TAG**. Resource tag to be used for hiding available resources, meaning that they are not going to be shown nor accessible. Ideally set value to `true` or `false` (e.g. `hide-resource=true`). If there's no value, it's interpreted as `true`. Disabled by default ([see below](#using-tags) for more info about using tags)
* **SDM_HIDE_ROLE_TAG**. Role tag to be used for hiding available roles, meaning that they are not going to be shown nor accessible. Ideally set value to `true` or `false` (e.g. `hide-role=true`). If there's no value, it's interpreted as `true`. Disabled by default ([see below](#using-tags) for more info about using tags)
Expand Down
43 changes: 43 additions & 0 deletions e2e/slack/test_accessbot_slack_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,49 @@ def test_access_command_dont_grant_access_when_duration_flag_has_duration_equals
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "You need to enter a duration greater than zero" in mocked_testbot.pop_message()

def test_access_command_with_duration_flag_value_lesser_than_duration_limit(self, mocked_testbot):
duration = '40m'
duration_limit = '45'
accessbot = mocked_testbot.bot.plugin_manager.plugins['AccessBot']
accessbot.config['GRANT_TIMEOUT_LIMIT'] = duration_limit
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "valid request" in mocked_testbot.pop_message()
assert "access request" in mocked_testbot.pop_message()

def test_access_command_with_duration_flag_value_equals_to_duration_limit(self, mocked_testbot):
duration = '40m'
duration_limit = '40'
accessbot = mocked_testbot.bot.plugin_manager.plugins['AccessBot']
accessbot.config['GRANT_TIMEOUT_LIMIT'] = duration_limit
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "valid request" in mocked_testbot.pop_message()
assert "access request" in mocked_testbot.pop_message()

def test_access_command_with_duration_flag_time_unit_different_than_duration_limit_unit(self, mocked_testbot):
duration = '1h'
duration_limit = '60'
accessbot = mocked_testbot.bot.plugin_manager.plugins['AccessBot']
accessbot.config['GRANT_TIMEOUT_LIMIT'] = duration_limit
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "valid request" in mocked_testbot.pop_message()
assert "access request" in mocked_testbot.pop_message()

def test_access_command_fails_with_duration_flag_value_greater_than_duration_limit(self, mocked_testbot):
duration = '45m'
duration_limit = '40'
accessbot = mocked_testbot.bot.plugin_manager.plugins['AccessBot']
accessbot.config['GRANT_TIMEOUT_LIMIT'] = duration_limit
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "need to enter a duration lesser or equals" in mocked_testbot.pop_message()

def test_access_command_fails_with_duration_flag_time_unit_different_than_duration_limit_unit(self, mocked_testbot):
duration = '2h'
duration_limit = '60'
accessbot = mocked_testbot.bot.plugin_manager.plugins['AccessBot']
accessbot.config['GRANT_TIMEOUT_LIMIT'] = duration_limit
mocked_testbot.push_message(f"access to Xxx --duration {duration}")
assert "need to enter a duration lesser or equals" in mocked_testbot.pop_message()

def test_access_command_fails_for_unreachable_admin_users(self, mocked_testbot_with_no_admin_users):
mocked_testbot_with_no_admin_users.push_message("access to Xxx")
assert "no active Slack Admin" in mocked_testbot_with_no_admin_users.pop_message()
Expand Down
1 change: 1 addition & 0 deletions e2e/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def create_config():
'APPROVERS_CHANNEL_TAG': None,
'ALLOW_RESOURCE_ACCESS_REQUEST_RENEWAL': False,
'ENABLE_BOT_STATE_HANDLING': False,
'GRANT_TIMEOUT_LIMIT': None,
}


Expand Down
1 change: 1 addition & 0 deletions plugins/sdm/config_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'APPROVERS_CHANNEL_TAG': os.getenv("SDM_APPROVERS_CHANNEL_TAG"),
'ALLOW_RESOURCE_ACCESS_REQUEST_RENEWAL': str(os.getenv("SDM_ALLOW_RESOURCE_ACCESS_REQUEST_RENEWAL", "")).lower() == 'true',
'ENABLE_BOT_STATE_HANDLING': str(os.getenv("SDM_ENABLE_BOT_STATE_HANDLING", "")).lower() == 'true',
'GRANT_TIMEOUT_LIMIT': os.getenv('SDM_GRANT_TIMEOUT_LIMIT'),
}

def get():
Expand Down
21 changes: 17 additions & 4 deletions plugins/sdm/lib/helper/resource_grant_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from grant_request_type import GrantRequestType
from .base_grant_helper import BaseGrantHelper
from ..exceptions import PermissionDeniedException
from ..util import VALID_TIME_UNITS
from ..util import VALID_TIME_UNITS, convert_duration_flag_to_timedelta
from readabledelta import readabledelta


class ResourceGrantHelper(BaseGrantHelper):
Expand Down Expand Up @@ -57,14 +58,19 @@ def duration_flag_validator(self, value: str):
match = re.match(r'^\d+[a-zA-Z]?$', value)
if not match:
raise Exception('You need to enter a valid duration, e.g. 60m, 2h, etc.')
time_unit_match = re.search(r'[a-zA-Z]', value)
short_time_unit = time_unit_match.group() if time_unit_match else 'm'
if not VALID_TIME_UNITS.get(short_time_unit):
short_time_unit = self.get_short_time_unit_from_duration(value)
if short_time_unit is None:
formatted_valid_time_units = ', '.join(VALID_TIME_UNITS.keys())
raise Exception(f'You need to enter a valid duration unit. Valid units are: {formatted_valid_time_units}.')
duration = int(re.search(r'\d+', value).group())
if duration == 0:
raise Exception('You need to enter a duration greater than zero.')
duration_limit = self.__bot.config['GRANT_TIMEOUT_LIMIT']
if duration_limit is not None:
duration_timedelta = convert_duration_flag_to_timedelta(value)
duration_limit_timedelta = convert_duration_flag_to_timedelta(f"{duration_limit}m")
if duration_timedelta > duration_limit_timedelta:
raise Exception(f"You need to enter a duration lesser or equals to {readabledelta(duration_limit_timedelta)}")
return True

def __verify_reason_template_match(self, value):
Expand All @@ -78,3 +84,10 @@ def __verify_reason_template_match(self, value):
if reason_template.match(value) is None:
raise Exception(f'You need to provide a valid reason following the template: /{template}/.')
return True

def get_short_time_unit_from_duration(self, duration):
time_unit_match = re.search(r'[a-zA-Z]', duration)
short_time_unit = time_unit_match.group() if time_unit_match else 'm'
if not VALID_TIME_UNITS.get(short_time_unit):
return None
return short_time_unit
1 change: 1 addition & 0 deletions requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ fuzzywuzzy
python-levenshtein-wheels
memoization
prometheus_client
readabledelta
email_validator

0 comments on commit d349a42

Please sign in to comment.