From 4fb41da48cdd5e708af7fd4bc697c8ab474d2d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Rom=C3=A1n?= Date: Fri, 17 Jul 2026 16:00:51 -0700 Subject: [PATCH 1/2] refactor(system): add system.secrets functions - createEmbeddedSecretConfig - createReferencedSecretConfig - readConfiguredSecretValue Closes: #55 --- .../ignition/gateway/secrets/__init__.py | 8 ++- src/system/secrets.py | 72 ++++++++++++++++++- .../ignition/gateway/secrets/__init__.pyi | 6 +- stubs/stubs/system/secrets.pyi | 6 ++ 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/com/inductiveautomation/ignition/gateway/secrets/__init__.py b/src/com/inductiveautomation/ignition/gateway/secrets/__init__.py index 2ede948..d1262bd 100644 --- a/src/com/inductiveautomation/ignition/gateway/secrets/__init__.py +++ b/src/com/inductiveautomation/ignition/gateway/secrets/__init__.py @@ -1,7 +1,7 @@ from typing import Optional, Union from java.io import Closeable -from java.lang import Object +from java.lang import Exception, Object, Throwable from java.nio.charset import Charset @@ -35,3 +35,9 @@ def getAsString(self): def getBytes(self): # type: () -> bytearray pass + + +class SecretException(Exception): + def __init__(self, message, cause=None): + # type: (str, Optional[Throwable]) -> None + super(SecretException, self).__init__(message, cause) diff --git a/src/system/secrets.py b/src/system/secrets.py index 1b9c8da..5bc1f96 100644 --- a/src/system/secrets.py +++ b/src/system/secrets.py @@ -7,10 +7,13 @@ from __future__ import print_function __all__ = [ + "createEmbeddedSecretConfig", + "createReferencedSecretConfig", "decrypt", "encrypt", "getProviders", "getSecrets", + "readConfiguredSecretValue", "readSecretValue", ] @@ -21,7 +24,52 @@ SecretMeta, SecretProviderMeta, ) -from com.inductiveautomation.ignition.gateway.secrets import Plaintext +from com.inductiveautomation.ignition.gateway.secrets import Plaintext, SecretException +from org.python.core import PyObject + + +def createEmbeddedSecretConfig(json): + # type: (Any) -> PyObject + """Creates a new Embedded SecretConfig instance given the JSON + representation of the encrypted data. + + Args: + json: The JSON object containing the encrypted secret. + + Returns: + A Dictionary containing the JSON representation of an Embedded + SecretConfig instance containing the encrypted secret. + + Raises: + ValueError: Throws a ValueError if there is no JSON. + """ + if not json: + raise ValueError("No JSON provided for creating an Embedded SecretConfig.") + return PyObject() + + +def createReferencedSecretConfig(providerName, secretName): + # type: (Union[str, unicode], Union[str, unicode]) -> PyObject + """Creates a new Referenced SecretConfig instance given the name of + the secret provider and the name of the secret stored in the + provider. + + Args: + providerName: The name of the Secret Provider to reference. + secretName: The name of the secret to reference. + + Returns: + PyObject: A Dictionary containing the JSON representation of a + Referenced SecretConfig instance with the provider and + secret names. + + Raises: + ValueError: Throws a ValueError if the providerName or + secretName parameters do not have any values. + """ + if not providerName or not secretName: + raise ValueError("Both providerName and secretName must be provided.") + return PyObject() def decrypt(json): @@ -96,6 +144,28 @@ def getSecrets(providerName): return [SecretMeta("SecretName")] +def readConfiguredSecretValue(secretConfig): + # type: (Any) -> PyPlaintext + """Reads the value of a secret configured by its SecretConfig. + + Args: + secretConfig: The JSON object containing the SecretConfig. + + Returns: + A PyPlaintext instance containing the specified secret. + + Raises: + ValueError: Throws a ValueError if there is no JSON. + SecretException: Throws a SecretException if there is a problem + reading the secret. + """ + if not secretConfig: + raise ValueError("There is no JSON.") + if not isinstance(secretConfig, dict): + raise SecretException("There is a problem eading the secret.") + return PyPlaintext(Plaintext()) + + def readSecretValue(providerName, secretName): # type: (Union[str, unicode], Union[str, unicode]) -> PyPlaintext """Reads the plaintext value of a secret given the name of the diff --git a/stubs/stubs/com/inductiveautomation/ignition/gateway/secrets/__init__.pyi b/stubs/stubs/com/inductiveautomation/ignition/gateway/secrets/__init__.pyi index 7392677..22cc9e4 100644 --- a/stubs/stubs/com/inductiveautomation/ignition/gateway/secrets/__init__.pyi +++ b/stubs/stubs/com/inductiveautomation/ignition/gateway/secrets/__init__.pyi @@ -1,7 +1,8 @@ from typing import Optional, Union from java.io import Closeable -from java.lang import Object +from java.lang import Exception, Object +from java.lang import Throwable as Throwable from java.nio.charset import Charset as Charset class Plaintext(Object, Closeable): @@ -16,3 +17,6 @@ class Plaintext(Object, Closeable): ) -> Plaintext: ... def getAsString(self) -> Union[str, unicode]: ... def getBytes(self) -> bytearray: ... + +class SecretException(Exception): + def __init__(self, message: str, cause: Optional[Throwable] = ...) -> None: ... diff --git a/stubs/stubs/system/secrets.pyi b/stubs/stubs/system/secrets.pyi index a947214..3f63c74 100644 --- a/stubs/stubs/system/secrets.pyi +++ b/stubs/stubs/system/secrets.pyi @@ -5,11 +5,17 @@ from com.inductiveautomation.ignition.common.secrets import ( SecretMeta, SecretProviderMeta, ) +from org.python.core import PyObject +def createEmbeddedSecretConfig(json: Any) -> PyObject: ... +def createReferencedSecretConfig( + providerName: Union[str, unicode], secretName: Union[str, unicode] +) -> PyObject: ... 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 readConfiguredSecretValue(secretConfig: Any) -> PyPlaintext: ... def readSecretValue( providerName: Union[str, unicode], secretName: Union[str, unicode] ) -> PyPlaintext: ... From 35707042919f822f65da09cfafb0ff0dbdb82b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Rom=C3=A1n?= Date: Fri, 17 Jul 2026 16:06:44 -0700 Subject: [PATCH 2/2] style: fix typo in implementation --- src/system/secrets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/secrets.py b/src/system/secrets.py index 5bc1f96..738bf29 100644 --- a/src/system/secrets.py +++ b/src/system/secrets.py @@ -162,7 +162,7 @@ def readConfiguredSecretValue(secretConfig): if not secretConfig: raise ValueError("There is no JSON.") if not isinstance(secretConfig, dict): - raise SecretException("There is a problem eading the secret.") + raise SecretException("There is a problem reading the secret.") return PyPlaintext(Plaintext())