Created
July 15, 2020 22:22
-
-
Save pirogoeth/afb28316950a7878c93c907b031a6192 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import functools | |
import operator | |
from typing import Optional | |
ANY = object() | |
class regex: | |
""" super stupid regex class for equality checking | |
""" | |
def __init__(self, ptn): | |
self.ptn = ptn | |
def __repr__(self): | |
return f"/{self.ptn}/" | |
def __eq__(self, o): | |
return self.ptn == o | |
cases = [ | |
( | |
"nomad.scale", | |
{"action": "nomad.scale", "params": {}}, | |
), | |
( | |
"nomad.scale{}", | |
{"action": "nomad.scale", "params": {}}, | |
), | |
( | |
"nomad.scale{region=/us-(east|west)-[12]/}", | |
{"action": "nomad.scale", "params": { | |
"region": regex("us-(east|west)-[12]"), | |
}} | |
), | |
( | |
"nomad.scale{region=*, service=\"usage\"}", | |
{"action": "nomad.scale", "params": { | |
"region": ANY, "service": "usage", | |
}} | |
), | |
( | |
"nomad.scale {}", | |
{"action": "nomad.scale", "params": {}}, | |
), | |
( | |
"nomad.scale { region=* , service=* } ", | |
{"action": "nomad.scale", "params": { | |
"region": ANY, "service": ANY, | |
}} | |
), | |
( | |
"nomad.scale { region=*", | |
Exception, | |
), | |
( | |
"nomad.scale{regions=[us-east-1,us-west-2], service=\"usage\"}", | |
{"action": "nomad.scale", "params": { | |
"regions": ["us-east-1", "us-west-2"], "service": "usage", | |
}} | |
), | |
( | |
"nomad.scale { service=\"usage\" , region=* }", | |
{"action": "nomad.scale", "params": { | |
"service": "usage", "region": ANY, | |
}} | |
) | |
] | |
def parse(spec: str) -> dict: | |
""" Parses an action specifier string into dictionary representation | |
""" | |
try: | |
params_start = spec.index("{") | |
except ValueError: | |
# This is just a plain action | |
return {"action": spec, "params": {}} | |
try: | |
params_end = spec.rindex("}") | |
except ValueError as err: | |
# Missing ending brace | |
raise Exception(f"Action spec is missing an ending brace: {spec=}") from err | |
action = spec[:params_start].strip() | |
params_str = spec[params_start+1:params_end].strip() | |
params = {} | |
while True: | |
if not params_str: | |
break | |
key, rest = params_str.split("=", 1) | |
key = key.strip() | |
# Peek ahead to determine the value type | |
if rest[0] == "/": | |
rest = rest[1:] | |
end = find_next_unescaped(rest, "/") | |
if end is None: | |
raise Exception(f"Unmatched `/` in spec: {spec=}") | |
value = rest[:end] | |
rest = rest[end+1:] | |
value = regex(value) | |
elif rest[0] == "[": | |
rest = rest[1:] | |
end = find_next_unescaped(rest, "]") | |
if end is None: | |
raise Exception(f"Unmatched `]` in spec: {spec=}") | |
value = rest[:end] | |
rest = rest[end+1:] | |
value = value.split(",") | |
value = [item.strip() for item in value] | |
elif rest[0] == "\"": | |
rest = rest[1:] | |
end = find_next_unescaped(rest, "\"") | |
if end is None: | |
raise Exception(f"Unmatched `\"` in spec: {spec=}") | |
value = rest[:end] | |
rest = rest[end+1:] | |
elif rest[0] == "*": | |
rest = rest[1:] | |
value = ANY | |
if len(rest.strip()) > 1 and rest.strip()[0] == ",": | |
rest = rest.strip()[1:].lstrip() | |
params[key] = value | |
params_str = rest | |
return { | |
"action": action, | |
"params": params, | |
} | |
def find_next_unescaped(haystack: str, needle: str) -> Optional[int]: | |
escapes = 0 | |
for idx, char in enumerate(haystack): | |
if char == needle and escapes % 2 == 0: | |
return idx | |
elif char == "\\": | |
escapes += 1 | |
else: | |
escapes = 0 | |
return None | |
def assertEq(value, expected): | |
ok = "✔️" | |
fail = "❌" | |
if value == expected: | |
print(f" {ok}\t{value=} == {expected=}") | |
else: | |
print(f" {fail}\t{value=} != {expected=}") | |
for test, expectation in cases: | |
print(f" -> {test}") | |
try: | |
if issubclass(expectation, Exception): | |
try: | |
parse(test) | |
except Exception as err: | |
assertEq(isinstance(err, expectation), True) | |
else: | |
# wut | |
raise "fuck" | |
except TypeError: | |
received = parse(test) | |
assertEq(received, expectation) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[sean:...ts/mailgun/director-chatops] λ python director_chatops/util/abac/naive.py ( ⇌ master ✱ ) (director-chatops) | |
-> nomad.scale | |
✔️ value={'action': 'nomad.scale', 'params': {}} == expected={'action': 'nomad.scale', 'params': {}} | |
-> nomad.scale{} | |
✔️ value={'action': 'nomad.scale', 'params': {}} == expected={'action': 'nomad.scale', 'params': {}} | |
-> nomad.scale{region=/us-(east|west)-[12]/} | |
✔️ value={'action': 'nomad.scale', 'params': {'region': /us-(east|west)-[12]/}} == expected={'action': 'nomad.scale', 'params': {'region': /us-(east|west)-[12]/}} | |
-> nomad.scale{region=*, service="usage"} | |
✔️ value={'action': 'nomad.scale', 'params': {'region': <object object at 0x10324eec0>, 'service': 'usage'}} == expected={'action': 'nomad.scale', 'params': {'region': <object object at 0x10324eec0>, 'service': 'usage'}} | |
-> nomad.scale {} | |
✔️ value={'action': 'nomad.scale', 'params': {}} == expected={'action': 'nomad.scale', 'params': {}} | |
-> nomad.scale { region=* , service=* } | |
✔️ value={'action': 'nomad.scale', 'params': {'region': <object object at 0x10324eec0>, 'service': <object object at 0x10324eec0>}} == expected={'action': 'nomad.scale', 'params': {'region': <object object at 0x10324eec0>, 'service': <object object at 0x10324eec0>}} | |
-> nomad.scale { region=* | |
✔️ value=True == expected=True | |
-> nomad.scale{regions=[us-east-1,us-west-2], service="usage"} | |
✔️ value={'action': 'nomad.scale', 'params': {'regions': ['us-east-1', 'us-west-2'], 'service': 'usage'}} == expected={'action': 'nomad.scale', 'params': {'regions': ['us-east-1', 'us-west-2'], 'service': 'usage'}} | |
-> nomad.scale { service="usage" , region=* } | |
✔️ value={'action': 'nomad.scale', 'params': {'service': 'usage', 'region': <object object at 0x10324eec0>}} == expected={'action': 'nomad.scale', 'params': {'service': 'usage', 'region': <object object at 0x10324eec0>}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment