From 0e9c87114734ce88c059e9ca76cb6aa872feadaa Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Wed, 1 Oct 2025 22:04:29 +0530 Subject: [PATCH 1/8] obfuscate the secret variable --- api/core/helper/encrypter.py | 58 +++++++++++++++++++++ api/core/workflow/nodes/agent/agent_node.py | 17 +++++- api/core/workflow/nodes/code/code_node.py | 18 ++++++- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/api/core/helper/encrypter.py b/api/core/helper/encrypter.py index 17345dc203..181c1b977b 100644 --- a/api/core/helper/encrypter.py +++ b/api/core/helper/encrypter.py @@ -1,4 +1,6 @@ import base64 +from collections.abc import Mapping +from typing import Any, overload from libs import rsa @@ -42,3 +44,59 @@ def get_decrypt_decoding(tenant_id: str): def decrypt_token_with_decoding(token: str, rsa_key, cipher_rsa): return rsa.decrypt_token_with_decoding(base64.b64decode(token), rsa_key, cipher_rsa) + + +# ========================= +# encrypt_secret_keys +# ========================= + + +# Overloads to preserve input type +@overload +def encrypt_secret_keys( + obj: Mapping[str, Any], + secret_variables: list[str] | None = None, + parent_key: str | None = None, +) -> Mapping[str, Any]: ... + + +@overload +def encrypt_secret_keys( + obj: list[Any], + secret_variables: list[str] | None = None, + parent_key: str | None = None, +) -> list[Any]: ... + + +@overload +def encrypt_secret_keys( + obj: Any, + secret_variables: list[str] | None = None, + parent_key: str | None = None, +) -> Any: ... + + +def encrypt_secret_keys( + obj: Any, + secret_variables: list[str] | None = None, + parent_key: str | None = None, +) -> Any: + """ + Recursively obfuscate the value if it belongs to a Secret Variable. + Preserves input type: dict -> dict, list -> list, scalar -> scalar. + """ + secret_variables = secret_variables or [] + + if isinstance(obj, dict): + # recurse into dict + return {key: encrypt_secret_keys(value, secret_variables, key) for key, value in obj.items()} + + elif isinstance(obj, list): + # recurse into all list elements + return [encrypt_secret_keys(value, secret_variables, None) for value in obj] + + else: + # leaf node: obfuscate if parent_key is a secret variable + if parent_key in secret_variables: + return obfuscated_token(str(obj)) + return obj diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index a01686a4b8..c7643854e6 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -10,6 +10,7 @@ from sqlalchemy.orm import Session from core.agent.entities import AgentToolEntity from core.agent.plugin_entities import AgentStrategyParameter from core.file import File, FileTransferMethod +from core.helper import encrypter from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance, ModelManager from core.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata @@ -24,6 +25,7 @@ from core.tools.entities.tool_entities import ( ) from core.tools.tool_manager import ToolManager from core.tools.utils.message_transformer import ToolFileMessageTransformer +from core.variables import SecretVariable from core.variables.segments import ArrayFileSegment, StringSegment from core.workflow.entities import VariablePool from core.workflow.enums import ( @@ -139,6 +141,15 @@ class AgentNode(Node): # get conversation id conversation_id = self.graph_runtime_state.variable_pool.get(["sys", SystemVariableKey.CONVERSATION_ID]) + env_vars = self.graph_runtime_state.variable_pool.variable_dictionary.get("env", {}) + + # get secret variables used + secret_variables = [ + var.name + for var in env_vars.values() # iterate over the values directly + if isinstance(var, SecretVariable) + ] + try: message_stream = strategy.invoke( params=parameters, @@ -171,6 +182,7 @@ class AgentNode(Node): node_type=self.node_type, node_id=self._node_id, node_execution_id=self.id, + secret_variables=secret_variables, ) except PluginDaemonClientSideError as e: transform_error = AgentMessageTransformError( @@ -488,6 +500,7 @@ class AgentNode(Node): node_type: NodeType, node_id: str, node_execution_id: str, + secret_variables: list[str] | None = None, ) -> Generator[NodeEventBase, None, None]: """ Convert ToolInvokeMessages into tuple[plain_text, files] @@ -671,9 +684,9 @@ class AgentNode(Node): parent_id=message.message.parent_id, error=message.message.error, status=message.message.status.value, - data=message.message.data, + data=encrypter.encrypt_secret_keys(message.message.data, secret_variables, None), label=message.message.label, - metadata=message.message.metadata, + metadata=encrypter.encrypt_secret_keys(message.message.metadata, secret_variables, None), node_id=node_id, ) diff --git a/api/core/workflow/nodes/code/code_node.py b/api/core/workflow/nodes/code/code_node.py index c87cbf9628..a5ef001c2f 100644 --- a/api/core/workflow/nodes/code/code_node.py +++ b/api/core/workflow/nodes/code/code_node.py @@ -3,10 +3,12 @@ from decimal import Decimal from typing import Any, cast from configs import dify_config +from core.helper import encrypter from core.helper.code_executor.code_executor import CodeExecutionError, CodeExecutor, CodeLanguage from core.helper.code_executor.code_node_provider import CodeNodeProvider from core.helper.code_executor.javascript.javascript_code_provider import JavascriptCodeProvider from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider +from core.variables import SecretVariable from core.variables.segments import ArrayFileSegment from core.variables.types import SegmentType from core.workflow.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus @@ -73,15 +75,24 @@ class CodeNode(Node): code_language = self._node_data.code_language code = self._node_data.code + # to store secret variables used in the code block. + secret_variables = [] + # Get variables variables = {} for variable_selector in self._node_data.variables: variable_name = variable_selector.variable variable = self.graph_runtime_state.variable_pool.get(variable_selector.value_selector) + if isinstance(variable, SecretVariable): + secret_variables.append(variable_name) + if isinstance(variable, ArrayFileSegment): variables[variable_name] = [v.to_dict() for v in variable.value] if variable.value else None else: variables[variable_name] = variable.to_object() if variable else None + + obfuscated_variables = encrypter.encrypt_secret_keys(variables, secret_variables, None) + # Run code try: result = CodeExecutor.execute_workflow_code_template( @@ -94,10 +105,13 @@ class CodeNode(Node): result = self._transform_result(result=result, output_schema=self._node_data.outputs) except (CodeExecutionError, CodeNodeError) as e: return NodeRunResult( - status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, error=str(e), error_type=type(e).__name__ + status=WorkflowNodeExecutionStatus.FAILED, + inputs=obfuscated_variables, + error=str(e), + error_type=type(e).__name__, ) - return NodeRunResult(status=WorkflowNodeExecutionStatus.SUCCEEDED, inputs=variables, outputs=result) + return NodeRunResult(status=WorkflowNodeExecutionStatus.SUCCEEDED, inputs=obfuscated_variables, outputs=result) def _check_string(self, value: str | None, variable: str) -> str | None: """ From 0ab42454627ddde76758b1c34369edbdfaf05317 Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Fri, 3 Oct 2025 21:20:19 +0530 Subject: [PATCH 2/8] code structure as per rules --- .../workflow/nodes/test_code.py | 71 ++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index e2f3a74bf9..2700ffbe02 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -5,6 +5,8 @@ from os import getenv import pytest from core.app.entities.app_invoke_entities import InvokeFrom +from core.helper import encrypter +from core.variables import SecretVariable from core.workflow.entities import GraphInitParams, GraphRuntimeState, VariablePool from core.workflow.enums import WorkflowNodeExecutionStatus from core.workflow.graph import Graph @@ -18,7 +20,7 @@ from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_co CODE_MAX_STRING_LENGTH = int(getenv("CODE_MAX_STRING_LENGTH", "10000")) -def init_code_node(code_config: dict): +def init_code_node(code_config: dict, with_defaults=True): graph_config = { "edges": [ { @@ -45,7 +47,7 @@ def init_code_node(code_config: dict): variable_pool = VariablePool( system_variables=SystemVariable(user_id="aaa", files=[]), user_inputs={}, - environment_variables=[], + environment_variables=[SecretVariable(name="secret_key", value="fake-secret-key")], conversation_variables=[], ) variable_pool.add(["code", "args1"], 1) @@ -394,3 +396,68 @@ def test_execute_code_scientific_notation(setup_code_executor_mock): result = node._run() assert isinstance(result, NodeRunResult) assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED + + +def test_execute_code_obfuscate_secret_variables(monkeypatch): + monkeypatch.setenv("MOCK_SWITCH", "false") + code = """ + def main(argument1: str): + return { + "result": argument1, + } + """ + # trim first 4 spaces at the beginning of each line + code = "\n".join([line[4:] for line in code.split("\n")]) + + variables = [ + { + "variable": "argument1", + "value_selector": ["env", "secret_key"], + }, + ] + code_config = { + "id": "secret_environment_code", + "data": { + "type": "code", + "outputs": { + "result": { + "type": "string", + }, + }, + "title": "secret_obfus", + "variables": variables, + "answer": "fake-secret-key", + "code_language": "python3", + "code": code, + }, + } + + node = init_code_node(code_config, False) + # Variable with values replaced with env variables + replaced_variables = node.graph_runtime_state.variable_pool.variable_dictionary.get("env", {}) + + secret_variable_value_map = {} + for var in replaced_variables.values(): + if isinstance(var, SecretVariable): + secret_variable_value_map[var.name] = var.value + + input_variables_argument_map = { + var["variable"]: var["value_selector"][1] for var in variables if var.get("value_selector", [None])[0] == "env" + } + + input_argument_value_map = { + k: secret_variable_value_map[v] + for k, v in input_variables_argument_map.items() + if v in secret_variable_value_map + } + + # execute node + result = node._run() + + assert isinstance(result, NodeRunResult) + assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED + assert result.outputs is not None + for name, value in result.inputs.items(): + if input_argument_value_map.get(name): + assert value == encrypter.obfuscated_token(input_argument_value_map.get(name)) + assert result.error == "" From 21035cfca0157e5dac9ee1138ae0f426ad9dcad9 Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Wed, 8 Oct 2025 22:09:13 +0530 Subject: [PATCH 3/8] use set for better performance --- api/core/helper/encrypter.py | 11 ++++++----- api/core/workflow/nodes/agent/agent_node.py | 6 +++--- api/core/workflow/nodes/code/code_node.py | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/api/core/helper/encrypter.py b/api/core/helper/encrypter.py index 181c1b977b..13f1024eec 100644 --- a/api/core/helper/encrypter.py +++ b/api/core/helper/encrypter.py @@ -55,7 +55,7 @@ def decrypt_token_with_decoding(token: str, rsa_key, cipher_rsa): @overload def encrypt_secret_keys( obj: Mapping[str, Any], - secret_variables: list[str] | None = None, + secret_variables: set[str] | None = None, parent_key: str | None = None, ) -> Mapping[str, Any]: ... @@ -63,7 +63,7 @@ def encrypt_secret_keys( @overload def encrypt_secret_keys( obj: list[Any], - secret_variables: list[str] | None = None, + secret_variables: set[str] | None = None, parent_key: str | None = None, ) -> list[Any]: ... @@ -71,21 +71,22 @@ def encrypt_secret_keys( @overload def encrypt_secret_keys( obj: Any, - secret_variables: list[str] | None = None, + secret_variables: set[str] | None = None, parent_key: str | None = None, ) -> Any: ... def encrypt_secret_keys( obj: Any, - secret_variables: list[str] | None = None, + secret_variables: set[str] | None = None, parent_key: str | None = None, ) -> Any: """ Recursively obfuscate the value if it belongs to a Secret Variable. Preserves input type: dict -> dict, list -> list, scalar -> scalar. """ - secret_variables = secret_variables or [] + if secret_variables is None: + secret_variables = set() if isinstance(obj, dict): # recurse into dict diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index c7643854e6..3ad26ea0ba 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -144,11 +144,11 @@ class AgentNode(Node): env_vars = self.graph_runtime_state.variable_pool.variable_dictionary.get("env", {}) # get secret variables used - secret_variables = [ + secret_variables = { var.name for var in env_vars.values() # iterate over the values directly if isinstance(var, SecretVariable) - ] + } try: message_stream = strategy.invoke( @@ -500,7 +500,7 @@ class AgentNode(Node): node_type: NodeType, node_id: str, node_execution_id: str, - secret_variables: list[str] | None = None, + secret_variables: set[str] | None = None, ) -> Generator[NodeEventBase, None, None]: """ Convert ToolInvokeMessages into tuple[plain_text, files] diff --git a/api/core/workflow/nodes/code/code_node.py b/api/core/workflow/nodes/code/code_node.py index a5ef001c2f..41ad3ceab3 100644 --- a/api/core/workflow/nodes/code/code_node.py +++ b/api/core/workflow/nodes/code/code_node.py @@ -76,7 +76,7 @@ class CodeNode(Node): code = self._node_data.code # to store secret variables used in the code block. - secret_variables = [] + secret_variables = set() # Get variables variables = {} @@ -84,7 +84,7 @@ class CodeNode(Node): variable_name = variable_selector.variable variable = self.graph_runtime_state.variable_pool.get(variable_selector.value_selector) if isinstance(variable, SecretVariable): - secret_variables.append(variable_name) + secret_variables.add(variable_name) if isinstance(variable, ArrayFileSegment): variables[variable_name] = [v.to_dict() for v in variable.value] if variable.value else None From 2468e57f52590f59a4312e7cbad58da0078d0054 Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Mon, 13 Oct 2025 16:24:35 +0530 Subject: [PATCH 4/8] for agentNode include all types like sys, env etc. --- api/core/helper/encrypter.py | 2 +- api/core/workflow/nodes/agent/agent_node.py | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/api/core/helper/encrypter.py b/api/core/helper/encrypter.py index 13f1024eec..a4e1d7c601 100644 --- a/api/core/helper/encrypter.py +++ b/api/core/helper/encrypter.py @@ -88,7 +88,7 @@ def encrypt_secret_keys( if secret_variables is None: secret_variables = set() - if isinstance(obj, dict): + if isinstance(obj, Mapping): # recurse into dict return {key: encrypt_secret_keys(value, secret_variables, key) for key, value in obj.items()} diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index 3ad26ea0ba..04f50ee0f6 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -141,14 +141,18 @@ class AgentNode(Node): # get conversation id conversation_id = self.graph_runtime_state.variable_pool.get(["sys", SystemVariableKey.CONVERSATION_ID]) - env_vars = self.graph_runtime_state.variable_pool.variable_dictionary.get("env", {}) - - # get secret variables used - secret_variables = { - var.name - for var in env_vars.values() # iterate over the values directly - if isinstance(var, SecretVariable) - } + # to store secret variables used in the Agent block. + secret_variables = set() + # get secret variables used. + for section_vars in self.graph_runtime_state.variable_pool.variable_dictionary.values(): + # Iterate over all the sections. e.g. sys, env etc. + if isinstance(section_vars, dict): + # Iterate over each variable in the section + for variable in section_vars.values(): + # Check if the variable is a SecretVariable + if isinstance(variable, SecretVariable): + # Add the variable name to the set + secret_variables.add(variable.name) try: message_stream = strategy.invoke( From 2871a2f2788a8dc1b6756d20b892f7aaf2c88c47 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 19 Oct 2025 18:53:17 +0000 Subject: [PATCH 5/8] [autofix.ci] apply automated fixes --- api/tests/integration_tests/workflow/nodes/test_code.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 47b157315d..f3d369b545 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -8,7 +8,6 @@ from core.app.entities.app_invoke_entities import InvokeFrom from core.helper import encrypter from core.variables import SecretVariable from core.workflow.entities import GraphInitParams, GraphRuntimeState, VariablePool -from core.workflow.entities import GraphInitParams from core.workflow.enums import WorkflowNodeExecutionStatus from core.workflow.graph import Graph from core.workflow.node_events import NodeRunResult From b848224c78a311ef444585c2975b503dcbd6991a Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Fri, 31 Oct 2025 22:56:39 +0530 Subject: [PATCH 6/8] removed integration case as it needs sanbox service to be up, added unit test case for secret variables encryption --- .../workflow/nodes/test_code.py | 65 ------------------- .../unit_tests/core/helper/test_encrypter.py | 54 +++++++++++++++ 2 files changed, 54 insertions(+), 65 deletions(-) diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 8ddf09d125..8476209ce9 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -396,68 +396,3 @@ def test_execute_code_scientific_notation(setup_code_executor_mock): result = node._run() assert isinstance(result, NodeRunResult) assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED - - -def test_execute_code_obfuscate_secret_variables(monkeypatch): - monkeypatch.setenv("MOCK_SWITCH", "false") - code = """ - def main(argument1: str): - return { - "result": argument1, - } - """ - # trim first 4 spaces at the beginning of each line - code = "\n".join([line[4:] for line in code.split("\n")]) - - variables = [ - { - "variable": "argument1", - "value_selector": ["env", "secret_key"], - }, - ] - code_config = { - "id": "secret_environment_code", - "data": { - "type": "code", - "outputs": { - "result": { - "type": "string", - }, - }, - "title": "secret_obfus", - "variables": variables, - "answer": "fake-secret-key", - "code_language": "python3", - "code": code, - }, - } - - node = init_code_node(code_config, False) - # Variable with values replaced with env variables - replaced_variables = node.graph_runtime_state.variable_pool.variable_dictionary.get("env", {}) - - secret_variable_value_map = {} - for var in replaced_variables.values(): - if isinstance(var, SecretVariable): - secret_variable_value_map[var.name] = var.value - - input_variables_argument_map = { - var["variable"]: var["value_selector"][1] for var in variables if var.get("value_selector", [None])[0] == "env" - } - - input_argument_value_map = { - k: secret_variable_value_map[v] - for k, v in input_variables_argument_map.items() - if v in secret_variable_value_map - } - - # execute node - result = node._run() - - assert isinstance(result, NodeRunResult) - assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED - assert result.outputs is not None - for name, value in result.inputs.items(): - if input_argument_value_map.get(name): - assert value == encrypter.obfuscated_token(input_argument_value_map.get(name)) - assert result.error == "" diff --git a/api/tests/unit_tests/core/helper/test_encrypter.py b/api/tests/unit_tests/core/helper/test_encrypter.py index 5890009742..4883b9a5a4 100644 --- a/api/tests/unit_tests/core/helper/test_encrypter.py +++ b/api/tests/unit_tests/core/helper/test_encrypter.py @@ -10,6 +10,7 @@ from core.helper.encrypter import ( encrypt_token, get_decrypt_decoding, obfuscated_token, + encrypt_secret_keys, ) from libs.rsa import PrivkeyNotFoundError @@ -36,6 +37,59 @@ class TestObfuscatedToken: assert token not in obfuscated assert "*" * 12 in obfuscated + def test_encrypt_secret_keys_simple_dict(self): + data = { + "api_key": "fake-secret-key", + "username": "admin" + } + secret_vars = {"api_key"} + + result = encrypt_secret_keys(data, secret_vars) + + # api_key should be obfuscated + assert result["api_key"] == obfuscated_token("fake-secret-key") + # username should remain unchanged + assert result["username"] == "admin" + + def test_encrypt_secret_keys_nested_dict(self): + data = { + "outer": { + "inner_secret": "super-secret", + "inner_public": "visible" + }, + "non_secret": "plain" + } + secret_vars = {"inner_secret"} + + result = encrypt_secret_keys(data, secret_vars) + + assert result["outer"]["inner_secret"] == obfuscated_token("super-secret") + assert result["outer"]["inner_public"] == "visible" + assert result["non_secret"] == "plain" + + def test_encrypt_secret_keys_list_of_dicts(self): + data = [ + {"token1": "abc123", "id": 1}, + {"token2": "xyz789", "id": 2} + ] + secret_vars = {"token1","token2"} + + result = encrypt_secret_keys(data, secret_vars) + + assert result[0]["token1"] == obfuscated_token("abc123") + assert result[1]["token2"] == obfuscated_token("xyz789") + assert result[0]["id"] == 1 + + + def test_encrypt_secret_keys_non_secret_scalar(self): + # When the object is just a string, it should remain unchanged + result = encrypt_secret_keys("hello-world", secret_variables={"api_key"}) + assert result == "hello-world" + + def test_encrypt_secret_keys_handles_empty_inputs(self): + assert encrypt_secret_keys({}, {"secret"}) == {} + assert encrypt_secret_keys([], {"secret"}) == [] + assert encrypt_secret_keys(None, {"secret"}) is None class TestEncryptToken: @patch("models.engine.db.session.query") From ef1392dc57d42287c234779cffc3e8c51ab879ad Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Fri, 31 Oct 2025 22:59:31 +0530 Subject: [PATCH 7/8] format code as per rules --- .../workflow/nodes/test_code.py | 1 - .../unit_tests/core/helper/test_encrypter.py | 24 +++++-------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 8476209ce9..0b603705cc 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -5,7 +5,6 @@ import pytest from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom -from core.helper import encrypter from core.variables import SecretVariable from core.workflow.entities import GraphInitParams, GraphRuntimeState, VariablePool from core.workflow.enums import WorkflowNodeExecutionStatus diff --git a/api/tests/unit_tests/core/helper/test_encrypter.py b/api/tests/unit_tests/core/helper/test_encrypter.py index 4883b9a5a4..ec9adf0db0 100644 --- a/api/tests/unit_tests/core/helper/test_encrypter.py +++ b/api/tests/unit_tests/core/helper/test_encrypter.py @@ -7,10 +7,10 @@ import pytest from core.helper.encrypter import ( batch_decrypt_token, decrypt_token, + encrypt_secret_keys, encrypt_token, get_decrypt_decoding, obfuscated_token, - encrypt_secret_keys, ) from libs.rsa import PrivkeyNotFoundError @@ -38,10 +38,7 @@ class TestObfuscatedToken: assert "*" * 12 in obfuscated def test_encrypt_secret_keys_simple_dict(self): - data = { - "api_key": "fake-secret-key", - "username": "admin" - } + data = {"api_key": "fake-secret-key", "username": "admin"} secret_vars = {"api_key"} result = encrypt_secret_keys(data, secret_vars) @@ -52,13 +49,7 @@ class TestObfuscatedToken: assert result["username"] == "admin" def test_encrypt_secret_keys_nested_dict(self): - data = { - "outer": { - "inner_secret": "super-secret", - "inner_public": "visible" - }, - "non_secret": "plain" - } + data = {"outer": {"inner_secret": "super-secret", "inner_public": "visible"}, "non_secret": "plain"} secret_vars = {"inner_secret"} result = encrypt_secret_keys(data, secret_vars) @@ -68,11 +59,8 @@ class TestObfuscatedToken: assert result["non_secret"] == "plain" def test_encrypt_secret_keys_list_of_dicts(self): - data = [ - {"token1": "abc123", "id": 1}, - {"token2": "xyz789", "id": 2} - ] - secret_vars = {"token1","token2"} + data = [{"token1": "abc123", "id": 1}, {"token2": "xyz789", "id": 2}] + secret_vars = {"token1", "token2"} result = encrypt_secret_keys(data, secret_vars) @@ -80,7 +68,6 @@ class TestObfuscatedToken: assert result[1]["token2"] == obfuscated_token("xyz789") assert result[0]["id"] == 1 - def test_encrypt_secret_keys_non_secret_scalar(self): # When the object is just a string, it should remain unchanged result = encrypt_secret_keys("hello-world", secret_variables={"api_key"}) @@ -91,6 +78,7 @@ class TestObfuscatedToken: assert encrypt_secret_keys([], {"secret"}) == [] assert encrypt_secret_keys(None, {"secret"}) is None + class TestEncryptToken: @patch("models.engine.db.session.query") @patch("libs.rsa.encrypt") From 1994582278c8882c385ffa5424003fbe6b1b2e8c Mon Sep 17 00:00:00 2001 From: Pankaj Kaushal Date: Fri, 31 Oct 2025 23:50:24 +0530 Subject: [PATCH 8/8] remove unwanted code --- api/tests/integration_tests/workflow/nodes/test_code.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 1b05da7bd4..78878cdeef 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -5,8 +5,7 @@ import pytest from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom -from core.variables import SecretVariable -from core.workflow.entities import GraphInitParams, GraphRuntimeState, VariablePool +from core.workflow.entities import GraphInitParams from core.workflow.enums import WorkflowNodeExecutionStatus from core.workflow.graph import Graph from core.workflow.node_events import NodeRunResult @@ -20,7 +19,7 @@ from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_co CODE_MAX_STRING_LENGTH = dify_config.CODE_MAX_STRING_LENGTH -def init_code_node(code_config: dict, with_defaults=True): +def init_code_node(code_config: dict): graph_config = { "edges": [ { @@ -47,7 +46,7 @@ def init_code_node(code_config: dict, with_defaults=True): variable_pool = VariablePool( system_variables=SystemVariable(user_id="aaa", files=[]), user_inputs={}, - environment_variables=[SecretVariable(name="secret_key", value="fake-secret-key")], + environment_variables=[], conversation_variables=[], ) variable_pool.add(["code", "args1"], 1)