Urgent Help Needed: ServiceNow to Jira Attachment Issue (Corrupted Files)

Andrea34
Tera Contributor

Good afternoon everyone, I hope you're doing well.

I'm reaching out for urgent assistance regarding an issue with a business rule that triggers when an attachment is added to a change request in ServiceNow. The rule is supposed to transfer the attachment to the corresponding issue in Jira, but it's not working correctly.

The main problem is that when the attachment is uploaded to Jira, its size doubles, making the file corrupted. I have attempted the following solutions without success:

  • GlideScriptedStream
  • Uint8Array
  • GlideBufferedInputStream
  • Setting Content-Type: application/octet-stream with setRequestBodyFromStream() (throws an error)
  • Using FORM DATA results in a 500 error

I urgently need your help in resolving this issue. Below is my current script:

 

 

 

 

 

(function executeRule(current, previous /*null when async*/) {
    gs.info("La Business Rule se está ejecutando. Adjunto: " + current.file_name);

    if (current.table_name.toLowerCase() == "change_request") {
        var changeTaskGR = new GlideRecord("change_request");

        if (changeTaskGR.get(current.table_sys_id)) {
            var jiraIssueId = changeTaskGR.getValue("u_id_hu");

            if (jiraIssueId) {
                gs.info("Jira Issue ID encontrado: " + jiraIssueId);

                // Enviar solo adjuntos nuevos
                sendNewAttachmentsToJira(
                    current.table_sys_id,
                    jiraIssueId,
                    "change_request",
                    current.sys_created_on
                );
            } else {
                gs.warn("El campo u_nreferens no tiene valor en la change_task con sys_id: " + current.table_sys_id);
            }
        } else {
            gs.warn("No se encontró un registro change_task con sys_id: " + current.table_sys_id);
        }
    }
})(current, previous);

function sendNewAttachmentsToJira(sysId, jiraIssueId, tableName, currentCreatedOn) {
    var attachmentGR = new GlideRecord("sys_attachment");
    attachmentGR.addQuery("table_name", tableName);
    attachmentGR.addQuery("table_sys_id", sysId);
    attachmentGR.addQuery("sys_created_on", ">=", currentCreatedOn);
    attachmentGR.query();

    while (attachmentGR.next()) {
        var fileName = attachmentGR.file_name;
        var contentType = attachmentGR.content_type;
        var attachmentSize = attachmentGR.size_bytes; // Tamaño del archivo

        // 🔍 Obtener el contenido del archivo en formato binario
        var attachmentContent = new GlideSysAttachment().getBytes(attachmentGR);

        if (!attachmentContent || attachmentContent.length === 0) {
            gs.warn("El archivo está vacío o no se pudo leer, no se enviará.");
            continue;
        }

        gs.info("📌 Archivo: " + fileName);
        gs.info("📏 Tamaño original en ServiceNow (bytes): " + attachmentSize);
        gs.info("📏 Tamaño obtenido con getBytes() (bytes): " + attachmentContent.length);

        var boundary = "----WebKitFormBoundary" + gs.generateGUID();
        var newLine = "\r\n";

        //  **Construcción del cuerpo multipart correctamente**
        var requestBody = "";
        requestBody += "--" + boundary + newLine;
        requestBody += 'Content-Disposition: form-data; name="file"; filename="' + fileName + '"' + newLine;
        requestBody += "Content-Type: " + contentType + newLine + newLine;

        var endBoundary = newLine + "--" + boundary + "--" + newLine;

        // 🟢 Crear un flujo de datos binario correctamente
        var combinedRequestBody = new GlideScriptedStream();
        combinedRequestBody.writeString(requestBody);
        combinedRequestBody.writeBytes(attachmentContent);
        combinedRequestBody.writeString(endBoundary);

        // 🔍 Medir el tamaño del cuerpo de la solicitud
        var requestSize = requestBody.length + attachmentContent.length + endBoundary.length;
        gs.info("📏 Tamaño final del request en binario (bytes): " + requestSize);

        var attachmentRequest = new sn_ws.RESTMessageV2();
        attachmentRequest.setHttpMethod("POST");
        attachmentRequest.setEndpoint(
            "https://{user_instance}.atlassian.net/rest/api/3/issue/" +
            jiraIssueId +
            "/attachments"
        );

        var base64Auth = GlideStringUtil.base64Encode(
            "user" + ":" + "user_token"
        );

        attachmentRequest.setRequestHeader("Authorization", "Basic " + base64Auth);
        attachmentRequest.setRequestHeader("X-Atlassian-Token", "no-check");
        attachmentRequest.setRequestHeader("Accept", "application/json");
        attachmentRequest.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

        //  **Enviar el archivo en formato binario puro**
        attachmentRequest.setBinaryBody(combinedRequestBody, "multipart/form-data");

        try {
            var attachmentResponse = attachmentRequest.execute();
            var status = attachmentResponse.getStatusCode();
            var responseBody = attachmentResponse.getBody();

            if (status == 200 || status == 201) {
                gs.info(
                    ' Attachment "' + fileName + '" subido exitosamente a Jira issue ID: ' + jiraIssueId
                );
            } else {
                gs.warn("⚠️ No se pudo subir el attachment. Status: " + status + ", Respuesta: " + responseBody);
            }
        } catch (ex) {
            gs.error(" Error al subir el attachment a Jira: " + ex.message);
        }
    }
}

 

 

 

7 REPLIES 7

Si necesito usar script include o otras cosas por favor dime, necesito una solución con urgencia 

Creo que lo que debes hacer es exactamente lo que tenemos en la comunidad en el enlace a continuación.


Prueba esto y si no puedes hacerlo házmelo saber, podemos programar una sesión para que pueda ayudarte con esto.

 

Business rule to send attachment to 3rd Party Tool via REST

Unable to send attachment via REST

Si mi respuesta te ayudó a llegar a la solución, ayúdame marcándola como la respuesta correcta.

- Carlos Petrucio

¿Lograste resolverlo?

Si mi respuesta te ayudó a llegar a la solución, ayúdame marcándola como la respuesta correcta.

- Carlos Petrucio