This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new 3dcd82b8e1 fix(workflow-operator): mask the HF API token field as a
password widget (#7215)
3dcd82b8e1 is described below
commit 3dcd82b8e1602e3fa44b5121f09c9cb2c8d3b86b
Author: Prateek Ganigi <[email protected]>
AuthorDate: Sun Aug 2 16:59:13 2026 -0700
fix(workflow-operator): mask the HF API token field as a password widget
(#7215)
### What changes were proposed in this PR?
The HuggingFace inference operator's `hfApiToken` field was a plain text
input, the token was visible in the property panel and stored verbatim
in the workflow JSON. This adds `@JsonSchemaInject(json =
UIWidget.UIWidgetPassword)` to the field so it renders as a masked
password input, following the same convention the SQL source operators
(`SQLSourceOpDesc`) already use for their password field.
### Any related issues, documentation, discussions?
Closes #7193.
### How was this PR tested?
`sbt "WorkflowOperator/testOnly
org.apache.texera.amber.operator.huggingFace.*
org.apache.texera.amber.operator.metadata.*"`: the Hugging Face suite
and the operator-metadata specs pass (146 tests). This includes a new
test asserting the generated JSON schema marks `hfApiToken` as a
password widget (`widget.formlyConfig.templateOptions.type ==
"password"`), and the `metadata.*` specs confirm operator-schema
generation still succeeds. scalafmt clean.
The password widget is a schema-only change reusing an existing, shipped
mechanism (`UIWidget.UIWidgetPassword`, already used by the SQL source
operators), so no UI change was needed.
### Was this PR authored or co-authored using generative AI tooling?
Yes, this PR was co-authored with Claude Opus 4.8 in compliance with
ASF.
---
.../operator/huggingFace/HuggingFaceInferenceOpDesc.scala | 5 +++--
.../huggingFace/HuggingFaceInferenceOpDescSpec.scala | 14 ++++++++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git
a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDesc.scala
b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDesc.scala
index c08084135b..6599625ddf 100644
---
a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDesc.scala
+++
b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDesc.scala
@@ -20,7 +20,7 @@
package org.apache.texera.amber.operator.huggingFace
import com.fasterxml.jackson.annotation.{JsonProperty, JsonPropertyDescription}
-import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaTitle
+import com.kjetland.jackson.jsonSchema.annotations.{JsonSchemaInject,
JsonSchemaTitle}
import org.apache.texera.amber.core.tuple.{AttributeType, Schema}
import org.apache.texera.amber.core.workflow.{InputPort, OutputPort,
PortIdentity}
import org.apache.texera.amber.operator.PythonOperatorDescriptor
@@ -34,7 +34,7 @@ import org.apache.texera.amber.operator.huggingFace.codegen.{
TaskCodegen,
TextGenCodegen
}
-import
org.apache.texera.amber.operator.metadata.annotations.AutofillAttributeName
+import
org.apache.texera.amber.operator.metadata.annotations.{AutofillAttributeName,
UIWidget}
import org.apache.texera.amber.operator.metadata.{OperatorGroupConstants,
OperatorInfo}
import org.apache.texera.amber.pybuilder.PyStringTypes.EncodableString
@@ -65,6 +65,7 @@ class HuggingFaceInferenceOpDesc extends
PythonOperatorDescriptor {
@JsonPropertyDescription(
"Your Hugging Face API token (from https://huggingface.co/settings/tokens)"
)
+ @JsonSchemaInject(json = UIWidget.UIWidgetPassword)
var hfApiToken: EncodableString = ""
@JsonProperty(value = "task", required = true, defaultValue =
"text-generation")
diff --git
a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
index 7fcfe541bf..99eb14ed6f 100644
---
a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
+++
b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
@@ -32,6 +32,7 @@ import
org.apache.texera.amber.operator.metadata.OperatorGroupConstants
import org.apache.texera.amber.pybuilder.PyStringTypes.EncodableString
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
+import org.apache.texera.amber.operator.metadata.OperatorMetadataGenerator
class HuggingFaceInferenceOpDescSpec extends AnyFlatSpec with Matchers {
@@ -647,4 +648,17 @@ class HuggingFaceInferenceOpDescSpec extends AnyFlatSpec
with Matchers {
val outSchema = out(desc.operatorInfo.outputPorts.head.id)
outSchema.getAttributeNames.contains("hf_response") shouldBe true
}
+
+ it should "mask the API token field as a password widget in the generated
schema" in {
+ val tokenProp = OperatorMetadataGenerator
+ .generateOperatorJsonSchema(classOf[HuggingFaceInferenceOpDesc])
+ .path("properties")
+ .path("hfApiToken")
+ tokenProp
+ .path("widget")
+ .path("formlyConfig")
+ .path("templateOptions")
+ .path("type")
+ .asText() shouldBe "password"
+ }
}