-
-
Notifications
You must be signed in to change notification settings - Fork 0
feat(system): add secrets module #41
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| from __future__ import print_function | ||
|
|
||
| from typing import Union | ||
|
|
||
| from java.lang import Record | ||
|
|
||
| from com.inductiveautomation.ignition.common.script.abc import ContextManager | ||
| from com.inductiveautomation.ignition.gateway.secrets import Plaintext | ||
|
|
||
|
|
||
| class PyPlaintext(ContextManager): | ||
| def __init__(self, plaintext): | ||
| # type: (Plaintext) -> None | ||
| super(PyPlaintext, self).__init__() | ||
|
|
||
| def clear(self): | ||
| # type: () -> None | ||
| pass | ||
|
|
||
| def getSecretsAsBytes(self): | ||
| # type: () -> bytearray | ||
| pass | ||
|
|
||
| def getSecretsAsString(self, charsetName=None): | ||
| # type: (Union[str, unicode, None]) -> Union[str, unicode] | ||
| pass | ||
|
|
||
|
|
||
| class SecretMeta(Record): | ||
| def __init__( | ||
| self, | ||
| name, # type: Union[str, unicode] | ||
| ): | ||
| # type: (...) -> None | ||
| super(SecretMeta, self).__init__() | ||
| self._name = name | ||
|
|
||
| def name(self): | ||
| # type: () -> Union[str, unicode] | ||
| return self._name | ||
|
|
||
|
|
||
| class SecretProviderMeta(Record): | ||
| def __init__( | ||
| self, | ||
| name, # type: Union[str, unicode] | ||
| description, # type: Union[str, unicode] | ||
| type_, # type: Union[str, unicode] | ||
| ): | ||
| # type: (...) -> None | ||
| super(SecretProviderMeta, self).__init__() | ||
| self._name = name | ||
| self._description = description | ||
| self._type = type_ | ||
|
|
||
| def description(self): | ||
| # type: () -> Union[str, unicode] | ||
| return self._description | ||
|
|
||
| def name(self): | ||
| # type: () -> Union[str, unicode] | ||
| return self._name | ||
|
|
||
| def type(self): | ||
| # type: () -> Union[str, unicode] | ||
| return self._type |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| from typing import Optional, Union | ||
|
|
||
| from java.io import Closeable | ||
| from java.lang import Object | ||
| from java.nio.charset import Charset | ||
|
|
||
|
|
||
| class Plaintext(Object, Closeable): | ||
| def __init__(self): | ||
| # type: () -> None | ||
| super(Plaintext, self).__init__() | ||
|
|
||
| def clear(self): | ||
| # type: () -> None | ||
| pass | ||
|
|
||
| def close(self): | ||
| # type: () -> None | ||
| pass | ||
|
|
||
| @staticmethod | ||
| def fromBytes(bytes): | ||
| # type: (bytearray) -> Plaintext | ||
| return Plaintext() | ||
|
|
||
| @staticmethod | ||
| def fromString(str, charset=None): | ||
| # type: (Union[str, unicode], Optional[Charset]) -> Plaintext | ||
| return Plaintext() | ||
|
|
||
| def getAsString(self): | ||
| # type: () -> Union[str, unicode] | ||
| pass | ||
|
|
||
| def getBytes(self): | ||
| # type: () -> bytearray | ||
| pass |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| """Secrets Functions. | ||
|
|
||
| The following functions are used to interact with encrypted secrets for | ||
| Secret Providers on the Gateway. | ||
| """ | ||
|
|
||
| from __future__ import print_function | ||
|
|
||
| __all__ = [ | ||
| "decrypt", | ||
| "encrypt", | ||
| "getProviders", | ||
| "getSecrets", | ||
| "readSecretValue", | ||
| ] | ||
|
|
||
| from typing import Any, Dict, List, Union | ||
|
|
||
| from com.inductiveautomation.ignition.common.secrets import ( | ||
| PyPlaintext, | ||
| SecretMeta, | ||
| SecretProviderMeta, | ||
| ) | ||
| from com.inductiveautomation.ignition.gateway.secrets import Plaintext | ||
|
|
||
|
|
||
| def decrypt(json): | ||
| # type: (Any) -> PyPlaintext | ||
| """Decrypts the given JSON object containing an encrypted secret | ||
| using the system encryption service. | ||
|
|
||
| Args: | ||
| json: The JSON object containing the encrypted secret to | ||
| decrypt. | ||
|
|
||
| Returns: | ||
| The decrypted value of the JSON string. | ||
| """ | ||
| return PyPlaintext(Plaintext.fromString(json)) | ||
|
|
||
|
|
||
| def encrypt(*args): | ||
| # type: (*Any) -> Dict[Union[str, unicode], Any] | ||
| """Encrypts supplied data using the Secrets Management system | ||
| encryption service and returns a JSON object containing the | ||
| encrypted secret. | ||
|
|
||
| Args: | ||
| *args: Variable length argument list. | ||
|
|
||
| Returns: | ||
| A PyDictionary containing the encrypted secret or None if the | ||
| JSON is empty. | ||
| """ | ||
| return { | ||
| "ciphertext": None, | ||
| "encrypted_key": None, | ||
| "iv": None, | ||
| "protected": True, | ||
| "tag": None, | ||
| } | ||
|
|
||
|
|
||
| def getProviders(): | ||
| # type: () -> List[SecretProviderMeta] | ||
| """Returns a list of Secret Providers configured in the Secrets | ||
| Management system on the Gateway. Each list entry includes the name, | ||
| description, and type of the provider. | ||
|
|
||
| Returns: | ||
| A List of SecretProviderMeta instances that represent all of | ||
| the Secret Providers. | ||
| """ | ||
| return [ | ||
| SecretProviderMeta( | ||
| "SecretProviderName", "SecretProviderDescription", "SecretProviderType" | ||
| ) | ||
| ] | ||
|
|
||
|
|
||
| def getSecrets(providerName): | ||
| # type: (Union[str, unicode]) -> List[SecretMeta] | ||
| """Returns a list of objects representing all secrets available for | ||
| the named Secret Provider. | ||
|
|
||
| Each list entry includes the name of the secret. | ||
|
|
||
| Args: | ||
| providerName: The name of the Secret Provider to fetch secrets | ||
| from. | ||
|
Comment on lines
+81
to
+90
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (bug_risk): Printing providerName in getSecrets introduces unexpected side effects. Having Suggested implementation: def getSecrets(providerName):
# type: (Union[str, unicode]) -> List[SecretMeta]
"""Returns a list of objects representing all secrets available for
the named Secret Provider.
Each list entry includes the name of the secret.
Args:
providerName: The name of the Secret Provider to fetch secrets
from.
Returns:
A list of SecretMeta instances that represent all secret names.
"""
return [SecretMeta("SecretName")]__all__ = [
"decrypt",
"encrypt",
"getProviders",
"getSecrets", |
||
|
|
||
| Returns: | ||
| A list of SecretMeta instances that represent all secret names. | ||
| """ | ||
| print(providerName) | ||
| return [SecretMeta("SecretName")] | ||
|
|
||
|
|
||
| def readSecretValue(providerName, secretName): | ||
| # type: (Union[str, unicode], Union[str, unicode]) -> PyPlaintext | ||
| """Reads the plaintext value of a secret given the name of the | ||
| Secret Provider and the name of the secret. | ||
|
|
||
| Args: | ||
| providerName: The name of the Secret Provider to read the secret | ||
| from. | ||
| secretName: The name of the secret to read. | ||
|
|
||
| Returns: | ||
| A PyPlaintext instance that contains the secret. | ||
| """ | ||
| print(providerName, secretName) | ||
| return PyPlaintext(Plaintext()) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| from typing import Union | ||
|
|
||
| from com.inductiveautomation.ignition.common.script.abc import ContextManager | ||
| from com.inductiveautomation.ignition.gateway.secrets import Plaintext | ||
| from java.lang import Record | ||
|
|
||
| class PyPlaintext(ContextManager): | ||
| def __init__(self, plaintext: Plaintext) -> None: ... | ||
| def clear(self) -> None: ... | ||
| def getSecretsAsBytes(self) -> bytearray: ... | ||
| def getSecretsAsString( | ||
| self, charsetName: Union[str, unicode, None] = ... | ||
| ) -> Union[str, unicode]: ... | ||
|
|
||
| class SecretMeta(Record): | ||
| def __init__(self, name: Union[str, unicode]) -> None: ... | ||
| def name(self) -> Union[str, unicode]: ... | ||
|
|
||
| class SecretProviderMeta(Record): | ||
| def __init__( | ||
| self, | ||
| name: Union[str, unicode], | ||
| description: Union[str, unicode], | ||
| type_: Union[str, unicode], | ||
| ) -> None: ... | ||
| def description(self) -> Union[str, unicode]: ... | ||
| def name(self) -> Union[str, unicode]: ... | ||
| def type(self) -> Union[str, unicode]: ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| from typing import Optional, Union | ||
|
|
||
| from java.io import Closeable | ||
| from java.lang import Object | ||
| from java.nio.charset import Charset as Charset | ||
|
|
||
| class Plaintext(Object, Closeable): | ||
| def __init__(self) -> None: ... | ||
| def clear(self) -> None: ... | ||
| def close(self) -> None: ... | ||
| @staticmethod | ||
| def fromBytes(bytes: bytearray) -> Plaintext: ... | ||
| @staticmethod | ||
| def fromString( | ||
| str: Union[str, unicode], charset: Optional[Charset] = ... | ||
| ) -> Plaintext: ... | ||
| def getAsString(self) -> Union[str, unicode]: ... | ||
| def getBytes(self) -> bytearray: ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from typing import Any, Dict, List, Union | ||
|
|
||
| from com.inductiveautomation.ignition.common.secrets import ( | ||
| PyPlaintext, | ||
| SecretMeta, | ||
| SecretProviderMeta, | ||
| ) | ||
|
|
||
| def decrypt(json: Any) -> PyPlaintext: ... | ||
| def encrypt(*args: Any) -> Dict[Union[str, unicode], Any]: ... | ||
| def getProviders() -> List[SecretProviderMeta]: ... | ||
| def getSecrets(providerName: Union[str, unicode]) -> List[SecretMeta]: ... | ||
| def readSecretValue( | ||
| providerName: Union[str, unicode], secretName: Union[str, unicode] | ||
| ) -> PyPlaintext: ... |
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.
issue (bug_risk): ContextManager’s enter/exit behavior is surprising for a reusable base class.
__enter__currently returnsNoneand both methods print on entry/exit. For a reusable base class,with ContextManager() as cm:(or via subclasses likePyPlaintext) will bindcmtoNone, which is likely to cause subtle bugs, and the prints will create noisy logs. Prefer returningselffrom__enter__and removing these prints, or make this an abstract shell that subclasses override.