Integrate security tools with GitLab

  • Release version: Australia
  • Updated March 12, 2026
  • 3 minutes to read
  • Configure security tool for GitLab which is not supported in the base system.

    Before you begin

    Role required: sn_devops.admin

    Procedure

    1. Navigate to DevOps > Integrations > Tool Integrations and open the GitLab orchestration tool integration record.
    2. Navigate to the Tool Integration Capability Mappings related list.
    3. Select New, and enter the following values in the form fields.
      Field Value
      Tool integration GitLab
      Tool type capability Security
      Tool Integration Capability Mapping form for GitLab
    4. Select Submit.
    5. Navigate to the Integration Capabilities related list, and select New.
    6. Enter the following values in the form fields.
      Field Value
      Tool integration GitLab
      Capability mapping Capability mapping record created in step 4.
      Action Notification
      Note:
      Do not edit tool action records.
      Active Selected
      Timeout (ms) Timeout for the corresponding subflow. If execution of the subflow exceeds this value, a timeout exception occurs. Value is in milliseconds (ms). Default is 45,000 (45 seconds).
      Subflow name sn_devops_vul_ints.devops_security_notification
      Domain global
      Integration capability form for GitLab
      Note:
      Deactivate the BR Seeded tool integrations not editable business rule to integrate security tools with GitLab.
    7. Modify the sn_devops_ints.DevOpsGitLabIntegrationHandler script include by navigating to System definitions > Script include, and searching for the DevOpsGitLabIntegrationHandler script.
      1. Modify the handleEvent method to process the security scan results from the GitLab pipeline. Ensure that your security stage name in your GitLab pipeline is same as the name you update in the VERACODE_STAGE_NAME, CMARX_ONE_STAGE_NAME, or CMARX_SAST_STAGE_NAME variable in the handleEvent method. Replace the handleEvent method code with the following code snippet.
         handleEvent: function(eventGr) {
            try {
                var renameHandler = new sn_devops.DevOpsPipelineRenameHandler(this.refTable, this.appContext, this.relatedRecord);
                renameHandler.handlePipelineRename(eventGr);
                var payload = JSON.parse(eventGr.getValue("original_payload"));
                this._logger.debug("typeof payload >>" + typeof payload);
                if (!gs.nil(payload) && typeof payload === 'object') {
                    var status = this.getTaskExecutionStatus(payload);
                    this._logger.debug("Task Execution status -> " + status);
                    if (gs.nil(status))
                        this.updateInboundEvent(eventGr, {
                            processing_details: gs.getMessage('Task execution status [{0}] is not handled', payload.build_status),
                            state: sn_devops.DevOpsCommonConstants.INBOUND_EVENT_STATE_IGNORED
                        });
                    else {
                        // create fake start event for cancelled job
                        if (status == 'cancelled') {
                            this.createFakeEvent(eventGr, payload, 'running');
                        }
                        var normalizedObject = {};
                        normalizedObject.taskExecution = this.getTaskExecutionObject(eventGr, payload, status);
                        normalizedObject.orchestrationTask = this.getOrchestrationTaskObject(normalizedObject.taskExecution, payload);
                        normalizedObject.callback = this.getCallbackObject(normalizedObject.taskExecution, payload);
                        var devopsUtil = new sn_devops.DevOpsUtil(this.refTable, this.appContext, this.relatedRecord);
                        normalizedObject = devopsUtil.schemaValidationForTransformedPayload(normalizedObject);
                        var VERACODE_STAGE_NAME = 'SN_VERACODE';
                        var CMARX_ONE_STAGE_NAME = 'SN_CMARX_ONE_STAGE_NAME';
                        var CMARX_SAST_STAGE_NAME = 'SN_CMARX_SAST_STAGE_NAME';
                        if (!gs.nil(payload.build_stage) && 
                            (   
                                payload.build_stage == VERACODE_STAGE_NAME ||
                                payload.build_stage == CMARX_ONE_STAGE_NAME ||
                                payload.build_stage == CMARX_SAST_STAGE_NAME 
                            )
                            && this.isCompleted(normalizedObject.taskExecution)) {
                            var queryParams = sn_devops.DevOpsQueryParamsHelper.convertToSingular(JSON.parse(eventGr.getValue('query_params')));
                            if (gs.nil(normalizedObject.taskExecution.securityScan)) {
                                normalizedObject.taskExecution.securityScan = {
                                    securityScanSummaryCount: 0
                                };
                            }
                            normalizedObject.taskExecution.securityScan.securityScanSummaryCount += 1;
                        }
                        this._logger.debug("Normalized Object: " + JSON.stringify(normalizedObject));
                        return JSON.stringify(normalizedObject);
                    }
                } else
                    this.updateInboundEvent(eventGr, {
                        processing_details: gs.getMessage('Payload is missing or invalid'),
                        state: sn_devops.DevOpsCommonConstants.INBOUND_EVENT_STATE_ERROR
                    });
            } catch (error) {
                throw sn_devops.DevOpsErrorHelper.createDevOpsScriptIncludeError(error, sn_devops_ints.DevOpsIntegrationsCommonMessages.GITLAB_INBOUND_EVENT_PROCESS_ISSUE, "DevOpsGitLabIntegrationHandler.handleEvent", "handleEvent");
            }
        },

        In the following examples the GitLab pipeline shows that the security stage name is same as the VERACODE_STAGE_NAME, CMARX_ONE_STAGE_NAME, or CMARX_SAST_STAGE_NAME variables respectively in the handleEvent method.

        VERACODE_STAGE_NAME is for Veracode.
        image: maven:latest
        stages:
          - build
          - SN_VERACODE
          - Deploy
        
        build_1:
          stage: build
          tags:
            - local-runner1
          script:
            - echo "build"
            
        security_test:
          stage: SN_VERACODE
          tags:
            - local-runner1
          script:
            - |
              curl "https://<instance>.service-now.com/api/sn_devops/v1/devops/tool/security?toolId=<gitlab_tool_sys_id> " \
                --request POST \
                --header "Accept:application/json" \
                --header "Content-Type:application/json" \
                --data "{
                      \"pipelineInfo\": {
                        \"buildNumber\": \"${CI_JOB_ID}\",
                        \"taskExecutionUrl\": \"${CI_JOB_URL}/\"
                      },
                      \"securityResultAttributes\": {
                        \"scanner\": \"Veracode\",
                        \"applicationName\": \"Application\"
                      }
                    }" \
                --user 'devops.system':’password’
        
        

        CMARX_ONE_STAGE_NAME is for Checkmarx One.

        image: maven:latest
        stages:
          - build
          - SN_CMARX_ONE_STAGE_NAME
          - Deploy
        
        build_1:
          stage: build
          tags:
            - local-runner1
          script:
            - echo "build"
            
        security_test:
          stage: SN_CMARX_ONE_STAGE_NAME
          tags:
            - local-runner1
          script:
            - |
              curl "https://<instance>.service-now.com/api/sn_devops/v1/devops/tool/security?toolId=<gitlab_tool_sys_id> " \
                --request POST \
                --header "Accept:application/json" \
                --header "Content-Type:application/json" \
                --data "{
                      \"pipelineInfo\": {
                        \"buildNumber\": \"${CI_JOB_ID}\",
                        \"taskExecutionUrl\": \"${CI_JOB_URL}/\"
                      },
                      \"securityResultAttributes\": {
                        \"scanner\": \"Checkmarx One\",
                        \"projectId\": \"projectId\",
                        \"scanId\": \"scanId\",
                      }
                    }" \
                --user 'devops.system':’password’

        CMARX_SAST_STAGE_NAME is for Checkmarx SAST.

        image: maven:latest
        stages:
          - build
          - SN_CMARX_SAST_STAGE_NAME
          - Deploy
        
        build_1:
          stage: build
          tags:
            - local-runner1
          script:
            - echo "build"
            
        security_test:
          stage: SN_CMARX_SAST_STAGE_NAME
          tags:
            - local-runner1
          script:
            - |
              curl "https://<instance>.service-now.com/api/sn_devops/v1/devops/tool/security?toolId=<gitlab_tool_sys_id> " \
                --request POST \
                --header "Accept:application/json" \
                --header "Content-Type:application/json" \
                --data "{
                      \"pipelineInfo\": {
                        \"buildNumber\": \"${CI_JOB_ID}\",
                        \"taskExecutionUrl\": \"${CI_JOB_URL}/\"
                      },
                      \"securityResultAttributes\": {
                        \"scanner\": \"Checkmarx\",
                        \"projectId\": \"projectId\"
                      }
                    }" \
                --user 'devops.system':’password’
      2. Add the getPipelineWithSecurityEventPayload method to the DevOpsGitLabIntegrationHandler script.
        getPipelineWithSecurityEventPayload: function(payload) {
                var gr = new GlideRecordSecure('sn_devops_task_execution');
                gr.addEncodedQuery("execution_url=" + payload.pipelineInfo.taskExecutionUrl);
                gr.query();
                var task = null;
                if (gr.next()) {
                    task = gr;
                }
                if (gs.nil(task) || gs.nil(task.orchestration_task) || gs.nil(task.orchestration_task.step)) {
                    throw "Pipeline Info not found";
                }
                var step = task.orchestration_task.step.getRefRecord();
                var pipelineDAO = new sn_devops.DevOpsPipelineDAO();
                var query = 'sys_id=' + step.pipeline;
                var pipeline = pipelineDAO.getLimitedRecordsByEncodedQuery(query);
                return pipeline;
            },