package org.sifappscanplugin.sensor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.exec.CommandLine;
import org.sif.Job;
import org.sif.Notifier;
import org.sif.Publisher;
import org.sif.Reporter;
import org.sif.Sensor;
import org.sif.core.io.SplitOutputStream;
import org.sif.core.concurrency.Executable;
import org.sifappscanplugin.publisher.ASERestServicesClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AppScanSourcePlugin implements Sensor, Publisher, Reporter
{
final Logger logger = LoggerFactory.getLogger( AppScanSourcePlugin.class );
private static final String APPSCAN_SOURCE_EXE = "\\bin\\AppScanSrcCli.exe";
// 90 minute timeout for scans
private int actualTimeout = 5400;
/**
* Need a no-argument constructor to support loading by ServiceLoader.
*/
public AppScanSourcePlugin()
{
}
// public AppScanSourcePlugin(HashMap<String, String> envVarMap, String
// scanWorkspaceDirectory,
// String appScanHomeDirectory, String asseDirectory, PrintStream
// outputStream)
// {
//
// // Set variables from parameters
// this.scanWorkspaceDirectory = scanWorkspaceDirectory;
// this.appScanHomeDirectory = appScanHomeDirectory;
// this.outputStream = outputStream;
// this.asseDirectory = asseDirectory;
//
// this.envVars = envVarMap;
//
// this.asseLogsDirectory = asseDirectory + "\\logs";
// this.assessmentFile = asseDirectory + "\\assessments\\assessment.ozasmt";
// this.filteredAssessmentFile = asseDirectory +
// "\\assessments\\assessment_filtered.ozasmt";
// this.baselineAssessmentFile = asseDirectory +
// "\\assessments\\assessment-baseline.ozasmt";
// this.reportFile = asseDirectory + "\\reports\\report.html";
// this.differentialReportFile = asseDirectory +
// "\\reports\\report-differential.html";
//
// this.asseScriptLocation = asseDirectory + "/resources/cli_script.txt";
// writeResource( "resources/scripts/cli_script.txt",
// this.asseScriptLocation );
//
// this.aseScriptLocation = asseDirectory + "/resources/cli_script_ASE.txt";
// writeResource( "resources/scripts/cli_script_ASE.txt",
// this.aseScriptLocation );
//
// }
private void copyFile(String fromFile, String toFile) throws IOException
{
logger.info( "Writing AppScan Source CLI script from " + fromFile + " to " + toFile );
FileChannel inChannel = new FileInputStream( fromFile ).getChannel();
FileChannel outChannel = new FileOutputStream( toFile ).getChannel();
try
{
inChannel.transferTo( 0, inChannel.size(), outChannel );
}
catch (IOException e)
{
throw e;
}
finally
{
if ( inChannel != null )
inChannel.close();
if ( outChannel != null )
outChannel.close();
}
}
private void copyResource(String resourcePath, String outputPath) throws IOException
{
logger.info( "Writing AppScan Source CLI script from " + resourcePath + " to " + outputPath );
logger.info( "Runtime classpath: " + System.getProperty( "java.class.path" ) );
InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream( resourcePath );
// FIXME: Verify that the resource was found (input != null)
BufferedReader reader = new BufferedReader( new InputStreamReader( input ) );
PrintWriter writer = null;
try
{
writer = new PrintWriter( new BufferedWriter( new FileWriter( resourcePath ) ) );
String line;
while ( ( line = reader.readLine() ) != null )
{
writer.println( line );
}
}
finally
{
if ( writer != null )
{
writer.flush();
writer.close();
}
}
}
private void printConsoleDivider()
{
logger.info( "######################################" );
}
public void addMarkup(String waflPath, String username, String password, String hostname, String installDir)
throws Exception
{
// java -jar AddMarkup.jar
// C:\DDrive\src\frameworkSamples\jsf2Sample\jsf2Sample\src\main\java
// USERNAME PASSWORD HOSTNAME C:\DDrive\IBM\AppScanSource
printConsoleDivider();
logger.info( "Invoking Add Markup" );
HashMap<String, String> environment = new HashMap<String, String>();
// commandLine = "ping -c 10 localhost"; // DEBUG
List<String> commandArray = new ArrayList<String>();
commandArray.add( "java" );
commandArray.add( "-jar" );
commandArray.add( "CustomSolutions.jar" );
commandArray.add( "addCustomMarkup" );
commandArray.add( waflPath );
commandArray.add( username );
commandArray.add( password );
commandArray.add( hostname );
commandArray.add( installDir );
Executable executable = new Executable( commandArray, environment, 0 );
executable.setDirectory( new File( "C:\\DDrive\\JarFiles" ) ); // FIXME:
// Hack!
executable.setOutputStream( System.out );
executable.redirectStdOut( new SplitOutputStream( System.out ) );
executable.redirectStdErr( new SplitOutputStream( System.out ) );
String output = executable.execute( actualTimeout );
// AddMarkup oneLineSetter = new AddMarkup(waflPath, username, password,
// hostname, installDir, outputStream);
}
public void generateDifferentialReport(String installDir, String destinationDir, String baselineAssessment,
String currentAssessment) throws Exception
{
// java -jar CustomSolutions.jar diffReportGen
// C:\DDrive\IBM\AppScanSource
// C:\SCAN\jsf2Sample-Continous-Integration\Scan_Workspace\ASSE\assessments
// C:\SCAN\jsf2Sample-Continous-Integration\Scan_Workspace\ASSE\assessments\assessment-baseline.ozasmt
// C:\SCAN\jsf2Sample-Continous-Integration\Scan_Workspace\ASSE\assessments\assessment.ozasmt
printConsoleDivider();
logger.info( "Invoking Differential Report Generation" );
HashMap<String, String> environment = new HashMap<String, String>();
// commandLine = "ping -c 10 localhost"; // DEBUG
List<String> commandArray = new ArrayList<String>();
commandArray.add( "java" );
commandArray.add( "-jar" );
commandArray.add( "CustomSolutions.jar" );
commandArray.add( "diffReportGen" );
commandArray.add( installDir );
commandArray.add( destinationDir );
commandArray.add( baselineAssessment );
commandArray.add( currentAssessment );
Executable executable = new Executable( commandArray, environment, 0 );
executable.setDirectory( new File( "C:\\DDrive\\JarFiles" ) ); // FIXME:
// Hack!
executable.setOutputStream( System.out );
executable.redirectStdOut( new SplitOutputStream( System.out ) );
executable.redirectStdErr( new SplitOutputStream( System.out ) );
String output = executable.execute( actualTimeout );
// AddMarkup oneLineSetter = new AddMarkup(waflPath, username, password,
// hostname, installDir);
}
@Override
public void sense(Job job, Notifier notifier, Map<String, String> parameters) throws Exception
{
logger.info( this.getClass().getSimpleName() + " performing scan actions" );
HashMap<String, String> environment = new HashMap<String, String>();
// String url = parameters.get( "url" );
// String username = parameters.get( "username" );
// String password = parameters.get( "password" );
// this.scanWorkspaceDirectory = parameters.get( "scanWorkspace.dir" );
// this.appScanHomeDirectory = parameters.get( "appScanSource.dir" );
// this.asseDirectory = parameters.get( "appScanEnterprise.dir" );
// this.assessmentFile = parameters.get( "assessmentFile" );
// System.out.println( "scanWorkspaceDirectory: " +
// scanWorkspaceDirectory );
environment.put( "asse.url", parameters.get( "asse.url" ) );
environment.put( "asse.username", parameters.get( "asse.username" ) );
environment.put( "asse.password", parameters.get( "asse.password" ) );
String scanWorkspaceDirectory = parameters.get( "scanWorkspace.dir" );
String asseDirectory = parameters.get( "asse.dir" );
String sifDirectory = parameters.get( "sif.dir" );
String applicationName = parameters.get( "application" );
String pafFile = new File(scanWorkspaceDirectory, applicationName + ".paf").getPath();
String assessmentFile = new File(scanWorkspaceDirectory, applicationName + ".ozasmt").getPath();
environment.put( "paf.file", pafFile );
environment.put( "assessment.file", assessmentFile );
environment.put( "scan.config", parameters.get( "scan.config" ) );
logger.info( "scanWorkspace.dir: " + parameters.get( "scanWorkspace.dir" ) );
// FIXME: Need to validate all paths (file or dir).
// For the CLI this is: new File(path).exists()
// For the Jenkins plugin it is: new FilePath( new File( this.pafFile )
// ).exists()
// this.envVars = envVarMap;
// this.asseLogsDirectory = asseDirectory + "\\logs";
// this.filteredAssessmentFile = asseDirectory +
// "\\assessments\\assessment_filtered.ozasmt";
// this.baselineAssessmentFile = asseDirectory +
// "\\assessments\\assessment-baseline.ozasmt";
// this.reportFile = asseDirectory + "\\reports\\report.html";
// this.differentialReportFile = asseDirectory +
// "\\reports\\report-differential.html";
// String scriptSourceDirectory = "src/main/resources"; // FIXME: Need to
// // know where
// // SIF is
// // installed
String asseScriptLocation = sifDirectory + "/src/main/resources/cli_script.txt";
// copyFile( scriptSourceDirectory + "/cli_script.txt", asseScriptLocation );
String command = doublequote( asseDirectory + APPSCAN_SOURCE_EXE ) + " script "
+ doublequote( asseScriptLocation );
executeCommand( command, environment );
}
private String doublequote(String s)
{
return "\"" + s + "\"";
}
private String executeCommand(String commandLine) throws Exception
{
return executeCommand( commandLine, new HashMap<String, String>() );
}
private String executeCommand(String commandLine, Map<String, String> environment) throws Exception
{
printConsoleDivider();
logger.info( "Executing command: " + commandLine );
logger.info( "Environment: " + environment );
// commandLine = "ping -c 10 localhost"; // DEBUG
List<String> commandArray = Arrays.asList( CommandLine.parse( commandLine ).toStrings() );
Executable executable = new Executable( commandArray, environment, 0 );
executable.setOutputStream( System.out );
executable.redirectStdOut( new SplitOutputStream( System.out ) );
executable.redirectStdErr( new SplitOutputStream( System.out ) );
String output = executable.execute( actualTimeout );
return output;
}
@Override
public void report(Job job, Notifier notifier, Map<String, String> parameters) throws Exception
{
logger.debug( "Reporting not yet implemented." );
// FIXME: Generate a full or a differential report depending on a
// parameter
}
private void copyEntryToMap(Map<String, String> sourceMap, Map<String, String> destinationMap, String key)
{
destinationMap.put( key, sourceMap.get( key ) );
}
/**
* This should be refactored into an ASE Reporting Console plugin so we can
* decouple ASSE integration and ASE integration.
*
* @param input
* @return
* @throws Exception
*/
@Override
public void publish(Job job, Notifier notifier, Map<String, String> parameters) throws Exception
{
logger.info( this.getClass().getSimpleName() + " performing publish actions" );
HashMap<String, String> environment = new HashMap<String, String>();
PublishParameters publishParameters = new PublishParameters( parameters );
// FIXME: Need error handling
copyEntryToMap( parameters, environment, "asse.url" );
copyEntryToMap( parameters, environment, "asse.username" );
copyEntryToMap( parameters, environment, "asse.password" );
copyEntryToMap( parameters, environment, "asse.acceptSsl" );
copyEntryToMap( parameters, environment, "ase.url" );
copyEntryToMap( parameters, environment, "ase.domain" );
copyEntryToMap( parameters, environment, "ase.username" );
copyEntryToMap( parameters, environment, "ase.password" );
copyEntryToMap( parameters, environment, "paf.file" );
copyEntryToMap( parameters, environment, "assessment.file" );
String scanWorkspaceDirectory = parameters.get( "scanWorkspace.dir" );
String targetFolder = parameters.get( "ase.target.dir" );
String applicationName = parameters.get( "application" );
String pafFile = new File(scanWorkspaceDirectory, applicationName + ".paf").getPath();
String assessmentFile = new File(scanWorkspaceDirectory, applicationName + ".ozasmt").getPath();
environment.put( "paf.file", pafFile );
environment.put( "assessment.file", assessmentFile );
// Create the project folder if necessary
// FIXME: Need error handling here
System.out.println( "ase.target.dir: " + targetFolder );
// targetFolder = targetFolder.substring(0, targetFolder.lastIndexOf("/"));
// FIXME: Should verify that the CloudBees Folders plugin is installed.
ASERestServicesClient aseClient = new ASERestServicesClient(publishParameters.getAseUrl(),
publishParameters.getAseDomain(), publishParameters.getAseUsername(),
publishParameters.getAsePassword(), publishParameters.isAseAcceptSsl());
if (aseClient.createFolderService(targetFolder, "", ""))
logger.debug("Folder created: " + targetFolder);
else
logger.debug("Folder not created: " + targetFolder);
// Get the folder id of the project folder
int id = aseClient.getFolderIdService(targetFolder);
// Publish to the folder id
publish( job, notifier, parameters, environment, id );
}
/**
* This is only if the launcher needs to get the id of a published project folder, for example, to email
* the project owner a link to the project's web page in the ASE front end.
* Don't really need this if we maintain a map of all id:folder pairs.
*
* @param folder
* @param url
* @param domain
* @param username
* @param password
* @param asseptSsl
* @return
* @throws Exception
*/
public int doGetFolderId(String folder, String url, String domain, String username, String password,
boolean asseptSsl) throws Exception
{
int id;
logger.info( "doGetFolderId called on: " + folder + ", " + url + ", " + domain + ", " + username + ", "
+ password + ", " + asseptSsl );
// Translate from the Jenkins job folder to the ASE publishing folder.
// folder = "ASE/" + folder; // FIXME: Rude
// FIXME: Need error handling here
// folder = folder.substring(0, folder.lastIndexOf("/"));
logger.info( "getting folder ID for: " + folder );
ASERestServicesClient aseClient = new ASERestServicesClient( url, domain, username, password, asseptSsl );
id = aseClient.getFolderIdService( folder );
logger.info( "Folder ID: " + id );
return id;
}
String publish(Job job, Notifier notifier, Map<String, String> parameters, Map<String, String> environment, int id)
throws Exception
{
logger.info( "Publishing to folder id " + id );
environment.put( "ase.dest.id", Integer.toString( id ) );
// String scriptSourceDirectory = "src/main/resources"; // FIXME: Need to
// know where
// SIF is
// installed
String asseDirectory = parameters.get( "asse.dir" );
String sifDirectory = parameters.get( "sif.dir" );
// String scanWorkspaceDirectory = parameters.get( "scanWorkspace.dir" );
// String aseScriptLocation = scanWorkspaceDirectory + "/scripts/cli_script_ASE.txt";
// copyFile( scriptSourceDirectory + "/cli_script_ASE.txt", aseScriptLocation );
String aseScriptLocation = sifDirectory + "/src/main/resources/cli_script_ASE.txt";
String command = doublequote( asseDirectory + APPSCAN_SOURCE_EXE ) + " script "
+ doublequote( aseScriptLocation );
logger.info( "Invoke AppScan Source command: " + command );
return executeCommand( command, environment );
}
class PublishParameters
{
private String asseUrl;
private String asseUsername;
private String assePassword;
private boolean asseAcceptSsl;
private String aseUrl;
private String aseDomain;
private String aseUsername;
private String asePassword;
private boolean aseAcceptSsl;
private String assessmentFile;
private String targetDir;
public PublishParameters(Map<String, String> parameters)
{
// FIXME: At least check for any missing parameters here.
asseUrl = parameters.get( "asse.url" );
asseUsername = parameters.get( "asse.username" );
assePassword = parameters.get( "asse.password" );
asseAcceptSsl = Boolean.valueOf( parameters.get( "asse.acceptSsl" ) );
aseUrl = parameters.get( "ase.url" );
aseUsername = parameters.get( "ase.username" );
asePassword = parameters.get( "ase.password" );
aseAcceptSsl = Boolean.valueOf( parameters.get( "ase.acceptSsl" ) );
assessmentFile = parameters.get( "assessment.file" );
targetDir = parameters.get( "ase.target.dir" );
}
public String getAsseUrl()
{
return asseUrl;
}
public String getAsseUsername()
{
return asseUsername;
}
public String getAssePassword()
{
return assePassword;
}
public boolean isAsseAcceptSsl()
{
return asseAcceptSsl;
}
public String getAseUrl()
{
return aseUrl;
}
public String getAseDomain()
{
return aseDomain;
}
public String getAseUsername()
{
return aseUsername;
}
public String getAsePassword()
{
return asePassword;
}
public boolean isAseAcceptSsl()
{
return aseAcceptSsl;
}
public String getAssessmentFile()
{
return assessmentFile;
}
public String getTargetDir()
{
return targetDir;
}
}
}