diff --git a/lib/galaxy/tool_util/deps/requirements.py b/lib/galaxy/tool_util/deps/requirements.py
index 7865bdb59435..b77566cc3cd9 100644
--- a/lib/galaxy/tool_util/deps/requirements.py
+++ b/lib/galaxy/tool_util/deps/requirements.py
@@ -306,28 +306,64 @@ def resource_requirements_from_list(requirements: Iterable[Dict[str, Any]]) -> L
return rr
-class SecretOrVariable:
+class Secret:
+ def __init__(
+ self,
+ name: str,
+ inject_as_env: str,
+ label: str = "",
+ description: str = "",
+ ) -> None:
+ self.name = name
+ self.inject_as_env = inject_as_env
+ self.label = label
+ self.description = description
+ if not self.inject_as_env:
+ raise ValueError("Missing inject_as_env")
+
+ def to_dict(self) -> Dict[str, Any]:
+ return {
+ "name": self.name,
+ "inject_as_env": self.inject_as_env,
+ "label": self.label,
+ "description": self.description,
+ }
+
+ @classmethod
+ def from_element(cls, elem) -> "Secret":
+ return cls(
+ name=elem.get("name"),
+ inject_as_env=elem.get("inject_as_env"),
+ label=elem.get("label", ""),
+ description=elem.get("description", ""),
+ )
+
+ @classmethod
+ def from_dict(cls, dict: Dict[str, Any]) -> "Secret":
+ name = dict["name"]
+ inject_as_env = dict["inject_as_env"]
+ label = dict.get("label", "")
+ description = dict.get("description", "")
+ return cls(name=name, inject_as_env=inject_as_env, label=label, description=description)
+
+
+class Variable:
def __init__(
self,
- type: str,
name: str,
inject_as_env: str,
label: str = "",
description: str = "",
) -> None:
- self.type = type
self.name = name
self.inject_as_env = inject_as_env
self.label = label
self.description = description
- if self.type not in {"secret", "variable"}:
- raise ValueError(f"Invalid credential type '{self.type}'")
if not self.inject_as_env:
raise ValueError("Missing inject_as_env")
def to_dict(self) -> Dict[str, Any]:
return {
- "type": self.type,
"name": self.name,
"inject_as_env": self.inject_as_env,
"label": self.label,
@@ -335,9 +371,8 @@ def to_dict(self) -> Dict[str, Any]:
}
@classmethod
- def from_element(cls, elem) -> "SecretOrVariable":
+ def from_element(cls, elem) -> "Variable":
return cls(
- type=elem.tag,
name=elem.get("name"),
inject_as_env=elem.get("inject_as_env"),
label=elem.get("label", ""),
@@ -345,13 +380,12 @@ def from_element(cls, elem) -> "SecretOrVariable":
)
@classmethod
- def from_dict(cls, dict: Dict[str, Any]) -> "SecretOrVariable":
- type = dict["type"]
+ def from_dict(cls, dict: Dict[str, Any]) -> "Variable":
name = dict["name"]
inject_as_env = dict["inject_as_env"]
label = dict.get("label", "")
description = dict.get("description", "")
- return cls(type=type, name=name, inject_as_env=inject_as_env, label=label, description=description)
+ return cls(name=name, inject_as_env=inject_as_env, label=label, description=description)
class CredentialsRequirement:
@@ -359,17 +393,21 @@ def __init__(
self,
name: str,
reference: str,
- required: bool = False,
+ optional: bool = True,
+ multiple: bool = False,
label: str = "",
description: str = "",
- secrets_and_variables: Optional[List[SecretOrVariable]] = None,
+ secrets: Optional[List[Secret]] = None,
+ variables: Optional[List[Variable]] = None,
) -> None:
self.name = name
self.reference = reference
- self.required = required
+ self.optional = optional
+ self.multiple = multiple
self.label = label
self.description = description
- self.secrets_and_variables = secrets_and_variables if secrets_and_variables is not None else []
+ self.secrets = secrets if secrets is not None else []
+ self.variables = variables if variables is not None else []
if not self.reference:
raise ValueError("Missing reference")
@@ -378,27 +416,33 @@ def to_dict(self) -> Dict[str, Any]:
return {
"name": self.name,
"reference": self.reference,
- "required": self.required,
+ "optional": self.optional,
+ "multiple": self.multiple,
"label": self.label,
"description": self.description,
- "secrets_and_variables": [s.to_dict() for s in self.secrets_and_variables],
+ "secrets": [s.to_dict() for s in self.secrets],
+ "variables": [v.to_dict() for v in self.variables],
}
@classmethod
def from_dict(cls, dict: Dict[str, Any]) -> "CredentialsRequirement":
name = dict["name"]
reference = dict["reference"]
- required = dict.get("required", False)
+ optional = dict.get("optional", True)
+ multiple = dict.get("multiple", False)
label = dict.get("label", "")
description = dict.get("description", "")
- secrets_and_variables = [SecretOrVariable.from_dict(s) for s in dict.get("secrets_and_variables", [])]
+ secrets = [Secret.from_dict(s) for s in dict.get("secrets", [])]
+ variables = [Variable.from_dict(v) for v in dict.get("variables", [])]
return cls(
name=name,
reference=reference,
- required=required,
+ optional=optional,
+ multiple=multiple,
label=label,
description=description,
- secrets_and_variables=secrets_and_variables,
+ secrets=secrets,
+ variables=variables,
)
@@ -490,15 +534,19 @@ def container_from_element(container_elem) -> ContainerDescription:
def credentials_from_element(credentials_elem) -> CredentialsRequirement:
name = credentials_elem.get("name")
reference = credentials_elem.get("reference")
- required = string_as_bool(credentials_elem.get("required", "false"))
+ optional = string_as_bool(credentials_elem.get("optional", "true"))
+ multiple = string_as_bool(credentials_elem.get("multiple", "false"))
label = credentials_elem.get("label", "")
description = credentials_elem.get("description", "")
- secrets_and_variables = [SecretOrVariable.from_element(elem) for elem in credentials_elem.findall("*")]
+ secrets = [Secret.from_element(elem) for elem in credentials_elem.findall("secret")]
+ variables = [Variable.from_element(elem) for elem in credentials_elem.findall("variable")]
return CredentialsRequirement(
name=name,
reference=reference,
- required=required,
+ optional=optional,
+ multiple=multiple,
label=label,
description=description,
- secrets_and_variables=secrets_and_variables,
+ secrets=secrets,
+ variables=variables,
)
diff --git a/lib/galaxy/tool_util/xsd/galaxy.xsd b/lib/galaxy/tool_util/xsd/galaxy.xsd
index c688fc4f8692..6700dbd18a22 100644
--- a/lib/galaxy/tool_util/xsd/galaxy.xsd
+++ b/lib/galaxy/tool_util/xsd/galaxy.xsd
@@ -739,11 +739,11 @@ It can contain multiple ``variable`` and ``secret`` tags.
```xml
-
-
-
-
-
+
+
+
+
+
```
]]>
@@ -772,9 +772,14 @@ It can contain multiple ``variable`` and ``secret`` tags.
The description of the credential set.
-
+
- Whether the credentials are required for the tool to run.
+ Whether the credentials are optional for the tool to run.
+
+
+
+
+ Indicates multiple sets of credentials can be provided.
diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py
index 286283e4e0b4..77d23113d6c7 100644
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2667,6 +2667,27 @@ def to_json(self, trans, kwd=None, job=None, workflow_building_mode=False, histo
state_inputs_json: ToolStateDumpedToJsonT = params_to_json(self.inputs, state_inputs, self.app)
+ credentials = []
+ for credential in self.credentials:
+ credential_dict = credential.to_dict()
+ credential_dict["variables"] = [
+ {
+ "name": variable.name,
+ "label": variable.label,
+ "description": variable.description,
+ }
+ for variable in credential.variables
+ ]
+ credential_dict["secrets"] = [
+ {
+ "name": secret.name,
+ "label": secret.label,
+ "description": secret.description,
+ }
+ for secret in credential.secrets
+ ]
+ credentials.append(credential_dict)
+
# update tool model
tool_model.update(
{
@@ -2679,6 +2700,7 @@ def to_json(self, trans, kwd=None, job=None, workflow_building_mode=False, histo
"warnings": tool_warnings,
"versions": self.tool_versions,
"requirements": [{"name": r.name, "version": r.version} for r in self.requirements],
+ "credentials": credentials,
"errors": state_errors,
"tool_errors": self.tool_errors,
"state_inputs": state_inputs_json,
diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py
index bbb72308cc1e..12d81a55a0be 100644
--- a/lib/galaxy/tools/evaluation.py
+++ b/lib/galaxy/tools/evaluation.py
@@ -195,19 +195,12 @@ def set_compute_environment(self, compute_environment: ComputeEnvironment, get_s
# user_vault = UserVaultWrapper(app.vault, self._user)
for credentials in self.tool.credentials:
reference = credentials.reference
- for secret_or_variable in credentials.secrets_and_variables:
- if secret_or_variable.type == "variable":
- # variable_value = self.param_dict.get(f"{reference}/{secret_or_variable.name}")
- variable_value = f"A variable: {reference}/{secret_or_variable.name}"
- self.environment_variables.append(
- {"name": secret_or_variable.inject_as_env, "value": variable_value}
- )
- elif secret_or_variable.type == "secret":
- # secret_value = user_vault.read_secret(f"{reference}/{secret_or_variable.name}")
- secret_value = f"A secret: {reference}/{secret_or_variable.name}"
- self.environment_variables.append(
- {"name": secret_or_variable.inject_as_env, "value": secret_value}
- )
+ for secret in credentials.secret:
+ secret_value = f"{reference}/{secret.name}"
+ self.environment_variables.append({"name": secret.inject_as_env, "value": secret_value})
+ for variable in credentials.variable:
+ variable_value = f"{reference}/{variable.name}"
+ self.environment_variables.append({"name": variable.inject_as_env, "value": variable_value})
def execute_tool_hooks(self, inp_data, out_data, incoming):
# Certain tools require tasks to be completed prior to job execution
diff --git a/test/functional/tools/secret_tool.xml b/test/functional/tools/secret_tool.xml
index bbcf9b7f91a3..998bf14dcb1a 100644
--- a/test/functional/tools/secret_tool.xml
+++ b/test/functional/tools/secret_tool.xml
@@ -1,15 +1,15 @@
-
+
+
+
+
+
'$output'
+echo \$service1_url > '$output' && echo \$service1_user >> '$output' && echo \$service1_pass >> '$output'
]]>
-
-
-
-
diff --git a/test/integration/test_vault_extra_prefs.py b/test/integration/test_vault_extra_prefs.py
index 2fde51a0201a..d9166a553b8a 100644
--- a/test/integration/test_vault_extra_prefs.py
+++ b/test/integration/test_vault_extra_prefs.py
@@ -11,11 +11,12 @@
)
from galaxy.model.db.user import get_user_by_email
-from galaxy_test.api.test_tools import TestsTools
-from galaxy_test.base.populators import (
- DatasetPopulator,
- skip_without_tool,
-)
+
+# from galaxy_test.api.test_tools import TestsTools
+# from galaxy_test.base.populators import (
+# DatasetPopulator,
+# skip_without_tool,
+# )
from galaxy_test.driver import integration_util
TEST_USER_EMAIL = "vault_test_user@bx.psu.edu"
diff --git a/test/unit/tool_util/test_parsing.py b/test/unit/tool_util/test_parsing.py
index 169d69ff8759..ea4ddb1f334f 100644
--- a/test/unit/tool_util/test_parsing.py
+++ b/test/unit/tool_util/test_parsing.py
@@ -50,10 +50,10 @@
1
2
67108864
-
-
-
-
+
+
+
+
@@ -368,11 +368,9 @@ def test_credentials(self):
*_, credentials = self._tool_source.parse_requirements_and_containers()
assert credentials[0].name == "Apollo"
assert credentials[0].reference == "gmod.org/apollo"
- assert credentials[0].required
- assert len(credentials[0].secrets_and_variables) == 3
- assert credentials[0].secrets_and_variables[0].type == "variable"
- assert credentials[0].secrets_and_variables[1].type == "secret"
- assert credentials[0].secrets_and_variables[2].type == "secret"
+ assert credentials[0].optional
+ assert len(credentials[0].secrets) == 2
+ assert len(credentials[0].variables) == 1
def test_outputs(self):
outputs, output_collections = self._tool_source.parse_outputs(object())