diff --git a/LICENSE.txt b/LICENSE.txt index 0282e86da3..235a5aa7d7 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright 2021 - 2023 Open Text or one of its affiliates +Copyright 2021 - 2024 Open Text or one of its affiliates Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index d9e498e7e7..5c80e4536c 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ The fcli utility can be used to interact with various Fortify products, like For + + + ## Support The only warranties for products and services of Open Text and its affiliates and licensors (“Open Text”) are as may be set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. Open Text shall not be liable for technical or editorial errors or omissions contained herein. The information contained herein is subject to change without notice. @@ -47,6 +50,9 @@ Support requests created through the GitHub Issues page may include bug reports, Support requests on the GitHub Issues page are handled on a best-effort basis; there is no guaranteed response time, no guarantee that reported bugs will be fixed, and no guarantee that enhancement requests will be implemented. If you require dedicated support for this and other Fortify software, please consider purchasing OpenText Fortify Professional Services. OpenText Fortify Professional Services can assist with general usage questions, integration of the software into your processes, and implementing customizations, bug fixes, and feature requests (subject to feasibility analysis). Please contact your OpenText Sales representative or fill in the [Professional Services Contact Form](https://www.microfocus.com/en-us/cyberres/contact/professional-services) to obtain more information on pricing and the services that OpenText Fortify Professional Services can provide. + + + --- *[This document was auto-generated from README.template.md; do not edit by hand](https://github.com/fortify/shared-doc-resources/blob/main/USAGE.md)* diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAccessControlRoleSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAccessControlRoleSpec.groovy new file mode 100644 index 0000000000..b42755578e --- /dev/null +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAccessControlRoleSpec.groovy @@ -0,0 +1,59 @@ +package com.fortify.cli.ftest.fod; + +import static com.fortify.cli.ftest._common.spec.FcliSessionType.FOD + +import com.fortify.cli.ftest._common.Fcli +import com.fortify.cli.ftest._common.spec.FcliBaseSpec +import com.fortify.cli.ftest._common.spec.FcliSession +import com.fortify.cli.ftest._common.spec.Prefix +import com.fortify.cli.ftest.fod._common.FoDWebAppSupplier +import com.fortify.cli.ftest.fod._common.FoDUserSupplier +import com.fortify.cli.ftest.fod._common.FoDUserGroupSupplier + +import spock.lang.AutoCleanup +import spock.lang.Shared +import spock.lang.Stepwise +import spock.lang.Unroll + +@Prefix("fod.role") @FcliSession(FOD) @Stepwise +class FoDAccessControlRoleSpec extends FcliBaseSpec { + @Shared @AutoCleanup FoDUserSupplier user = new FoDUserSupplier() + @Shared @AutoCleanup FoDUserGroupSupplier group = new FoDUserGroupSupplier() + @Shared @AutoCleanup FoDWebAppSupplier app = new FoDWebAppSupplier() + + def "list"() { + def args = "fod ac list-roles --store roles" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[0].replace(' ', '').equals("IdName") + } + } + + def "updateUserRole"() { + def args = "fod ac update-user ${user.get().userName} --lastname updatedLastname --firstname updatedFirstname --phone 5678 --role=Developer" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()==2 + } + } + + def "verifyUpdated"() { + + def args = "fod ac get-user ${user.get().userName}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>2 + it[9].equals("roleName: \"Developer\"") + } + } + + +} + diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAppSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAppSpec.groovy index cb36d47b48..38b679c663 100644 --- a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAppSpec.groovy +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDAppSpec.groovy @@ -15,13 +15,14 @@ import spock.lang.Stepwise @Prefix("fod.app") @FcliSession(FOD) @Stepwise class FoDAppSpec extends FcliBaseSpec { - /* - @Shared FoDWebAppSupplier webAppSupplier = null; - @Shared FoDMobileAppSupplier mobileAppSupplier = null; - @Shared FoDMicroservicesAppSupplier microservicesAppSupplier = null; + + @Shared FoDWebAppSupplier webApp = new FoDWebAppSupplier(); + @Shared FoDMobileAppSupplier mobileApp = new FoDMobileAppSupplier(); + @Shared FoDMicroservicesAppSupplier microservicesApp = new FoDMicroservicesAppSupplier(); + @Shared FoDWebApp def "list"() { - def args = "fod app list" + def args = "fod app list --store=apps" when: def result = Fcli.run(args) then: @@ -35,96 +36,111 @@ class FoDAppSpec extends FcliBaseSpec { } } + def "list-scans"() { + def args = "fod app list-scans --app=::apps::get(0).applicationId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=0 + if(size()>1) { + it[0].replace(' ', '').equals("IdTypeAnalysisStatusNameMicroserviceReleaseStartedCompletedScanMethod") + } else { + it[0].equals("No data") + } + } + } + def "createWebApp"() { when: - webApp = new FoDWebAppSupplier().createWebApp(); + webApp.get(); then: noExceptionThrown() } def "createMicroserviceApp"() { when: - microservicesApp = new FoDWebAppSupplier().createMicroservicesApp(); + microservicesApp.get(); then: noExceptionThrown() } def "createMobileApp"() { when: - mobileApp = new FoDWebAppSupplier().createMobileApp(); + mobileApp.get(); then: noExceptionThrown() } def "get.byIdWebApp"() { - def args = "fod app get " + webApp.get("applicationId") + def args = "fod app get " + webApp.get().get("applicationId") when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[2].equals("applicationName: \"" + webApp.appName + ":" + webApp.versionName +"\"") + it[2].equals("applicationName: \"" + webApp.get().appName + "\"") } } def "get.byIdMobileApp"() { - def args = "fod app get " + mobileApp.get("applicationId") + def args = "fod app get " + mobileApp.get().get("applicationId") when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[2].equals("applicationName: \"" + mobileApp.appName + ":" + mobileApp.versionName +"\"") + it[2].equals("applicationName: \"" + mobileApp.get().appName + "\"") } } def "get.byIdMicroservicesApp"() { - def args = "fod app get " + microservicesApp.get("applicationId") + def args = "fod app get " + microservicesApp.get().get("applicationId") when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[2].equals("applicationName: \"" + microservicesApp.appName + ":" + microservicesApp.versionName +"\"") + it[2].equals("applicationName: \"" + microservicesApp.get().appName + "\"") } } def "get.byNameWebApp"() { - def args = "fod app get " + webApp.appName + def args = "fod app get " + webApp.get().appName when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[1].startsWith("applicationId: " + webApp.get("applicationId")) + it[1].startsWith("applicationId: " + webApp.get().get("applicationId")) } } def "get.byNameMobileApp"() { - def args = "fod app get " + mobileApp.appName + def args = "fod app get " + mobileApp.get().appName when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[1].startsWith("applicationId: " + mobileApp.get("applicationId")) + it[1].startsWith("applicationId: " + mobileApp.get().get("applicationId")) } } def "get.byNameMicroservicesApp"() { - def args = "fod app get " + microservicesApp.appName + def args = "fod app get " + microservicesApp.get().appName when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>2 - it[1].startsWith("applicationId: " + microservicesApp.get("applicationId")) + it[1].startsWith("applicationId: " + microservicesApp.get().get("applicationId")) } } def "update"() { - def args = "fod app update " + webApp.appName + " --business-criticality High" + def args = "fod app update " + webApp.get().appName + " --business-criticality High" when: def result = Fcli.run(args) then: @@ -134,7 +150,7 @@ class FoDAppSpec extends FcliBaseSpec { } def "verifyUpdated"() { - def args = "fod app get " + webApp.get("applicationId") + def args = "fod app get " + webApp.get().get("applicationId") when: def result = Fcli.run(args) then: @@ -170,12 +186,12 @@ class FoDAppSpec extends FcliBaseSpec { def result = Fcli.run(args) then: verifyAll(result.stdout) { - !it.any { it.contains(webApp.appName) } - !it.any { it.contains(microservicesApp.appName) } - !it.any { it.contains(mobileApp.appName) } + !it.any { it.contains(webApp.get().appName) } + !it.any { it.contains(microservicesApp.get().appName) } + !it.any { it.contains(mobileApp.get().appName) } } } - */ + } diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDReleaseSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDReleaseSpec.groovy index 622a6c8f30..9c826d8708 100644 --- a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDReleaseSpec.groovy +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDReleaseSpec.groovy @@ -17,7 +17,7 @@ class FoDReleaseSpec extends FcliBaseSpec { @Shared @AutoCleanup FoDMicroservicesAppSupplier app = new FoDMicroservicesAppSupplier() def "list"() { - def args = "fod release list" + def args = "fod release list --store=releases" when: def result = Fcli.run(args) then: @@ -26,6 +26,36 @@ class FoDReleaseSpec extends FcliBaseSpec { it[0].replace(' ', '').equals("IdNameMicroserviceApplicationSDLCStatus") } } + + def "list-scans"() { + def args = "fod release list-scans --rel=::releases::get(0).releaseId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=0 + if(size()>1) { + it[0].replace(' ', '').equals("IdTypeAnalysisStatusApplicationMicroserviceNameStartedCompletedScanMethod") + } else { + it[0].equals("No data") + } + } + } + + def "list-assessment-types"() { + def args = "fod release lsat --rel=::releases::get(0).releaseId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=0 + if(size()>1) { + it[0].replace(' ', '').equals("IdNameScantypeFrequencytypeUnitsEntitlementidEntitlementdescription") + } else { + it[0].equals("No data") + } + } + } def "create"() { def args = "fod release create ${app.get().qualifiedMicroserviceName}:testrel --sdlc-status=Development --store testrel" diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDScanSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDScanSpec.groovy index cad4b9ad12..9081726115 100644 --- a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDScanSpec.groovy +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/FoDScanSpec.groovy @@ -2,36 +2,34 @@ package com.fortify.cli.ftest.fod; import static com.fortify.cli.ftest._common.spec.FcliSessionType.FOD -import com.fortify.cli.ftest._common.Fcli import com.fortify.cli.ftest._common.spec.FcliBaseSpec import com.fortify.cli.ftest._common.spec.FcliSession import com.fortify.cli.ftest._common.spec.Prefix import com.fortify.cli.ftest._common.spec.TestResource -import com.fortify.cli.ftest.fod._common.FoDWebAppSupplier -import com.fortify.cli.ftest.fod._common.FoDUserSupplier import com.fortify.cli.ftest.fod._common.FoDMobileAppSupplier -import com.fortify.cli.ftest.fod._common.FoDUserGroupSupplier +import com.fortify.cli.ftest.fod._common.FoDWebAppSupplier import spock.lang.AutoCleanup import spock.lang.Shared import spock.lang.Stepwise -import spock.lang.Unroll @Prefix("fod.scan") @FcliSession(FOD) @Stepwise class FoDScanSpec extends FcliBaseSpec { - /* + @Shared @TestResource("runtime/shared/EightBall-22.1.0.fpr") String sastResults @Shared @TestResource("runtime/shared/iwa_net_scandata.fpr") String dastResults @Shared @TestResource("runtime/shared/iwa_net_cyclonedx.json") String ossResults @Shared @TestResource("runtime/shared/iwa_mobile.fpr") String mobileResults - @Shared @TestResource("runtime/shared/EightBall-package.zip") String sastpackage + @Shared @TestResource("runtime/shared/EightBall-package.zip") String sastPackage + @Shared @TestResource("runtime/shared/HelloWorld.apk") String mastPackage + @Shared @TestResource("runtime/shared/oss_package.zip") String ossPackage @Shared @AutoCleanup FoDWebAppSupplier webApp = new FoDWebAppSupplier() @Shared @AutoCleanup FoDMobileAppSupplier mobileApp = new FoDMobileAppSupplier() - + /* def "import-sast"() { - def args = "fod sast-scan import --release=${webApp.get().qualifiedRelease} --file=$sastResults --store uploadsast" + def args = "fod sast-scan import --release=${webApp.get().qualifiedRelease} --file=$tar --store uploadsast" when: def result = Fcli.run(args) then: @@ -39,9 +37,11 @@ class FoDScanSpec extends FcliBaseSpec { size()>2 it.last().contains("IMPORT_REQUESTED") } + cleanup: + Files.delete(tar); } - - def "import-mobile"() { + /* + def "import-mast"() { def args = "fod mast-scan import --release=${mobileApp.get().qualifiedRelease} --file=$mobileResults --store uploadmast" when: def result = Fcli.run(args) @@ -74,7 +74,6 @@ class FoDScanSpec extends FcliBaseSpec { } } - def "waitForScans"() { when: def relScanurl = Fcli.run("fod release get ${webApp.get().qualifiedRelease} -o expr=/api/v3/releases/{releaseId}/scans --store relId").stdout[0] @@ -83,7 +82,8 @@ class FoDScanSpec extends FcliBaseSpec { def success = true; while(true){ def result = Fcli.run("fod rest call ${relScanurl}") - if(result.stdout.findAll{element -> element.contains("analysisStatusType: \"Completed\"")}.size()==3) { + if(result.stdout.findAll{ + element -> element.contains("analysisStatusType: \"Completed\"")}.size()==4) { success=true; break; } else if(System.currentTimeMillis()-start > timeoutMs) { @@ -97,7 +97,7 @@ class FoDScanSpec extends FcliBaseSpec { def "list.sast-scans"() { - def args = "fod sast-scan list --release=fcli-1698140484524:v1698140484524 --store sastscans" + def args = "fod sast-scan list --release=${webApp.get().qualifiedRelease} --store sastscans" when: def result = Fcli.run(args) then: @@ -118,17 +118,27 @@ class FoDScanSpec extends FcliBaseSpec { } } + def "setup.sast-scan"() { + def args = "fod sast-scan setup --assessment-type=Static\\ Assessment --audit-preference=Automated --frequency=SingleScan --technology-stack=Go --release=${webApp.get().qualifiedRelease}" + when: + def result = Fcli.run(args) + then: + def e = thrown(UnexpectedFcliResultException) + e.result.stderr.any { it.contains("the entitlement has expired") } + e.result.stdout.first().replace(" ", "").equals("AssessmenttypeidEntitlementidEntitlementfrequencytypeReleaseidTechnologystackidTechnologystackLanguagelevelidLanguagelevelOSSAnalysisAuditpreferencetypeIncludethirdpartylibrariesUsesourcecontrolScanbinaryBsitokenApplicationReleaseMicroserviceAction") + } + def "get-config.sast-scan"() { - def args = "fod sast-scan get-config --release=fcli-1698140484524:v1698140484524" + def args = "fod sast-scan get-config --release=${webApp.get().qualifiedRelease}" when: def result = Fcli.run(args) then: verifyAll(result.stdout) { size()>=2 - it.last().contains("state: \"Not configured\"") + it.last().contains("state: \"Configured\"") } } - + /* def "download.sast-scan-byId"() { def args = "fod sast-scan download ::sastscans::get(0).scanId -f=byId.fpr" when: @@ -141,7 +151,7 @@ class FoDScanSpec extends FcliBaseSpec { } def "download-latest.sast-scan"() { - def args = "fod sast-scan download-latest --release=fcli-1698140484524:v1698140484524 -f=latest.fpr" + def args = "fod sast-scan download-latest --release=${webApp.get().qualifiedRelease} -f=latest.fpr" when: def result = Fcli.run(args) then: @@ -151,8 +161,41 @@ class FoDScanSpec extends FcliBaseSpec { } } - def "start.sast-scan"() { - def args = "fod sast-scan download-latest --release=fcli-1698140484524:v1698140484524 -f=latest.fpr" + def "list.dast-scans"() { + def args = "fod dast-scan list --release=${webApp.get().qualifiedRelease} --store dastscans" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("FPRImport") + } + } + + def "get.dast-scan"() { + def args = "fod dast-scan get ::dastscans::get(0).scanId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + //it.any {it.contains("applicationName: \"${webApp.get().appName}\"")} + } + } + + def "get-config.dast-scan"() { + def args = "fod dast-scan get-config --release=${webApp.get().qualifiedRelease}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("state: \"Not configured\"") + } + } + + def "download.dast-scan-byId"() { + def args = "fod dast-scan download ::dastscans::get(0).scanId -f=byId.fpr" when: def result = Fcli.run(args) then: @@ -161,42 +204,218 @@ class FoDScanSpec extends FcliBaseSpec { it[1].contains("SCAN_DOWNLOADED") } } - /* - def "import-sast"() { - //get release id - def appRelId = Fcli.run("fod release get " + app.appName + ":" + app.versionName + " --store release") - def args = "fod scan import-sast ::release::releaseId -f " + sastResults + " --store upload" + + def "download-latest.dast-scan"() { + def args = "fod dast-scan download-latest --release=${webApp.get().qualifiedRelease} -f=latest.fpr" when: def result = Fcli.run(args) then: verifyAll(result.stdout) { - size()>2 - it[1].startsWith("startedByUserId: ") + size()>=2 + it[1].contains("SCAN_DOWNLOADED") + } + } + + def "list.mast-scans"() { + def args = "fod mast-scan list --release=${mobileApp.get().qualifiedRelease} --store mastscans" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("FPRImport") + } + } + + def "get.mast-scan"() { + def args = "fod mast-scan get ::mastscans::get(0).scanId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + //it.any {it.contains("applicationName: \"${webApp.get().appName}\"")} + } + } + + def "get-config.mast-scan"() { + def args = "fod mast-scan get-config --release=${mobileApp.get().qualifiedRelease}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("state: \"Not configured\"") + } + } + + def "download.mast-scan-byId"() { + def args = "fod mast-scan download ::mastscans::get(0).scanId -f=byId.fpr" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("SCAN_DOWNLOADED") + } + } + + def "download-latest.mast-scan"() { + def args = "fod mast-scan download-latest --release=${mobileApp.get().qualifiedRelease} -f=latest.fpr" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("SCAN_DOWNLOADED") + } + } + + def "list.oss-scans"() { + def args = "fod oss-scan list --release=${webApp.get().qualifiedRelease} --store ossscans" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("FPRImport") + } + } + + def "get.oss-scan"() { + def args = "fod oss-scan get ::ossscans::get(0).scanId" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + //it.any {it.contains("applicationName: \"${webApp.get().appName}\"")} + } + } + + def "get-config.oss-scan"() { + def args = "fod oss-scan get-config --release=${webApp.get().qualifiedRelease}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("state: \"Not configured\"") + } + } + + def "download.oss-scan-byId"() { + def args = "fod oss-scan download ::ossscans::get(0).scanId -f=byId.fpr" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("SCAN_DOWNLOADED") + } + } + + def "download-latest.oss-scan"() { + def args = "fod oss-scan download-latest --release=${webApp.get().qualifiedRelease} -f=latest.fpr" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it[1].contains("SCAN_DOWNLOADED") + } + } + + def "start.sast-scan"() { + def args = "fod sast-scan start --release=fcli-1698140484524:v2 --file=$sastPackage --store sastScan" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("STARTED") } } - def "wait-for-import-sast"() { - def args = "fod scan wait-for ::upload:: -i 2s --until=all-match --any-scan-state=COMPLETED,CANCELLED,FAILED,RUNNING" + def "wait-for-sast"() { + def args = "fod sast-scan wait-for ::sastScan:: -i 2s --until=all-match --any-state=Completed,In_Progress,Queued" when: def result = Fcli.run(args) then: verifyAll(result.stdout) { // } - }*/ + } + + def "start.oss-scan"() { + def args = "fod oss-scan start --release=fcli-1698140484524:v2 --file=$ossPackage --store ossScan" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("STARTED") + } + } - /*the manpages description of scan-id is "Scan id(s)" implying the posibility - of providing multiple ids, this does not seem to work - def "get.byIdMultiple"() { - def scanId1= Fcli.run("util var contents scans -q scanId==#var('scans').get(0).scanId -o expr={scanId}"); - def scanId2= Fcli.run("util var contents scans -q scanId==#var('scans').get(1).scanId -o expr={scanId}"); - def args = "fod scan get " + scanId1.stdout[0] + "," + scanId2.stdout[0] + def "wait-for-oss"() { + def args = "fod oss-scan wait-for ::ossScan:: -i 2s --until=all-match --any-state=Completed,In_Progress,Queued" when: def result = Fcli.run(args) then: verifyAll(result.stdout) { - size()>2 - it[1].startsWith("userId: ") + // + } + } + + def "start.mast-scan"() { + def args = "fod mast-scan start --release=fcli-mobile:m1 --file=$mastPackage --assessment-type=Mobile\\ Assessment --framework=Android --frequency=Subscription --store mastScan" + when: + def result=null; + try { + result = Fcli.run(args) + } catch(UnexpectedFcliResultException e) { + if(e.result.stderr.any { it.contains("the entitlement has expired") }) { + result = e.result; + } else { + throw e; + } + } + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("STARTED") + } + } + + def "wait-for-mast"() { + def args = "fod mast-scan wait-for ::mastScan:: -i 2s --until=all-match --any-state=Completed,In_Progress,Queued" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + // + } + } + /* currently not implemented, awaiting availability of automated dast scan on fod + def "start.dast-scan"() { + def args = "fod dast-scan start --release=fcli-1698140484524:v2 --store dastScan" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>=2 + it.last().contains("STARTED") + } + } + + def "wait-for-dast"() { + def args = "fod dast-scan wait-for ::dastScan:: -i 2s --until=all-match --any-state=Completed,In_Progress,Queued" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + // } }*/ diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/_common/FoDUserSupplier.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/_common/FoDUserSupplier.groovy index fa625828a2..2e982fe565 100644 --- a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/_common/FoDUserSupplier.groovy +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/fod/_common/FoDUserSupplier.groovy @@ -29,7 +29,7 @@ public class FoDUserSupplier extends AbstractCloseableEntitySupplier { public FoDUser create() { Fcli.run("fod rest lookup Roles --store roles") - Fcli.run("fod ac create-user $userName --email=test@test.test --firstname=test --lastname=user --phone=1234 --role=::roles::get(0).value " + + Fcli.run("fod ac create-user $userName --email=$random@test.test --firstname=test --lastname=user --phone=1234 --role=::roles::get(0).value " + "--store $variableName", {it.expectSuccess(true, "Unable to create user")}) return this diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCAppVersionSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCAppVersionSpec.groovy index a21d6c6901..3b7ca8a6e3 100644 --- a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCAppVersionSpec.groovy +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCAppVersionSpec.groovy @@ -16,6 +16,7 @@ import spock.lang.Stepwise @Prefix("ssc.appversion") @FcliSession(SSC) @Stepwise class SSCAppVersionSpec extends FcliBaseSpec { @Shared @AutoCleanup SSCAppVersionSupplier versionSupplier = new SSCAppVersionSupplier() + @Shared @AutoCleanup SSCAppVersionSupplier versionSupplier2 = new SSCAppVersionSupplier() def "list"() { def args = "ssc appversion list" @@ -29,7 +30,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "get.byName"() { - def args = "ssc appversion get " + versionSupplier.version.appName + ":" + versionSupplier.version.versionName + def args = "ssc appversion get ${versionSupplier.version.appName}:${versionSupplier.version.versionName}" when: def result = Fcli.run(args) then: @@ -39,7 +40,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "get.byId"() { - def args = "ssc appversion get " + versionSupplier.version.get("id") + def args = "ssc appversion get ${versionSupplier.version.get("id")}" when: def result = Fcli.run(args) then: @@ -50,7 +51,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "updateName"() { - def args = "ssc appversion update " + versionSupplier.version.get("id") + " --name updatedVersionName --description updated1 -o table=name,description" + def args = "ssc appversion update ${versionSupplier.version.get("id")} --name updatedVersionName --description updated1 --attrs=DevPhase=Retired -o table=name,description" when: def result = Fcli.run(args) then: @@ -61,7 +62,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "updateNameWithMatchingAppName"() { - def args = "ssc appversion update " + versionSupplier.version.get("id") + " --name " + versionSupplier.version.appName + ":updatedVersionName2 --description updated2 -o table=name,description" + def args = "ssc appversion update ${versionSupplier.version.get("id")} --name ${versionSupplier.version.appName}:updatedVersionName2 --description updated2 -o table=name,description" when: def result = Fcli.run(args) then: @@ -72,7 +73,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "updateNameWithMatchingAppNameAndCustomDelimiter"() { - def args = "ssc appversion update " + versionSupplier.version.get("id") + " --name " + versionSupplier.version.appName + "|updatedVersionName3 --description updated2 --delim | -o table=name,description" + def args = "ssc appversion update ${versionSupplier.version.get("id")} --name ${versionSupplier.version.appName}|updatedVersionName3 --description updated2 --delim | -o table=name,description" when: def result = Fcli.run(args) then: @@ -84,7 +85,7 @@ class SSCAppVersionSpec extends FcliBaseSpec { } def "updateNameWithNonMatchingAppName"() { - def args = "ssc appversion update " + versionSupplier.version.get("id") + " --name nonExistingAppversion123:updatedVersionName3 --description updated3" + def args = "ssc appversion update ${versionSupplier.version.get("id")} --name nonExistingAppversion123:updatedVersionName3 --description updated3" when: def result = Fcli.run(args) then: @@ -93,4 +94,54 @@ class SSCAppVersionSpec extends FcliBaseSpec { it[0].startsWith("java.lang.IllegalArgumentException: --name option must contain either a plain name or ${versionSupplier.version.appName}:, current: nonExistingAppversion123:updatedVersionName3") } } + + + def "createWithCopy"() { + def args = "ssc appversion create --from=10060 --auto-required-attrs --issue-template=Prioritized\\ High\\ Risk\\ Issue\\ Template ${versionSupplier.version.appName}:copied --store=copied" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()==2 + it[1].endsWith("CREATED ") + } + } + + def "verifyCopy"() { + Thread.sleep(5000) + def args = "ssc issue count --appversion=::copied::id" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()==3 + it[1].contains("High 2") + } + } + + def "copy-state"() { + def args = "ssc appversion copy-state --from=10060 --to=${versionSupplier2.version.get("id")}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()==2 + it[1].endsWith("COPY_REQUESTED ") + } + } + + def "verifyCopy2"() { + Thread.sleep(5000) + def args = "ssc issue count --appversion=${versionSupplier2.version.get("id")}" + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()==3 + it[1].contains("High 2") + } + } + //TODO add tests to verify copying of attributes once that is implemented + //the copy action in the UI using the /bulk endpoint sets a copyVersionAttributes flag which doesnt seem to do anything atm + //waiting for feedback from PM if that is supposed to be working, if not Alex plans to implement it client side } \ No newline at end of file diff --git a/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/HelloWorld.apk b/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/HelloWorld.apk new file mode 100644 index 0000000000..2cdf053915 Binary files /dev/null and b/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/HelloWorld.apk differ diff --git a/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/oss_package.zip b/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/oss_package.zip new file mode 100644 index 0000000000..477d7b69f8 Binary files /dev/null and b/fcli-other/fcli-functional-test/src/ftest/resources/runtime/shared/oss_package.zip differ