-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deploy system user assertion to device #212
Deploy system user assertion to device #212
Conversation
ff1289a
to
119d149
Compare
119d149
to
aa55dcd
Compare
landscape/client/snap_utils.py
Outdated
# [...] | ||
# pyyaml tries to parse the * as the start of an alias leading to errors | ||
yaml.Loader.fetch_alias = yaml.Loader.fetch_plain | ||
yaml.Loader.yaml_implicit_resolvers.pop("*", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like it could have far-reaching side-effects, but I don't think we use yaml (or yaml aliases) in enough other places for it to matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've created a new class IgnoreYamlAliasesLoader(yaml.SafeLoader)
with the custom behavior and left yaml.SafeLoader
untouched.
For posterity's sake, these were the other attempts:
Attempt 1
# load the specific module we want
loader_spec = importlib.util.find_spec("yaml.loader")
loader = importlib.util.module_from_spec(loader_spec)
loader_spec.loader.exec_module(loader)
# patch it
loader.SafeLoader.fetch_alias = loader.SafeLoader.fetch_plain
loader.SafeLoader.yaml_implicit_resolvers.pop("*", None)
import sys
# prints: 130478141495936 130478198317968
print(id(sys.modules["yaml.loader"]), id(sys.modules["yaml"]))
safe_loader = loader.SafeLoader(headers)
assertion = safe_loader.get_single_data()
safe_loader.dispose()
assertion["signature"] = signature
import yaml
# prints: 130478141495936 130478198317968
print(id(sys.modules["yaml.loader"]), id(sys.modules["yaml"]))
# this raises the error as before (original behavior without patching)
yaml.safe_load(headers)
If we do this, yaml.safe_load(headers)
retains its original behavior but the catch is the modules in sys.modules
both point to the same objects which is suspicious (ids are the same)
Attempt 2 (reloading)
# patch
yaml.SafeLoader.fetch_alias = yaml.SafeLoader.fetch_plain
yaml.SafeLoader.yaml_implicit_resolvers.pop("*", None)
import sys
# prints: 123975180118560 123975179908128
print(id(sys.modules["yaml.loader"]), id(sys.modules["yaml"]))
assertion = yaml.load(headers, yaml.SafeLoader)
assertion["signature"] = signature
importlib.reload(yaml)
# prints: 123975180118560 123975179908128
print(id(sys.modules["yaml.loader"]), id(sys.modules["yaml"]))
yaml.safe_load(headers) # no error raised (original behavior not recovered)
landscape/client/snap_utils.py
Outdated
yaml.Loader.fetch_alias = yaml.Loader.fetch_plain | ||
yaml.Loader.yaml_implicit_resolvers.pop("*", None) | ||
|
||
assertion = yaml.load(headers, yaml.Loader) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious: why can't we use safe_load
anymore? Is it because the above monkeypatching doesn't work the same on yaml.SafeLoader
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
safe_load
only takes the input and no other arguments but load
allows you to customize the loader.
It works with load(headers, yaml.SafeLoader)
though, good catch,... thanks
landscape/client/user/management.py
Outdated
# adding an assertion is idempotent | ||
snap_http.add_assertion(assertion) | ||
except SnapdHttpException as e: | ||
result = json.loads(e.args[0])["result"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In view or canonical/snap-http#8 being merged can we perhaps use SnapdHttpException.json
here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made the changes
dcf4ca2
to
495e96b
Compare
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.yaml_implicit_resolvers.pop("*", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate to continue to pick on this, but yaml_implicit_resolvers
seems to be a class attribute on SafeLoader
, so pop
ping on it is mutative. See:
>>> import yaml
>>> yaml.SafeLoader.yaml_implicit_resolvers["*"]
[('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))]
>>> class MyLoader(yaml.SafeLoader):
... def __init__(self, *args, **kwargs):
... super().__init__(*args, **kwargs)
... self.yaml_implicit_resolvers.pop("*", None)
...
>>> import io
>>> my_loader = MyLoader(io.StringIO())
>>> yaml.SafeLoader.yaml_implicit_resolvers["*"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '*'
I think the proper way to exempt this resolver's behaviour is either to override resolve
(too complex to do here, probably) or override with a copy and mutate that copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copying seems to work:
In [1]: import io
...: import yaml
...: from copy import deepcopy
...:
In [2]: yaml.SafeLoader.yaml_implicit_resolvers["*"]
Out[2]: [('tag:yaml.org,2002:yaml', re.compile(r'^(?:!|&|\*)$', re.UNICODE))]
In [3]: class MyLoader(yaml.SafeLoader):
...: def __init__(self, *args, **kwargs):
...: super().__init__(*args, **kwargs)
...: self.yaml_implicit_resolvers = deepcopy(super().yaml_implicit_resolvers)
...: self.yaml_implicit_resolvers.pop("*", None)
...:
In [4]: my_loader = MyLoader(io.StringIO())
In [5]: yaml.SafeLoader.yaml_implicit_resolvers["*"]
Out[5]: [('tag:yaml.org,2002:yaml', re.compile(r'^(?:!|&|\*)$', re.UNICODE))]
Lemme switch to that.
495e96b
to
66250c6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work, thanks!
Depends on #210