com.ibm.appscan.bamboo.plugin.impl.SASTScanner.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.appscan.bamboo.plugin.impl.SASTScanner.java

Source

/**
 * (c) Copyright IBM Corporation 2016.
 * LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0
 */

package com.ibm.appscan.bamboo.plugin.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.SystemUtils;

import com.atlassian.bamboo.build.LogEntry;
import com.atlassian.bamboo.process.ExternalProcessBuilder;
import com.atlassian.bamboo.process.ProcessService;
import com.atlassian.bamboo.task.TaskContext;
import com.atlassian.bamboo.task.TaskException;
import com.atlassian.bamboo.variable.VariableContext;
import com.atlassian.bamboo.variable.VariableDefinitionContext;
import com.atlassian.utils.process.ExternalProcess;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SASTScanner implements ISASTConstants, IJSONConstants {

    private static final String APPSCAN_OPTS = "APPSCAN_OPTS"; //$NON-NLS-1$
    private static final String APPSCAN_INTERVAL = "APPSCAN_INTERVAL"; //$NON-NLS-1$

    private static final String STATUS_FAILED = "Failed"; //$NON-NLS-1$
    private static final String STATUS_READY = "Ready"; //$NON-NLS-1$

    private static final int MIN_TIME_TO_SLEEP = 30;
    private static final int TIME_TO_SLEEP = 120;
    private static final int MAX_CONSEC_FAILS = 5;

    private LogHelper logger;
    private ProcessService processService;

    private String username;
    private String password;

    private File workingDir;
    private String utilPath;

    private String irxBaseName;
    private String jobId;

    private long high;
    private long medium;
    private long low;

    public SASTScanner(LogHelper logger, ProcessService processService) {
        this.logger = logger;
        this.processService = processService;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setWorkingDir(File workingDir) {
        this.workingDir = workingDir;
    }

    public void setUtilPath(String utilPath) {
        if (SystemUtils.IS_OS_WINDOWS)
            this.utilPath = utilPath + "\\bin\\appscan.bat"; //$NON-NLS-1$
        else
            this.utilPath = utilPath + "/bin/appscan.sh"; //$NON-NLS-1$
    }

    private String getVariableValue(TaskContext taskContext, String name) {
        VariableContext variables = taskContext.getBuildContext().getVariableContext();
        VariableDefinitionContext variable = variables.getEffectiveVariables().get(name);
        return variable == null ? null : variable.getValue();
    }

    private ExternalProcessBuilder createExternalProcessBuilder(TaskContext taskContext, String... commands) {

        ExternalProcessBuilder builder = new ExternalProcessBuilder();
        builder.workingDirectory(workingDir);

        String appscanOpts = getVariableValue(taskContext, APPSCAN_OPTS);
        if (appscanOpts != null)
            builder.env(APPSCAN_OPTS, appscanOpts);

        List<String> list = new ArrayList<String>();
        list.add(utilPath);
        list.addAll(Arrays.asList(commands));
        builder.command(list);

        return builder;
    }

    public void generateIRX(TaskContext taskContext, IArtifactPublisher publisher) throws TaskException {

        irxBaseName = taskContext.getBuildContext().getBuildResultKey();

        logger.info("generate.irx", irxBaseName, workingDir); //$NON-NLS-1$

        ExternalProcess process = processService.executeExternalProcess(taskContext,
                createExternalProcessBuilder(taskContext, "prepare", //$NON-NLS-1$
                        "-n", irxBaseName)); //$NON-NLS-1$

        publisher.publishArtifact(taskContext, "IRX", workingDir, irxBaseName + "*.*"); //$NON-NLS-1$ //$NON-NLS-2$

        int exitCode = process.getHandler().getExitCode();
        if (exitCode != 0)
            throw new TaskException(logger.getText("generate.irx.failed", exitCode)); //$NON-NLS-1$
    }

    private String getLastLogEntry(TaskContext taskContext) {

        List<LogEntry> logs = taskContext.getBuildLogger().getLastNLogEntries(2);
        Collections.reverse(logs);

        String text = ""; //$NON-NLS-1$

        for (LogEntry log : logs) {
            text = log.getUnstyledLog();
            if (!text.trim().isEmpty())
                break;
        }

        return text;
    }

    private void loginToASoC(TaskContext taskContext) {
        processService.executeExternalProcess(taskContext, createExternalProcessBuilder(taskContext, "api_login", //$NON-NLS-1$
                "-u", username, //$NON-NLS-1$
                "-P", password, //$NON-NLS-1$
                "-persist")); //$NON-NLS-1$
    }

    public void submitIRX(TaskContext taskContext) throws TaskException {

        logger.info("submit.irx"); //$NON-NLS-1$

        loginToASoC(taskContext);

        String appId = taskContext.getConfigurationMap().get(CFG_APP_ID);

        ExternalProcess process = processService.executeExternalProcess(taskContext,
                createExternalProcessBuilder(taskContext, "queue_analysis", //$NON-NLS-1$
                        "-a", appId, //$NON-NLS-1$
                        "-n", irxBaseName + ".irx")); //$NON-NLS-1$ //$NON-NLS-2$

        int exitCode = process.getHandler().getExitCode();
        if (exitCode != 0)
            throw new TaskException(logger.getText("submit.irx.failed", exitCode)); //$NON-NLS-1$

        jobId = getLastLogEntry(taskContext);
        if (!jobId.matches("^[-0-9a-zA-Z]+$")) //$NON-NLS-1$
            throw new TaskException(logger.getText("submit.irx.failed2")); //$NON-NLS-1$
    }

    private int getTimeToSleep(TaskContext taskContext) {

        String value = getVariableValue(taskContext, APPSCAN_INTERVAL);
        if (value != null) {
            try {
                return Math.max(Integer.parseInt(value), MIN_TIME_TO_SLEEP);
            } catch (NumberFormatException e) {
                // fall through
            }
        }

        return TIME_TO_SLEEP;
    }

    private JsonNode pollForStatus(TaskContext taskContext) {

        processService.executeExternalProcess(taskContext, createExternalProcessBuilder(taskContext, "info", //$NON-NLS-1$
                "-i", jobId, //$NON-NLS-1$
                "-json")); //$NON-NLS-1$

        try {
            return new ObjectMapper().readTree(getLastLogEntry(taskContext));
        } catch (IOException e) {
            return null;
        }
    }

    private boolean isReady(TaskContext taskContext) throws TaskException {

        logger.info("status.check"); //$NON-NLS-1$

        JsonNode response = pollForStatus(taskContext);
        if (response == null) {
            loginToASoC(taskContext);
            response = pollForStatus(taskContext);
            if (response == null)
                throw new StatusCheckException(logger.getText("status.check.failed")); //$NON-NLS-1$
        }

        String status = response.at(STATUS).asText(STATUS_FAILED);
        logger.info("status.check.is", status); //$NON-NLS-1$

        if (!STATUS_FAILED.equals(status)) {

            if (!STATUS_READY.equals(status))
                return false;

            high = response.at(HIGH).asLong(-1);
            medium = response.at(MEDIUM).asLong(-1);
            low = response.at(LOW).asLong(-1);

            return true;
        }

        throw new TaskException(logger.getText("scan.failed")); //$NON-NLS-1$
    }

    public void waitForReady(TaskContext taskContext) throws TaskException, InterruptedException {

        int consecFails = 0;

        for (;;) {

            Thread.sleep(getTimeToSleep(taskContext) * 1000L);

            try {
                if (isReady(taskContext))
                    return;

                consecFails = 0;
            } catch (StatusCheckException e) {
                if (++consecFails == MAX_CONSEC_FAILS)
                    throw e;
            }
        }
    }

    public void downloadResult(TaskContext taskContext, IArtifactPublisher publisher) throws TaskException {

        logger.info("download.result"); //$NON-NLS-1$

        String html = irxBaseName + ".html"; //$NON-NLS-1$

        ExternalProcess process = processService.executeExternalProcess(taskContext,
                createExternalProcessBuilder(taskContext, "get_result", //$NON-NLS-1$
                        "-i", jobId, //$NON-NLS-1$
                        "-d", html)); //$NON-NLS-1$

        publisher.publishArtifact(taskContext, logger.getText("result.artifact"), workingDir, html); //$NON-NLS-1$

        int exitCode = process.getHandler().getExitCode();
        if (exitCode != 0)
            throw new TaskException(logger.getText("download.result.failed", exitCode)); //$NON-NLS-1$
    }

    public long getHighCount() {
        return high;
    }

    public long getMediumCount() {
        return medium;
    }

    public long getLowCount() {
        return low;
    }
}