2020-05-25 19:48:59 +02:00
package fortify
import (
"bytes"
2021-02-26 14:43:03 +02:00
"encoding/base64"
2020-05-25 19:48:59 +02:00
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
ff "github.com/piper-validation/fortify-client-go/fortify"
"github.com/piper-validation/fortify-client-go/fortify/artifact_of_project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/attribute_of_project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/auth_entity_of_project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/file_token_controller"
"github.com/piper-validation/fortify-client-go/fortify/filter_set_of_project_version_controller"
2022-02-08 15:10:40 +02:00
"github.com/piper-validation/fortify-client-go/fortify/issue_audit_comment_of_issue_controller"
2020-05-25 19:48:59 +02:00
"github.com/piper-validation/fortify-client-go/fortify/issue_group_of_project_version_controller"
2022-02-08 15:10:40 +02:00
"github.com/piper-validation/fortify-client-go/fortify/issue_of_project_version_controller"
2020-05-25 19:48:59 +02:00
"github.com/piper-validation/fortify-client-go/fortify/issue_selector_set_of_project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/issue_statistics_of_project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/project_controller"
"github.com/piper-validation/fortify-client-go/fortify/project_version_controller"
"github.com/piper-validation/fortify-client-go/fortify/project_version_of_project_controller"
"github.com/piper-validation/fortify-client-go/fortify/saved_report_controller"
"github.com/piper-validation/fortify-client-go/models"
piperHttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
2021-06-15 14:53:42 +02:00
// ReportsDirectory defines the subfolder for the Fortify reports which are generated
const ReportsDirectory = "fortify"
2020-05-25 19:48:59 +02:00
// System is the interface abstraction of a specific SystemInstance
type System interface {
GetProjectByName ( name string , autoCreate bool , projectVersion string ) ( * models . Project , error )
GetProjectVersionDetailsByProjectIDAndVersionName ( id int64 , name string , autoCreate bool , projectName string ) ( * models . ProjectVersion , error )
GetProjectVersionAttributesByProjectVersionID ( id int64 ) ( [ ] * models . Attribute , error )
SetProjectVersionAttributesByProjectVersionID ( id int64 , attributes [ ] * models . Attribute ) ( [ ] * models . Attribute , error )
CreateProjectVersionIfNotExist ( projectName , projectVersionName , description string ) ( * models . ProjectVersion , error )
LookupOrCreateProjectVersionDetailsForPullRequest ( projectID int64 , masterProjectVersion * models . ProjectVersion , pullRequestName string ) ( * models . ProjectVersion , error )
CreateProjectVersion ( version * models . ProjectVersion ) ( * models . ProjectVersion , error )
ProjectVersionCopyFromPartial ( sourceID , targetID int64 ) error
ProjectVersionCopyCurrentState ( sourceID , targetID int64 ) error
ProjectVersionCopyPermissions ( sourceID , targetID int64 ) error
CommitProjectVersion ( id int64 ) ( * models . ProjectVersion , error )
MergeProjectVersionStateOfPRIntoMaster ( downloadEndpoint , uploadEndpoint string , masterProjectID , masterProjectVersionID int64 , pullRequestName string ) error
GetArtifactsOfProjectVersion ( id int64 ) ( [ ] * models . Artifact , error )
GetFilterSetOfProjectVersionByTitle ( id int64 , title string ) ( * models . FilterSet , error )
GetIssueFilterSelectorOfProjectVersionByName ( id int64 , names [ ] string , options [ ] string ) ( * models . IssueFilterSelectorSet , error )
GetFilterSetByDisplayName ( issueFilterSelectorSet * models . IssueFilterSelectorSet , name string ) * models . IssueFilterSelector
GetProjectIssuesByIDAndFilterSetGroupedBySelector ( id int64 , filter , filterSetGUID string , issueFilterSelectorSet * models . IssueFilterSelectorSet ) ( [ ] * models . ProjectVersionIssueGroup , error )
ReduceIssueFilterSelectorSet ( issueFilterSelectorSet * models . IssueFilterSelectorSet , names [ ] string , options [ ] string ) * models . IssueFilterSelectorSet
GetIssueStatisticsOfProjectVersion ( id int64 ) ( [ ] * models . IssueStatistics , error )
GenerateQGateReport ( projectID , projectVersionID , reportTemplateID int64 , projectName , projectVersionName , reportFormat string ) ( * models . SavedReport , error )
GetReportDetails ( id int64 ) ( * models . SavedReport , error )
2022-02-08 15:10:40 +02:00
GetIssueDetails ( projectVersionId int64 , issueInstanceId string ) ( [ ] * models . ProjectVersionIssue , error )
2022-04-07 13:11:52 +02:00
GetAllIssueDetails ( projectVersionId int64 ) ( [ ] * models . ProjectVersionIssue , error )
2022-02-08 15:10:40 +02:00
GetIssueComments ( parentId int64 ) ( [ ] * models . IssueAuditComment , error )
2020-05-25 19:48:59 +02:00
UploadResultFile ( endpoint , file string , projectVersionID int64 ) error
2020-10-27 14:12:31 +02:00
DownloadReportFile ( endpoint string , reportID int64 ) ( [ ] byte , error )
2020-05-25 19:48:59 +02:00
DownloadResultFile ( endpoint string , projectVersionID int64 ) ( [ ] byte , error )
}
// SystemInstance is the specific instance
type SystemInstance struct {
timeout time . Duration
token string
serverURL string
client * ff . Fortify
httpClient * piperHttp . Client
logger * logrus . Entry
}
// NewSystemInstance - creates an returns a new SystemInstance
2023-08-31 13:48:18 +02:00
func NewSystemInstance ( serverURL , apiEndpoint , authToken , proxyUrl string , timeout time . Duration ) * SystemInstance {
2020-08-11 18:07:06 +02:00
// If serverURL ends in a trailing slash, UploadResultFile() will construct a URL with two or more
// consecutive slashes and actually fail with a 503. https://github.com/SAP/jenkins-library/issues/1826
// Also, since the step outputs a lot of URLs to the log, those will look nicer without redundant slashes.
serverURL = strings . TrimRight ( serverURL , "/" )
2020-05-25 19:48:59 +02:00
format := strfmt . Default
dateTimeFormat := models . Iso8601MilliDateTime { }
format . Add ( "datetime" , & dateTimeFormat , models . IsDateTime )
clientInstance := ff . NewHTTPClientWithConfig ( format , createTransportConfig ( serverURL , apiEndpoint ) )
2021-02-26 14:43:03 +02:00
encodedAuthToken := base64EndodePlainToken ( authToken )
2020-05-25 19:48:59 +02:00
httpClientInstance := & piperHttp . Client { }
2021-02-26 14:43:03 +02:00
httpClientOptions := piperHttp . ClientOptions { Token : "FortifyToken " + encodedAuthToken , TransportTimeout : timeout }
2020-05-25 19:48:59 +02:00
2023-08-31 13:48:18 +02:00
if proxyUrl != "" {
transportProxy , err := url . Parse ( proxyUrl )
if err != nil {
log . Entry ( ) . Warningf ( "Failed to parse proxy url %v" , proxyUrl )
} else {
httpClientOptions . TransportProxy = transportProxy
}
}
httpClientInstance . SetOptions ( httpClientOptions )
2021-02-26 14:43:03 +02:00
return NewSystemInstanceForClient ( clientInstance , httpClientInstance , serverURL , encodedAuthToken , timeout )
2020-05-25 19:48:59 +02:00
}
func createTransportConfig ( serverURL , apiEndpoint string ) * ff . TransportConfig {
scheme , host := splitSchemeAndHost ( serverURL )
host , hostEndpoint := splitHostAndEndpoint ( host )
2020-08-11 18:07:06 +02:00
// Cleaning up any slashes here is mostly for cleaner log-output.
hostEndpoint = strings . TrimRight ( hostEndpoint , "/" )
apiEndpoint = strings . Trim ( apiEndpoint , "/" )
2020-05-25 19:48:59 +02:00
return & ff . TransportConfig {
Host : host ,
Schemes : [ ] string { scheme } ,
BasePath : fmt . Sprintf ( "%v/%v" , hostEndpoint , apiEndpoint ) }
}
func splitSchemeAndHost ( url string ) ( scheme , host string ) {
schemeEnd := strings . Index ( url , "://" )
if schemeEnd >= 0 {
scheme = url [ 0 : schemeEnd ]
host = url [ schemeEnd + 3 : ]
} else {
scheme = "https"
host = url
}
return
}
func splitHostAndEndpoint ( urlWithoutScheme string ) ( host , endpoint string ) {
hostEnd := strings . Index ( urlWithoutScheme , "/" )
if hostEnd >= 0 {
host = urlWithoutScheme [ 0 : hostEnd ]
endpoint = urlWithoutScheme [ hostEnd + 1 : ]
} else {
host = urlWithoutScheme
endpoint = ""
}
return
}
2021-02-26 14:43:03 +02:00
func base64EndodePlainToken ( authToken string ) ( encodedAuthToken string ) {
isEncoded := strings . Index ( authToken , "-" ) < 0
if isEncoded {
return authToken
}
return base64 . StdEncoding . EncodeToString ( [ ] byte ( authToken ) )
}
2020-05-25 19:48:59 +02:00
// NewSystemInstanceForClient - creates a new SystemInstance
func NewSystemInstanceForClient ( clientInstance * ff . Fortify , httpClientInstance * piperHttp . Client , serverURL , authToken string , requestTimeout time . Duration ) * SystemInstance {
return & SystemInstance {
timeout : requestTimeout ,
token : authToken ,
serverURL : serverURL ,
client : clientInstance ,
httpClient : httpClientInstance ,
logger : log . Entry ( ) . WithField ( "package" , "SAP/jenkins-library/pkg/fortify" ) ,
}
}
// AuthenticateRequest authenticates the request
func ( sys * SystemInstance ) AuthenticateRequest ( req runtime . ClientRequest , formats strfmt . Registry ) error {
req . SetHeaderParam ( "Authorization" , fmt . Sprintf ( "FortifyToken %v" , sys . token ) )
return nil
}
// GetProjectByName returns the project identified by the name provided
// autoCreate and projectVersion parameters only used if autoCreate=true
func ( sys * SystemInstance ) GetProjectByName ( projectName string , autoCreate bool , projectVersionName string ) ( * models . Project , error ) {
2021-04-28 13:59:59 +02:00
nameParam := fmt . Sprintf ( ` name:"%v" ` , projectName )
2021-01-21 17:20:46 +02:00
params := & project_controller . ListProjectParams { Q : & nameParam }
2020-05-25 19:48:59 +02:00
params . WithTimeout ( sys . timeout )
result , err := sys . client . ProjectController . ListProject ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
for _ , project := range result . GetPayload ( ) . Data {
if * project . Name == projectName {
return project , nil
}
}
// Project with specified name was NOT found, check if autoCreate flag is set, if not stop otherwise create it automatically
if ! autoCreate {
2020-11-11 14:04:45 +02:00
log . SetErrorCategory ( log . ErrorConfiguration )
2020-05-25 19:48:59 +02:00
return nil , fmt . Errorf ( "Project with name %v not found in backend and automatic creation not enabled" , projectName )
}
log . Entry ( ) . Debugf ( "No projects found with name: %v auto-creating one now..." , projectName )
projectVersion , err := sys . CreateProjectVersionIfNotExist ( projectName , projectVersionName , "Created by Go script" )
if err != nil {
return nil , fmt . Errorf ( "failed to auto-create new project: %w" , err )
}
log . Entry ( ) . Debugf ( "Finished creating project: %v" , projectVersion )
return projectVersion . Project , nil
}
// GetProjectVersionDetailsByProjectIDAndVersionName returns the project version details of the project version identified by the id and project versionname
// projectName parameter is only used if autoCreate=true
func ( sys * SystemInstance ) GetProjectVersionDetailsByProjectIDAndVersionName ( id int64 , versionName string , autoCreate bool , projectName string ) ( * models . ProjectVersion , error ) {
2022-12-16 11:52:30 +02:00
nameParam := fmt . Sprintf ( ` name:"%v" ` , versionName )
2021-01-21 17:20:46 +02:00
params := & project_version_of_project_controller . ListProjectVersionOfProjectParams { ParentID : id , Q : & nameParam }
2020-05-25 19:48:59 +02:00
params . WithTimeout ( sys . timeout )
result , err := sys . client . ProjectVersionOfProjectController . ListProjectVersionOfProject ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
2022-06-27 14:43:57 +02:00
if result . Payload . Count > 0 {
projectVersion := result . GetPayload ( ) . Data [ 0 ]
return projectVersion , nil
2020-05-25 19:48:59 +02:00
}
// projectVersion not found for specified project id and name, check if autoCreate is enabled
if ! autoCreate {
2020-11-11 14:04:45 +02:00
log . SetErrorCategory ( log . ErrorConfiguration )
2020-05-25 19:48:59 +02:00
return nil , errors . New ( fmt . Sprintf ( "Project version with name %v not found in project with ID %v and automatic creation not enabled" , versionName , id ) )
}
log . Entry ( ) . Debugf ( "Could not find project version with name %v under project %v auto-creating one now..." , versionName , projectName )
version , err := sys . CreateProjectVersionIfNotExist ( projectName , versionName , "Created by Go script" )
if err != nil {
return nil , errors . Wrapf ( err , "failed to auto-create project version: %v for project %v" , versionName , projectName )
}
log . Entry ( ) . Debugf ( "Successfully created project version %v for project %v" , versionName , projectName )
return version , nil
}
// CreateProjectVersionIfNotExist creates a new ProjectVersion if it does not already exist.
// If the projectName also does not exist, it will create that as well.
func ( sys * SystemInstance ) CreateProjectVersionIfNotExist ( projectName , projectVersionName , description string ) ( * models . ProjectVersion , error ) {
var projectID int64 = 0
// check if project with projectName exists
projectResp , err := sys . GetProjectByName ( projectName , false , "" )
if err == nil {
// project already exists, all we need to do is append a new ProjectVersion to it
// save the project id for later
projectID = projectResp . ID
}
issueTemplateID := "4c5799c9-1940-4abe-b57a-3bcad88eb041"
active := true
committed := true
projectVersionDto := & models . ProjectVersion {
Name : & projectVersionName ,
Description : & description ,
IssueTemplateID : & issueTemplateID ,
Active : & active ,
Committed : & committed ,
Project : & models . Project { ID : projectID } ,
}
if projectVersionDto . Project . ID == 0 { // project does not exist, set one up
projectVersionDto . Project = & models . Project {
Name : & projectName ,
Description : description ,
IssueTemplateID : & issueTemplateID ,
}
}
projectVersion , err := sys . CreateProjectVersion ( projectVersionDto )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to create new project version %v for projectName %v" , projectVersionName , projectName )
}
_ , err = sys . CommitProjectVersion ( projectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to commit project version %v: %v" , projectVersion . ID , err )
}
return projectVersion , nil
}
// LookupOrCreateProjectVersionDetailsForPullRequest looks up a project version for pull requests or creates it from scratch
func ( sys * SystemInstance ) LookupOrCreateProjectVersionDetailsForPullRequest ( projectID int64 , masterProjectVersion * models . ProjectVersion , pullRequestName string ) ( * models . ProjectVersion , error ) {
projectVersion , _ := sys . GetProjectVersionDetailsByProjectIDAndVersionName ( projectID , pullRequestName , false , "" )
if nil != projectVersion {
return projectVersion , nil
}
newVersion := & models . ProjectVersion { }
newVersion . Name = & pullRequestName
newVersion . Description = masterProjectVersion . Description
newVersion . Active = masterProjectVersion . Active
newVersion . Committed = masterProjectVersion . Committed
newVersion . Project = & models . Project { }
newVersion . Project . Name = masterProjectVersion . Project . Name
newVersion . Project . Description = masterProjectVersion . Project . Description
newVersion . Project . ID = masterProjectVersion . Project . ID
newVersion . IssueTemplateID = masterProjectVersion . IssueTemplateID
projectVersion , err := sys . CreateProjectVersion ( newVersion )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to create new project version for pull request %v" , pullRequestName )
}
attributes , err := sys . GetProjectVersionAttributesByProjectVersionID ( masterProjectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to load project version attributes for master project version %v" , masterProjectVersion . ID )
}
for _ , attribute := range attributes {
attribute . ID = 0
}
_ , err = sys . SetProjectVersionAttributesByProjectVersionID ( projectVersion . ID , attributes )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to update project version attributes for pull request project version %v" , projectVersion . ID )
}
err = sys . ProjectVersionCopyFromPartial ( masterProjectVersion . ID , projectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to copy from partial of project version %v to %v" , masterProjectVersion . ID , projectVersion . ID )
}
_ , err = sys . CommitProjectVersion ( projectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to commit project version %v: %v" , projectVersion . ID , err )
}
err = sys . ProjectVersionCopyCurrentState ( masterProjectVersion . ID , projectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to copy current state of project version %v to %v" , masterProjectVersion . ID , projectVersion . ID )
}
err = sys . ProjectVersionCopyPermissions ( masterProjectVersion . ID , projectVersion . ID )
if err != nil {
return nil , errors . Wrapf ( err , "Failed to copy permissions of project version %v to %v" , masterProjectVersion . ID , projectVersion . ID )
}
return projectVersion , nil
}
// GetProjectVersionAttributesByProjectVersionID returns the project version attributes of the project version identified by the id
func ( sys * SystemInstance ) GetProjectVersionAttributesByProjectVersionID ( id int64 ) ( [ ] * models . Attribute , error ) {
params := & attribute_of_project_version_controller . ListAttributeOfProjectVersionParams { ParentID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . AttributeOfProjectVersionController . ListAttributeOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// SetProjectVersionAttributesByProjectVersionID sets the project version attributes of the project version identified by the id
func ( sys * SystemInstance ) SetProjectVersionAttributesByProjectVersionID ( id int64 , attributes [ ] * models . Attribute ) ( [ ] * models . Attribute , error ) {
params := & attribute_of_project_version_controller . UpdateCollectionAttributeOfProjectVersionParams { ParentID : id , Data : attributes }
params . WithTimeout ( sys . timeout )
result , err := sys . client . AttributeOfProjectVersionController . UpdateCollectionAttributeOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// CreateProjectVersion creates the project version with the provided details
func ( sys * SystemInstance ) CreateProjectVersion ( version * models . ProjectVersion ) ( * models . ProjectVersion , error ) {
params := & project_version_controller . CreateProjectVersionParams { Resource : version }
params . WithTimeout ( sys . timeout )
result , err := sys . client . ProjectVersionController . CreateProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// ProjectVersionCopyFromPartial copies parts of the source project version to the target project version identified by their ids
func ( sys * SystemInstance ) ProjectVersionCopyFromPartial ( sourceID , targetID int64 ) error {
enable := true
settings := models . ProjectVersionCopyPartialRequest {
ProjectVersionID : & targetID ,
PreviousProjectVersionID : & sourceID ,
CopyAnalysisProcessingRules : & enable ,
CopyBugTrackerConfiguration : & enable ,
CopyCustomTags : & enable ,
}
params := & project_version_controller . CopyProjectVersionParams { Resource : & settings }
params . WithTimeout ( sys . timeout )
_ , err := sys . client . ProjectVersionController . CopyProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return nil
}
// ProjectVersionCopyCurrentState copies the project version state of sourceID into the new project version addressed by targetID
func ( sys * SystemInstance ) ProjectVersionCopyCurrentState ( sourceID , targetID int64 ) error {
settings := models . ProjectVersionCopyCurrentStateRequest {
ProjectVersionID : & targetID ,
PreviousProjectVersionID : & sourceID ,
}
params := & project_version_controller . CopyCurrentStateForProjectVersionParams { Resource : & settings }
params . WithTimeout ( sys . timeout )
_ , err := sys . client . ProjectVersionController . CopyCurrentStateForProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return nil
}
func ( sys * SystemInstance ) getAuthEntityOfProjectVersion ( id int64 ) ( [ ] * models . AuthenticationEntity , error ) {
embed := "roles"
params := & auth_entity_of_project_version_controller . ListAuthEntityOfProjectVersionParams { Embed : & embed , ParentID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . AuthEntityOfProjectVersionController . ListAuthEntityOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
func ( sys * SystemInstance ) updateCollectionAuthEntityOfProjectVersion ( id int64 , data [ ] * models . AuthenticationEntity ) error {
params := & auth_entity_of_project_version_controller . UpdateCollectionAuthEntityOfProjectVersionParams { ParentID : id , Data : data }
params . WithTimeout ( sys . timeout )
_ , err := sys . client . AuthEntityOfProjectVersionController . UpdateCollectionAuthEntityOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return nil
}
// ProjectVersionCopyPermissions copies the authentication entity of the project version addressed by sourceID to the one of targetID
func ( sys * SystemInstance ) ProjectVersionCopyPermissions ( sourceID , targetID int64 ) error {
result , err := sys . getAuthEntityOfProjectVersion ( sourceID )
if err != nil {
return err
}
err = sys . updateCollectionAuthEntityOfProjectVersion ( targetID , result )
if err != nil {
return err
}
return nil
}
func ( sys * SystemInstance ) updateProjectVersionDetails ( id int64 , details * models . ProjectVersion ) ( * models . ProjectVersion , error ) {
params := & project_version_controller . UpdateProjectVersionParams { ID : id , Resource : details }
params . WithTimeout ( sys . timeout )
result , err := sys . client . ProjectVersionController . UpdateProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// CommitProjectVersion commits the project version with the provided id
func ( sys * SystemInstance ) CommitProjectVersion ( id int64 ) ( * models . ProjectVersion , error ) {
enabled := true
update := models . ProjectVersion { Committed : & enabled }
return sys . updateProjectVersionDetails ( id , & update )
}
func ( sys * SystemInstance ) inactivateProjectVersion ( id int64 ) ( * models . ProjectVersion , error ) {
enabled := true
disabled := false
update := models . ProjectVersion { Committed : & enabled , Active : & disabled }
return sys . updateProjectVersionDetails ( id , & update )
}
// GetArtifactsOfProjectVersion returns the list of artifacts related to the project version addressed with id
func ( sys * SystemInstance ) GetArtifactsOfProjectVersion ( id int64 ) ( [ ] * models . Artifact , error ) {
scans := "scans"
params := & artifact_of_project_version_controller . ListArtifactOfProjectVersionParams { ParentID : id , Embed : & scans }
params . WithTimeout ( sys . timeout )
result , err := sys . client . ArtifactOfProjectVersionController . ListArtifactOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// MergeProjectVersionStateOfPRIntoMaster merges the PR project version's fpr result file into the master project version
func ( sys * SystemInstance ) MergeProjectVersionStateOfPRIntoMaster ( downloadEndpoint , uploadEndpoint string , masterProjectID , masterProjectVersionID int64 , pullRequestName string ) error {
log . Entry ( ) . Debugf ( "Looking up project version with name '%v' to merge audit status into master version" , pullRequestName )
prProjectVersion , _ := sys . GetProjectVersionDetailsByProjectIDAndVersionName ( masterProjectID , pullRequestName , false , "" )
if nil != prProjectVersion {
log . Entry ( ) . Debugf ( "Found project version with ID '%v', starting transfer" , prProjectVersion . ID )
data , err := sys . DownloadResultFile ( downloadEndpoint , prProjectVersion . ID )
if err != nil {
return errors . Wrapf ( err , "Failed to download current state FPR of PR project version %v" , prProjectVersion . ID )
}
err = sys . uploadResultFileContent ( uploadEndpoint , "prMergeTransfer.fpr" , bytes . NewReader ( data ) , masterProjectVersionID )
if err != nil {
return errors . Wrapf ( err , "Failed to upload PR project version state to master project version %v" , masterProjectVersionID )
}
_ , err = sys . inactivateProjectVersion ( prProjectVersion . ID )
if err != nil {
log . Entry ( ) . Warnf ( "Failed to inactivate merged PR project version %v" , prProjectVersion . ID )
}
} else {
log . Entry ( ) . Debug ( "No related project version found in SSC" )
}
return nil
}
// GetFilterSetOfProjectVersionByTitle returns the filter set with the given title related to the project version addressed with id, if no title is provided the default filter set will be returned
func ( sys * SystemInstance ) GetFilterSetOfProjectVersionByTitle ( id int64 , title string ) ( * models . FilterSet , error ) {
params := & filter_set_of_project_version_controller . ListFilterSetOfProjectVersionParams { ParentID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . FilterSetOfProjectVersionController . ListFilterSetOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
var defaultFilterSet * models . FilterSet
for _ , filterSet := range result . GetPayload ( ) . Data {
if len ( title ) > 0 && filterSet . Title == title {
return filterSet , nil
}
if filterSet . DefaultFilterSet {
defaultFilterSet = filterSet
}
}
if len ( title ) > 0 {
log . Entry ( ) . Warnf ( "Failed to load filter set with title '%v', falling back to default filter set" , title )
}
if nil != defaultFilterSet {
return defaultFilterSet , nil
}
return nil , fmt . Errorf ( "Failed to identify requested filter set and default filter" )
}
// GetIssueFilterSelectorOfProjectVersionByName returns the groupings with the given names related to the project version addressed with id
func ( sys * SystemInstance ) GetIssueFilterSelectorOfProjectVersionByName ( id int64 , names [ ] string , options [ ] string ) ( * models . IssueFilterSelectorSet , error ) {
params := & issue_selector_set_of_project_version_controller . GetIssueSelectorSetOfProjectVersionParams { ParentID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . IssueSelectorSetOfProjectVersionController . GetIssueSelectorSetOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return sys . ReduceIssueFilterSelectorSet ( result . GetPayload ( ) . Data , names , options ) , nil
}
// ReduceIssueFilterSelectorSet filters the set to the relevant filter display names
func ( sys * SystemInstance ) ReduceIssueFilterSelectorSet ( issueFilterSelectorSet * models . IssueFilterSelectorSet , names [ ] string , options [ ] string ) * models . IssueFilterSelectorSet {
groupingList := [ ] * models . IssueSelector { }
if issueFilterSelectorSet . GroupBySet != nil {
for _ , group := range issueFilterSelectorSet . GroupBySet {
if piperutils . ContainsString ( names , * group . DisplayName ) {
log . Entry ( ) . Debugf ( "adding new grouping '%v' to reduced list" , * group . DisplayName )
groupingList = append ( groupingList , group )
}
}
}
filterList := [ ] * models . IssueFilterSelector { }
if issueFilterSelectorSet . FilterBySet != nil {
for _ , filter := range issueFilterSelectorSet . FilterBySet {
if piperutils . ContainsString ( names , filter . DisplayName ) {
newFilter := & models . IssueFilterSelector { }
newFilter . DisplayName = filter . DisplayName
newFilter . Description = filter . Description
newFilter . EntityType = filter . EntityType
newFilter . FilterSelectorType = filter . FilterSelectorType
newFilter . GUID = filter . GUID
newFilter . Value = filter . Value
newFilter . SelectorOptions = [ ] * models . SelectorOption { }
for _ , option := range filter . SelectorOptions {
if ( nil != options && piperutils . ContainsString ( options , option . DisplayName ) ) || options == nil || len ( options ) == 0 {
log . Entry ( ) . Debugf ( "adding selector option '%v' to list for filter selector '%v'" , option . DisplayName , newFilter . DisplayName )
newFilter . SelectorOptions = append ( newFilter . SelectorOptions , option )
}
}
log . Entry ( ) . Debugf ( "adding new filter '%v' to reduced list with selector options '%v'" , newFilter . DisplayName , newFilter . SelectorOptions )
filterList = append ( filterList , newFilter )
}
}
}
return & models . IssueFilterSelectorSet { GroupBySet : groupingList , FilterBySet : filterList }
}
2022-11-02 13:48:54 +02:00
// GetFilterSetByDisplayName returns the set identified by the provided name or nil
2020-05-25 19:48:59 +02:00
func ( sys * SystemInstance ) GetFilterSetByDisplayName ( issueFilterSelectorSet * models . IssueFilterSelectorSet , name string ) * models . IssueFilterSelector {
if issueFilterSelectorSet . FilterBySet != nil {
for _ , filter := range issueFilterSelectorSet . FilterBySet {
if filter . DisplayName == name {
return filter
}
}
}
return nil
}
func ( sys * SystemInstance ) getIssuesOfProjectVersion ( id int64 , filter , filterset , groupingtype string ) ( [ ] * models . ProjectVersionIssueGroup , error ) {
enable := true
params := & issue_group_of_project_version_controller . ListIssueGroupOfProjectVersionParams { ParentID : id , Showsuppressed : & enable , Filterset : & filterset , Groupingtype : & groupingtype }
params . WithTimeout ( sys . timeout )
if len ( filter ) > 0 {
params . WithFilter ( & filter )
}
result , err := sys . client . IssueGroupOfProjectVersionController . ListIssueGroupOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// GetProjectIssuesByIDAndFilterSetGroupedBySelector returns issues of the project version addressed with id filtered with the respective set and grouped by the issue filter selector grouping
func ( sys * SystemInstance ) GetProjectIssuesByIDAndFilterSetGroupedBySelector ( id int64 , filter , filterSetGUID string , issueFilterSelectorSet * models . IssueFilterSelectorSet ) ( [ ] * models . ProjectVersionIssueGroup , error ) {
groupingTypeGUID := ""
if issueFilterSelectorSet != nil {
groupingTypeGUID = * issueFilterSelectorSet . GroupBySet [ 0 ] . GUID
}
result , err := sys . getIssuesOfProjectVersion ( id , filter , filterSetGUID , groupingTypeGUID )
if err != nil {
return nil , err
}
return result , nil
}
// GetIssueStatisticsOfProjectVersion returns the issue statistics related to the project version addressed with id
func ( sys * SystemInstance ) GetIssueStatisticsOfProjectVersion ( id int64 ) ( [ ] * models . IssueStatistics , error ) {
params := & issue_statistics_of_project_version_controller . ListIssueStatisticsOfProjectVersionParams { ParentID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . IssueStatisticsOfProjectVersionController . ListIssueStatisticsOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// GenerateQGateReport returns the issue statistics related to the project version addressed with id
func ( sys * SystemInstance ) GenerateQGateReport ( projectID , projectVersionID , reportTemplateID int64 , projectName , projectVersionName , reportFormat string ) ( * models . SavedReport , error ) {
paramIdentifier := "projectVersionId"
paramType := "SINGLE_PROJECT"
paramName := "Q-gate-report"
reportType := "PORTFOLIO"
2020-05-29 15:42:35 +02:00
inputReportParameters := [ ] * models . InputReportParameter { { Name : & paramName , Identifier : & paramIdentifier , ParamValue : projectVersionID , Type : & paramType } }
reportProjectVersions := [ ] * models . ReportProjectVersion { { ID : projectVersionID , Name : projectVersionName } }
reportProjects := [ ] * models . ReportProject { { ID : projectID , Name : projectName , Versions : reportProjectVersions } }
2020-05-25 19:48:59 +02:00
report := models . SavedReport { Name : fmt . Sprintf ( "FortifyReport: %v:%v" , projectName , projectVersionName ) , Type : & reportType , ReportDefinitionID : & reportTemplateID , Format : & reportFormat , Projects : reportProjects , InputReportParameters : inputReportParameters }
params := & saved_report_controller . CreateSavedReportParams { Resource : & report }
params . WithTimeout ( sys . timeout )
result , err := sys . client . SavedReportController . CreateSavedReport ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// GetReportDetails returns the details of the report addressed with id
func ( sys * SystemInstance ) GetReportDetails ( id int64 ) ( * models . SavedReport , error ) {
params := & saved_report_controller . ReadSavedReportParams { ID : id }
params . WithTimeout ( sys . timeout )
result , err := sys . client . SavedReportController . ReadSavedReport ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
2022-02-08 15:10:40 +02:00
// GetIssueDetails returns the details of an issue with its issueInstanceId and projectVersionId
func ( sys * SystemInstance ) GetIssueDetails ( projectVersionId int64 , issueInstanceId string ) ( [ ] * models . ProjectVersionIssue , error ) {
qmStr := "issues"
2022-07-19 17:20:22 +02:00
showSuppressed := true
params := & issue_of_project_version_controller . ListIssueOfProjectVersionParams { ParentID : projectVersionId , Q : & issueInstanceId , Qm : & qmStr , Showsuppressed : & showSuppressed }
2022-02-08 15:10:40 +02:00
params . WithTimeout ( sys . timeout )
result , err := sys . client . IssueOfProjectVersionController . ListIssueOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2022-02-08 15:10:40 +02:00
}
return result . GetPayload ( ) . Data , nil
}
2022-04-07 13:11:52 +02:00
// GetAllIssueDetails returns the details of all issues of the project with id projectVersionId
func ( sys * SystemInstance ) GetAllIssueDetails ( projectVersionId int64 ) ( [ ] * models . ProjectVersionIssue , error ) {
var limit int32
limit = - 1
2022-07-19 17:20:22 +02:00
showSuppressed := true
params := & issue_of_project_version_controller . ListIssueOfProjectVersionParams { ParentID : projectVersionId , Limit : & limit , Showsuppressed : & showSuppressed }
2022-04-07 13:11:52 +02:00
params . WithTimeout ( sys . timeout )
result , err := sys . client . IssueOfProjectVersionController . ListIssueOfProjectVersion ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2022-04-07 13:11:52 +02:00
}
return result . GetPayload ( ) . Data , nil
}
2022-02-08 15:10:40 +02:00
// GetIssueComments returns the details of an issue comments with its unique parentId
func ( sys * SystemInstance ) GetIssueComments ( parentId int64 ) ( [ ] * models . IssueAuditComment , error ) {
params := & issue_audit_comment_of_issue_controller . ListIssueAuditCommentOfIssueParams { ParentID : parentId }
params . WithTimeout ( sys . timeout )
result , err := sys . client . IssueAuditCommentOfIssueController . ListIssueAuditCommentOfIssue ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2022-02-08 15:10:40 +02:00
}
return result . GetPayload ( ) . Data , nil
}
2020-05-25 19:48:59 +02:00
func ( sys * SystemInstance ) invalidateFileTokens ( ) error {
log . Entry ( ) . Debug ( "invalidating file tokens" )
params := & file_token_controller . MultiDeleteFileTokenParams { }
params . WithTimeout ( sys . timeout )
_ , err := sys . client . FileTokenController . MultiDeleteFileToken ( params , sys )
2022-11-02 13:48:54 +02:00
if err != nil {
return fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
}
return nil
2020-05-25 19:48:59 +02:00
}
func ( sys * SystemInstance ) getFileToken ( tokenType string ) ( * models . FileToken , error ) {
2020-05-29 15:42:35 +02:00
log . Entry ( ) . Debugf ( "fetching file token of type %v" , tokenType )
2020-05-25 19:48:59 +02:00
token := models . FileToken { FileTokenType : & tokenType }
params := & file_token_controller . CreateFileTokenParams { Resource : & token }
params . WithTimeout ( sys . timeout )
result , err := sys . client . FileTokenController . CreateFileToken ( params , sys )
if err != nil {
2022-11-02 13:48:54 +02:00
return nil , fmt . Errorf ( "Error from url %s %w" , sys . serverURL , err )
2020-05-25 19:48:59 +02:00
}
return result . GetPayload ( ) . Data , nil
}
// UploadResultFile uploads a fpr file to the fortify backend
func ( sys * SystemInstance ) UploadResultFile ( endpoint , file string , projectVersionID int64 ) error {
fileHandle , err := os . Open ( file )
if err != nil {
return errors . Wrapf ( err , "Unable to locate file %v" , file )
}
defer fileHandle . Close ( )
return sys . uploadResultFileContent ( endpoint , file , fileHandle , projectVersionID )
}
func ( sys * SystemInstance ) uploadResultFileContent ( endpoint , file string , fileContent io . Reader , projectVersionID int64 ) error {
2020-05-29 15:42:35 +02:00
token , err := sys . getFileToken ( "UPLOAD" )
2020-05-25 19:48:59 +02:00
if err != nil {
return err
}
defer sys . invalidateFileTokens ( )
header := http . Header { }
header . Add ( "Cache-Control" , "no-cache, no-store, must-revalidate" )
header . Add ( "Pragma" , "no-cache" )
formFields := map [ string ] string { }
formFields [ "entityId" ] = fmt . Sprintf ( "%v" , projectVersionID )
_ , err = sys . httpClient . Upload ( piperHttp . UploadRequestData {
Method : http . MethodPost ,
URL : fmt . Sprintf ( "%v%v?mat=%v" , sys . serverURL , endpoint , token . Token ) ,
File : file ,
FileFieldName : "file" ,
FormFields : formFields ,
FileContent : fileContent ,
Header : header ,
} )
return err
}
// DownloadFile downloads a file from Fortify backend
2020-10-27 14:12:31 +02:00
func ( sys * SystemInstance ) downloadFile ( endpoint , method , acceptType , tokenType string , fileID int64 ) ( [ ] byte , error ) {
2020-05-29 15:42:35 +02:00
token , err := sys . getFileToken ( tokenType )
if err != nil {
return nil , errors . Wrap ( err , "Error fetching file token" )
}
defer sys . invalidateFileTokens ( )
2020-05-25 19:48:59 +02:00
header := http . Header { }
header . Add ( "Cache-Control" , "no-cache, no-store, must-revalidate" )
header . Add ( "Pragma" , "no-cache" )
header . Add ( "Accept" , acceptType )
header . Add ( "Content-Type" , "application/form-data" )
body := url . Values {
2020-10-27 14:12:31 +02:00
"id" : { fmt . Sprintf ( "%v" , fileID ) } ,
2020-05-29 15:42:35 +02:00
"mat" : { token . Token } ,
2020-05-25 19:48:59 +02:00
}
var response * http . Response
if method == http . MethodGet {
response , err = sys . httpClient . SendRequest ( method , fmt . Sprintf ( "%v%v?%v" , sys . serverURL , endpoint , body . Encode ( ) ) , nil , header , nil )
} else {
response , err = sys . httpClient . SendRequest ( method , fmt . Sprintf ( "%v%v" , sys . serverURL , endpoint ) , strings . NewReader ( body . Encode ( ) ) , header , nil )
}
if err != nil {
return nil , err
}
2023-08-16 12:57:04 +02:00
data , err := io . ReadAll ( response . Body )
2020-05-25 19:48:59 +02:00
defer response . Body . Close ( )
if err != nil {
return nil , errors . Wrap ( err , "Error reading the response data" )
}
return data , nil
}
// DownloadReportFile downloads a report file from Fortify backend
2020-10-27 14:12:31 +02:00
func ( sys * SystemInstance ) DownloadReportFile ( endpoint string , reportID int64 ) ( [ ] byte , error ) {
data , err := sys . downloadFile ( endpoint , http . MethodGet , "application/octet-stream" , "REPORT_FILE" , reportID )
2020-05-25 19:48:59 +02:00
if err != nil {
return nil , errors . Wrap ( err , "Error downloading report file" )
}
return data , nil
}
// DownloadResultFile downloads a result file from Fortify backend
func ( sys * SystemInstance ) DownloadResultFile ( endpoint string , projectVersionID int64 ) ( [ ] byte , error ) {
2020-05-29 15:42:35 +02:00
data , err := sys . downloadFile ( endpoint , http . MethodGet , "application/zip" , "DOWNLOAD" , projectVersionID )
2020-05-25 19:48:59 +02:00
if err != nil {
return nil , errors . Wrap ( err , "Error downloading result file" )
}
return data , nil
}