Yeah, that’s ugly. But you can use the generated id (uuiddc64...) to extract it from the password store. It does not matter anymore, whether the user chose “explicit” or “stored” – it will be in the store anyway. You can (and should) use password_store.lookup_for_bakery for now.
For a v2 of the bakery API I intend to do something similar (and yet the contrary) of what we do in the server_side_calls API: The bakery plugins should get a dedicated object, that does contain the actual secret. For bakery plugins we will always need access to it – no need to make the plugin developers look it up themselves. I intend to replace the ugly tuple you described by something like this:
class Secret(NamedTuple):
# it seems that NamedTuple is the most reasonable way to create a pydantic compatible class
# without adding a dependency on pydantic
"""Represents a configured secret to the bakery plugin
This class aims to reduce the chances of accidentally exposing the secret in crash reports and log messages.
However, a bakery plug-in produces configuration files that are deployed to the target system.
Therefor the plugin needs access to the actual secret.
As a result, we cannot guarantee that bakery plugins will not expose the secret in any way:
Example:
# this is passed by the backend to the bakery plugin
>>> s = Secret("s3cr3t")
>>> print(f"This is the secret as string: {s}")
This is the secret as string: 4e738ca5563c06cfd0018299933d58db1dd8bf97f6973dc99bf6cdc64b5550bd
>>> print(f"This is the secrets `repr`: {s!r}")
This is the secrets `repr`: Secret('4e738ca5563c06cfd0018299933d58db1dd8bf97f6973dc99bf6cdc64b5550bd')
>>> print(f"But we can see the actual value: {s.revealed!r}")
But we can see the actual value: 's3cr3t'
"""
revealed: str
def _hash(self) -> str:
return hashlib.sha256(self.revealed.encode("utf-8")).hexdigest()
def __str__(self) -> str:
return self._hash()
def __repr__(self) -> str:
"""Mask the actual value of the secret
This deliberately breaks the semantics of the `repr` function.
"""
# The backend uses the `repr` function (pprint) to create a hash of the secret,
# so make sure to not return something constant here.
return f"Secret('{self._hash()}')"
Oh. Too bad I didn’t backport this into 2.3. Would it help you if I did, or is too late anyway?
The question here is: Do you expect the bakery to use the pending configuration, or the activated one. We decided to use the activated one in lookup_for_bakery in 2.4 – so if you want to be consitent with that you should use password_store.core_password_store_path(password_store.LATEST_CONFIG) (not tested).
For example: If a user creates a new rule (or, maybe even more surprising) changes an entry in the password store, but they did not yet activate the changes – would expect the change to be reflected in a newly baked agent package?
I don’t think this question has an obvious answer, but bakery plugins should behave consistently here.
Yes. On the other hand, the general idea is that fiddling with the configuration will not break the running monitoring as long as changes are not activated.
But I understand that you are in favor of using the pending config?