Skip to content

Commit 2d8b962

Browse files
committed
new spec: mgc cli bucket policy basic usage
This patch adds specs covering the basic usage of the bucket policy feature using the mgc cli. The examples in here should include the same examples on the other specs: - https://docs.magalu.cloud/docs/storage/object-storage/how-to/permissions/policies - https://github.com/MagaluCloud/s3-tester/blob/main/spec/091_bucket-policy_spec.sh
1 parent 39b17d0 commit 2d8b962

File tree

4 files changed

+198
-11
lines changed

4 files changed

+198
-11
lines changed

docs/conftest.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ def mgc_path(default_profile):
7878
else:
7979
spec_dir = os.path.dirname(get_spec_path())
8080
path = os.path.join(spec_dir, default_profile.get(mgc_path_field_name))
81-
if not os.path.isfile(path):
82-
pytest.fail(f"The specified mgc_path '{path}' (absolute: {os.path.abspath(path)}) does not exist or is not a file.")
81+
abspath = os.path.abspath(path) if path and os.path.isfile(path) else path
82+
if not abspath:
83+
pytest.fail(f"The specified mgc_path '{path}' (absolute: {abspath}) does not exist or is not a file.")
8384
return path
8485

8586
@pytest.fixture
@@ -233,7 +234,7 @@ def bucket_with_one_object(request, s3_client):
233234
'object_prefix': "",
234235
'object_key_list': ['test-object-1.txt', 'test-object-2.txt']
235236
}])
236-
def bucket_with_many_objects(request, s3_client):
237+
def bucket_with_many_objects(request, s3_client, policy_wait_time):
237238
# this fixture accepts an optional request.param['object_key_list'] with a list of custom key names
238239
object_key_list = request.param['object_key_list']
239240
# and a string prefix to prepend on all objects
@@ -249,10 +250,7 @@ def bucket_with_many_objects(request, s3_client):
249250
# Yield the bucket name and object details to the test
250251
yield bucket_name, object_prefix, content
251252

252-
# Teardown: Delete the object and bucket after the test
253-
for object_key in object_key_list:
254-
delete_object_and_wait(s3_client, bucket_name, object_key)
255-
delete_bucket_and_wait(s3_client, bucket_name)
253+
delete_policy_and_bucket_and_wait(s3_client, bucket_name, policy_wait_time)
256254

257255

258256

@@ -464,12 +462,12 @@ def bucket_with_one_object_policy(multiple_s3_clients, policy_wait_time, request
464462
yield bucket_name, object_key
465463

466464
# Teardown: delete the bucket after the test
467-
delete_policy_and_bucket_and_wait(client, bucket_name, policy_wait_time, request)
465+
delete_policy_and_bucket_and_wait(client, bucket_name, policy_wait_time)
468466

469467

470468

471469

472-
@pytest.fixture
470+
@pytest.fixture(params=[{'number_clients': 1}])
473471
def multiple_s3_clients(request, test_params):
474472
"""
475473
Creates multiple S3 clients based on the profiles provided in the test parameters.

docs/policy_cli_test.py

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# ---
2+
# jupyter:
3+
# kernelspec:
4+
# name: s3-specs
5+
# display_name: S3 Specs
6+
# language_info:
7+
# name: python
8+
# ---
9+
10+
# # Bucket Policy via MGC CLI
11+
#
12+
# Restringir determinadas ações passíveis de serem executadas em um bucket, ou
13+
# compartilhar acessos de leitura e escrita com outros usuários (Principals),
14+
# são exemplos de possibilidades que a funcionalidade de Bucket Policy (políticas
15+
# do conteiner) permitem.
16+
#
17+
# A configuração, remoção e atualização de políticas em um bucket, por documentos
18+
# de policy (arquivos JSON) pode ser feita via MGC CLI. Este é o assunto desta
19+
# especificação.
20+
#
21+
22+
# + tags=["parameters"]
23+
config = "../params.example.yaml"
24+
config = "../params.yaml"
25+
config = "../params/br-ne1.yaml"
26+
# -
27+
28+
# + {"jupyter": {"source_hidden": true}}
29+
import pytest
30+
import logging
31+
import subprocess
32+
from shlex import split
33+
from s3_helpers import (
34+
run_example,
35+
)
36+
pytestmark = [pytest.mark.basic, pytest.mark.cli]
37+
# -
38+
# ## Como fazer
39+
40+
# ### Listar os comandos disponíveis
41+
#
42+
# O manual de uso com os comandos disponíveis na CLI relacionados a Bucket Policy
43+
# pode ser consultado via terminal usando o comando abaixo:
44+
45+
commands = [
46+
"{mgc_path} object-storage buckets policy --help",
47+
]
48+
49+
# + {"jupyter": {"source_hidden": true}}
50+
@pytest.mark.parametrize("cmd_template", commands)
51+
def test_cli_help_policy(cmd_template, mgc_path):
52+
cmd = split(cmd_template.format(mgc_path=mgc_path))
53+
result = subprocess.run(cmd, capture_output=True, text=True)
54+
55+
assert result.returncode == 0, f"Command failed with error: {result.stderr}"
56+
logging.debug(f"Output from {cmd_template}: {result.stdout}")
57+
assert all(snippet in result.stdout for snippet in ["delete", "get", "set"])
58+
59+
run_example(__name__, "test_cli_help_policy", config=config)
60+
# -
61+
62+
# ### Documento de política válido
63+
#
64+
# Para fins de exemplificar o uso dos comandos, usaremos um documento JSON de política
65+
# válido bem simples, que habilita o download de todos os objetos (`*`) em um bucket
66+
# (`Resource`) para qualquer (`*`) usuário (`Principal`).
67+
68+
# +
69+
@pytest.fixture
70+
def valid_simple_policy():
71+
return """{
72+
"Version": "2012-10-17",
73+
"Statement": [
74+
{
75+
"Effect": "Allow",
76+
"Principal": "*",
77+
"Action": "s3:GetObject",
78+
"Resource": "<bucket_name>/*"
79+
}
80+
]
81+
}"""
82+
# -
83+
84+
# > **Nota:** Substitua `<bucket_name>` pelo nome do seu bucket.
85+
86+
# ### Atribuir uma política a um bucket
87+
#
88+
# Para definir uma política de bucket usando a MGC CLI, utilize o comando:
89+
90+
set_policy_commands = [
91+
"{mgc_path} object-storage buckets policy set --dst {bucket_name} --policy '{policy_json_content}'",
92+
]
93+
94+
# + {"jupyter": {"source_hidden": true}}
95+
@pytest.mark.parametrize("cmd_template", set_policy_commands)
96+
def test_cli_set_policy(cmd_template, active_mgc_workspace, mgc_path, valid_simple_policy, existing_bucket_name):
97+
bucket_name = existing_bucket_name
98+
policy = valid_simple_policy.replace("<bucket_name>", bucket_name)
99+
logging.info(policy)
100+
cmd = split(cmd_template.format(
101+
mgc_path=mgc_path,
102+
bucket_name=bucket_name,
103+
policy_json_content=policy
104+
))
105+
logging.info(f"{cmd}")
106+
result = subprocess.run(cmd, capture_output=True, text=True)
107+
108+
assert result.returncode == 0, f"Command failed with error: {result.stderr}"
109+
logging.info(f"Output from {cmd_template}: {result.stdout}")
110+
111+
run_example(__name__, "test_cli_set_policy", config=config)
112+
# -
113+
114+
# ### Remover uma política de um bucket
115+
#
116+
# Para deletar uma política de bucket usando a MGC CLI, utilize o comando:
117+
118+
delete_policy_commands = [
119+
"{mgc_path} object-storage buckets policy delete --dst {bucket_name}",
120+
]
121+
122+
# + {"jupyter": {"source_hidden": true}}
123+
from utils.policy import fixture_bucket_with_policy
124+
125+
@pytest.mark.parametrize(
126+
"cmd_template",
127+
delete_policy_commands,
128+
)
129+
def test_cli_delete_policy(cmd_template, fixture_bucket_with_policy, active_mgc_workspace, mgc_path):
130+
bucket_name, _policy_doc, _s3_clients, _object_prefix, _content = fixture_bucket_with_policy
131+
cmd = split(cmd_template.format(mgc_path=mgc_path, bucket_name=bucket_name))
132+
logging.info(f"{cmd}")
133+
result = subprocess.run(cmd, capture_output=True, text=True)
134+
135+
assert result.returncode == 0, f"Command failed with error: {result.stderr}"
136+
logging.info(f"Output from {cmd_template}: {result.stdout}")
137+
138+
run_example(__name__, "test_cli_delete_policy", config=config)
139+
# -
140+
141+
# ## Documentos relacionados
142+
#
143+
# Uma breve lista de outras referências sobre Bucket Policy
144+
#
145+
# - Docs Magalu Cloud: [Docs > Armazenamento > Object Storage > Como Fazer > Permissões > Bucket Policy](https://docs.magalu.cloud/docs/storage/object-storage/how-to/permissions/policies)
146+
# - Docs Magalu Cloud: [Docs > Armazenamento > Object Storage > Controle de Acesso de Dados > Bucket Policy](https://docs.magalu.cloud/docs/storage/object-storage/access-control/bucket_policy_overview/)
147+
# - s3-specs: [python/boto3 policies spec 1](https://magalucloud.github.io/s3-specs/runs/profiles_policies_test_br-ne1.html)
148+
# - s3-specs: [python/boto3 policies spec 2](https://magalucloud.github.io/s3-specs/runs/policies_test_test_br-ne1.html)
149+
# - s3-tester (specs legadas): [legacy s3-tester spec id:091](https://github.com/MagaluCloud/s3-tester/blob/main/spec/091_bucket-policy_spec.sh)
150+
# - AWS S3: [Bucket Policies for Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html)
151+
# - AWS S3: [Bucket policies](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-example-bucket-policies.html)
152+

docs/s3_helpers.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,11 @@ def delete_all_objects_and_wait(s3_client, bucket_name):
108108
for obj in response['Contents']:
109109
delete_object_and_wait(s3_client, bucket_name, obj['Key'])
110110

111-
def delete_policy_and_bucket_and_wait(s3_client, bucket_name, policy_wait_time, request):
111+
def delete_policy_and_bucket_and_wait(s3_client, bucket_name, policy_wait_time):
112112
retries = 3
113113
sleeptime = 5
114114
for attempt_number in range(retries):
115115
try:
116-
change_policies_json(bucket_name, {"policy_dict": request.param['policy_dict'], "actions": ["s3:GetObjects", "*"], "effect": "Allow"}, tenants=["*"])
117116
logging.info(f"deleting policy of bucket {bucket_name}...")
118117
s3_client.delete_bucket_policy(Bucket=bucket_name)
119118
break

docs/utils/policy.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import logging
2+
import pytest
3+
4+
allow_get_object_policy = """{
5+
"Version": "2012-10-17",
6+
"Statement": [
7+
{
8+
"Effect": "Allow",
9+
"Principal": "*",
10+
"Action": "s3:GetObject",
11+
"Resource": "<bucket_name>/*"
12+
}
13+
]
14+
}"""
15+
16+
17+
# This fixture accepts indirect arguments in a dict:
18+
# policy_doc: is a string with a json and <bucket_name>
19+
# on the places that will be replaced with the name
20+
# of the generated bucket
21+
#
22+
# This fixture depends on the bucket_with_many_objects
23+
# fixture so if your test needs custom onject keys you
24+
# need to indirect pass the arguments for that dependency
25+
#
26+
# This fixture depends on the multiple_s3_clients
27+
# fixture so if your test needs custom number of clients you
28+
# need to indirect pass the arguments for that dependency
29+
@pytest.fixture(params=[{'policy_doc': allow_get_object_policy}])
30+
def fixture_bucket_with_policy(request, multiple_s3_clients, bucket_with_many_objects):
31+
s3_clients = multiple_s3_clients
32+
bucket_owner_client = s3_clients[0]
33+
bucket_name, object_prefix, content = bucket_with_many_objects
34+
policy_template = request.param['policy_doc']
35+
policy_doc = policy_template.replace("<bucket_name>", bucket_name)
36+
bucket_owner_client.put_bucket_policy(Bucket=bucket_name, Policy = policy_doc)
37+
38+
return bucket_name, policy_doc, s3_clients, object_prefix, content

0 commit comments

Comments
 (0)