Copilot commented on code in PR #12715:
URL: https://github.com/apache/gravitino/pull/12715#discussion_r3894476113


##########
docs/open-api/jobs.yaml:
##########
@@ -586,6 +586,10 @@ components:
           format: date-time
           nullable: true
           description: The time when the job finished execution, or null if 
the job has not finished execution yet
+        runtimeJobTemplate:
+          description: The resolved job template that was actually submitted 
for execution, with placeholders replaced and referenced files downloaded. 
Omitted for jobs run before this field was introduced
+          allOf:
+            - $ref: "#/components/schemas/JobTemplate"

Review Comment:
   The API description states this field can be omitted for older jobs, but the 
server-side behavior/tests also indicate it may be present as `null` (e.g., 
malformed stored JSON or missing historical data). To match actual responses, 
mark `runtimeJobTemplate` as `nullable: true` (and keep it non-required). 
Optionally replace `allOf` with a direct `$ref` unless you plan to extend it 
with additional constraints.



##########
clients/client-python/gravitino/dto/job/job_template_dto.py:
##########
@@ -97,17 +97,25 @@ def validate(self) -> None:
             raise ValueError('"executable" is required and cannot be empty')
 
     @classmethod
-    def from_json(
-        cls, s: str, infer_missing: bool = False, **kwargs
+    def from_dict_by_type(
+        cls, data: Dict, infer_missing: bool = False
     ) -> "JobTemplateDTO":
-        """Creates a JobTemplateDTO from a JSON string."""
-        data = json.loads(s)
+        """Creates a JobTemplateDTO from a dict, dispatching to the concrete 
subclass based
+        on the "jobType" field.
+        """
         job_type = JobType.job_type_deserialize(data.get("jobType"))
         subclass = JOB_TYPE_TEMPLATE_MAPPING.get(job_type)
         if not subclass:
             raise ValueError(f"Unsupported job type: {job_type}")
         return subclass.from_dict(data, infer_missing=infer_missing)
 
+    @classmethod
+    def from_json(
+        cls, s: str, infer_missing: bool = False, **kwargs
+    ) -> "JobTemplateDTO":
+        """Creates a JobTemplateDTO from a JSON string."""
+        return cls.from_dict_by_type(json.loads(s), 
infer_missing=infer_missing)

Review Comment:
   `from_json(..., **kwargs)` now silently ignores `**kwargs`, which can be 
confusing for callers and makes future changes harder (it looks like kwargs are 
supported but they aren’t). Consider either removing `**kwargs` from the 
signature, or explicitly documenting that kwargs are ignored; if backward 
compatibility requires keeping it, pass through supported options where 
applicable.



##########
common/src/main/java/org/apache/gravitino/dto/util/DTOConverters.java:
##########
@@ -1413,6 +1415,82 @@ public static JobTemplate fromDTO(JobTemplateDTO 
jobTemplateDTO) {
     }
   }
 
+  /**
+   * Converts a JobTemplate to a JobTemplateDTO.
+   *
+   * @param jobTemplate The job template to be converted.
+   * @param audit The audit information to attach to the DTO. A bare {@link 
JobTemplate} carries no
+   *     audit info of its own, so the caller supplies it (e.g. the 
originating template entity's
+   *     audit info, when serializing a resolved runtime template).
+   * @return The job template DTO.
+   */
+  public static JobTemplateDTO toDTO(JobTemplate jobTemplate, AuditDTO audit) {
+    switch (jobTemplate.jobType()) {
+      case SHELL:
+        ShellJobTemplate shellJobTemplate = (ShellJobTemplate) jobTemplate;
+        return ShellJobTemplateDTO.builder()
+            .withName(shellJobTemplate.name())
+            .withComment(shellJobTemplate.comment())
+            .withJobType(shellJobTemplate.jobType())
+            .withExecutable(shellJobTemplate.executable())
+            .withArguments(shellJobTemplate.arguments())
+            .withEnvironments(shellJobTemplate.environments())
+            .withCustomFields(shellJobTemplate.customFields())
+            .withScripts(shellJobTemplate.scripts())
+            .withAudit(audit)
+            .build();
+
+      case SPARK:
+        SparkJobTemplate sparkJobTemplate = (SparkJobTemplate) jobTemplate;
+        return SparkJobTemplateDTO.builder()
+            .withName(sparkJobTemplate.name())
+            .withComment(sparkJobTemplate.comment())
+            .withJobType(sparkJobTemplate.jobType())
+            .withExecutable(sparkJobTemplate.executable())
+            .withArguments(sparkJobTemplate.arguments())
+            .withEnvironments(sparkJobTemplate.environments())
+            .withCustomFields(sparkJobTemplate.customFields())
+            .withClassName(sparkJobTemplate.className())
+            .withJars(sparkJobTemplate.jars())
+            .withFiles(sparkJobTemplate.files())
+            .withArchives(sparkJobTemplate.archives())
+            .withConfigs(sparkJobTemplate.configs())
+            .withAudit(audit)
+            .build();
+
+      default:
+        throw new IllegalArgumentException(
+            "Unsupported job template type: " + jobTemplate.jobType());
+    }
+  }
+
+  /**
+   * Deserializes a job entity's stored runtime job template JSON, if any, 
back into a {@link
+   * JobTemplateDTO}. {@link JobTemplateDTO}'s {@code @JsonTypeInfo} handles 
the Shell/Spark
+   * dispatch automatically.
+   *
+   * @param runtimeJobTemplateJson The serialized runtime job template, or 
null if the job has none.
+   * @param jobName The name of the job the template belongs to, used in the 
error message on
+   *     failure.
+   * @return The deserialized job template DTO, or null if 
runtimeJobTemplateJson is null.
+   */
+  public static JobTemplateDTO fromRuntimeJobTemplateJson(
+      String runtimeJobTemplateJson, String jobName) {
+    if (runtimeJobTemplateJson == null) {
+      return null;
+    }
+
+    try {
+      return JsonUtils.anyFieldMapper().readValue(runtimeJobTemplateJson, 
JobTemplateDTO.class);
+    } catch (JsonProcessingException e) {
+      throw new RuntimeException(
+          String.format(
+              "Failed to deserialize the runtime job template for job %s, raw 
content: %s",
+              jobName, runtimeJobTemplateJson),
+          e);
+    }
+  }

Review Comment:
   The exception message includes the full raw runtime template JSON, which can 
contain sensitive data (e.g., environment variables, custom fields, local 
paths) and can also introduce log-injection risk if logged (newlines/control 
chars). Prefer not embedding full raw content in exception messages; instead 
include safe metadata (job id, content length, a hash, and/or a 
truncated/sanitized prefix) and keep full content only behind an explicit debug 
flag if needed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to