Skip to content

Commit

Permalink
Merge pull request #404 from noqdev/task/iambic-convert
Browse files Browse the repository at this point in the history
`iambic convert` - Ease conversion between IAM and IAMbic policies
  • Loading branch information
castrapel committed May 12, 2023
2 parents e0a06e4 + 3a6478b commit e03f4e6
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 2 deletions.
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@
],
"justMyCode": true
},
{
"name": "Iambic: Convert",
"type": "python",
"request": "launch",
"module": "iambic.main",
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/.env",
"args": [
"convert",
],
"justMyCode": true
},
{
"name": "Iambic: Lambda App Import",
"type": "python",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
title: Converting IAM Policy Syntax to IAMbic YAML
---
8 changes: 8 additions & 0 deletions docs/web/docs/2-how_to_guides/1-AWS/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: AWS
toc_min_heading_level: 2
toc_max_heading_level: 5
---

This material contains guidance for specific AWS scenarios. For information on setting up
and running IAMbic for AWS, please refer to the [AWS Getting Started guide](/getting_started/aws).
Binary file added docs/web/static/img/generic/iambic_iamops.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions iambic/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,3 +731,36 @@ async def remove_expired_resources(
setattr(resource, field_name, new_value)

return resource


def convert_between_json_and_yaml(input_string: str) -> str:
"""
Convert a string from AWS PascalCase JSON to IAMbic compatible YAML, or visa-versa.
When converting from JSON to YAML, dictionary keys are converted from PascalCase to snake_case.
When converting from YAML to JSON, dictionary keys are converted from snake_case to PascalCase.
:param input_string: The input string, which should be valid JSON or YAML.
:return: The converted string.
"""
from json import JSONDecodeError

from stringcase import pascalcase, snakecase

from iambic.core.utils import yaml

try:
# Try parsing the input as JSON
data = json.loads(input_string)
# Convert keys from PascalCase/camelCase to snake_case
converted_data = normalize_dict_keys(data, snakecase)
# Convert to YAML
output = yaml.dump(converted_data)
except JSONDecodeError:
# If the input is not JSON, try parsing it as YAML
data = yaml.load(input_string)
# Convert keys from snake_case to PascalCase
converted_data = normalize_dict_keys(data, pascalcase)
# Convert to JSON
output = json.dumps(converted_data, indent=2)

return output
12 changes: 12 additions & 0 deletions iambic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from iambic.core.models import ExecutionMessage, TemplateChangeDetails
from iambic.core.parser import load_templates
from iambic.core.utils import (
convert_between_json_and_yaml,
exceptions_in_proposed_changes,
gather_templates,
init_writable_directory,
Expand Down Expand Up @@ -474,6 +475,17 @@ def setup(repo_dir: str, is_more_options: bool):
ConfigurationWizard(repo_dir, is_more_options=is_more_options).run()


@cli.command()
def convert():
"""
Convert a string from AWS PascalCase JSON to IAMbic compatible YAML, or visa-versa.
"""
user_input = click.edit()
if user_input is not None:
output = convert_between_json_and_yaml(user_input)
click.echo(output)


if __name__ == "__main__":
init_writable_directory()
cli()
15 changes: 13 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ dictdiffer = "^0.9.0"
msal = "^1.21.0"
aiohttp = "^3.8.4"
pyopenssl = "^23.0.0"
stringcase = "^1.2.0"

[tool.poetry.scripts]
iambic = "iambic.main:cli"
Expand Down
30 changes: 30 additions & 0 deletions test/core/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@

import pytest
from mock import AsyncMock
from stringcase import pascalcase, snakecase

from iambic.core.models import BaseModel
from iambic.core.utils import (
GlobalRetryController,
convert_between_json_and_yaml,
create_commented_map,
normalize_dict_keys,
simplify_dt,
sort_dict,
transform_comments,
Expand Down Expand Up @@ -261,3 +264,30 @@ async def test_gather_templates(tmpdir):
# despite the function signature returns a list, we expect all
# elements to be unique.
assert len(result) == len(set(result))


def test_normalize_dict_keys():
# Test converting dictionary keys to snake_case
data = {"MyKey": {"InnerKey": "value"}}
expected_result = {"my_key": {"inner_key": "value"}}
result = normalize_dict_keys(data, snakecase)
assert result == expected_result

# Test converting dictionary keys to PascalCase
data = {"my_key": {"inner_key": "value"}}
expected_result = {"MyKey": {"InnerKey": "value"}}
result = normalize_dict_keys(data, pascalcase)
assert result == expected_result


def test_convert_between_json_and_yaml():
# Test converting JSON to YAML
json_input = '{"MyKey": {"InnerKey": "value"}}'
yaml_output = convert_between_json_and_yaml(json_input)
assert "my_key:\n inner_key: value\n" in yaml_output

# Test converting YAML to JSON
yaml_input = "my_key:\n inner_key: value\n"
json_output = convert_between_json_and_yaml(yaml_input)
expected_json_output = '{\n "MyKey": {\n "InnerKey": "value"\n }\n}'
assert json_output == expected_json_output

0 comments on commit e03f4e6

Please sign in to comment.