├── Jenkinsfile
├── .github
├── CODEOWNERS
├── release-drafter.yml
├── dependabot.yml
├── workflows
│ ├── release-drafter.yml
│ ├── workflow-test.yaml
│ └── test.yml
└── aws_signer.py
├── .mvn
├── maven.config
└── extensions.xml
├── .gitignore
├── src
├── main
│ ├── java
│ │ └── io
│ │ │ └── jenkins
│ │ │ └── plugins
│ │ │ └── appdome
│ │ │ └── build
│ │ │ └── to
│ │ │ └── secure
│ │ │ ├── platform
│ │ │ ├── PlatformType.java
│ │ │ ├── SignType.java
│ │ │ ├── PlatformDescriptor.java
│ │ │ ├── ios
│ │ │ │ ├── certificate
│ │ │ │ │ └── method
│ │ │ │ │ │ ├── CertificateMethodDescriptor.java
│ │ │ │ │ │ ├── PrivateSign.java
│ │ │ │ │ │ ├── CertificateMethod.java
│ │ │ │ │ │ ├── AutoDevSign.java
│ │ │ │ │ │ └── AutoSign.java
│ │ │ │ └── IosPlatform.java
│ │ │ ├── android
│ │ │ │ ├── certificate
│ │ │ │ │ └── method
│ │ │ │ │ │ ├── CertificateMethodDescriptor.java
│ │ │ │ │ │ ├── CertificateMethod.java
│ │ │ │ │ │ ├── PrivateSign.java
│ │ │ │ │ │ ├── AutoDevSign.java
│ │ │ │ │ │ ├── AutoGoogleSign.java
│ │ │ │ │ │ └── AutoSign.java
│ │ │ │ ├── Datadog.java
│ │ │ │ ├── Crashlytics.java
│ │ │ │ └── AndroidPlatform.java
│ │ │ └── Platform.java
│ │ │ ├── SecondOutput.java
│ │ │ ├── BuildToTest.java
│ │ │ ├── DynamicCertificate.java
│ │ │ ├── VendorManager.java
│ │ │ ├── AppdomeBuilderConstants.java
│ │ │ ├── StringWarp.java
│ │ │ └── AppdomeBuilder.java
│ └── resources
│ │ ├── index.jelly
│ │ └── io
│ │ └── jenkins
│ │ └── plugins
│ │ └── appdome
│ │ └── build
│ │ └── to
│ │ └── secure
│ │ ├── platform
│ │ ├── android
│ │ │ ├── certificate
│ │ │ │ └── method
│ │ │ │ │ ├── AutoDevSign
│ │ │ │ │ └── config.jelly
│ │ │ │ │ ├── PrivateSign
│ │ │ │ │ └── config.jelly
│ │ │ │ │ └── AutoSign
│ │ │ │ │ └── config.jelly
│ │ │ └── AndroidPlatform
│ │ │ │ └── config.jelly
│ │ └── ios
│ │ │ ├── IosPlatform
│ │ │ └── config.jelly
│ │ │ └── certificate
│ │ │ └── method
│ │ │ ├── PrivateSign
│ │ │ └── config.jelly
│ │ │ ├── AutoDevSign
│ │ │ └── config.jelly
│ │ │ └── AutoSign
│ │ │ └── config.jelly
│ │ └── AppdomeBuilder
│ │ └── config.jelly
└── test
│ └── java
│ └── io
│ └── jenkins
│ └── plugins
│ └── appdome
│ └── build
│ └── to
│ └── secure
│ ├── AppdomeBuilderTest.java
│ ├── Tests.java
│ └── PipelineTest.java
├── LICENSE.md
├── README.md
└── pom.xml
/Jenkinsfile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @jenkinsci/appdome-build-2secure-plugin-developers
2 |
--------------------------------------------------------------------------------
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -Pconsume-incrementals
2 | -Pmight-produce-incrementals
3 |
4 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | _extends: .github
2 | tag-template: appdome-build-2secure-$NEXT_MINOR_VERSION
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 |
3 | # mvn hpi:run
4 | work
5 |
6 | # IntelliJ IDEA project files
7 | *.iml
8 | *.iws
9 | *.ipr
10 | .idea
11 |
12 | # Eclipse project files
13 | .settings
14 | .classpath
15 | .project
16 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/PlatformType.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform;
2 |
3 | public enum PlatformType {
4 | IOS,
5 | ANDROID
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/resources/index.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 | Appdome Build-2secure integrates Jenkins with
4 |
Appdome
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/SignType.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform;
2 |
3 | public enum SignType {
4 | AUTO,
5 | PRIVATE,
6 | AUTODEV,
7 | NONE
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/PlatformDescriptor.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform;
2 |
3 | import hudson.model.Descriptor;
4 |
5 | public class PlatformDescriptor extends Descriptor {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/CertificateMethodDescriptor.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method;
2 |
3 | import hudson.model.Descriptor;
4 |
5 |
6 | public class CertificateMethodDescriptor extends Descriptor {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/CertificateMethodDescriptor.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.model.Descriptor;
4 |
5 | public class CertificateMethodDescriptor extends Descriptor {
6 | }
7 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates
2 |
3 | version: 2
4 | updates:
5 | - package-ecosystem: maven
6 | directory: /
7 | schedule:
8 | interval: monthly
9 | - package-ecosystem: github-actions
10 | directory: /
11 | schedule:
12 | interval: monthly
13 |
--------------------------------------------------------------------------------
/.mvn/extensions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.jenkins.tools.incrementals
4 | git-changelist-maven-extension
5 | 1.6
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/AutoDevSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/PrivateSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | # Automates creation of Release Drafts using Release Drafter
2 | # More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc
3 |
4 | on:
5 | push:
6 | branches:
7 | - master
8 | - main
9 |
10 | jobs:
11 | update_release_draft:
12 | runs-on: ubuntu-latest
13 | steps:
14 | # Drafts your next Release notes as Pull Requests are merged into the default branch
15 | - name: Update Release Draft
16 | uses: release-drafter/release-drafter@v5
17 | env:
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/SecondOutput.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import org.kohsuke.stapler.DataBoundConstructor;
4 | import org.kohsuke.stapler.DataBoundSetter;
5 |
6 | public class SecondOutput {
7 | private String secondOutput;
8 |
9 | @DataBoundConstructor
10 | public SecondOutput(String secondOutput) {
11 | this.secondOutput = secondOutput;
12 | }
13 |
14 | @DataBoundSetter
15 | public void setSecondOutput(String secondOutput) {
16 | this.secondOutput = secondOutput;
17 | }
18 |
19 | public String getSecondOutput() {
20 | return secondOutput;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/BuildToTest.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import org.kohsuke.stapler.DataBoundConstructor;
4 | import org.kohsuke.stapler.DataBoundSetter;
5 |
6 | public class BuildToTest {
7 | private String selectedVendor;
8 |
9 | @DataBoundConstructor
10 | public BuildToTest(String selectedVendor) {
11 | this.selectedVendor = selectedVendor;
12 | }
13 |
14 | @DataBoundSetter
15 | public void setSelectedVendor(String selectedVendor) {
16 | this.selectedVendor = selectedVendor;
17 | }
18 |
19 | public String getSelectedVendor() {
20 | return selectedVendor;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/DynamicCertificate.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import org.kohsuke.stapler.DataBoundConstructor;
4 | import org.kohsuke.stapler.DataBoundSetter;
5 |
6 | public class DynamicCertificate {
7 | private String dynamicCertificate;
8 |
9 | @DataBoundConstructor
10 | public DynamicCertificate(String dynamicCertificate) {
11 | this.dynamicCertificate = dynamicCertificate;
12 | }
13 |
14 | @DataBoundSetter
15 | public void setDynamicCertificate(String dynamicCertificate) {
16 | this.dynamicCertificate = dynamicCertificate;
17 | }
18 |
19 | public String getDynamicCertificate() {
20 | return this.dynamicCertificate;
21 | }
22 |
23 | }
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/ios/IosPlatform/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/PrivateSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/Datadog.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android;
2 |
3 | import hudson.Extension;
4 | import hudson.model.AbstractDescribableImpl;
5 | import hudson.model.Descriptor;
6 | import org.kohsuke.stapler.DataBoundConstructor;
7 | import org.jenkinsci.Symbol;
8 | import org.kohsuke.stapler.export.Exported;
9 |
10 | public class Datadog extends AbstractDescribableImpl {
11 |
12 | private final String datadogKey;
13 |
14 | @DataBoundConstructor
15 | public Datadog(String datadogKey) {
16 | this.datadogKey = datadogKey;
17 | }
18 |
19 | @Exported
20 | public String getDatadogKey() {
21 | return datadogKey;
22 | }
23 |
24 | @Symbol("Datadog")
25 | @Extension
26 | public static class DescriptorImpl extends Descriptor {
27 | public String getDisplayName() {
28 | return "Datadog Configuration";
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/CertificateMethod.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.ExtensionPoint;
4 | import hudson.model.Describable;
5 | import hudson.model.Descriptor;
6 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
7 | import jenkins.model.Jenkins;
8 |
9 | public class CertificateMethod implements Describable, ExtensionPoint {
10 | private SignType signType;
11 |
12 | public CertificateMethod(SignType signType) {
13 | this.signType = signType;
14 | }
15 |
16 |
17 | public SignType getSignType() {
18 | return signType;
19 | }
20 |
21 | public void setSignType(SignType signType) {
22 | this.signType = signType;
23 | }
24 | @Override
25 | public Descriptor getDescriptor() {
26 | return Jenkins.get().getDescriptorOrDie(getClass());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright 2023
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/VendorManager.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import hudson.util.ListBoxModel;
4 |
5 | public class VendorManager {
6 |
7 | public enum Vendor {
8 | SAUCELABS,
9 | BITBAR,
10 | LAMBDATEST,
11 | BROWSERSTACK,
12 | PERFECTO,
13 | FIREBASE,
14 | KATALON,
15 | TOSCA,
16 | AWS_DEVICE_FARM
17 | }
18 |
19 | private static final VendorManager instance = new VendorManager();
20 |
21 | private VendorManager() {
22 | }
23 |
24 | public static VendorManager getInstance() {
25 | return instance;
26 | }
27 |
28 | public ListBoxModel getVendors() {
29 | ListBoxModel vendors = new ListBoxModel();
30 | for (Vendor vendor : Vendor.values()) {
31 | String name = vendor.name();
32 | String formattedName = name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();
33 | vendors.add(formattedName, name);
34 | }
35 | return vendors;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/Crashlytics.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android;
2 |
3 | import hudson.Extension;
4 | import hudson.model.Describable;
5 | import hudson.model.Descriptor;
6 | import jenkins.model.Jenkins;
7 | import org.jenkinsci.Symbol;
8 | import org.kohsuke.stapler.DataBoundConstructor;
9 | import org.kohsuke.stapler.export.Exported;
10 |
11 | public class Crashlytics implements Describable {
12 |
13 | private final String firebaseAppId;
14 |
15 | @DataBoundConstructor
16 | public Crashlytics(String firebaseAppId) {
17 | this.firebaseAppId = firebaseAppId;
18 | }
19 |
20 | @Exported
21 | public String getFirebaseAppId() {
22 | return firebaseAppId;
23 | }
24 |
25 | @Override
26 | public Descriptor getDescriptor() {
27 | return Jenkins.get().getDescriptor(Crashlytics.class);
28 | }
29 |
30 | @Symbol("Crashlytics") // ✅ Register as DSL symbol
31 | @Extension
32 | public static class DescriptorImpl extends Descriptor {
33 | @Override
34 | public String getDisplayName() {
35 | return "Crashlytics Configuration";
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/PrivateSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method;
2 |
3 | import hudson.Extension;
4 | import io.jenkins.plugins.appdome.build.to.secure.StringWarp;
5 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
6 | import org.jenkinsci.Symbol;
7 | import org.kohsuke.stapler.DataBoundConstructor;
8 |
9 | import java.util.List;
10 |
11 | public class PrivateSign extends CertificateMethod {
12 | private final List provisioningProfiles;
13 |
14 | @DataBoundConstructor
15 | public PrivateSign(List provisioningProfiles) {
16 | super(SignType.PRIVATE);
17 | this.provisioningProfiles = provisioningProfiles;
18 | }
19 |
20 | public List getProvisioningProfiles() {
21 | return provisioningProfiles;
22 | }
23 |
24 | public String getProvisioningProfilesPath() {
25 | return concatenateStrings(provisioningProfiles);
26 | }
27 |
28 | @Symbol("iOS_PrivateSign")
29 | @Extension
30 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
31 | @Override
32 | public String getDisplayName() {
33 | return "Private Signing";
34 | }
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Appdome Build-2secure-plugin for Jenkins
2 |
3 |
4 | ## Introduction
5 |
6 | The Build-2Secure plugin for Jenkins automates three important steps in delivering more secure mobile applications to your users faster:
7 | (1) Building app-level protections into mobile apps
8 | (2) Code signing the protected mobile app
9 | (3) Certifying the security of each protected mobile app.
10 | [The Appdome Build-2Secure](https://www.appdome.com) plugin for Jenkins can be used to deliver Certifed Secure™ mobile app security, anti-fraud, anti-malware, mobile anti-bot, and other cyber defense updates to mobile apps on the Appdome Cyber Defense Automation Platform. Use this plugin for Jenkins as a stand-alone DevSecOps integration or in combination with other DevSecOps integrations in your CI/CD pipeline. Developers have the option of using Freestyle or Pipeline projects to configure.
11 |
12 |
13 | ## Getting started
14 |
15 | For documentation on how to use the plugin, see the [Appdome Build-2secure plugin](https://www.appdome.com/how-to/devsecops-automation-mobile-cicd/mobile-app-security-anti-fraud-cicd/use-appdome-build-2secure-plugin-for-jenkins/).
16 |
17 | ## Issues
18 |
19 | Please report issues and enhancements through the [Github issue tracker](https://github.com/jenkinsci/appdome-build-2secure-plugin/issues/new/choose).
20 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/android/AndroidPlatform/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/AutoDevSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/CertificateMethod.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method;
2 |
3 | import hudson.ExtensionPoint;
4 | import hudson.model.Describable;
5 | import hudson.model.Descriptor;
6 |
7 | import io.jenkins.plugins.appdome.build.to.secure.StringWarp;
8 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
9 | import jenkins.model.Jenkins;
10 |
11 | import java.util.List;
12 |
13 | public class CertificateMethod implements Describable, ExtensionPoint {
14 | private SignType signType;
15 |
16 | public CertificateMethod(SignType signType) {
17 | this.signType = signType;
18 | }
19 |
20 |
21 | public SignType getSignType() {
22 | return signType;
23 | }
24 |
25 | public void setSignType(SignType signType) {
26 | this.signType = signType;
27 | }
28 |
29 | public String concatenateStrings(List strList) {
30 | if (strList != null) {
31 | StringBuilder concatenatePath = new StringBuilder();
32 | for (StringWarp path : strList) {
33 | concatenatePath.append(((StringWarp) path).getItem()).append(',');
34 | }
35 | return concatenatePath.substring(0, concatenatePath.length() - 1).trim();
36 | }
37 | return null;
38 | }
39 |
40 |
41 | @Override
42 | public Descriptor getDescriptor() {
43 | return Jenkins.get().getDescriptorOrDie(getClass());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/Platform.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform;
2 |
3 | import hudson.ExtensionPoint;
4 | import hudson.model.Describable;
5 | import hudson.model.Descriptor;
6 | import jenkins.model.Jenkins;
7 |
8 | public abstract class Platform implements Describable, ExtensionPoint {
9 |
10 | private String appPath;
11 | private String fusionSetId;
12 | private PlatformType platformType;
13 |
14 |
15 | public Platform(PlatformType platformType) {
16 | this.platformType = platformType;
17 | }
18 |
19 | public PlatformType getPlatformType() {
20 | return platformType;
21 | }
22 |
23 | public void setPlatformType(PlatformType platformType) {
24 | this.platformType = platformType;
25 | }
26 |
27 |
28 | public String getAppPath() {
29 | return appPath;
30 | }
31 |
32 |
33 | public void setAppPath(String appPath) {
34 | this.appPath = appPath;
35 | }
36 |
37 |
38 | public void setFusionSetId(String fusionSetId) {
39 | this.fusionSetId = fusionSetId;
40 | }
41 |
42 | public String getFusionSetId() {
43 | return fusionSetId;
44 | }
45 |
46 |
47 | @Override
48 | public Descriptor getDescriptor() {
49 | return Jenkins.get().getDescriptorOrDie(getClass());
50 | }
51 |
52 | //
53 | // @Extension
54 | // public static class DescriptorImpl extends Descriptor {
55 | //
56 | //
57 | // public String getDisplayName() {
58 | // return null;
59 | // }
60 | // }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/AutoSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/AutoDevSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method;
2 |
3 | import hudson.Extension;
4 | import io.jenkins.plugins.appdome.build.to.secure.StringWarp;
5 | import org.jenkinsci.Symbol;
6 | import org.kohsuke.stapler.DataBoundConstructor;
7 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
8 | import java.util.List;
9 |
10 | public class AutoDevSign extends CertificateMethod {
11 | private final List provisioningProfiles;
12 | private final List entitlements;
13 |
14 | @DataBoundConstructor
15 | public AutoDevSign(List provisioningProfiles, List entitlements) {
16 | super(SignType.AUTODEV);
17 | this.provisioningProfiles = provisioningProfiles;
18 | this.entitlements = entitlements;
19 | }
20 |
21 | public List getProvisioningProfiles() {
22 | return provisioningProfiles;
23 | }
24 |
25 | public List getEntitlements() {
26 | return entitlements;
27 | }
28 |
29 | public String getEntitlementsPath() {
30 | return concatenateStrings(entitlements);
31 | }
32 |
33 | public String getProvisioningProfilesPath() {
34 | return concatenateStrings(provisioningProfiles);
35 | }
36 |
37 |
38 | @Symbol("iOS_AutoDevSign")
39 | @Extension
40 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
41 | @Override
42 | public String getDisplayName() {
43 | return "Auto-Dev Signing";
44 | }
45 |
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/AutoSign/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/AppdomeBuilderConstants.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | public interface AppdomeBuilderConstants {
4 | /**
5 | * Environment variables
6 | **/
7 | String APP_PATH = "APP_PATH";
8 | String KEYSTORE_PATH_ENV = "KEYSTORE_PATH";
9 | String MOBILE_PROVISION_PROFILE_PATHS_ENV = "MOBILE_PROVISION_PROFILE_PATHS";
10 | String ENTITLEMENTS_PATHS_ENV = "ENTITLEMENTS_PATHS";
11 | String APPDOME_HEADER_ENV_NAME = "APPDOME_CLIENT_HEADER";
12 | String APPDOME_BUILDE2SECURE_VERSION = "Jenkins/1.3.0";
13 |
14 | /**
15 | * FLAGS
16 | **/
17 |
18 | String KEY_FLAG = " --api_key ";
19 | String FUSION_SET_ID_FLAG = " --fusion_set_id ";
20 | String TEAM_ID_FLAG = " --team_id ";
21 | String APP_FLAG = " --app ";
22 | String OUTPUT_FLAG = " --output ";
23 | String SIGN_ON_APPDOME_FLAG = " --sign_on_appdome ";
24 | String KEYSTORE_FLAG = " --keystore ";
25 | String KEYSTORE_PASS_FLAG = " --keystore_pass ";
26 | String KEYSOTRE_ALIAS_FLAG = " --keystore_alias ";
27 | String KEY_PASS_FLAG = " --key_pass ";
28 | String PROVISION_PROFILES_FLAG = " --provisioning_profiles ";
29 | String ENTITLEMENTS_FLAG = " --entitlements ";
30 | String PRIVATE_SIGN_FLAG = " --private_signing ";
31 | String AUTO_DEV_PRIVATE_SIGN_FLAG = " --auto_dev_private_signing ";
32 | String GOOGLE_PLAY_SIGN_FLAG = " --google_play_signing ";
33 | String FINGERPRINT_FLAG = " --signing_fingerprint ";
34 | String CERTIFIED_SECURE_PDF_FLAG = " --certificate_output ";
35 | String CERTIFIED_SECURE_JSON_FLAG = " --certificate_json ";
36 | String BUILD_WITH_LOGS = " --build_logs ";
37 | String BUILD_TO_TEST = " --build_to_test_vendor ";
38 | String SECOND_OUTPUT = " --second_output ";
39 |
40 | String DYNAMIC_CERTIFICATE = " --cert_pinning_zip ";
41 |
42 |
43 | String DEOBFUSCATION_OUTPUT = " --deobfuscation_script_output ";
44 | String FIREBASE_APP_ID = " --app_id ";
45 | String DATADOG_API_KEY = " --datadog_api_key ";
46 | String WORKFLOW_OUTPUT_LOGS_FLAG = " --workflow_output_logs ";
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/PrivateSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.util.FormValidation;
6 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
7 | import jenkins.model.Jenkins;
8 | import org.jenkinsci.Symbol;
9 | import org.kohsuke.stapler.DataBoundConstructor;
10 | import org.kohsuke.stapler.DataBoundSetter;
11 | import org.kohsuke.stapler.QueryParameter;
12 | import org.kohsuke.stapler.verb.POST;
13 |
14 | public class PrivateSign extends CertificateMethod {
15 |
16 | private final String fingerprint;
17 | private Boolean googleSigning;
18 |
19 | @DataBoundConstructor
20 | public PrivateSign(String fingerprint) {
21 | super(SignType.PRIVATE);
22 | this.fingerprint = fingerprint;
23 | }
24 |
25 | public String getFingerprint() {
26 | return fingerprint;
27 | }
28 |
29 | public Boolean getGoogleSigning() {
30 | return googleSigning;
31 | }
32 |
33 | @DataBoundSetter
34 | public void setGoogleSigning(Boolean googleSigning) {
35 | this.googleSigning = googleSigning;
36 | }
37 |
38 | @Symbol("Android_PrivateSign")
39 | @Extension
40 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
41 |
42 | @POST
43 | public FormValidation doCheckFingerprint(@QueryParameter String fingerprint) {
44 | Jenkins.get().checkPermission(Jenkins.READ);
45 | if (fingerprint != null && Util.fixEmptyAndTrim(fingerprint) == null) {
46 | return FormValidation.error("Fingerprint must be provided.");
47 | }else if (fingerprint != null && fingerprint.contains(" ")) {
48 | return FormValidation.error("White spaces are not allowed in FingerPrint.");
49 | }
50 | // Perform any additional validation here
51 | return FormValidation.ok();
52 | }
53 |
54 | @Override
55 | public String getDisplayName() {
56 | return "Private Signing";
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/AutoDevSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.util.FormValidation;
6 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
7 | import jenkins.model.Jenkins;
8 | import org.jenkinsci.Symbol;
9 | import org.kohsuke.stapler.DataBoundConstructor;
10 | import org.kohsuke.stapler.DataBoundSetter;
11 | import org.kohsuke.stapler.QueryParameter;
12 | import org.kohsuke.stapler.verb.POST;
13 |
14 | public class AutoDevSign extends CertificateMethod {
15 |
16 | private final String fingerprint;
17 | private Boolean googleSigning;
18 |
19 | @DataBoundConstructor
20 | public AutoDevSign(String fingerprint) {
21 |
22 | super(SignType.AUTODEV);
23 | this.fingerprint = fingerprint;
24 | }
25 |
26 | public String getFingerprint() {
27 | return fingerprint;
28 | }
29 |
30 | public Boolean getGoogleSigning() {
31 | return googleSigning;
32 | }
33 |
34 | @DataBoundSetter
35 | public void setGoogleSigning(Boolean googleSigning) {
36 | this.googleSigning = googleSigning;
37 | }
38 |
39 | @Symbol("Android_AutoDevSign")
40 | @Extension
41 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
42 |
43 | @POST
44 | public FormValidation doCheckFingerprint(@QueryParameter String fingerprint) {
45 | Jenkins.get().checkPermission(Jenkins.READ);
46 | if (fingerprint != null && Util.fixEmptyAndTrim(fingerprint) == null) {
47 | return FormValidation.error("Fingerprint must be provided.");
48 | }else if (fingerprint != null && fingerprint.contains(" ")) {
49 | return FormValidation.error("White spaces are not allowed in Fingerprint.");
50 | }
51 | // Perform any additional validation here
52 | return FormValidation.ok();
53 | }
54 |
55 | @Override
56 | public String getDisplayName() {
57 | return "Auto-Dev Signing";
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/AutoGoogleSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.model.AbstractDescribableImpl;
6 | import hudson.model.Descriptor;
7 | import hudson.util.FormValidation;
8 | import jenkins.model.Jenkins;
9 | import org.jenkinsci.Symbol;
10 | import org.kohsuke.stapler.DataBoundConstructor;
11 | import org.kohsuke.stapler.DataBoundSetter;
12 | import org.kohsuke.stapler.QueryParameter;
13 | import org.kohsuke.stapler.verb.POST;
14 |
15 | public class AutoGoogleSign extends AbstractDescribableImpl {
16 |
17 | private String googleSignFingerPrint;
18 |
19 |
20 | private Boolean isEnableGoogleSign;
21 |
22 | @DataBoundConstructor
23 | public AutoGoogleSign(String googleSignFingerPrint) {
24 | if (googleSignFingerPrint != null) {
25 | this.googleSignFingerPrint = googleSignFingerPrint;
26 | this.isEnableGoogleSign = true;
27 | } else {
28 | this.googleSignFingerPrint = null;
29 | this.isEnableGoogleSign = false;
30 | }
31 | }
32 |
33 | public String getGoogleSignFingerPrint() {
34 | return googleSignFingerPrint;
35 | }
36 |
37 | public Boolean getIsEnableGoogleSign() {
38 | return isEnableGoogleSign;
39 | }
40 |
41 | @DataBoundSetter
42 | public void setGoogleSignFingerPrint(String googleSignFingerPrint) {
43 | if (googleSignFingerPrint != null) {
44 | this.googleSignFingerPrint = googleSignFingerPrint;
45 | this.isEnableGoogleSign = true;
46 | } else {
47 | this.googleSignFingerPrint = null;
48 | this.isEnableGoogleSign = false;
49 | }
50 | }
51 |
52 |
53 | @Symbol({"Android_AutoGoogleSign", "SignOnAppdome_GoogleSign"})
54 | @Extension
55 | public static class DescriptorImpl extends Descriptor {
56 |
57 | @POST
58 | public FormValidation doCheckGoogleSignFingerPrint(@QueryParameter String googleSignFingerPrint) {
59 | Jenkins.get().checkPermission(Jenkins.READ);
60 | if (googleSignFingerPrint != null && Util.fixEmptyAndTrim(googleSignFingerPrint) == null) {
61 | return FormValidation.error("If Google Sign is enabled, fingerprint must be provided.");
62 | }else if (googleSignFingerPrint != null && googleSignFingerPrint.contains(" ")) {
63 | return FormValidation.error("White spaces are not allowed in FingerPrint.");
64 | }
65 | // Perform any additional validation here
66 | return FormValidation.ok();
67 | }
68 | public String getDisplayName() {
69 | return "";
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/resources/io/jenkins/plugins/appdome/build/to/secure/AppdomeBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/.github/aws_signer.py:
--------------------------------------------------------------------------------
1 | import os
2 | import boto3
3 | import json
4 |
5 |
6 | def main():
7 | aws_access_key_id = os.environ.get('AWS_ACCESS_KEY_ID')
8 | aws_secret_access_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
9 | aws_default_region = 'eu-central-1'
10 | bucket_name = "appdome-automation-vanilla-apps"
11 | objects = {
12 | 'aab_app.aab': 'Thomas/PipelineFiles/Apps/FileFinder.aab',
13 | 'apk_app_1.apk': 'Thomas/PipelineFiles/Apps/TimeCard.apk',
14 | 'apk_app_2.apk': 'Thomas/PipelineFiles/Apps/AndroidMediaPlayer.apk',
15 | 'keystore_file.keystore': 'Thomas/PipelineFiles/appdome.keystore',
16 | 'ipa_app_1.ipa': 'Thomas/PipelineFiles/Apps/FileFinder.ipa',
17 | 'ipa_app_2.ipa': 'Thomas/PipelineFiles/Apps/Trends256-iOS16.ipa',
18 | 'ipa_app_3.ipa': 'Thomas/PipelineFiles/Apps/Trends256-ForWatchKit.ipa',
19 | 'certificate_file1.p12': 'Thomas/PipelineFiles/AutomationCert.p12',
20 | 'certificate_file2.p12': 'Thomas/PipelineFiles/meirtsvi75.p12',
21 | 'ipa_1_mobile_provisioning.mobileprovision': 'Thomas/PipelineFiles/Automation.mobileprovision',
22 | 'ipa_1_entitlements.plist': 'Thomas/PipelineFiles/AutomationEntitlements.plist',
23 | 'ipa_2_mobile_provisioning_1.mobileprovision': 'Thomas/PipelineFiles/Trendsappstoredist.mobileprovision',
24 | 'ipa_2_mobile_provisioning_2.mobileprovision': 'Thomas/PipelineFiles/Trends_watchkit_appstoredist.mobileprovision',
25 | 'ipa_2_mobile_provisioning_3.mobileprovision': 'Thomas/PipelineFiles/Trends_watchkit_extension_appstoredist.mobileprovision',
26 | 'ipa_2_entitlements_1.plist': 'Thomas/PipelineFiles/main.plist',
27 | 'ipa_2_entitlements_2.plist': 'Thomas/PipelineFiles/watchkit.plist',
28 | 'ipa_2_entitlements_3.plist': 'Thomas/PipelineFiles/watchkitextension.plist',
29 | }
30 |
31 | if aws_access_key_id is None or aws_secret_access_key is None:
32 | print("Missing required environment variables.")
33 | exit(1)
34 |
35 | s3 = boto3.client('s3', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key,
36 | region_name=aws_default_region)
37 |
38 | presigned_urls = {}
39 |
40 | for key, object_key in objects.items():
41 | presigned_url = s3.generate_presigned_url(
42 | 'get_object',
43 | Params={
44 | 'Bucket': bucket_name,
45 | 'Key': object_key
46 | },
47 | ExpiresIn=3600 # 1 hour
48 | )
49 | presigned_urls[key] = presigned_url
50 |
51 | destination_folder = "presigned_urls"
52 | # Specify the path to the JSON file
53 | json_file_path = os.path.join(destination_folder, 'presigned_urls.json')
54 |
55 | # Create destination folder if it doesn't exist
56 | os.makedirs(destination_folder, exist_ok=True)
57 | # Write the dictionary to the JSON file
58 | with open(json_file_path, 'w') as json_file:
59 | json.dump(presigned_urls, json_file)
60 |
61 | print(f"The presigned URLs have been written to {json_file_path}")
62 |
63 |
64 | if __name__ == "__main__":
65 | main()
66 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.jenkins-ci.plugins
6 | plugin
7 | 4.55
8 |
9 |
10 | io.jenkins.plugins
11 | appdome-build-2secure
12 | ${revision}${changelist}
13 | hpi
14 | Appdome Build-2secure
15 | https://github.com/jenkinsci/${project.artifactId}-plugin
16 |
17 |
18 | MIT License
19 | https://opensource.org/licenses/MIT
20 |
21 |
22 |
23 | scm:git:https://github.com/${gitHubRepo}
24 | scm:git:https://github.com/${gitHubRepo}
25 | appdome-build-2secure-1.2.8
26 | https://github.com/${gitHubRepo}
27 |
28 |
29 | 1.2.10
30 | -SNAPSHOT
31 |
32 | 2.361.4
33 | jenkinsci/${project.artifactId}-plugin
34 | true
35 |
36 |
37 |
38 |
39 |
40 | io.jenkins.tools.bom
41 | bom-2.387.x
42 | 2543.vfb_1a_5fb_9496d
43 | pom
44 | import
45 |
46 |
47 |
48 |
49 |
50 | org.jenkins-ci.plugins
51 | credentials
52 | 1139.veb_9579fca_33b_
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | repo.jenkins-ci.org
61 | https://repo.jenkins-ci.org/public/
62 |
63 |
64 |
65 |
66 | repo.jenkins-ci.org
67 | https://repo.jenkins-ci.org/public/
68 |
69 |
70 |
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-surefire-plugin
75 |
76 | methods
77 | 6
78 |
79 | ${jenkins.version}
80 |
81 | 0
82 | true
83 | false
84 | false
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/StringWarp.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.model.AbstractDescribableImpl;
6 | import hudson.model.Descriptor;
7 | import hudson.util.FormValidation;
8 | import jenkins.model.Jenkins;
9 | import org.jenkinsci.Symbol;
10 | import org.kohsuke.stapler.DataBoundConstructor;
11 | import org.kohsuke.stapler.QueryParameter;
12 | import org.kohsuke.stapler.verb.POST;
13 |
14 | public class StringWarp extends AbstractDescribableImpl {
15 |
16 | private final String item;
17 |
18 | @DataBoundConstructor
19 | public StringWarp(String item) {
20 | this.item = item;
21 | }
22 |
23 | public String getItem() {
24 | return this.item;
25 | }
26 |
27 | public String getProvisioningProfiles() {
28 | return this.item;
29 | }
30 |
31 | public String getEntitlements() {
32 | return this.item;
33 | }
34 |
35 | public String getSecondOutput() {
36 | return this.item;
37 | }
38 |
39 | public String getDynamicCertificate() {
40 | return this.item;
41 | }
42 |
43 |
44 | @Symbol("StringWarp")
45 | @Extension
46 | public static class DescriptorImpl extends Descriptor {
47 |
48 | @POST
49 | public FormValidation doCheckProvisioningProfiles(@QueryParameter String item) {
50 | Jenkins.get().checkPermission(Jenkins.READ);
51 | if (item != null && Util.fixEmptyAndTrim(item) == null) {
52 | return FormValidation.warning("please add at least one Provisioning Profile file and ensure that all entries" +
53 | " are filled without any empty fields.Or please ensure that a valid path is provided " +
54 | "for Provisioning Profile files in the environment variable named 'MOBILE_PROVISION_PROFILE_PATHS' instead");
55 | } else if (item != null && item.contains(" ")) {
56 | return FormValidation.error("White spaces are not allowed in the path.");
57 | } else if (item != null && !(item.lastIndexOf(".") != -1
58 | && item.substring(item.lastIndexOf(".")).equals(".mobileprovision"))) {
59 | return FormValidation.error("Provisioning profile - File extension is not allowed," +
60 | " allowed extensions are: '.mobileprovision'. Please rename your file or upload a different file.");
61 | }
62 | return FormValidation.ok();
63 | }
64 |
65 | @POST
66 | public FormValidation doCheckEntitlements(@QueryParameter String item) {
67 | Jenkins.get().checkPermission(Jenkins.READ);
68 | if (item != null && Util.fixEmptyAndTrim(item) == null) {
69 | return FormValidation.warning("please add at least one entitlement file and ensure that all entries" +
70 | " are filled without any empty fields.Or please ensure that a valid path is provided " +
71 | "for entitlements files in the environment variable named 'ENTITLEMENTS_PATHS' instead");
72 | } else if (item != null && item.contains(" ")) {
73 | return FormValidation.error("White spaces are not allowed in the path.");
74 | } else if (item != null && !(item.lastIndexOf(".") != -1
75 | && item.substring(item.lastIndexOf(".")).equals(".plist"))) {
76 | return FormValidation.error("Entitlements - File extension is not allowed," +
77 | " allowed extensions are: '.plist'. Please rename your file or upload a different file.");
78 | }
79 |
80 | // Perform any additional validation here
81 | return FormValidation.ok();
82 | }
83 |
84 | public String getDisplayName() {
85 | return "";
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/IosPlatform.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios;
2 |
3 | import hudson.DescriptorExtensionList;
4 | import hudson.Extension;
5 | import hudson.Util;
6 | import hudson.model.Descriptor;
7 | import hudson.util.FormValidation;
8 | import io.jenkins.plugins.appdome.build.to.secure.platform.Platform;
9 | import io.jenkins.plugins.appdome.build.to.secure.platform.PlatformDescriptor;
10 | import io.jenkins.plugins.appdome.build.to.secure.platform.PlatformType;
11 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.CertificateMethod;
12 | import jenkins.model.Jenkins;
13 | import org.jenkinsci.Symbol;
14 | import org.kohsuke.stapler.DataBoundConstructor;
15 | import org.kohsuke.stapler.DataBoundSetter;
16 | import org.kohsuke.stapler.QueryParameter;
17 | import org.kohsuke.stapler.verb.POST;
18 |
19 | import static io.jenkins.plugins.appdome.build.to.secure.AppdomeBuilder.isHttpUrl;
20 |
21 | public class IosPlatform extends Platform {
22 |
23 | private final CertificateMethod certificateMethod;
24 |
25 | @DataBoundConstructor
26 | public IosPlatform(CertificateMethod certificateMethod) {
27 | super(PlatformType.IOS);
28 | this.certificateMethod = certificateMethod;
29 | }
30 |
31 | @DataBoundSetter
32 | public void setAppPath(String appPath) {
33 | super.setAppPath(appPath);
34 | }
35 |
36 |
37 | @DataBoundSetter
38 | public void setFusionSetId(String fusionSetId) {
39 | super.setFusionSetId(fusionSetId);
40 | }
41 |
42 | public String getAppPath() {
43 | return super.getAppPath();
44 | }
45 |
46 | public String getFusionSetId() {
47 | return super.getFusionSetId();
48 | }
49 |
50 | public CertificateMethod getCertificateMethod() {
51 | return certificateMethod;
52 | }
53 |
54 | public DescriptorExtensionList> getCertificateMethodDescriptors() {
55 | return Jenkins.get().getDescriptorList(CertificateMethod.class);
56 | }
57 |
58 | @Symbol("IosPlatform")
59 | @Extension
60 | public static final class DescriptorImpl extends PlatformDescriptor {
61 |
62 | @POST
63 | public FormValidation doCheckAppPath(@QueryParameter String appPath) {
64 | Jenkins.get().checkPermission(Jenkins.READ);
65 | if (appPath != null && Util.fixEmptyAndTrim(appPath) == null) {
66 | return FormValidation.warning("Application path was not provided.\n " +
67 | "Please ensure that a valid path is provided for non-protected applications in the environment variable called 'APP_PATH'.");
68 | } else if (appPath != null && appPath.contains(" ")) {
69 | return FormValidation.error("White spaces are not allowed in the path.");
70 | } else if (appPath != null && isHttpUrl(appPath)) {
71 | return FormValidation.ok("Application remote url provided.");
72 | } else if (appPath != null && !(appPath.endsWith(".ipa"))) {
73 | return FormValidation.error("iOS app - File extension is not allowed," +
74 | " allowed extensions are: '.ipa'. Please rename your file or upload a different file.");
75 | }
76 | // Perform any additional validation here
77 | return FormValidation.ok();
78 | }
79 |
80 | @POST
81 | public FormValidation doCheckFusionSetId(@QueryParameter String fusionSetId) {
82 | Jenkins.get().checkPermission(Jenkins.READ);
83 | if (fusionSetId != null && Util.fixEmptyAndTrim(fusionSetId) == null) {
84 | return FormValidation.error("FusionSet-ID must be provided.");
85 | } else if (fusionSetId != null && fusionSetId.contains(" ")) {
86 | return FormValidation.error("White spaces are not allowed in FusionSetId.");
87 | }
88 | // Perform any additional validation here
89 | return FormValidation.ok("Chosen fusionSet: " + fusionSetId);
90 | }
91 |
92 | @Override
93 | public String getDisplayName() {
94 | return "iOS";
95 | }
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/ios/certificate/method/AutoSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.util.FormValidation;
6 | import hudson.util.Secret;
7 | import io.jenkins.plugins.appdome.build.to.secure.StringWarp;
8 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
9 | import jenkins.model.Jenkins;
10 | import org.jenkinsci.Symbol;
11 | import org.kohsuke.stapler.DataBoundConstructor;
12 | import org.kohsuke.stapler.DataBoundSetter;
13 | import org.kohsuke.stapler.QueryParameter;
14 | import org.kohsuke.stapler.verb.POST;
15 |
16 | import java.util.List;
17 |
18 | public class AutoSign extends CertificateMethod {
19 |
20 | @SuppressWarnings("lgtm[jenkins/plaintext-storage]")
21 | private final String keystorePath;
22 | private final Secret keystorePassword;
23 | private List provisioningProfiles;
24 | private final List entitlements;
25 |
26 | @DataBoundConstructor
27 | public AutoSign(String keystorePath, Secret keystorePassword, List provisioningProfiles, List entitlements) {
28 | super(SignType.AUTO);
29 | this.keystorePath = keystorePath;
30 | this.keystorePassword = keystorePassword;
31 | this.provisioningProfiles = provisioningProfiles;
32 | this.entitlements = entitlements;
33 | }
34 |
35 | public String getKeystorePath() {
36 | return keystorePath;
37 | }
38 |
39 | public Secret getKeystorePassword() {
40 | return keystorePassword;
41 | }
42 |
43 | public List getProvisioningProfiles() {
44 | return provisioningProfiles;
45 | }
46 |
47 | @DataBoundSetter
48 | public void setProvisioningProfiles(List provisioningProfiles) {
49 | this.provisioningProfiles = provisioningProfiles;
50 | }
51 |
52 | public List getEntitlements() {
53 | return entitlements;
54 | }
55 |
56 |
57 | public String getEntitlementsPath() {
58 | return concatenateStrings(entitlements);
59 | }
60 |
61 | public String getProvisioningProfilesPath() {
62 | return concatenateStrings(provisioningProfiles);
63 | }
64 |
65 |
66 | @Symbol({"iOS_AutoSign", "iOS_SignOnAppdome"})
67 | @Extension
68 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
69 |
70 |
71 | @POST
72 | public FormValidation doCheckKeystorePath(@QueryParameter String keystorePath) {
73 | Jenkins.get().checkPermission(Jenkins.READ);
74 | if (keystorePath != null && Util.fixEmptyAndTrim(keystorePath) == null) {
75 | return FormValidation.warning("Path to keystore file must be provided." +
76 | "Or please ensure that a valid path is provided for non-protected applications " +
77 | "in the environment variable named 'KEYSTORE_PATH`'.");
78 | } else if (keystorePath != null && keystorePath.contains(" ")) {
79 | return FormValidation.error("White spaces are not allowed in the path.");
80 | } else if (keystorePath != null && !(keystorePath.lastIndexOf(".") != -1
81 | && keystorePath.substring(keystorePath.lastIndexOf(".")).equals(".p12"))) {
82 | return FormValidation.error("iOS keystore - File extension is not allowed," +
83 | " allowed extensions are: '.p12'. Please rename your file or upload a different file.");
84 | }
85 | // Perform any additional validation here
86 | return FormValidation.ok();
87 | }
88 |
89 | @POST
90 | public FormValidation doCheckKeystorePassword(@QueryParameter Secret keystorePassword) {
91 | Jenkins.get().checkPermission(Jenkins.READ);
92 | if (keystorePassword != null && Util.fixEmptyAndTrim(keystorePassword.getPlainText()) == null) {
93 | return FormValidation.error("Keystore's password must be provided.");
94 | }
95 | // Perform any additional validation here
96 | return FormValidation.ok();
97 | }
98 |
99 |
100 | @Override
101 | public String getDisplayName() {
102 | return "Sign On Appdome";
103 | }
104 |
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/certificate/method/AutoSign.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method;
2 |
3 | import hudson.Extension;
4 | import hudson.Util;
5 | import hudson.util.FormValidation;
6 | import hudson.util.Secret;
7 | import io.jenkins.plugins.appdome.build.to.secure.platform.SignType;
8 | import jenkins.model.Jenkins;
9 | import org.jenkinsci.Symbol;
10 | import org.kohsuke.stapler.DataBoundConstructor;
11 | import org.kohsuke.stapler.DataBoundSetter;
12 | import org.kohsuke.stapler.QueryParameter;
13 | import org.kohsuke.stapler.verb.POST;
14 |
15 | public class AutoSign extends CertificateMethod {
16 |
17 | @SuppressWarnings("lgtm[jenkins/plaintext-storage]")
18 | private final String keystorePath;
19 | private final Secret keystorePassword;
20 | private final Secret keystoreAlias;
21 | private final Secret keyPass;
22 | private AutoGoogleSign googleSignFingerPrint;
23 | private Boolean isEnableGoogleSign;
24 |
25 | @DataBoundConstructor
26 | public AutoSign(String keystorePath, Secret keystorePassword, Secret keystoreAlias, Secret keyPass, AutoGoogleSign googleSignFingerPrint) {
27 | super(SignType.AUTO);
28 | this.keystorePath = keystorePath;
29 | this.keystorePassword = keystorePassword;
30 | this.keystoreAlias = keystoreAlias;
31 | this.keyPass = keyPass;
32 | this.googleSignFingerPrint = googleSignFingerPrint;
33 | }
34 |
35 | @DataBoundSetter
36 | public void setGoogleSignFingerPrint(AutoGoogleSign googleSignFingerPrint) {
37 | this.googleSignFingerPrint = googleSignFingerPrint;
38 | }
39 |
40 | public Boolean getEnableGoogleSign() {
41 | return isEnableGoogleSign;
42 | }
43 |
44 | public void setEnableGoogleSign(Boolean enableGoogleSign) {
45 | isEnableGoogleSign = enableGoogleSign;
46 | }
47 |
48 | public String getKeystorePath() {
49 | return keystorePath;
50 | }
51 |
52 | public Secret getKeystorePassword() {
53 | return keystorePassword;
54 | }
55 |
56 | public Secret getKeystoreAlias() {
57 | return keystoreAlias;
58 | }
59 |
60 | public Secret getKeyPass() {
61 | return keyPass;
62 | }
63 |
64 |
65 | public String getGoogleSignFingerPrint() {
66 | if (googleSignFingerPrint != null) {
67 | return googleSignFingerPrint.getGoogleSignFingerPrint();
68 | }
69 | return null;
70 | }
71 |
72 | public Boolean getIsEnableGoogleSign() {
73 | if (googleSignFingerPrint != null) {
74 | return googleSignFingerPrint.getIsEnableGoogleSign();
75 | }
76 | return false;
77 | }
78 |
79 |
80 | @DataBoundSetter
81 | public void setGoogleSign(AutoGoogleSign googleSignFingerPrint) {
82 | this.googleSignFingerPrint = googleSignFingerPrint;
83 | }
84 |
85 | @Symbol({"Android_AutoSign", "Android_SignOnAppdome"})
86 | @Extension
87 | public static final class DescriptorImpl extends CertificateMethodDescriptor {
88 |
89 | @POST
90 | public FormValidation doCheckKeystorePath(@QueryParameter String keystorePath) {
91 | Jenkins.get().checkPermission(Jenkins.READ);
92 | if (keystorePath != null && Util.fixEmptyAndTrim(keystorePath) == null) {
93 | return FormValidation.warning("Path to keystore file must be provided." +
94 | "Or please ensure that a valid path is provided for non-protected applications in the environment variable named 'KEYSTORE_PATH'.");
95 | } else if (keystorePath != null && keystorePath.contains(" ")) {
96 | return FormValidation.error("White spaces are not allowed in the path.");
97 | }
98 | // Perform any additional validation here
99 | return FormValidation.ok();
100 | }
101 |
102 | @POST
103 | public FormValidation doCheckKeystorePassword(@QueryParameter Secret keystorePassword) {
104 | Jenkins.get().checkPermission(Jenkins.READ);
105 | if (keystorePassword != null && Util.fixEmptyAndTrim(keystorePassword.getPlainText()) == null) {
106 | return FormValidation.error("Keystore's Password must be provided.");
107 | }
108 | // Perform any additional validation here
109 | return FormValidation.ok();
110 | }
111 |
112 | @POST
113 | public FormValidation doCheckKeystoreAlias(@QueryParameter Secret keystoreAlias) {
114 | Jenkins.get().checkPermission(Jenkins.READ);
115 | if (keystoreAlias != null && Util.fixEmptyAndTrim(keystoreAlias.getPlainText()) == null) {
116 | return FormValidation.error("Keystore alias must be provided.");
117 | }
118 | // Perform any additional validation here
119 | return FormValidation.ok();
120 | }
121 |
122 | @POST
123 | public FormValidation doCheckKeyPass(@QueryParameter Secret keyPass) {
124 | Jenkins.get().checkPermission(Jenkins.READ);
125 | if (keyPass != null && Util.fixEmptyAndTrim(keyPass.getPlainText()) == null) {
126 | return FormValidation.error("Key pass must be provided.");
127 | }
128 | // Perform any additional validation here
129 | return FormValidation.ok();
130 | }
131 |
132 |
133 | @POST
134 | public FormValidation doCheckGoogleSignFingerPrint(@QueryParameter String googleSignFingerPrint) {
135 | Jenkins.get().checkPermission(Jenkins.READ);
136 | if (googleSignFingerPrint != null && Util.fixEmptyAndTrim(googleSignFingerPrint) == null) {
137 | return FormValidation.error("If Google Sign is enabled, fingerprint must be provided.");
138 | }else if (googleSignFingerPrint != null && googleSignFingerPrint.contains(" ")) {
139 | return FormValidation.error("White spaces are not allowed in FingerPrint.");
140 | }
141 | // Perform any additional validation here
142 | return FormValidation.ok();
143 | }
144 |
145 | @Override
146 | public String getDisplayName() {
147 | return "Sign On Appdome";
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/platform/android/AndroidPlatform.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure.platform.android;
2 |
3 | import hudson.DescriptorExtensionList;
4 | import hudson.Extension;
5 | import hudson.Util;
6 | import hudson.model.Descriptor;
7 | import hudson.util.FormValidation;
8 | import io.jenkins.cli.shaded.org.apache.commons.lang.StringUtils;
9 | import io.jenkins.plugins.appdome.build.to.secure.platform.Platform;
10 | import io.jenkins.plugins.appdome.build.to.secure.platform.PlatformDescriptor;
11 | import io.jenkins.plugins.appdome.build.to.secure.platform.PlatformType;
12 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.CertificateMethod;
13 | import jenkins.model.Jenkins;
14 | import org.jenkinsci.Symbol;
15 | import org.kohsuke.stapler.DataBoundConstructor;
16 | import org.kohsuke.stapler.DataBoundSetter;
17 | import org.kohsuke.stapler.QueryParameter;
18 | import org.kohsuke.stapler.verb.POST;
19 |
20 | import static io.jenkins.plugins.appdome.build.to.secure.AppdomeBuilder.isHttpUrl;
21 |
22 | public class AndroidPlatform extends Platform {
23 |
24 | private final CertificateMethod certificateMethod;
25 | private Crashlytics crashlytics;
26 |
27 | private Datadog datadog;
28 |
29 | @DataBoundConstructor
30 | public AndroidPlatform(CertificateMethod certificateMethod) {
31 | super(PlatformType.ANDROID);
32 | this.certificateMethod = certificateMethod;
33 | }
34 |
35 |
36 | // Crashlytics
37 | public Boolean getIsCrashlytics() {
38 | return this.crashlytics != null && this.crashlytics.getFirebaseAppId() != null;
39 | }
40 |
41 | public Crashlytics getCrashlytics() { // Changed from getCrashlyticsPublisher to getCrashlytics
42 | return crashlytics;
43 | }
44 |
45 | @DataBoundSetter
46 | public void setCrashlytics(Crashlytics crashlytics) {
47 | this.crashlytics = crashlytics;
48 | }
49 |
50 | public String getFirebaseAppId() {
51 | if (this.crashlytics != null) {
52 | return this.crashlytics.getFirebaseAppId().toString();
53 | } else
54 | return null;
55 | }
56 |
57 | // DATADOG
58 | public Boolean getIsDatadog() {
59 | return this.datadog != null && this.datadog.getDatadogKey() != null;
60 | }
61 |
62 | public Datadog getDatadog() {
63 | return datadog;
64 | }
65 |
66 | @DataBoundSetter
67 | public void setDatadog(Datadog datadog) {
68 | this.datadog = datadog;
69 | }
70 |
71 | public String getDatadogKey() {
72 | if (this.datadog != null) {
73 | return this.datadog.getDatadogKey();
74 | } else {
75 | return null;
76 | }
77 | }
78 |
79 |
80 | public String getAppPath() {
81 | return super.getAppPath();
82 | }
83 |
84 | @DataBoundSetter
85 | public void setAppPath(String appPath) {
86 | super.setAppPath(appPath);
87 | }
88 |
89 | public String getFusionSetId() {
90 | return super.getFusionSetId();
91 | }
92 |
93 | @DataBoundSetter
94 | public void setFusionSetId(String fusionSetId) {
95 | super.setFusionSetId(fusionSetId);
96 | }
97 |
98 | public CertificateMethod getCertificateMethod() {
99 | return certificateMethod;
100 | }
101 |
102 |
103 | public DescriptorExtensionList> getCertificateMethodDescriptors() {
104 | return Jenkins.get().getDescriptorList(CertificateMethod.class);
105 | }
106 |
107 | @Symbol("AndroidPlatform")
108 | @Extension
109 | public static final class DescriptorImpl extends PlatformDescriptor {
110 |
111 | @POST
112 | public FormValidation doCheckAppPath(@QueryParameter String appPath) {
113 | Jenkins.get().checkPermission(Jenkins.READ);
114 | if (appPath != null && Util.fixEmptyAndTrim(appPath) == null) {
115 | return FormValidation.warning("Application path was not provided.\n " +
116 | "Or please ensure that a valid path is provided for non-protected applications" +
117 | " in the environment variable named 'APP_PATH'.");
118 | } else if (appPath != null && appPath.contains(" ")) {
119 | return FormValidation.error("White spaces are not allowed in the path.");
120 | } else if (appPath != null && isHttpUrl(appPath)) {
121 | return FormValidation.ok("Application remote url provided.");
122 | } else if (appPath != null && !(appPath.endsWith(".aab") || appPath.endsWith(".apk"))) {
123 | return FormValidation.error("Android app - File extension is not allowed," +
124 | " allowed extensions are: '.apk' or '.aab'. Please rename your file or upload a different file.");
125 | }
126 | // Perform any additional validation here
127 | return FormValidation.ok();
128 | }
129 |
130 | @POST
131 | public FormValidation doCheckFusionSetId(@QueryParameter String fusionSetId) {
132 | Jenkins.get().checkPermission(Jenkins.READ);
133 | if (fusionSetId != null && Util.fixEmptyAndTrim(fusionSetId) == null) {
134 | return FormValidation.error("FusionSet-ID must be provided.");
135 | } else if (fusionSetId != null && fusionSetId.contains(" ")) {
136 | return FormValidation.error("White spaces are not allowed in FusionSetId.");
137 | }
138 | // Perform any additional validation here
139 | return FormValidation.ok("Chosen fusionSet: " + fusionSetId);
140 | }
141 |
142 | @POST
143 | public FormValidation doCheckFirebaseAppId(@QueryParameter String firebaseAppId) {
144 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); // Ensure correct permission
145 |
146 | if (StringUtils.isBlank(firebaseAppId)) {
147 | return FormValidation.error("Firebase App ID must be provided.");
148 | } else if (firebaseAppId.contains(" ")) {
149 | return FormValidation.error("White spaces are not allowed in Firebase App ID.");
150 | }
151 |
152 | // Additional validation logic
153 | try {
154 | // Simulate additional checks here
155 | return FormValidation.ok("Chosen Firebase App ID: " + firebaseAppId);
156 | } catch (Exception e) {
157 | return FormValidation.error("An error occurred: " + e.getMessage());
158 | }
159 | }
160 |
161 |
162 | @POST
163 | public FormValidation doCheckDatadogKey(@QueryParameter String datadogKey) {
164 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); // Ensure correct permission
165 |
166 | if (StringUtils.isBlank(datadogKey)) {
167 | return FormValidation.error("Firebase App ID must be provided.");
168 | } else if (datadogKey.contains(" ")) {
169 | return FormValidation.error("White spaces are not allowed in Firebase App ID.");
170 | }
171 |
172 | // Additional validation logic
173 | try {
174 | // Simulate additional checks here
175 | return FormValidation.ok("Datadog key: " + datadogKey);
176 | } catch (Exception e) {
177 | return FormValidation.error("An error occurred: " + e.getMessage());
178 | }
179 | }
180 |
181 | @Override
182 | public String getDisplayName() {
183 | return "Android";
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/.github/workflows/workflow-test.yaml:
--------------------------------------------------------------------------------
1 | name: Maven CI
2 |
3 | on:
4 | # push:
5 | # branches:
6 | # - main
7 | # - testing-enviorment
8 | # tags:
9 | # - v*
10 | # pull_request:
11 | # branches:
12 | # - main
13 | # - testing-enviorment
14 | workflow_dispatch:
15 | inputs:
16 | branch:
17 | description: 'Branch or tag to run tests on'
18 | required: true
19 | default: 'main'
20 | environment:
21 | description: 'Deployment environment'
22 | required: true
23 | default: 'development'
24 | type: choice
25 | options:
26 | - development
27 | - staging
28 | - production
29 | buildParams:
30 | description: 'Build parameters in JSON format'
31 | required: true
32 | default: '{"appdomeServerBaseUrl":"default-appdomeServerBaseUrl",teamId":"default-teamId", "signOption":"default-signOption", "appFilePath":"default-appFilePath", "keystoreFilePath":"default-keystoreFilePath", "certificateFilePath":"default-certificateFilePath", "fusionSetId":"default-fusionSetId", "signFingerprint":"default-signFingerprint", "entitlementsPath":"default1,default2", "mobileProvisionProfilesPath":"default1,default2", "buildToTest":"default-buildToTest", "buildWithLogs":"false", "googlePlaySign":"false", "secondOutput":"default-secondOutput","outputName":"protected_app","firebaseAppId":"default-firebaseAppId","datadogKey":"default-datadogKey","workflowOutputLogs":"false"}'
33 | secretParams:
34 | description: 'Build parameters in JSON format'
35 | required: true
36 | default: '{"APPDOME_API_TOKEN":"default-APPDOME_API_TOKEN", "KEYSTORE_ALIAS":"default-KEYSTORE_ALIAS", "KEYSTORE_KEY_PASS":"default-KEYSTORE_KEY_PASS", "KEYSTORE_PASSWORD":"default-KEYSTORE_PASSWORD", "P12_PASSWORD":"default-P12_PASSWORD"}'
37 | logLevel:
38 | description: 'Set the log level for Maven builds'
39 | required: false
40 | default: 'info'
41 | type: choice
42 | options:
43 | - info
44 | - warning
45 | - debug
46 | dispatch_id:
47 | description: 'run_unique_id'
48 | required: true
49 | type: string
50 |
51 | jobs:
52 | build-and-test:
53 | name: run_${{ github.event.inputs.dispatch_id }}
54 | runs-on: ubuntu-latest
55 | steps:
56 | - uses: actions/checkout@v2
57 | with:
58 | ref: ${{ github.event.inputs.branch }}
59 |
60 | - name: Set up JDK 11
61 | uses: actions/setup-java@v2
62 | with:
63 | java-version: '11'
64 | distribution: 'temurin'
65 | cache: 'maven'
66 |
67 | - name: Install jq
68 | run: sudo apt-get install jq
69 |
70 | - name: Parse Secret Params
71 | id: parse_secrets
72 | run: |
73 | echo "Parsing secret parameters..."
74 | secretParams=$(echo '${{ github.event.inputs.secretParams }}' | jq -r '.')
75 | echo "APPDOME_API_TOKEN_PIPELINE=$(echo "$secretParams" | jq -r '.APPDOME_API_TOKEN')" >> $GITHUB_ENV
76 | echo "KEYSTORE_ALIAS_PIPELINE=$(echo "$secretParams" | jq -r '.KEYSTORE_ALIAS')" >> $GITHUB_ENV
77 | echo "KEYSTORE_KEY_PASS_PIPELINE=$(echo "$secretParams" | jq -r '.KEYSTORE_KEY_PASS')" >> $GITHUB_ENV
78 | echo "KEYSTORE_PASSWORD_PIPELINE=$(echo "$secretParams" | jq -r '.KEYSTORE_PASSWORD')" >> $GITHUB_ENV
79 | echo "P12_PASSWORD_PIPELINE=$(echo "$secretParams" | jq -r '.P12_PASSWORD')" >> $GITHUB_ENV
80 |
81 |
82 | - name: Download files from AWS S3 URLs
83 | id: download_files # Assign an ID to the step to use outputs
84 | run: |
85 | # Function to get file extension from URL
86 | get_file_extension() {
87 | local url=$1
88 | if [[ "$url" == *".apk"* ]]; then
89 | echo "apk"
90 | elif [[ "$url" == *".aab"* ]]; then
91 | echo "aab"
92 | elif [[ "$url" == *".ipa"* ]]; then
93 | echo "ipa"
94 | else
95 | echo "unknown"
96 | fi
97 | }
98 |
99 | # Create output directory
100 | mkdir -p /tmp/output
101 |
102 | # Extract parameters from JSON input
103 | buildParams='${{ github.event.inputs.buildParams }}'
104 | appFilePath=$(echo $buildParams | jq -r '.appFilePath')
105 | keystoreFilePath=$(echo $buildParams | jq -r '.keystoreFilePath')
106 | certificateFilePath=$(echo $buildParams | jq -r '.certificateFilePath')
107 | entitlementsPath=$(echo $buildParams | jq -r '.entitlementsPath')
108 | mobileProvisionProfilesPath=$(echo $buildParams | jq -r '.mobileProvisionProfilesPath')
109 | APPDOME_SERVER_BASE_URL=$(echo $buildParams | jq -r '.appdomeServerBaseUrl')
110 |
111 | # Initialize local file paths
112 | localAppFilePath=""
113 | localKeystoreFilePath=""
114 | localCertificateFilePath=""
115 | localEntitlementsPaths=""
116 | localMobileProvisionPaths=""
117 |
118 | # Download app file with dynamic extension
119 | if [ "$appFilePath" != "None" ]; then
120 | extension=$(get_file_extension "$appFilePath")
121 |
122 | # Set a default name based on the detected extension
123 | localFileName="/tmp/app.$extension"
124 |
125 | # Download the file
126 | curl -L -o "$localFileName" "$appFilePath"
127 | echo "Downloaded app file to $localFileName"
128 | localAppFilePath="$localFileName"
129 | else
130 | echo "App file path is 'None', skipping download."
131 | fi
132 |
133 | # Download keystore file
134 | if [ "$keystoreFilePath" != "None" ]; then
135 | curl -L -o /tmp/keystore.keystore "$keystoreFilePath"
136 | echo "Downloaded keystore file to /tmp/keystore.keystore"
137 | localKeystoreFilePath="/tmp/keystore.keystore"
138 | else
139 | echo "Keystore file path is 'None', skipping download."
140 | fi
141 |
142 | # Download certificate file
143 | if [ "$certificateFilePath" != "None" ]; then
144 | curl -L -o /tmp/certificate.p12 "$certificateFilePath"
145 | echo "Downloaded certificate file to /tmp/certificate.p12"
146 | localCertificateFilePath="/tmp/certificate.p12"
147 | else
148 | echo "Certificate file path is 'None', skipping download."
149 | fi
150 |
151 | # Download entitlementsPath files, only if they are not "None"
152 | if [ "$entitlementsPath" != "None" ]; then
153 | IFS=',' read -ra entitlementUrls <<< "$entitlementsPath"
154 | counter=1
155 | for url in "${entitlementUrls[@]}"; do
156 | fileName="/tmp/entitlement${counter}.plist"
157 | curl -L -o "$fileName" "$url"
158 | localEntitlementsPaths="$localEntitlementsPaths,$fileName"
159 | counter=$((counter+1))
160 | done
161 | echo "Downloaded entitlement files: $localEntitlementsPaths"
162 | else
163 | echo "Entitlements path is 'None', skipping download."
164 | fi
165 |
166 | localEntitlementsPaths="${localEntitlementsPaths#,}"
167 |
168 | # Download mobileProvisionProfilesPath files, only if they are not "None"
169 | if [ "$mobileProvisionProfilesPath" != "None" ]; then
170 | IFS=',' read -ra provisionUrls <<< "$mobileProvisionProfilesPath"
171 | counter=1
172 | for url in "${provisionUrls[@]}"; do
173 | # Use a constant name for provision files
174 | fileName="/tmp/provision${counter}.mobileprovision"
175 | curl -L -o "$fileName" "$url"
176 |
177 | # If localMobileProvisionPaths is empty, don't add the comma
178 | if [ -z "$localMobileProvisionPaths" ]; then
179 | localMobileProvisionPaths="$fileName"
180 | else
181 | localMobileProvisionPaths="$localMobileProvisionPaths,$fileName"
182 | fi
183 |
184 | counter=$((counter+1))
185 | done
186 | echo "Downloaded mobile provision profiles: $localMobileProvisionPaths"
187 | else
188 | echo "Mobile provision profiles path is 'None', skipping download."
189 | fi
190 |
191 | # Set outputs for next steps using Environment Files
192 | echo "Setting environment variables for next steps..."
193 |
194 | echo "appFilePath: $localAppFilePath"
195 | echo "appFilePath=$localAppFilePath" >> $GITHUB_ENV
196 |
197 | echo "keystoreFilePath: $localKeystoreFilePath"
198 | echo "keystoreFilePath=$localKeystoreFilePath" >> $GITHUB_ENV
199 |
200 | echo "certificateFilePath: $localCertificateFilePath"
201 | echo "certificateFilePath=$localCertificateFilePath" >> $GITHUB_ENV
202 | echo "mobileProvisionProfilesPath: $localMobileProvisionPaths"
203 | echo "mobileProvisionProfilesPath=$localMobileProvisionPaths" >> $GITHUB_ENV
204 |
205 | echo "entitlementsPath: $localEntitlementsPaths"
206 | echo "entitlementsPath=$localEntitlementsPaths" >> $GITHUB_ENV
207 |
208 | echo "APPDOME_SERVER_BASE_URL: $APPDOME_SERVER_BASE_URL"
209 | echo "APPDOME_SERVER_BASE_URL=$APPDOME_SERVER_BASE_URL" >> $GITHUB_ENV
210 |
211 | - name: Build and Test with Maven
212 | run: |
213 | # Extract other parameters from JSON input
214 | buildParams='${{ github.event.inputs.buildParams }}'
215 | appdomeServerBaseUrl=$(echo $buildParams | jq -r '.appdomeServerBaseUrl')
216 | teamId=$(echo $buildParams | jq -r '.teamId')
217 | signOption=$(echo $buildParams | jq -r '.signOption')
218 | fusionSetId=$(echo $buildParams | jq -r '.fusionSetId')
219 | firebaseAppId=$(echo $buildParams | jq -r '.firebaseAppId')
220 | workflowOutputLogs=$(echo $buildParams | jq -r '.workflowOutputLogs')
221 | datadogKey=$(echo $buildParams | jq -r '.datadogKey')
222 | signFingerprint=$(echo $buildParams | jq -r '.signFingerprint')
223 | buildToTest=$(echo $buildParams | jq -r '.buildToTest')
224 | buildWithLogs=$(echo $buildParams | jq -r '.buildWithLogs')
225 | googlePlaySign=$(echo $buildParams | jq -r '.googlePlaySign')
226 | secondOutput=$(echo $buildParams | jq -r '.secondOutput')
227 | outputName=$(echo $buildParams | jq -r '.outputName') # Fixed this line
228 | # Use the environment variables directly
229 | appFilePath="$appFilePath"
230 | keystoreFilePath="$keystoreFilePath"
231 | certificateFilePath="$certificateFilePath"
232 | entitlementsPath="$entitlementsPath"
233 | mobileProvisionProfilesPath="$mobileProvisionProfilesPath"
234 |
235 | # Echo each parameter to verify parsing worked correctly
236 | echo "Parsed Parameters:"
237 | echo "appdomeServerBaseUrl: $appdomeServerBaseUrl"
238 | echo "teamId: $teamId"
239 | echo "signOption: $signOption"
240 | echo "appFilePath: $appFilePath"
241 | echo "keystoreFilePath: $keystoreFilePath"
242 | echo "certificateFilePath: $certificateFilePath"
243 | echo "fusionSetId: $fusionSetId"
244 | echo "firebaseAppId: $firebaseAppId"
245 | echo "datadogKey: $datadogKey"
246 | echo "workflowOutputLogs: $workflowOutputLogs"
247 | echo "signFingerprint: $signFingerprint"
248 | echo "entitlementsPath: $entitlementsPath"
249 | echo "mobileProvisionProfilesPath: $mobileProvisionProfilesPath"
250 | echo "buildToTest: $buildToTest"
251 | echo "buildWithLogs: $buildWithLogs"
252 | echo "googlePlaySign: $googlePlaySign"
253 | echo "secondOutput: $secondOutput"
254 | echo "outputName: $outputName"
255 |
256 | # Run the Maven command with extracted parameters
257 | mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false clean verify \
258 | -Dtest=PipelineTest#workFlowTest \
259 | -DteamId="$teamId" \
260 | -DsignOption="$signOption" \
261 | -DappFilePath="$appFilePath" \
262 | -DkeystoreFilePath="$keystoreFilePath" \
263 | -DcertificateFilePath="$certificateFilePath" \
264 | -DfusionSetId="$fusionSetId" \
265 | -DsignFingerprint="$signFingerprint" \
266 | -DentitlementsPath="$entitlementsPath" \
267 | -DmobileProvisionProfilesPath="$mobileProvisionProfilesPath" \
268 | -DbuildToTest="$buildToTest" \
269 | -DbuildWithLogs="$buildWithLogs" \
270 | -DgooglePlaySign="$googlePlaySign" \
271 | -DsecondOutput="$secondOutput" \
272 | -DoutputName="$outputName" \
273 | -DfirebaseAppId="$firebaseAppId" \
274 | -DdatadogKey="$datadogKey" \
275 | -DworkflowOutputLogs="$workflowOutputLogs" \
276 | -Denvironment="${{ github.event.inputs.environment }}" \
277 | package
278 | env:
279 | APPDOME_SERVER_BASE_URL: ${{ env.APPDOME_SERVER_BASE_URL }}
280 | APPDOME_API_TOKEN: ${{ env.APPDOME_API_TOKEN_PIPELINE }}
281 | KEYSTORE_ALIAS: ${{ env.KEYSTORE_ALIAS_PIPELINE }}
282 | KEYSTORE_KEY_PASS: ${{ env.KEYSTORE_KEY_PASS_PIPELINE }}
283 | KEYSTORE_PASSWORD: ${{ env.KEYSTORE_PASSWORD_PIPELINE }}
284 | P12_PASSWORD: ${{ env.P12_PASSWORD_PIPELINE }}
285 |
286 | # Step to upload the downloaded files as artifacts (using wildcard)
287 | - name: Upload artifacts
288 | uses: actions/upload-artifact@v4
289 | with:
290 | name: downloaded-files-artifact
291 | path: /home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/tmp/output/*
292 | if-no-files-found: warn
--------------------------------------------------------------------------------
/src/test/java/io/jenkins/plugins/appdome/build/to/secure/AppdomeBuilderTest.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import hudson.EnvVars;
4 | import hudson.FilePath;
5 | import hudson.model.FreeStyleBuild;
6 | import hudson.model.FreeStyleProject;
7 | import hudson.model.Result;
8 | import hudson.slaves.EnvironmentVariablesNodeProperty;
9 | import hudson.util.Secret;
10 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.AndroidPlatform;
11 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoDevSign;
12 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoGoogleSign;
13 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoSign;
14 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.PrivateSign;
15 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.IosPlatform;
16 | import org.junit.Before;
17 | import org.junit.Rule;
18 | import org.junit.Test;
19 | import org.jvnet.hudson.test.JenkinsRule;
20 |
21 | import java.io.File;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 | import java.util.logging.Logger;
25 |
26 | import static org.junit.Assert.assertTrue;
27 |
28 | public class AppdomeBuilderTest {
29 |
30 | @Rule
31 | public JenkinsRule jenkins = new JenkinsRule();
32 | private static final String PATH_TO_FILES = "downloaded_files/";
33 | final String androidFusionSet = "8c693120-7cab-11ee-8275-c54d0e1c9b7a";
34 | final String iosFusionSet = "13ded0a0-7cad-11ee-b531-29c8c84aedcc";
35 | final String fingerprint = "8DF593C1B6EAA6EADADCE36831FE82B08CAC8D74";
36 | private String token;
37 | final String teamId = "46002310-7cab-11ee-bfde-d76f94716e7a";
38 | private String aabAppPath;
39 | private String apkApp1Path;
40 | private String apkApp2Path;
41 | private String certificateFile1Path;
42 | private String certificateFile2Path;
43 | private String ipa1EntitlementsPath;
44 | private String ipa1MobileProvisioningPath;
45 | private String ipa2Entitlements1Path;
46 | private String ipa2Entitlements2Path;
47 | private String ipa2Entitlements3Path;
48 | private String ipa2MobileProvisioning1Path;
49 | private String ipa2MobileProvisioning2Path;
50 | private String ipa2MobileProvisioning3Path;
51 | private String ipaApp1Path;
52 | private String ipaApp2Path;
53 | private String ipaApp3Path;
54 | private String keystoreFilePath;
55 |
56 | private String keystoreAlias;
57 | private String keystoreKeyPass;
58 | private String keystorePassword;
59 | private String p12Password;
60 |
61 | @Before
62 | public void setUp() throws Exception {
63 | this.token = System.getenv("APPDOME_API_TOKEN");
64 | this.keystoreAlias = System.getenv("KEYSTORE_ALIAS");
65 | this.keystoreKeyPass = System.getenv("KEYSTORE_KEY_PASS");
66 | this.keystorePassword = System.getenv("KEYSTORE_PASSWORD");
67 | this.p12Password = System.getenv("P12_PASSWORD");
68 |
69 |
70 | this.
71 | setCommonEnvironmentVariables();
72 | setFiles();
73 | }
74 |
75 | private void setFiles() {
76 | this.aabAppPath = buildFilePath("aab_app.aab");
77 | this.apkApp1Path = buildFilePath("apk_app_1.apk");
78 | this.apkApp2Path = buildFilePath("apk_app_2.apk");
79 | this.certificateFile1Path = buildFilePath("certificate_file1.p12");
80 | this.certificateFile2Path = buildFilePath("certificate_file2.p12");
81 | this.ipa1EntitlementsPath = buildFilePath("ipa_1_entitlements.plist");
82 | this.ipa1MobileProvisioningPath = buildFilePath("ipa_1_mobile_provisioning.mobileprovision");
83 | this.ipa2Entitlements1Path = buildFilePath("ipa_2_entitlements_1.plist");
84 | this.ipa2Entitlements2Path = buildFilePath("ipa_2_entitlements_2.plist");
85 | this.ipa2Entitlements3Path = buildFilePath("ipa_2_entitlements_3.plist");
86 | this.ipa2MobileProvisioning1Path = buildFilePath("ipa_2_mobile_provisioning_1.mobileprovision");
87 | this.ipa2MobileProvisioning2Path = buildFilePath("ipa_2_mobile_provisioning_2.mobileprovision");
88 | this.ipa2MobileProvisioning3Path = buildFilePath("ipa_2_mobile_provisioning_3.mobileprovision");
89 | this.ipaApp1Path = buildFilePath("ipa_app_1.ipa");
90 | this.ipaApp2Path = buildFilePath("ipa_app_2.ipa");
91 | this.ipaApp3Path = buildFilePath("ipa_app_3.ipa");
92 | this.keystoreFilePath = buildFilePath("keystore_file.keystore");
93 |
94 |
95 | }
96 |
97 |
98 | private String buildFilePath(String filename) {
99 | File file = new File(PATH_TO_FILES, filename);
100 | System.out.println(filename + " : " + file.getAbsolutePath().toString());
101 | if (!file.exists()) {
102 | throw new IllegalStateException("Required file not found: " + file.getAbsolutePath());
103 | }
104 | return file.getAbsolutePath();
105 | }
106 |
107 | private void setCommonEnvironmentVariables() {
108 | EnvironmentVariablesNodeProperty prop = new EnvironmentVariablesNodeProperty();
109 | EnvVars env = prop.getEnvVars();
110 | env.put("APPDOME_SERVER_BASE_URL", "https://qamaster.dev.appdome.com");
111 | jenkins.jenkins.getGlobalNodeProperties().add(prop);
112 | }
113 |
114 | @Test
115 | public void testApkAndroidPrivateSignBuild() throws Exception {
116 | FreeStyleProject project = jenkins.createFreeStyleProject();
117 | // Create configuration objects
118 | PrivateSign privateSign = new PrivateSign(fingerprint);
119 | privateSign.setGoogleSigning(false);
120 | AndroidPlatform androidPlatform = new AndroidPlatform(privateSign);
121 | androidPlatform.setFusionSetId(androidFusionSet);
122 | androidPlatform.setAppPath(this.apkApp1Path);
123 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, null,null);
124 |
125 | appdomeBuilder.setBuildToTest(null);
126 | appdomeBuilder.setBuildWithLogs(true);
127 |
128 | project.getBuildersList().add(appdomeBuilder);
129 | checkingResults(project, false);
130 | }
131 |
132 | @Test
133 | public void testAAbAndroidPrivateSignBuild() throws Exception {
134 | FreeStyleProject project = jenkins.createFreeStyleProject();
135 | // Create configuration objects
136 | PrivateSign privateSign = new PrivateSign(fingerprint);
137 | privateSign.setGoogleSigning(false);
138 | AndroidPlatform androidPlatform = new AndroidPlatform(privateSign);
139 | androidPlatform.setFusionSetId(androidFusionSet);
140 | androidPlatform.setAppPath(this.aabAppPath);
141 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, null,null);
142 |
143 | appdomeBuilder.setBuildToTest(null);
144 | appdomeBuilder.setBuildWithLogs(true);
145 |
146 | project.getBuildersList().add(appdomeBuilder);
147 | checkingResults(project, false);
148 |
149 | }
150 |
151 | @Test
152 | public void testApkAndroidAutoDevSignBuild() throws Exception {
153 | FreeStyleProject project = jenkins.createFreeStyleProject();
154 | // Create configuration objects
155 | AutoDevSign autoDevSign = new AutoDevSign(fingerprint);
156 | autoDevSign.setGoogleSigning(true);
157 | AndroidPlatform androidPlatform = new AndroidPlatform(autoDevSign);
158 | androidPlatform.setFusionSetId(androidFusionSet);
159 | androidPlatform.setAppPath(this.apkApp2Path);
160 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, null,null);
161 | BuildToTest buildToTest = new BuildToTest(VendorManager.Vendor.SAUCELABS.name());
162 | appdomeBuilder.setBuildToTest(buildToTest);
163 | appdomeBuilder.setBuildWithLogs(false);
164 |
165 | project.getBuildersList().add(appdomeBuilder);
166 | checkingResults(project, false);
167 | }
168 |
169 | @Test
170 | public void testAabAndroidAutoDevSignBuild() throws Exception {
171 | FreeStyleProject project = jenkins.createFreeStyleProject();
172 | // Create configuration objects
173 | AutoDevSign autoDevSign = new AutoDevSign(fingerprint);
174 | autoDevSign.setGoogleSigning(true);
175 | AndroidPlatform androidPlatform = new AndroidPlatform(autoDevSign);
176 | androidPlatform.setFusionSetId(androidFusionSet);
177 | androidPlatform.setAppPath(this.aabAppPath);
178 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, null,null);
179 | BuildToTest buildToTest = new BuildToTest(VendorManager.Vendor.SAUCELABS.name());
180 | appdomeBuilder.setBuildToTest(buildToTest);
181 | appdomeBuilder.setBuildWithLogs(false);
182 |
183 | project.getBuildersList().add(appdomeBuilder);
184 | checkingResults(project, false);
185 | }
186 |
187 | @Test
188 | public void testApkAndroidAutoSignBuild() throws Exception {
189 | FreeStyleProject project = jenkins.createFreeStyleProject();
190 |
191 | // Create configuration objects
192 |
193 | AutoSign autoSign =
194 | new AutoSign(this.keystoreFilePath,
195 | Secret.fromString(this.keystorePassword), Secret.fromString(this.keystoreAlias),
196 | Secret.fromString(keystoreKeyPass), null);
197 |
198 | AndroidPlatform androidPlatform = new AndroidPlatform(autoSign);
199 | androidPlatform.setFusionSetId(androidFusionSet);
200 | androidPlatform.setAppPath(apkApp1Path);
201 |
202 |
203 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId,
204 | androidPlatform, null,null);
205 |
206 | appdomeBuilder.setBuildToTest(null);
207 |
208 | project.getBuildersList().add(appdomeBuilder);
209 | checkingResults(project, false);
210 | }
211 |
212 | @Test
213 | public void testAabAndroidAutoSignBuild() throws Exception {
214 | FreeStyleProject project = jenkins.createFreeStyleProject();
215 |
216 | // Create configuration objects
217 |
218 | AutoSign autoSign =
219 | new AutoSign(this.keystoreFilePath,
220 | Secret.fromString(this.keystorePassword), Secret.fromString(this.keystoreAlias),
221 | Secret.fromString(keystoreKeyPass), null);
222 |
223 | AndroidPlatform androidPlatform = new AndroidPlatform(autoSign);
224 | androidPlatform.setFusionSetId(androidFusionSet);
225 | androidPlatform.setAppPath(aabAppPath);
226 |
227 |
228 | File secondOutputLocation = new File("/home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/output/");
229 | secondOutputLocation.mkdirs();
230 | String secondOutputPath = secondOutputLocation.getPath() + File.separator + "second_output.apk";
231 |
232 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId,
233 | androidPlatform, new StringWarp(secondOutputPath),null);
234 |
235 | appdomeBuilder.setBuildToTest(null);
236 |
237 |
238 | project.getBuildersList().add(appdomeBuilder);
239 | checkingResults(project, false);
240 | }
241 |
242 |
243 | @Test
244 | public void testIosAutoSignBuild() throws Exception {
245 | FreeStyleProject project = jenkins.createFreeStyleProject();
246 | List provision_profiles = new ArrayList<>();
247 | provision_profiles.add(new StringWarp(ipa2MobileProvisioning1Path));
248 | provision_profiles.add(new StringWarp(ipa2MobileProvisioning2Path));
249 | provision_profiles.add(new StringWarp(ipa2MobileProvisioning3Path));
250 | List entitlements = new ArrayList<>();
251 | entitlements.add(new StringWarp(ipa2Entitlements1Path));
252 | entitlements.add(new StringWarp(ipa2Entitlements2Path));
253 | entitlements.add(new StringWarp(ipa2Entitlements3Path));
254 |
255 | // Create configuration objects
256 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoSign autoSign
257 | = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
258 | AutoSign(this.certificateFile2Path, Secret.fromString(this.p12Password), provision_profiles, entitlements);
259 |
260 | IosPlatform iosPlatform = new IosPlatform(autoSign);
261 | iosPlatform.setFusionSetId(iosFusionSet);
262 | iosPlatform.setAppPath(this.ipaApp2Path);
263 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null,null);
264 | BuildToTest buildToTest = new BuildToTest(VendorManager.Vendor.SAUCELABS.name());
265 | appdomeBuilder.setBuildToTest(buildToTest);
266 | appdomeBuilder.setBuildWithLogs(true);
267 |
268 | project.getBuildersList().add(appdomeBuilder);
269 | checkingResults(project, false);
270 | }
271 |
272 | private void checkingResults(FreeStyleProject project, boolean isSecondOutput) throws Exception {
273 | FreeStyleBuild build = jenkins.buildAndAssertSuccess(project);
274 | String consoleOutput = build.getLog();
275 | FilePath workspace = build.getWorkspace();
276 |
277 | // Check that the file exists in the workspace
278 | FilePath output_location = workspace.child("output");
279 | assertTrue("output_location should exist", output_location.exists());
280 | if (isSecondOutput) {
281 | jenkins.assertLogContains("Download Second Output", build);
282 | }
283 | System.out.println("build console output = " + consoleOutput);
284 | System.out.println("build status = " + build.getResult().toString());
285 | jenkins.assertBuildStatus(Result.SUCCESS, build); // Check build status
286 | }
287 |
288 | @Test
289 | public void testIosPrivateSignBuild() throws Exception {
290 | FreeStyleProject project = jenkins.createFreeStyleProject();
291 | List provision_profiles = new ArrayList<>();
292 | provision_profiles.add(new StringWarp(ipa1MobileProvisioningPath));
293 |
294 |
295 | // Create configuration objects
296 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.PrivateSign privateSign
297 | = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
298 | PrivateSign(provision_profiles);
299 | IosPlatform iosPlatform = new IosPlatform(privateSign);
300 | iosPlatform.setFusionSetId(iosFusionSet);
301 | iosPlatform.setAppPath(this.ipaApp1Path);
302 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null,null);
303 | BuildToTest buildToTest = new BuildToTest(VendorManager.Vendor.BROWSERSTACK.name());
304 | appdomeBuilder.setBuildToTest(buildToTest);
305 | appdomeBuilder.setBuildWithLogs(false);
306 |
307 | project.getBuildersList().add(appdomeBuilder);
308 | checkingResults(project, false);
309 |
310 | }
311 |
312 | @Test
313 | public void testIosAutoDevPrivateSignBuild() throws Exception {
314 | FreeStyleProject project = jenkins.createFreeStyleProject();
315 | List provision_profiles = new ArrayList<>();
316 | provision_profiles.add(new StringWarp(ipa1MobileProvisioningPath));
317 | List entitlements = new ArrayList<>();
318 | entitlements.add(new StringWarp(this.ipa1EntitlementsPath));
319 |
320 | // Create configuration objects
321 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoDevSign
322 | autoDevSign = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
323 | AutoDevSign(provision_profiles, entitlements);
324 | IosPlatform iosPlatform = new IosPlatform(autoDevSign);
325 | iosPlatform.setFusionSetId(iosFusionSet);
326 | iosPlatform.setAppPath(this.ipaApp3Path);
327 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null,null);
328 |
329 | project.getBuildersList().add(appdomeBuilder);
330 | checkingResults(project, false);
331 |
332 | }
333 |
334 |
335 | }
--------------------------------------------------------------------------------
/src/test/java/io/jenkins/plugins/appdome/build/to/secure/Tests.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import hudson.FilePath;
4 | import hudson.model.FreeStyleBuild;
5 | import hudson.model.FreeStyleProject;
6 | import hudson.model.Result;
7 | import hudson.util.Secret;
8 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.AndroidPlatform;
9 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.Crashlytics;
10 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.Datadog;
11 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoDevSign;
12 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoGoogleSign;
13 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.AutoSign;
14 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.certificate.method.PrivateSign;
15 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.IosPlatform;
16 | import org.junit.Test;
17 | import org.jvnet.hudson.test.JenkinsRule;
18 |
19 | import java.io.File;
20 | import java.util.List;
21 | import java.util.logging.Logger;
22 |
23 | import static org.junit.Assert.assertTrue;
24 |
25 | public class Tests {
26 |
27 | public static final String PLUGIN_TMP_OUTPUT = "/home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/tmp/output/";
28 |
29 | public static void testAndroidAutoSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet, String keystoreFilePath,
30 | String keystorePassword, String keystoreAlias, String keystoreKeyPass,
31 | String fingerprint, StringWarp secondOutput, BuildToTest buildToTest,
32 | Boolean buildWithLogs, String outputName, Crashlytics crashlytics, Datadog datadog, Boolean workflowOutputLogs, Logger logger) throws Exception {
33 | logger.info("Inside testAndroidAutoSignBuild");
34 | String output_location = PLUGIN_TMP_OUTPUT + outputName + "." + getFileExtension(appPath);
35 |
36 | FreeStyleProject project = jenkins.createFreeStyleProject();
37 | // Create configuration objects
38 | AutoGoogleSign autoGoogleSign = null;
39 | if (fingerprint != null) {
40 | autoGoogleSign = new AutoGoogleSign(fingerprint);
41 | }
42 | Boolean isSecondOutput = false;
43 | if (secondOutput != null) {
44 | isSecondOutput = true;
45 | }
46 |
47 |
48 | AutoSign autoSign =
49 | new AutoSign(keystoreFilePath,
50 | Secret.fromString(keystorePassword), Secret.fromString(keystoreAlias),
51 | Secret.fromString(keystoreKeyPass), autoGoogleSign);
52 |
53 | AndroidPlatform androidPlatform = new AndroidPlatform(autoSign);
54 | androidPlatform.setFusionSetId(fusionSet);
55 | androidPlatform.setAppPath(appPath);
56 |
57 | if (crashlytics != null) {
58 | androidPlatform.setCrashlytics(new Crashlytics(crashlytics.getFirebaseAppId()));
59 | }
60 |
61 | if (datadog != null) {
62 | androidPlatform.setDatadog(new Datadog(datadog.getDatadogKey()));
63 | }
64 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId,
65 | androidPlatform, secondOutput, null);
66 |
67 | appdomeBuilder.setBuildToTest(buildToTest);
68 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
69 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
70 | appdomeBuilder.setOutputLocation(output_location);
71 |
72 |
73 | logger.info("The protected app will be saved to: " + output_location);
74 | project.getBuildersList().add(appdomeBuilder);
75 | checkingResults(project, isSecondOutput, jenkins, logger);
76 | }
77 |
78 | public static void testAndroidPrivateSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet, String fingerprint,
79 | StringWarp secondOutput, BuildToTest buildToTest, Boolean buildWithLogs,
80 | Boolean googleSigning, String outputName, Crashlytics crashlytics, Datadog datadog, Boolean workflowOutputLogs, Logger logger) throws Exception {
81 | logger.info("Inside testAndroidPrivateSignBuild");
82 | String output_location = PLUGIN_TMP_OUTPUT + outputName + "." + getFileExtension(appPath);
83 |
84 | FreeStyleProject project = jenkins.createFreeStyleProject();
85 | Boolean isSecondOutput = false;
86 | if (secondOutput != null) {
87 | isSecondOutput = true;
88 | }
89 | // Create configuration objects
90 | PrivateSign privateSign = new PrivateSign(fingerprint);
91 | privateSign.setGoogleSigning(googleSigning);
92 | AndroidPlatform androidPlatform = new AndroidPlatform(privateSign);
93 | androidPlatform.setFusionSetId(fusionSet);
94 | androidPlatform.setAppPath(appPath);
95 | if (crashlytics != null) {
96 | androidPlatform.setCrashlytics(new Crashlytics(crashlytics.getFirebaseAppId()));
97 | }
98 | if (androidPlatform.getDatadog() != null) {
99 | androidPlatform.setDatadog(new Datadog(androidPlatform.getDatadog().getDatadogKey()));
100 | }
101 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, secondOutput, null);
102 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
103 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
104 | appdomeBuilder.setBuildToTest(buildToTest);
105 | appdomeBuilder.setOutputLocation(output_location);
106 | logger.info("The protected app will be saved to: " + output_location);
107 | project.getBuildersList().add(appdomeBuilder);
108 | checkingResults(project, isSecondOutput, jenkins, logger);
109 | }
110 |
111 | public static void testAndroidAutoDevSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet, String fingerprint,
112 | StringWarp secondOutput, BuildToTest buildToTest, Boolean buildWithLogs,
113 | Boolean googleSigning, String outputName, Crashlytics crashlytics, Datadog datadog, Boolean workflowOutputLogs, Logger logger) throws Exception {
114 | logger.info("Inside testAndroidAutoDevSignBuild");
115 | String output_location = PLUGIN_TMP_OUTPUT + outputName + ".sh";
116 |
117 | FreeStyleProject project = jenkins.createFreeStyleProject();
118 | // Create configuration objects
119 | Boolean isSecondOutput = false;
120 | if (secondOutput != null) {
121 | isSecondOutput = true;
122 | }
123 |
124 | AutoDevSign autoDevSign = new AutoDevSign(fingerprint);
125 | if (googleSigning == null) {
126 | googleSigning = false;
127 | } else if (googleSigning) {
128 | googleSigning = true;
129 | }
130 |
131 | autoDevSign.setGoogleSigning(googleSigning);
132 | AndroidPlatform androidPlatform = new AndroidPlatform(autoDevSign);
133 | androidPlatform.setFusionSetId(fusionSet);
134 | androidPlatform.setAppPath(appPath);
135 | if (crashlytics != null) {
136 | androidPlatform.setCrashlytics(new Crashlytics(crashlytics.getFirebaseAppId()));
137 | }
138 | if (datadog != null) {
139 | androidPlatform.setDatadog(new Datadog(datadog.getDatadogKey()));
140 | }
141 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, androidPlatform, secondOutput, null);
142 | appdomeBuilder.setBuildToTest(buildToTest);
143 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
144 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
145 | appdomeBuilder.setOutputLocation(output_location);
146 | logger.info("The protected app will be saved to: " + output_location);
147 | project.getBuildersList().add(appdomeBuilder);
148 | checkingResults(project, isSecondOutput, jenkins, logger);
149 | }
150 |
151 |
152 | public static void testIosAutoSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet,
153 | String certificateFilePath, String certificatePassword, List
154 | provisionProfiles, List entitlements, BuildToTest buildToTest,
155 | Boolean buildWithLogs, String outputName, Boolean workflowOutputLogs, Logger logger) throws Exception {
156 | logger.info("Inside testIosAutoSignBuild");
157 | String output_location = PLUGIN_TMP_OUTPUT + outputName + ".ipa";
158 | FreeStyleProject project = jenkins.createFreeStyleProject();
159 | // Create configuration objects
160 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoSign autoSign
161 | = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
162 | AutoSign(certificateFilePath, Secret.fromString(certificatePassword), provisionProfiles, entitlements);
163 |
164 | IosPlatform iosPlatform = new IosPlatform(autoSign);
165 | iosPlatform.setFusionSetId(fusionSet);
166 | iosPlatform.setAppPath(appPath);
167 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null, null);
168 | appdomeBuilder.setBuildToTest(buildToTest);
169 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
170 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
171 | appdomeBuilder.setOutputLocation(output_location);
172 | logger.info("The protected app will be saved to: " + output_location);
173 | project.getBuildersList().add(appdomeBuilder);
174 | checkingResults(project, false, jenkins, logger);
175 | }
176 |
177 |
178 | public static void testIosPrivateSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet,
179 | List provisionProfiles, BuildToTest buildToTest,
180 | Boolean buildWithLogs, String outputName, Boolean workflowOutputLogs, Logger logger) throws Exception {
181 | logger.info("Inside testIosPrivateSignBuild");
182 | String output_location = PLUGIN_TMP_OUTPUT + outputName + ".ipa";
183 |
184 | FreeStyleProject project = jenkins.createFreeStyleProject();
185 |
186 | // Create configuration objects
187 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.PrivateSign privateSign
188 | = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
189 | PrivateSign(provisionProfiles);
190 | IosPlatform iosPlatform = new IosPlatform(privateSign);
191 | iosPlatform.setFusionSetId(fusionSet);
192 | iosPlatform.setAppPath(appPath);
193 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null, null);
194 | appdomeBuilder.setBuildToTest(buildToTest);
195 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
196 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
197 | appdomeBuilder.setOutputLocation(output_location);
198 | logger.info("The protected app will be saved to: " + output_location);
199 |
200 | project.getBuildersList().add(appdomeBuilder);
201 | logger.info("Printing provision profiles:");
202 | // Loop through each item in the provisionProfiles list
203 | for (StringWarp provisionProfile : provisionProfiles) {
204 | String filePath = provisionProfile.getProvisioningProfiles(); // Assuming StringWarp has a method to get the string
205 |
206 | // Log the provision profile being checked
207 | logger.info("Checking provision profile: " + filePath);
208 |
209 | // Create a File object for the profile
210 | File file = new File(filePath);
211 |
212 | // Check if the file exists and log the result
213 | if (file.exists()) {
214 | // Log the size of the file
215 | long fileSizeInBytes = file.length();
216 | logger.info("Provision profile exists. Size: " + fileSizeInBytes + " bytes");
217 | } else {
218 | logger.warning("Provision profile does not exist: " + filePath);
219 | }
220 | }
221 | checkingResults(project, false, jenkins, logger);
222 |
223 | }
224 |
225 |
226 | public static void testIosAutoDevPrivateSignBuild(JenkinsRule jenkins, String token, String teamId, String appPath, String fusionSet,
227 | List provisionProfiles, List entitlements,
228 | BuildToTest buildToTest, Boolean buildWithLogs, String outputName, Boolean workflowOutputLogs, Logger logger) throws Exception {
229 | logger.info("Inside testIosAutoDevPrivateSignBuild");
230 | String output_location = PLUGIN_TMP_OUTPUT + outputName + ".sh";
231 |
232 | FreeStyleProject project = jenkins.createFreeStyleProject();
233 |
234 | // Create configuration objects
235 | io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoDevSign
236 | autoDevSign = new io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.
237 | AutoDevSign(provisionProfiles, entitlements);
238 | IosPlatform iosPlatform = new IosPlatform(autoDevSign);
239 | iosPlatform.setFusionSetId(fusionSet);
240 | iosPlatform.setAppPath(appPath);
241 | AppdomeBuilder appdomeBuilder = new AppdomeBuilder(Secret.fromString(token), teamId, iosPlatform, null, null);
242 | appdomeBuilder.setBuildToTest(buildToTest);
243 | appdomeBuilder.setWorkflowOutputLogs(workflowOutputLogs);
244 | appdomeBuilder.setBuildWithLogs(buildWithLogs);
245 | appdomeBuilder.setOutputLocation(output_location);
246 | logger.info("The protected app will be saved to: " + output_location);
247 | project.getBuildersList().add(appdomeBuilder);
248 | checkingResults(project, false, jenkins, logger);
249 |
250 | }
251 |
252 |
253 | private static void checkingResults(FreeStyleProject project, boolean isSecondOutput, JenkinsRule jenkins, Logger logger) throws Exception {
254 | FreeStyleBuild build = jenkins.buildAndAssertSuccess(project);
255 | String consoleOutput = build.getLog();
256 |
257 | // Get the workspace of the current build
258 | FilePath workspace = build.getWorkspace();
259 | if (workspace == null) {
260 | throw new IllegalStateException("Workspace not found for the build");
261 | }
262 |
263 | // Print the current working directory (pwd)
264 | String currentWorkingDirectory = System.getProperty("user.dir");
265 | System.out.println("Current Working Directory (pwd): " + currentWorkingDirectory);
266 |
267 |
268 | // Define the output location inside /tmp/output/
269 | FilePath output_location = new FilePath(new File(PLUGIN_TMP_OUTPUT));
270 |
271 | // Print the path to PLUGIN_TMP_OUTPUT "/home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/tmp/output/"
272 | System.out.println("Output Location Path: " + output_location.getRemote());
273 |
274 | // Check if the directory exists and print its contents
275 | if (output_location.exists()) {
276 | System.out.println("\"/home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/tmp/output/\" exists. Listing files:");
277 | for (FilePath file : output_location.list()) {
278 | System.out.println(file.getName());
279 | }
280 | } else {
281 | System.out.println("\"/home/runner/work/appdome-build-2secure-plugin/appdome-build-2secure-plugin/tmp/output/\" does not exist.");
282 | }
283 |
284 | // Further assertions and logging
285 | if (isSecondOutput) {
286 | jenkins.assertLogContains("Download Second Output", build);
287 | }
288 |
289 | System.out.println("build console output = " + consoleOutput);
290 | System.out.println("build status = " + build.getResult().toString());
291 | jenkins.assertBuildStatus(Result.SUCCESS, build);
292 | }
293 |
294 | private static String getFileExtension(String fileName) {
295 | if (fileName == null || fileName.isEmpty()) {
296 | return null;
297 | }
298 |
299 | int dotIndex = fileName.lastIndexOf('.');
300 | if (dotIndex >= 0) { // Make sure there is a '.' in the filename
301 | return fileName.substring(dotIndex + 1).toLowerCase();
302 | } else {
303 | return null; // No extension found
304 | }
305 | }
306 |
307 | }
308 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Java CI with Maven
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | Presign_URLs:
7 | runs-on: "ubuntu-latest"
8 | container:
9 | image: python:3.9-slim
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v3
13 |
14 | - name: Install boto3
15 | run: |
16 | python -m pip install --upgrade pip
17 | pip install boto3
18 | pip install requests
19 | shell: bash
20 |
21 | - name: Generate and Publish Presigned URLs
22 | run: python .github/aws_signer.py
23 | env:
24 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
25 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
26 |
27 | - name: Upload Presigned URLs Artifact
28 | uses: actions/upload-artifact@v4
29 | with:
30 | name: presigned-urls
31 | path: presigned_urls
32 |
33 | android_aab_private_sign:
34 | runs-on: ubuntu-latest
35 | needs: android_aab_auto_sign
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 | - name: Download Presigned URLs Artifact
40 | uses: actions/download-artifact@v4
41 | with:
42 | name: presigned-urls
43 | path: presigned_urls
44 | - name: Install jq
45 | run: sudo apt-get install jq
46 | - name: Print working directory and list files
47 | run: |
48 | pwd
49 | ls -a
50 | ls -a presigned_urls
51 | cd presigned_urls
52 | pwd
53 | ls -a
54 | cat presigned_urls.json
55 |
56 | - name: Download files from presigned URLs
57 | run: |
58 | mkdir downloaded_files
59 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
60 | echo "Downloading $key from $url"
61 | curl -o "downloaded_files/${key}" "$url"
62 | done
63 | ls downloaded_files
64 | - name: Set up JDK 11 with Maven Cache
65 | uses: actions/setup-java@v2
66 | with:
67 | java-version: '11'
68 | distribution: 'adopt'
69 | cache: 'maven'
70 | - name: Download dependencies
71 | run: mvn -B dependency:go-offline
72 | - name: Build and test for Android
73 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false clean verify -Dspotbugs.skip=true -Dtest=AppdomeBuilderTest#testAabAndroidPrivateSignBuild package
74 | env:
75 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
76 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
77 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
78 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
79 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
80 | android_apk_private_sign:
81 | runs-on: ubuntu-latest
82 | needs: android_apk_auto_sign
83 | steps:
84 | - name: Checkout repository
85 | uses: actions/checkout@v2
86 | - name: Download Presigned URLs Artifact
87 | uses: actions/download-artifact@v4
88 | with:
89 | name: presigned-urls
90 | path: presigned_urls
91 | - name: Install jq
92 | run: sudo apt-get install jq
93 | - name: Print working directory and list files
94 | run: |
95 | pwd
96 | ls -a
97 | ls -a presigned_urls
98 | cd presigned_urls
99 | pwd
100 | ls -a
101 | cat presigned_urls.json
102 |
103 | - name: Download files from presigned URLs
104 | run: |
105 | mkdir downloaded_files
106 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
107 | echo "Downloading $key from $url"
108 | curl -o "downloaded_files/${key}" "$url"
109 | done
110 | ls downloaded_files
111 | - name: Set up JDK 11 with Maven Cache
112 | uses: actions/setup-java@v2
113 | with:
114 | java-version: '11'
115 | distribution: 'adopt'
116 | cache: 'maven'
117 | - name: Download dependencies
118 | run: mvn -B dependency:go-offline
119 | - name: Build and test for Android
120 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testApkAndroidPrivateSignBuild package
121 | env:
122 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
123 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
124 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
125 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
126 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
127 |
128 | android_apk_auto_dev_private_sign:
129 | runs-on: ubuntu-latest
130 | needs: android_apk_private_sign
131 | steps:
132 | - name: Checkout repository
133 | uses: actions/checkout@v2
134 | - name: Download Presigned URLs Artifact
135 | uses: actions/download-artifact@v4
136 | with:
137 | name: presigned-urls
138 | path: presigned_urls
139 | - name: Install jq
140 | run: sudo apt-get install jq
141 | - name: Print working directory and list files
142 | run: |
143 | pwd
144 | ls -a
145 | ls -a presigned_urls
146 | cd presigned_urls
147 | pwd
148 | ls -a
149 | cat presigned_urls.json
150 |
151 | - name: Download files from presigned URLs
152 | run: |
153 | mkdir downloaded_files
154 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
155 | echo "Downloading $key from $url"
156 | curl -o "downloaded_files/${key}" "$url"
157 | done
158 | ls downloaded_files
159 | - name: Set up JDK 11 with Maven Cache
160 | uses: actions/setup-java@v2
161 | with:
162 | java-version: '11'
163 | distribution: 'adopt'
164 | cache: 'maven'
165 | - name: Download dependencies
166 | run: mvn -B dependency:go-offline
167 | - name: Build and test for Android
168 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testApkAndroidAutoDevSignBuild package
169 | env:
170 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
171 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
172 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
173 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
174 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
175 |
176 | android_aab_auto_dev_private_sign:
177 | runs-on: ubuntu-latest
178 | needs: android_aab_private_sign
179 | steps:
180 | - name: Checkout repository
181 | uses: actions/checkout@v2
182 | - name: Download Presigned URLs Artifact
183 | uses: actions/download-artifact@v4
184 | with:
185 | name: presigned-urls
186 | path: presigned_urls
187 | - name: Install jq
188 | run: sudo apt-get install jq
189 | - name: Print working directory and list files
190 | run: |
191 | pwd
192 | ls -a
193 | ls -a presigned_urls
194 | cd presigned_urls
195 | pwd
196 | ls -a
197 | cat presigned_urls.json
198 |
199 | - name: Download files from presigned URLs
200 | run: |
201 | mkdir downloaded_files
202 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
203 | echo "Downloading $key from $url"
204 | curl -o "downloaded_files/${key}" "$url"
205 | done
206 | ls downloaded_files
207 | - name: Set up JDK 11 with Maven Cache
208 | uses: actions/setup-java@v2
209 | with:
210 | java-version: '11'
211 | distribution: 'adopt'
212 | cache: 'maven'
213 | - name: Download dependencies
214 | run: mvn -B dependency:go-offline
215 | - name: Build and test for Android
216 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testAabAndroidAutoDevSignBuild package
217 | env:
218 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
219 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
220 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
221 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
222 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
223 |
224 |
225 | android_aab_auto_sign:
226 | runs-on: ubuntu-latest
227 | needs: Presign_URLs
228 | steps:
229 | - name: Checkout repository
230 | uses: actions/checkout@v2
231 | - name: Download Presigned URLs Artifact
232 | uses: actions/download-artifact@v4
233 | with:
234 | name: presigned-urls
235 | path: presigned_urls
236 | - name: Install jq
237 | run: sudo apt-get install jq
238 | - name: Print working directory and list files
239 | run: |
240 | pwd
241 | ls -a
242 | ls -a presigned_urls
243 | cd presigned_urls
244 | pwd
245 | ls -a
246 | cat presigned_urls.json
247 |
248 | - name: Download files from presigned URLs
249 | run: |
250 | mkdir downloaded_files
251 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
252 | echo "Downloading $key from $url"
253 | curl -o "downloaded_files/${key}" "$url"
254 | done
255 | ls downloaded_files
256 | - name: Set up JDK 11 with Maven Cache
257 | uses: actions/setup-java@v2
258 | with:
259 | java-version: '11'
260 | distribution: 'adopt'
261 | cache: 'maven'
262 | - name: Download dependencies
263 | run: mvn -B dependency:go-offline
264 | - name: Build and test for Android
265 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testAabAndroidAutoSignBuild package
266 | env:
267 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
268 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
269 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
270 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
271 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
272 |
273 | android_apk_auto_sign:
274 | runs-on: ubuntu-latest
275 | needs: Presign_URLs
276 | steps:
277 | - name: Checkout repository
278 | uses: actions/checkout@v2
279 | - name: Download Presigned URLs Artifact
280 | uses: actions/download-artifact@v4
281 | with:
282 | name: presigned-urls
283 | path: presigned_urls
284 | - name: Install jq
285 | run: sudo apt-get install jq
286 | - name: Print working directory and list files
287 | run: |
288 | pwd
289 | ls -a
290 | ls -a presigned_urls
291 | cd presigned_urls
292 | pwd
293 | ls -a
294 | cat presigned_urls.json
295 |
296 | - name: Download files from presigned URLs
297 | run: |
298 | mkdir downloaded_files
299 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
300 | echo "Downloading $key from $url"
301 | curl -o "downloaded_files/${key}" "$url"
302 | done
303 | ls downloaded_files
304 | - name: Set up JDK 11 with Maven Cache
305 | uses: actions/setup-java@v2
306 | with:
307 | java-version: '11'
308 | distribution: 'adopt'
309 | cache: 'maven'
310 | - name: Download dependencies
311 | run: mvn -B dependency:go-offline
312 | - name: Build and test for Android
313 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testApkAndroidAutoSignBuild package
314 | env:
315 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
316 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
317 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
318 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
319 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
320 |
321 | ios_auto_sign:
322 | runs-on: ubuntu-latest
323 | needs: Presign_URLs
324 | steps:
325 | - name: Checkout repository
326 | uses: actions/checkout@v2
327 | - name: Download Presigned URLs Artifact
328 | uses: actions/download-artifact@v4
329 | with:
330 | name: presigned-urls
331 | path: presigned_urls
332 | - name: Install jq
333 | run: sudo apt-get install jq
334 | - name: Print working directory and list files
335 | run: |
336 | pwd
337 | ls -a
338 | ls -a presigned_urls
339 | cd presigned_urls
340 | pwd
341 | ls -a
342 | cat presigned_urls.json
343 |
344 | - name: Download files from presigned URLs
345 | run: |
346 | mkdir downloaded_files
347 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
348 | echo "Downloading $key from $url"
349 | curl -o "downloaded_files/${key}" "$url"
350 | done
351 | ls downloaded_files
352 | - name: Set up JDK 11 with Maven Cache
353 | uses: actions/setup-java@v2
354 | with:
355 | java-version: '11'
356 | distribution: 'adopt'
357 | cache: 'maven'
358 | - name: Download dependencies
359 | run: mvn -B dependency:go-offline
360 | - name: Build and test for iOS
361 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testIosAutoSignBuild package
362 | env:
363 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
364 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
365 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
366 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
367 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
368 |
369 | ios_private_sign:
370 | runs-on: ubuntu-latest
371 | needs: Presign_URLs
372 | steps:
373 | - name: Checkout repository
374 | uses: actions/checkout@v2
375 | - name: Download Presigned URLs Artifact
376 | uses: actions/download-artifact@v4
377 | with:
378 | name: presigned-urls
379 | path: presigned_urls
380 | - name: Install jq
381 | run: sudo apt-get install jq
382 | - name: Print working directory and list files
383 | run: |
384 | pwd
385 | ls -a
386 | ls -a presigned_urls
387 | cd presigned_urls
388 | pwd
389 | ls -a
390 | cat presigned_urls.json
391 |
392 | - name: Download files from presigned URLs
393 | run: |
394 | mkdir downloaded_files
395 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
396 | echo "Downloading $key from $url"
397 | curl -o "downloaded_files/${key}" "$url"
398 | done
399 | ls downloaded_files
400 | - name: Set up JDK 11 with Maven Cache
401 | uses: actions/setup-java@v2
402 | with:
403 | java-version: '11'
404 | distribution: 'adopt'
405 | cache: 'maven'
406 | - name: Download dependencies
407 | run: mvn -B dependency:go-offline
408 | - name: Build and test for iOS
409 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testIosPrivateSignBuild package
410 | env:
411 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
412 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
413 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
414 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
415 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
416 |
417 |
418 | ios_auto_dev_private_sign:
419 | runs-on: ubuntu-latest
420 | needs: Presign_URLs
421 | steps:
422 | - name: Checkout repository
423 | uses: actions/checkout@v2
424 | - name: Download Presigned URLs Artifact
425 | uses: actions/download-artifact@v4
426 | with:
427 | name: presigned-urls
428 | path: presigned_urls
429 | - name: Install jq
430 | run: sudo apt-get install jq
431 | - name: Print working directory and list files
432 | run: |
433 | pwd
434 | ls -a
435 | ls -a presigned_urls
436 | cd presigned_urls
437 | pwd
438 | ls -a
439 | cat presigned_urls.json
440 |
441 | - name: Download files from presigned URLs
442 | run: |
443 | mkdir downloaded_files
444 | jq -r 'to_entries|map("\(.key) \(.value|tostring)")|.[]' presigned_urls/presigned_urls.json | while read -r key url; do
445 | echo "Downloading $key from $url"
446 | curl -o "downloaded_files/${key}" "$url"
447 | done
448 | ls downloaded_files
449 | - name: Set up JDK 11 with Maven Cache
450 | uses: actions/setup-java@v2
451 | with:
452 | java-version: '11'
453 | distribution: 'adopt'
454 | cache: 'maven'
455 | - name: Download dependencies
456 | run: mvn -B dependency:go-offline
457 | - name: Build and test for iOS
458 | run: mvn -V --color always -ntp -B -Djenkins.test.timeout=700 -Dsurefire.printSummary=true -Dsurefire.useFile=false -Dspotbugs.skip=true clean verify -Dtest=AppdomeBuilderTest#testIosAutoDevPrivateSignBuild package
459 | env:
460 | APPDOME_API_TOKEN: ${{ secrets.APPDOME_API_TOKEN }}
461 | KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
462 | KEYSTORE_KEY_PASS: ${{ secrets.KEYSTORE_KEY_PASS }}
463 | KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
464 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
--------------------------------------------------------------------------------
/src/test/java/io/jenkins/plugins/appdome/build/to/secure/PipelineTest.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import java.io.File;
4 |
5 | import hudson.EnvVars;
6 | import hudson.slaves.EnvironmentVariablesNodeProperty;
7 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.Crashlytics;
8 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.Datadog;
9 | import org.junit.Before;
10 | import org.junit.Rule;
11 | import org.junit.Test;
12 | import org.jvnet.hudson.test.JenkinsRule;
13 |
14 | import java.io.IOException;
15 | import java.util.Arrays;
16 | import java.util.List;
17 | import java.util.Objects;
18 | import java.util.logging.Logger;
19 | import java.util.stream.Collectors;
20 |
21 | import static io.jenkins.plugins.appdome.build.to.secure.Tests.PLUGIN_TMP_OUTPUT;
22 | import static org.junit.Assert.assertTrue;
23 | import static org.junit.Assert.fail;
24 |
25 | public class PipelineTest {
26 | private final static Logger logger = Logger.getLogger(PipelineTest.class.getName());
27 |
28 | @Rule
29 | public JenkinsRule jenkins = new JenkinsRule();
30 | private String token;
31 | private String teamId;
32 | private String signOption;
33 | private String appFilePath;
34 | private String keystoreFilePath;
35 | private String keystoreAlias;
36 | private String keystoreKeyPass;
37 | private String keystorePassword;
38 | private String certificateFilePath;
39 | private String certificatePassword;
40 | private String fusionSetId;
41 | private String signFingerprint;
42 |
43 | private String firebaseAppId;
44 | private String datadogKey;
45 | private List entitlementsPath;
46 | private List mobileProvisionProfilesPath;
47 | private BuildToTest buildToTest;
48 | private Boolean buildWithLogs;
49 | private Boolean workflowOutputLogs;
50 | private Boolean googlePlaySign;
51 | private String secondOutput;
52 |
53 | private String outputName;
54 |
55 | @Before
56 | public void setUp() throws Exception {
57 | createOutputLocation();
58 | logger.info("Loading environment variables...");
59 | loadEnvironmentVariables();
60 |
61 | logger.info("Loading system properties...");
62 | loadSystemProperties();
63 |
64 | checkAndSetNullValues();
65 | logger.info("Printing all variables...");
66 | printAllValues(); // Print all values after setup for visibility
67 |
68 | logger.info("Checking if files exist:");
69 | // Check if files exist for paths that are not empty
70 | checkFileExists(this.appFilePath, "App File Path");
71 | if (!Objects.equals(this.keystoreFilePath, "null")) {
72 | checkFileExists(this.keystoreFilePath, "Keystore File Path");
73 | }
74 | if (!Objects.equals(this.certificateFilePath, "null")) {
75 | checkFileExists(this.certificateFilePath, "Certificate File Path");
76 | }
77 |
78 | // Check if files exist for each entitlement and provision profile path
79 | if (!Objects.equals(this.entitlementsPath.get(0).getItem(), "null")) {
80 | checkFilesExist(this.entitlementsPath, "Entitlements Path");
81 | }
82 | if (!Objects.equals(this.mobileProvisionProfilesPath.get(0).getItem(), "null")) {
83 | checkFilesExist(this.mobileProvisionProfilesPath, "Mobile Provision Profiles Path");
84 | }
85 | }
86 |
87 | private void createOutputLocation() {
88 | File dir = new File(PLUGIN_TMP_OUTPUT);
89 | if (!dir.exists()) {
90 | dir.mkdirs(); // Create directories if they do not exist
91 | }
92 | }
93 |
94 |
95 | /**
96 | * Loads environment variables used across various tests.
97 | */
98 | private void loadEnvironmentVariables() {
99 | // Environment variables are typically more secure and can be used for sensitive data
100 | this.token = System.getenv("APPDOME_API_TOKEN");
101 | this.keystoreAlias = System.getenv("KEYSTORE_ALIAS");
102 | this.keystoreKeyPass = System.getenv("KEYSTORE_KEY_PASS");
103 | this.keystorePassword = System.getenv("KEYSTORE_PASSWORD");
104 | this.certificatePassword = System.getenv("P12_PASSWORD");
105 | }
106 |
107 | /**
108 | * Loads system properties, providing defaults where necessary to ensure tests have all necessary data.
109 | */
110 | private void loadSystemProperties() {
111 | this.teamId = System.getProperty("teamId", "default-teamId");
112 | this.signOption = System.getProperty("signOption", "default-signOption");
113 | this.appFilePath = System.getProperty("appFilePath", "default-appFilePath");
114 | this.keystoreFilePath = System.getProperty("keystoreFilePath", "default-keystoreFilePath");
115 | this.certificateFilePath = System.getProperty("certificateFilePath", "default-certificateFilePath");
116 | this.fusionSetId = System.getProperty("fusionSetId", "default-fusionSetId");
117 | this.signFingerprint = System.getProperty("signFingerprint", "default-signFingerprint");
118 | this.firebaseAppId = System.getProperty("firebaseAppId", "default-firebaseAppId");
119 | this.datadogKey = System.getProperty("datadogKey", "default-datadogKey");
120 |
121 |
122 | // Convert CSV from system properties to List for entitlements and provisions
123 | String entitlementsCsv = System.getProperty("entitlementsPath", "default1,default2");
124 | this.entitlementsPath = convertCsvToListStringWarp(entitlementsCsv);
125 |
126 | String mobileProvisionsCsv = System.getProperty("mobileProvisionProfilesPath", "default1,default2");
127 | this.mobileProvisionProfilesPath = convertCsvToListStringWarp(mobileProvisionsCsv);
128 |
129 | // Mock object for BuildToTest - you might need to set this differently based on your test environment
130 | this.buildToTest = new BuildToTest(System.getProperty("buildToTest", "default-buildToTest"));
131 |
132 | this.buildWithLogs = Boolean.parseBoolean(System.getProperty("buildWithLogs", "false"));
133 | this.workflowOutputLogs = Boolean.parseBoolean(System.getProperty("workflowOutputLogs", "false"));
134 |
135 | this.googlePlaySign = Boolean.parseBoolean(System.getProperty("googlePlaySign", "false"));
136 | this.secondOutput = System.getProperty("secondOutput", "default-secondOutput");
137 | this.outputName = System.getProperty("outputName", "protected_app");
138 | }
139 |
140 |
141 | // Add the method to check all values and set to null if needed
142 | public void checkAndSetNullValues() {
143 | if (isNoneOrEmpty(this.token)) this.token = null;
144 | if (isNoneOrEmpty(this.teamId)) this.teamId = null;
145 | if (isNoneOrEmpty(this.signOption)) this.signOption = null;
146 | if (isNoneOrEmpty(this.appFilePath)) this.appFilePath = null;
147 | if (isNoneOrEmpty(this.keystoreFilePath)) this.keystoreFilePath = null;
148 | if (isNoneOrEmpty(this.keystoreAlias)) this.keystoreAlias = null;
149 | if (isNoneOrEmpty(this.keystoreKeyPass)) this.keystoreKeyPass = null;
150 | if (isNoneOrEmpty(this.keystorePassword)) this.keystorePassword = null;
151 | if (isNoneOrEmpty(this.certificateFilePath)) this.certificateFilePath = null;
152 | if (isNoneOrEmpty(this.certificatePassword)) this.certificatePassword = null;
153 | if (isNoneOrEmpty(this.fusionSetId)) this.fusionSetId = null;
154 | if (isNoneOrEmpty(this.signFingerprint)) this.signFingerprint = null;
155 | if (this.buildToTest != null && Objects.equals(this.buildToTest.getSelectedVendor().toLowerCase(), "none")) {
156 | this.buildToTest = null;
157 | }
158 | if (this.entitlementsPath != null && this.entitlementsPath.isEmpty()) this.entitlementsPath = null;
159 | if (this.mobileProvisionProfilesPath != null && this.mobileProvisionProfilesPath.isEmpty())
160 | this.mobileProvisionProfilesPath = null;
161 | if (this.buildWithLogs != null && !this.buildWithLogs) this.buildWithLogs = null;
162 | if (this.workflowOutputLogs != null && !this.workflowOutputLogs) this.workflowOutputLogs = null;
163 |
164 | if (this.googlePlaySign != null && !this.googlePlaySign) this.googlePlaySign = null;
165 | if (isNoneOrEmpty(this.secondOutput)) this.secondOutput = null;
166 | if (isNoneOrEmpty(this.outputName)) this.outputName = null;
167 | if (isNoneOrEmpty(this.firebaseAppId)) this.firebaseAppId = null;
168 | if (isNoneOrEmpty(this.datadogKey)) this.datadogKey = null;
169 |
170 |
171 | }
172 |
173 | // Helper method to check if a string is "None" or empty
174 | private boolean isNoneOrEmpty(String value) {
175 | return value == null || value.trim().isEmpty() || value.equalsIgnoreCase("none");
176 | }
177 |
178 |
179 | /**
180 | * Checks if a file exists at the given path.
181 | *
182 | * @param filePath The path of the file to check.
183 | * @param description Description of the file for logging purposes.
184 | */
185 | private void checkFileExists(String filePath, String description) {
186 | if (filePath != null && !filePath.isEmpty()) {
187 | File file = new File(filePath);
188 | if (!file.exists()) {
189 | logger.severe(description + " does not exist: " + filePath);
190 |
191 | // Get the directory name and list the contents
192 | File dir = file.getParentFile(); // Get the parent directory
193 | if (dir != null && dir.exists() && dir.isDirectory()) {
194 | String[] files = dir.list();
195 | logger.info("Contents of directory " + dir.getAbsolutePath() + ": " + Arrays.toString(files));
196 | } else {
197 | logger.warning("The parent directory does not exist or is not a directory.");
198 | }
199 | throw new IllegalArgumentException(description + " does not exist: " + filePath);
200 |
201 | } else {
202 | logger.info(description + " exists: " + filePath);
203 | }
204 | }
205 | }
206 |
207 |
208 | /**
209 | * Checks if a list of files exist.
210 | *
211 | * @param filePaths List of file paths to check.
212 | * @param description Description of the file type being checked (for logging purposes).
213 | */
214 | private void checkFilesExist(List filePaths, String description) {
215 | if (filePaths != null && !filePaths.isEmpty()) {
216 | for (StringWarp filePathWarp : filePaths) {
217 | String filePath = filePathWarp.getItem().toString();
218 | checkFileExists(filePath, description);
219 | }
220 | } else {
221 | logger.info(description + " is empty or not provided.");
222 | }
223 | }
224 |
225 |
226 | /**
227 | * Converts a CSV string to a List of StringWarp objects.
228 | *
229 | * @param csv The comma-separated string to convert.
230 | * @return A list of StringWarp objects.
231 | */
232 | private List convertCsvToListStringWarp(String csv) {
233 | return Arrays.asList(csv.split(",")).stream()
234 | .map(StringWarp::new)
235 | .collect(Collectors.toList());
236 | }
237 |
238 | private static String getFileExtension(String fileName) {
239 | if (fileName == null || fileName.isEmpty()) {
240 | return null;
241 | }
242 |
243 | int dotIndex = fileName.lastIndexOf('.');
244 | if (dotIndex >= 0) { // Make sure there is a '.' in the filename
245 | return fileName.substring(dotIndex + 1).toLowerCase();
246 | } else {
247 | return null; // No extension found
248 | }
249 | }
250 |
251 | @Test
252 | public void workFlowTest() throws Exception {
253 |
254 | try {
255 | String platform = getFileExtension(this.appFilePath);
256 | if (platform == null) {
257 | throw new IllegalArgumentException("App file path does not have a valid extension.");
258 | }
259 | logger.info("The app extension is " + platform);
260 |
261 |
262 | // Platform-specific tests
263 | if (Objects.equals(platform, "ipa")) {
264 | logger.info("Goes to method performIosTests");
265 | performIosTests();
266 | } else {
267 | logger.info("Goes to method performAndroidTests");
268 | performAndroidTests(platform);
269 | }
270 |
271 |
272 | } catch (Exception e) {
273 | logger.severe("Error during workflow test: " + e.getMessage());
274 | fail("Test failed due to exception: " + e.getMessage());
275 | }
276 | }
277 |
278 |
279 | /**
280 | * Tests Android-specific functionality. Asserts that operations complete successfully.
281 | *
282 | * @param extension The file extension to check for specific configurations.
283 | */
284 | private void performAndroidTests(String extension) throws Exception {
285 | logger.info("performAndroidTests");
286 | StringWarp stringWarpSecondOutput = null;
287 | if (extension.equals("aab")) {
288 | if (secondOutput != null) {
289 | stringWarpSecondOutput = new StringWarp(secondOutput);
290 | }
291 | }
292 | if (this.workflowOutputLogs != null && this.workflowOutputLogs) {
293 | File file = new File(PLUGIN_TMP_OUTPUT + "workflow_output_logs.logs");
294 | try {
295 | if (file.createNewFile()) {
296 | System.out.println("File created successfully: " + file.getName());
297 | } else {
298 | System.out.println("File already exists: " + file.getName());
299 | }
300 | } catch (IOException e) {
301 | System.err.println("An error occurred while creating the file: " + e.getMessage());
302 | e.printStackTrace();
303 | }
304 | }
305 |
306 | logger.info("signOption is " + signOption);
307 | Crashlytics crashlytics = null;
308 | if (this.firebaseAppId != null) {
309 | crashlytics = new Crashlytics(this.firebaseAppId);
310 | }
311 | Datadog datadog = null;
312 | if (this.datadogKey != null) {
313 | datadog = new Datadog(datadogKey);
314 | }
315 | switch (this.signOption) {
316 | case "SIGN_ON_APPDOME":
317 | logger.info("Android: sign on appdome");
318 | Tests.testAndroidAutoSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
319 | this.fusionSetId, this.keystoreFilePath, this.keystorePassword, this.keystoreAlias,
320 | this.keystoreKeyPass, this.signFingerprint, stringWarpSecondOutput, this.buildToTest,
321 | this.buildWithLogs, this.outputName, crashlytics, datadog, this.workflowOutputLogs, logger);
322 | break;
323 | case "PRIVATE_SIGNING":
324 | logger.info("Android: private sign");
325 | Tests.testAndroidPrivateSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
326 | this.fusionSetId, this.signFingerprint, stringWarpSecondOutput, this.buildToTest,
327 | this.buildWithLogs, this.googlePlaySign, this.outputName, crashlytics, datadog, this.workflowOutputLogs, logger);
328 | break;
329 | case "AUTO_DEV_SIGNING":
330 | logger.info("Android: auto dev sign");
331 | Tests.testAndroidAutoDevSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
332 | this.fusionSetId, this.signFingerprint, stringWarpSecondOutput, this.buildToTest,
333 | this.buildWithLogs, this.googlePlaySign, this.outputName, crashlytics, datadog, this.workflowOutputLogs, logger);
334 | break;
335 | default:
336 | logger.info("That's not a valid sign option.");
337 | fail("Invalid sign option provided: " + this.signOption);
338 | break;
339 | }
340 | }
341 |
342 |
343 | /**
344 | * Tests iOS-specific functionality. Asserts expected outcomes based on operations.
345 | */
346 | private void performIosTests() throws Exception {
347 | logger.info("Inside performIosTests");
348 | logger.info("signOption is " + signOption);
349 | switch (this.signOption) {
350 | case "SIGN_ON_APPDOME":
351 | logger.info("iOS: sign on appdome");
352 | Tests.testIosAutoSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
353 | this.fusionSetId, this.certificateFilePath, this.certificatePassword,
354 | this.mobileProvisionProfilesPath, this.entitlementsPath, buildToTest, buildWithLogs, this.outputName, this.workflowOutputLogs, logger);
355 | break;
356 | case "PRIVATE_SIGNING":
357 | logger.info("iOS: private sign");
358 | Tests.testIosPrivateSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
359 | this.fusionSetId, this.mobileProvisionProfilesPath, buildToTest, buildWithLogs, this.outputName, this.workflowOutputLogs, logger);
360 | break;
361 | case "AUTO_DEV_SIGNING":
362 | logger.info("iOS: auto dev sign");
363 | Tests.testIosAutoDevPrivateSignBuild(this.jenkins, this.token, this.teamId, this.appFilePath,
364 | this.fusionSetId, this.mobileProvisionProfilesPath, this.entitlementsPath, buildToTest, buildWithLogs, this.outputName, this.workflowOutputLogs, logger);
365 | break;
366 | default:
367 | logger.info("That's not a valid sign option.");
368 | break;
369 | }
370 | }
371 |
372 | /**
373 | * Prints all the values of the class properties for debugging.
374 | */
375 | private void printAllValues() {
376 | logger.info("Current Test Configuration:");
377 | logger.info("Token: " + (this.token != null ? this.token : "null"));
378 | logger.info("Team ID: " + (this.teamId != null ? this.teamId : "null"));
379 | logger.info("Sign Option: " + (this.signOption != null ? this.signOption : "null"));
380 | logger.info("App File Path: " + (this.appFilePath != null ? this.appFilePath : "null"));
381 | logger.info("Keystore File Path: " + (this.keystoreFilePath != null ? this.keystoreFilePath : "null"));
382 | logger.info("Keystore Alias: " + (this.keystoreAlias != null ? this.keystoreAlias : "null"));
383 | logger.info("Keystore Key Pass: " + (this.keystoreKeyPass != null ? this.keystoreKeyPass : "null"));
384 | logger.info("Keystore Password: " + (this.keystorePassword != null ? this.keystorePassword : "null"));
385 | logger.info("Certificate File Path: " + (this.certificateFilePath != null ? this.certificateFilePath : "null"));
386 | logger.info("Certificate Password: " + (this.certificatePassword != null ? this.certificatePassword : "null"));
387 | logger.info("Fusion Set ID: " + (this.fusionSetId != null ? this.fusionSetId : "null"));
388 | logger.info("Sign Fingerprint: " + (this.signFingerprint != null ? this.signFingerprint : "null"));
389 |
390 | // Safely handle potential nulls for lists and objects
391 | logger.info("Entitlements Path: " + (this.entitlementsPath != null ?
392 | this.entitlementsPath.stream().map(StringWarp::toString).toString() : "null"));
393 | logger.info("Mobile Provision Profiles Path: " + (this.mobileProvisionProfilesPath != null ?
394 | this.mobileProvisionProfilesPath.stream().map(StringWarp::toString).toString() : "null"));
395 |
396 | logger.info("Build To Test: " + (this.buildToTest != null ? this.buildToTest.getSelectedVendor() : "null"));
397 | logger.info("Build With Logs: " + (this.buildWithLogs != null ? this.buildWithLogs : "null"));
398 | logger.info("Workflow output logs: " + (this.workflowOutputLogs != null ? this.workflowOutputLogs : "null"));
399 | logger.info("Google Play Sign: " + (this.googlePlaySign != null ? this.googlePlaySign : "null"));
400 | logger.info("Second Output: " + (this.secondOutput != null ? this.secondOutput : "null"));
401 | }
402 |
403 | }
404 |
--------------------------------------------------------------------------------
/src/main/java/io/jenkins/plugins/appdome/build/to/secure/AppdomeBuilder.java:
--------------------------------------------------------------------------------
1 | package io.jenkins.plugins.appdome.build.to.secure;
2 |
3 | import edu.umd.cs.findbugs.annotations.NonNull;
4 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
5 | import hudson.*;
6 | import hudson.model.*;
7 | import hudson.tasks.BuildStepDescriptor;
8 | import hudson.tasks.Builder;
9 | import hudson.util.*;
10 | import io.jenkins.plugins.appdome.build.to.secure.platform.Platform;
11 | import io.jenkins.plugins.appdome.build.to.secure.platform.android.AndroidPlatform;
12 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.IosPlatform;
13 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoDevSign;
14 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.AutoSign;
15 | import io.jenkins.plugins.appdome.build.to.secure.platform.ios.certificate.method.PrivateSign;
16 | import jenkins.model.Jenkins;
17 | import jenkins.tasks.SimpleBuildStep;
18 | import org.jenkinsci.Symbol;
19 | import org.kohsuke.stapler.DataBoundConstructor;
20 | import org.kohsuke.stapler.DataBoundSetter;
21 | import org.kohsuke.stapler.QueryParameter;
22 | import org.kohsuke.stapler.verb.POST;
23 |
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 | import java.net.URL;
29 | import java.util.InputMismatchException;
30 | import java.util.List;
31 | import java.util.stream.Collectors;
32 | import java.util.stream.Stream;
33 |
34 | import static io.jenkins.plugins.appdome.build.to.secure.AppdomeBuilderConstants.*;
35 |
36 | public class AppdomeBuilder extends Builder implements SimpleBuildStep {
37 |
38 | private final Secret token;
39 | private final String teamId;
40 | private final Platform platform;
41 | private String outputLocation;
42 | private StringWarp secondOutput;
43 |
44 | private StringWarp dynamicCertificate;
45 |
46 | private Boolean buildWithLogs;
47 | private Boolean workflowOutputLogs;
48 | private BuildToTest buildToTest;
49 |
50 | private boolean isAutoDevPrivateSign = false;
51 |
52 | @DataBoundConstructor
53 | public AppdomeBuilder(Secret token, String teamId, Platform platform, StringWarp secondOutput, StringWarp dynamicCertificate) {
54 | this.teamId = teamId;
55 | this.token = token;
56 | this.platform = platform;
57 | this.secondOutput = secondOutput;
58 | this.dynamicCertificate = dynamicCertificate;
59 |
60 | }
61 |
62 | @DataBoundSetter
63 | public void setBuildToTest(BuildToTest buildToTest) {
64 | this.buildToTest = buildToTest;
65 | }
66 |
67 | public BuildToTest getBuildToTest() {
68 | return buildToTest;
69 | }
70 |
71 | public String getSelectedVendor() {
72 | if (this.buildToTest != null) {
73 | return buildToTest.getSelectedVendor();
74 | }
75 | return null;
76 | }
77 |
78 | public Secret getToken() {
79 | return token;
80 | }
81 |
82 | public String getTeamId() {
83 | return teamId;
84 | }
85 |
86 | public String getOutputLocation() {
87 | return this.outputLocation;
88 | }
89 |
90 | public Boolean getBuildWithLogs() {
91 | return buildWithLogs;
92 | }
93 |
94 | @DataBoundSetter
95 | public void setBuildWithLogs(Boolean buildWithLogs) {
96 | this.buildWithLogs = buildWithLogs;
97 | }
98 |
99 | public Boolean getWorkflowOutputLogs() {
100 | return this.workflowOutputLogs;
101 | }
102 |
103 | @DataBoundSetter
104 | public void setWorkflowOutputLogs(Boolean workflowOutputLogs) {
105 | this.workflowOutputLogs = workflowOutputLogs;
106 | }
107 |
108 | @DataBoundSetter
109 | public void setOutputLocation(String outputLocation) {
110 | this.outputLocation = outputLocation;
111 | }
112 |
113 | public void perform(@NonNull Run, ?> run, FilePath workspace, EnvVars env, Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
114 |
115 | int exitCode;
116 | FilePath appdomeWorkspace = workspace.createTempDir("AppdomeBuild", "Build");
117 | listener.getLogger().println("Appdome Build2Secure " + APPDOME_BUILDE2SECURE_VERSION);
118 | exitCode = CloneAppdomeApi(listener, appdomeWorkspace, launcher);
119 | if (exitCode == 0) {
120 | listener
121 | .getLogger()
122 | .println("Appdome engine updated successfully");
123 | try {
124 | exitCode = ExecuteAppdomeApi(listener, appdomeWorkspace, workspace, env, launcher);
125 | } catch (Exception e) {
126 | listener.error("Couldn't run Appdome Builder, read logs for more information. error:" + e);
127 | run.setResult(Result.FAILURE);
128 | deleteAppdomeWorkspacce(listener, appdomeWorkspace);
129 | }
130 | if (exitCode == 0) {
131 | listener.getLogger().println("Executed Build successfully");
132 | } else {
133 |
134 | listener.error("Couldn't run Appdome Builder, exitcode " + exitCode + ".\nCouldn't run Appdome Builder, read logs for more information.");
135 | run.setResult(Result.FAILURE);
136 | deleteAppdomeWorkspacce(listener, appdomeWorkspace);
137 | }
138 | } else {
139 | listener.error("Couldn't Update Appdome engine, read logs for more information.");
140 | run.setResult(Result.FAILURE);
141 | deleteAppdomeWorkspacce(listener, appdomeWorkspace);
142 | }
143 | deleteAppdomeWorkspacce(listener, appdomeWorkspace);
144 | }
145 |
146 | private int ExecuteAppdomeApi(TaskListener listener, FilePath appdomeWorkspace, FilePath agentWorkspace, EnvVars env, Launcher launcher) throws Exception {
147 | FilePath scriptPath = appdomeWorkspace.child("appdome-api-bash");
148 | String command = ComposeAppdomeCommand(appdomeWorkspace, agentWorkspace, env, launcher, listener);
149 | List filteredCommandList = Stream.of(command.split("\\s+(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))
150 | .filter(s -> !s.isEmpty()).map(s -> s.replaceAll("\"", ""))
151 | .collect(Collectors.toList());
152 | // Add the APPDOME_CLIENT_HEADER environment variable to the subprocess
153 | env.put(APPDOME_HEADER_ENV_NAME, APPDOME_BUILDE2SECURE_VERSION);
154 | // String debugMode = env.get("ACTIONS_STEP_DEBUG");
155 | // listener.getLogger().println("[debug] command : " + command);
156 | //
157 | // if ("true".equalsIgnoreCase(debugMode)) {
158 | // listener.getLogger().println("[debug] command : " + command);
159 | // }
160 | listener.getLogger().println("Launching Appdome engine");
161 | return launcher.launch()
162 | .cmds(filteredCommandList)
163 | .pwd(scriptPath)
164 | .envs(env)
165 | .stdout(listener.getLogger())
166 | .stderr(listener.getLogger())
167 | .quiet(true)
168 | .join();
169 | }
170 |
171 | private String ComposeAppdomeCommand(FilePath appdomeWorkspace, FilePath agentWorkspace, EnvVars env, Launcher launcher, TaskListener listener) throws Exception {
172 | //common:
173 | StringBuilder command = new StringBuilder("./appdome_api.sh");
174 | command.append(KEY_FLAG)
175 | .append(this.token)
176 | .append(FUSION_SET_ID_FLAG)
177 | .append(platform.getFusionSetId());
178 |
179 | //concatenate the team id if it is not empty:
180 | if (!(Util.fixEmptyAndTrim(this.teamId) == null)) {
181 | command.append(TEAM_ID_FLAG)
182 | .append(this.teamId);
183 | }
184 |
185 | String appPath = "";
186 | //concatenate the app path if it is not empty:
187 | if (!(Util.fixEmptyAndTrim(this.platform.getAppPath()) == null)) {
188 | appPath = DownloadFilesOrContinue(this.platform.getAppPath(), appdomeWorkspace, launcher);
189 | } else {
190 | appPath = DownloadFilesOrContinue(UseEnvironmentVariable(env, APP_PATH,
191 | appPath, APP_FLAG.trim().substring(2)), appdomeWorkspace, launcher);
192 | }
193 | switch (platform.getPlatformType()) {
194 | case ANDROID:
195 | ComposeAndroidCommand(command, env, appdomeWorkspace, launcher, listener);
196 | break;
197 | case IOS:
198 | ComposeIosCommand(command, env, appdomeWorkspace, launcher);
199 | break;
200 | default:
201 | return null;
202 | }
203 |
204 | if (appPath.isEmpty()) {
205 | throw new RuntimeException("App path was not provided.");
206 | } else {
207 | command.append(APP_FLAG)
208 | .append("\"" + appPath + "\"");
209 | }
210 |
211 | if (this.buildWithLogs != null && this.buildWithLogs) {
212 | command.append(BUILD_WITH_LOGS);
213 | }
214 |
215 | if (this.buildToTest != null) {
216 | command.append(BUILD_TO_TEST)
217 | .append(this.buildToTest.getSelectedVendor());
218 | }
219 |
220 | String basename = new File(appPath).getName();
221 | ArgumentListBuilder args;
222 | FilePath output_location;
223 |
224 |
225 | if (!(Util.fixEmptyAndTrim(this.outputLocation) == null)) {
226 | setOutputLocation(checkExtension(this.outputLocation, basename, this.isAutoDevPrivateSign, false));
227 |
228 | command.append(OUTPUT_FLAG)
229 | .append(getOutputLocation());
230 | command.append(CERTIFIED_SECURE_PDF_FLAG)
231 | .append(getOutputLocation().substring(0, this.outputLocation.lastIndexOf("/") + 1))
232 | .append("Certified_Secure.pdf");
233 | command.append(CERTIFIED_SECURE_JSON_FLAG)
234 | .append(getOutputLocation().substring(0, this.outputLocation.lastIndexOf("/") + 1))
235 | .append("Certified_Secure.json");
236 | command.append(DEOBFUSCATION_OUTPUT)
237 | .append(getOutputLocation().substring(0, this.outputLocation.lastIndexOf("/") + 1))
238 | .append("Deobfuscation_Mapping_Files.zip");
239 | if (this.workflowOutputLogs != null && this.workflowOutputLogs) {
240 | command.append(WORKFLOW_OUTPUT_LOGS_FLAG)
241 | .append(getOutputLocation().substring(0, this.outputLocation.lastIndexOf("/") + 1))
242 | .append("workflow_output_logs.log");
243 | }
244 |
245 | } else {
246 |
247 |
248 | output_location = agentWorkspace.child("output");
249 | output_location.mkdirs();
250 |
251 | setOutputLocation(checkExtension(String.valueOf(output_location + "/"), "Appdome_Protected_" + basename, this.isAutoDevPrivateSign, false));
252 |
253 |
254 | command.append(OUTPUT_FLAG)
255 | .append(getOutputLocation());
256 |
257 | command.append(CERTIFIED_SECURE_PDF_FLAG)
258 | .append(output_location.getRemote())
259 | .append(File.separator)
260 | .append("Certified_Secure.pdf");
261 |
262 | command.append(CERTIFIED_SECURE_JSON_FLAG)
263 | .append(output_location.getRemote())
264 | .append(File.separator)
265 | .append("Certified_Secure.json");
266 |
267 | command.append(DEOBFUSCATION_OUTPUT)
268 | .append(output_location.getRemote())
269 | .append(File.separator)
270 | .append("Deobfuscation_Mapping_Files.zip");
271 |
272 | if (this.workflowOutputLogs != null && this.workflowOutputLogs) {
273 |
274 | command.append(WORKFLOW_OUTPUT_LOGS_FLAG)
275 | .append(output_location.getRemote())
276 | .append(File.separator)
277 | .append("workflow_output_logs.log");
278 | }
279 | }
280 |
281 | if (!(Util.fixEmptyAndTrim(this.getSecondOutput()) == null)) {
282 | String secondOutputVar = this.getSecondOutput();
283 | secondOutputVar = checkExtension(secondOutputVar, new File(secondOutputVar).getName(), false, true);
284 | command.append(SECOND_OUTPUT).append(secondOutputVar);
285 | }
286 |
287 |
288 | if (!(Util.fixEmptyAndTrim(this.getDynamicCertificate()) == null)) {
289 | command.append(DYNAMIC_CERTIFICATE).append(DownloadFilesOrContinue(this.getDynamicCertificate(), appdomeWorkspace, launcher));
290 | }
291 | return command.toString();
292 | }
293 |
294 | private String checkExtension(String outputLocation, String basename, Boolean isThisAutoDevPrivate, Boolean isThisSecondOutput) {
295 | int dotIndex = basename.lastIndexOf('.');
296 |
297 | // Extract the extension from basename, if present
298 | String extensionFromBaseName = (dotIndex != -1) ? basename.substring(dotIndex + 1) : "";
299 |
300 | // Extract the basename without the extension
301 | String basenameWithoutExtension = (dotIndex != -1) ? basename.substring(0, dotIndex) : basename;
302 |
303 | String extension = extensionFromBaseName;
304 | String outputName = "";
305 |
306 |
307 | // Check if outputLocation ends with a known extension and if so, remove that extension from outputLocation
308 | if (outputLocation.endsWith(".ipa") || outputLocation.endsWith(".aab") || outputLocation.endsWith(".apk") || outputLocation.endsWith(".sh")) {
309 | dotIndex = outputLocation.lastIndexOf('.');
310 | outputLocation = outputLocation.substring(0, dotIndex); // Remove the extension from outputLocation
311 | } else if (!outputLocation.endsWith("/")) {
312 | outputName = new File(outputLocation).getName().toString();
313 | outputLocation = new File(outputLocation).getParent().toString();
314 | }
315 |
316 | // Overwrite the extension based on the provided booleans
317 | if (isThisSecondOutput) {
318 | extension = "apk";
319 | } else if (isThisAutoDevPrivate) {
320 | extension = "sh";
321 | }
322 |
323 | // Construct the final output location string
324 | String finalOutputLocation;
325 | if (outputLocation.endsWith("/")) {
326 | finalOutputLocation = outputLocation + basenameWithoutExtension + "." + extension;
327 | } else {
328 | if (!outputName.isEmpty()) {
329 | finalOutputLocation = outputLocation + "/" + outputName + "/" + basenameWithoutExtension + "." + extension;
330 | } else {
331 | finalOutputLocation = outputLocation + "." + extension;
332 |
333 | }
334 | }
335 |
336 | return finalOutputLocation;
337 | }
338 |
339 |
340 | private String UseEnvironmentVariable(EnvVars env, String envName, String fieldValue, String filedName) {
341 | if (fieldValue == null || fieldValue.isEmpty() && (env.get(envName) != null && !(Util.fixEmptyAndTrim(env.get(envName)) == null))) {
342 | return env.get(envName, fieldValue);
343 | }
344 | if (filedName.equals("entitlements")) {
345 | //Do nothing
346 | return null;
347 | }
348 | throw new InputMismatchException("The field '" + filedName + "' was not provided correctly. " +
349 | "Kindly ensure that the environment variable '" + envName + "' has been correctly inserted.");
350 | }
351 |
352 |
353 | private void ComposeIosCommand(StringBuilder command, EnvVars env, FilePath appdomeWorkspace, Launcher launcher) throws Exception {
354 | IosPlatform iosPlatform = ((IosPlatform) platform);
355 |
356 |
357 | switch (iosPlatform.getCertificateMethod().getSignType()) {
358 | case AUTO:
359 | AutoSign autoSign = (AutoSign) iosPlatform.getCertificateMethod();
360 | command.append(SIGN_ON_APPDOME_FLAG)
361 | .append(KEYSTORE_FLAG)
362 | .append(autoSign.getKeystorePath() == null
363 | || autoSign.getKeystorePath().isEmpty()
364 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, KEYSTORE_PATH_ENV, autoSign.getKeystorePath(),
365 | KEYSTORE_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
366 | : DownloadFilesOrContinue(autoSign.getKeystorePath(), appdomeWorkspace, launcher))
367 | .append(KEYSTORE_PASS_FLAG)
368 | .append(autoSign.getKeystorePassword())
369 | .append(PROVISION_PROFILES_FLAG)
370 | .append(autoSign.getProvisioningProfilesPath() == null
371 | || autoSign.getProvisioningProfilesPath().isEmpty()
372 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, MOBILE_PROVISION_PROFILE_PATHS_ENV,
373 | autoSign.getProvisioningProfilesPath(),
374 | PROVISION_PROFILES_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
375 | : DownloadFilesOrContinue(autoSign.getProvisioningProfilesPath(), appdomeWorkspace, launcher))
376 | .append(ENTITLEMENTS_FLAG)
377 | .append(autoSign.getEntitlementsPath() == null
378 | || autoSign.getEntitlementsPath().isEmpty()
379 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, ENTITLEMENTS_PATHS_ENV, autoSign.getEntitlementsPath(),
380 | ENTITLEMENTS_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
381 | : DownloadFilesOrContinue(autoSign.getEntitlementsPath(), appdomeWorkspace, launcher));
382 | break;
383 | case PRIVATE:
384 | PrivateSign privateSign = (PrivateSign) iosPlatform.getCertificateMethod();
385 | command.append(PRIVATE_SIGN_FLAG)
386 | .append(PROVISION_PROFILES_FLAG)
387 | .append(privateSign.getProvisioningProfilesPath() == null
388 | || privateSign.getProvisioningProfilesPath().isEmpty()
389 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, MOBILE_PROVISION_PROFILE_PATHS_ENV,
390 | privateSign.getProvisioningProfilesPath(),
391 | PROVISION_PROFILES_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
392 | : DownloadFilesOrContinue(privateSign.getProvisioningProfilesPath(), appdomeWorkspace, launcher));
393 | break;
394 | case AUTODEV:
395 | isAutoDevPrivateSign = true;
396 | AutoDevSign autoDevSign = (AutoDevSign) iosPlatform.getCertificateMethod();
397 | command.append(AUTO_DEV_PRIVATE_SIGN_FLAG)
398 | .append(PROVISION_PROFILES_FLAG).append(autoDevSign.getProvisioningProfilesPath() == null
399 | || autoDevSign.getProvisioningProfilesPath().isEmpty()
400 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, MOBILE_PROVISION_PROFILE_PATHS_ENV,
401 | autoDevSign.getProvisioningProfilesPath(),
402 | PROVISION_PROFILES_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
403 | : DownloadFilesOrContinue(autoDevSign.getProvisioningProfilesPath(), appdomeWorkspace, launcher))
404 | .append(ENTITLEMENTS_FLAG).append(autoDevSign.getEntitlementsPath() == null
405 | || autoDevSign.getEntitlementsPath().isEmpty()
406 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, ENTITLEMENTS_PATHS_ENV, autoDevSign.getEntitlementsPath(),
407 | ENTITLEMENTS_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
408 | : DownloadFilesOrContinue(autoDevSign.getEntitlementsPath(), appdomeWorkspace, launcher));
409 | break;
410 | case NONE:
411 | default:
412 | break;
413 | }
414 | cleanCommand(command);
415 | }
416 |
417 | /**
418 | * Cleans the provided command represented by a StringBuilder by removing any flags immediately followed by "NULL".
419 | * This method processes the command by checking each segment, and selectively modifying the original StringBuilder
420 | * to exclude the unwanted flags and "NULL" values.
421 | *
422 | * @param command The StringBuilder containing the command string to be cleaned directly.
423 | */
424 | public static void cleanCommand(StringBuilder command) {
425 | String[] parts = command.toString().split(" ");
426 | command.setLength(0); // Clear the original StringBuilder
427 |
428 | for (int i = 0; i < parts.length; i++) {
429 | if (i < parts.length - 1 && parts[i + 1].equals("NULL")) {
430 | i++; // Skip the flag and the "NULL"
431 | } else {
432 | command.append(parts[i]).append(" ");
433 | }
434 | }
435 |
436 | if (command.length() > 0) { // Remove the trailing space if present
437 | command.setLength(command.length() - 1);
438 | }
439 | }
440 |
441 | private void ComposeAndroidCommand(StringBuilder command, EnvVars env, FilePath appdomeWorkspace, Launcher launcher, TaskListener listener) throws Exception {
442 | AndroidPlatform androidPlatform = ((AndroidPlatform) platform);
443 |
444 | switch (androidPlatform.getCertificateMethod().getSignType()) {
445 | case AUTO:
446 | io.jenkins.plugins.appdome.build.to.secure.platform
447 | .android.certificate.method.AutoSign autoSign =
448 | (io.jenkins.plugins.appdome.build.to.secure.platform
449 | .android.certificate.method.AutoSign)
450 | androidPlatform.getCertificateMethod();
451 |
452 | command.append(SIGN_ON_APPDOME_FLAG)
453 | .append(KEYSTORE_FLAG)
454 | .append(autoSign.getKeystorePath() == null || autoSign.getKeystorePath().isEmpty()
455 | ? DownloadFilesOrContinue(UseEnvironmentVariable(env, KEYSTORE_PATH_ENV, autoSign.getKeystorePath(),
456 | KEYSTORE_FLAG.trim().substring(2)), appdomeWorkspace, launcher)
457 | : DownloadFilesOrContinue(autoSign.getKeystorePath(), appdomeWorkspace, launcher))
458 | .append(KEYSTORE_PASS_FLAG)
459 | .append(autoSign.getKeystorePassword())
460 | .append(KEYSOTRE_ALIAS_FLAG)
461 | .append(autoSign.getKeystoreAlias())
462 | .append(KEY_PASS_FLAG)
463 | .append(autoSign.getKeyPass());
464 |
465 | if (autoSign.getIsEnableGoogleSign()) {
466 | String signFingerPrint = autoSign.getGoogleSignFingerPrint();
467 | command.append(GOOGLE_PLAY_SIGN_FLAG);
468 | if (Util.fixEmptyAndTrim(signFingerPrint) != null) {
469 | command.append(FINGERPRINT_FLAG)
470 | .append(signFingerPrint);
471 | }
472 | }
473 | break;
474 | case PRIVATE:
475 | io.jenkins.plugins.appdome.build.to.secure.platform
476 | .android.certificate.method.PrivateSign privateSign =
477 | (io.jenkins.plugins.appdome.build.to.secure.platform
478 | .android.certificate.method.PrivateSign)
479 | androidPlatform.getCertificateMethod();
480 | command.append(PRIVATE_SIGN_FLAG)
481 | .append(FINGERPRINT_FLAG)
482 | .append(privateSign.getFingerprint());
483 | if (privateSign.getGoogleSigning() != null ? privateSign.getGoogleSigning() : false) {
484 | command.append(GOOGLE_PLAY_SIGN_FLAG);
485 | }
486 | break;
487 | case AUTODEV:
488 | this.isAutoDevPrivateSign = true;
489 | io.jenkins.plugins.appdome.build.to.secure.platform
490 | .android.certificate.method.AutoDevSign autoDev =
491 | (io.jenkins.plugins.appdome.build.to.secure.platform
492 | .android.certificate.method.AutoDevSign)
493 | androidPlatform.getCertificateMethod();
494 | command.append(AUTO_DEV_PRIVATE_SIGN_FLAG)
495 | .append(FINGERPRINT_FLAG)
496 | .append(autoDev.getFingerprint());
497 | if (autoDev.getGoogleSigning()) {
498 | command.append(GOOGLE_PLAY_SIGN_FLAG);
499 | }
500 | break;
501 | case NONE:
502 | default:
503 | break;
504 | }
505 |
506 | if (androidPlatform.getIsCrashlytics()) {
507 | if (androidPlatform.getFirebaseAppId() != null && !androidPlatform.getFirebaseAppId().isEmpty()) {
508 | listener.getLogger().println("The Firebase app id inserted: " + androidPlatform.getFirebaseAppId());
509 | try {
510 | installFirebaseCLI(env, appdomeWorkspace, launcher, listener);
511 | listener.getLogger().println("Firebase CLI installed successfully");
512 | command.append(FIREBASE_APP_ID).append(androidPlatform.getFirebaseAppId());
513 | } catch (Exception e) {
514 | listener.getLogger().println("Failed to install Firebase CLI binary: " + e);
515 | listener.getLogger().println("Continuing without it.");
516 | }
517 | } else {
518 | listener.getLogger().println("No Firebase App ID provided; upload to Firebase and Crashlytics will not proceed.");
519 | }
520 | }
521 |
522 |
523 | if (androidPlatform.getIsDatadog()) {
524 | if (androidPlatform.getDatadogKey() != null && !androidPlatform.getDatadogKey().isEmpty()) {
525 | listener.getLogger().println("The Datadog key inserted: " + androidPlatform.getDatadogKey());
526 | command.append(DATADOG_API_KEY).append(androidPlatform.getDatadogKey());
527 | }
528 | }
529 | }
530 |
531 | @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Null value is expected and handled elsewhere")
532 | private void installFirebaseCLI(EnvVars env, FilePath workspace, Launcher launcher, TaskListener listener) throws Exception {
533 | listener.getLogger().println("Installing Firebase CLI...");
534 | boolean isUnix = launcher.isUnix();
535 | String firebaseBinaryName = isUnix ? "firebase" : "firebase.exe";
536 | FilePath firebaseBinary = workspace.child(firebaseBinaryName);
537 |
538 | if (!firebaseBinary.exists()) {
539 | String downloadUrl = "https://firebase.tools/bin/win/latest";
540 | if (isUnix) {
541 | downloadUrl = System.getProperty("os.name").toLowerCase().contains("linux")
542 | ? "https://firebase.tools/bin/linux/latest"
543 | : "https://firebase.tools/bin/macos/latest";
544 | }
545 |
546 | listener.getLogger().println("Downloading Firebase CLI from " + downloadUrl);
547 |
548 | try (InputStream in = new URL(downloadUrl).openStream(); OutputStream out = firebaseBinary.write()) {
549 | IOUtils.copy(in, out);
550 | listener.getLogger().println("Firebase CLI downloaded successfully.");
551 | } catch (IOException e) {
552 | throw new Exception("Failed to download Firebase CLI binary.", e);
553 | }
554 |
555 | if (isUnix) {
556 | firebaseBinary.chmod(0755);
557 | listener.getLogger().println("Execute permissions set for Firebase CLI.");
558 | }
559 | } else {
560 | listener.getLogger().println("Firebase CLI already exists in workspace.");
561 | }
562 |
563 | String pathDelimiter = isUnix ? ":" : ";";
564 | String newPath = env.get("PATH") + pathDelimiter + firebaseBinary.getParent().getRemote();
565 | env.put("PATH", newPath);
566 | listener.getLogger().println("PATH updated with Firebase CLI directory.");
567 | }
568 |
569 | public static boolean isHttpUrl(String urlString) {
570 | String regex = "^https?://.*$";
571 | return urlString.matches(regex);
572 | }
573 |
574 | @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Null value is expected and handled elsewhere")
575 | private static String DownloadFilesOrContinue(String paths, FilePath agentWorkspace, Launcher launcher) throws Exception {
576 | if (paths == null) {
577 | return "NULL";
578 | }
579 | ArgumentListBuilder args;
580 | FilePath userFilesPath;
581 | StringBuilder pathsToFilesOnAgent = new StringBuilder();
582 | String[] splitPathFiles = paths.split(",");
583 |
584 | for (String singlePath : splitPathFiles) {
585 | if (!isHttpUrl(singlePath)) {
586 | pathsToFilesOnAgent.append(singlePath).append(',');
587 | } else {
588 |
589 | try {
590 | userFilesPath = agentWorkspace.child("user_files");
591 | userFilesPath.mkdirs();
592 | pathsToFilesOnAgent.append(DownloadFiles(userFilesPath, launcher, singlePath)).append(',');
593 |
594 | } catch (IOException | InterruptedException e) {
595 | // Handle exceptions
596 | throw new RuntimeException("Could not create or process files in the 'user_files' folder", e);
597 | }
598 | }
599 | }
600 | return pathsToFilesOnAgent.substring(0, pathsToFilesOnAgent.length() - 1).trim();
601 | }
602 |
603 | private static String DownloadFiles(FilePath userFilesPath, Launcher launcher, String url) throws IOException, InterruptedException {
604 | String fileName = getFileNameFromUrl(url);
605 | FilePath outputPath = userFilesPath.child(fileName);
606 | if (!userFilesPath.exists()) {
607 | userFilesPath.mkdirs();
608 | }
609 | System.out.println("Output Path: " + outputPath.getRemote());
610 | ArgumentListBuilder args = new ArgumentListBuilder("curl", "-LO", url);
611 | launcher.launch()
612 | .cmds(args)
613 | .pwd(userFilesPath)
614 | .quiet(true)
615 | .join();
616 |
617 |
618 | return outputPath.getRemote();
619 | }
620 |
621 | private static String getFileNameFromUrl(String url) {
622 | String decodedUrl = url.split("\\?")[0];
623 | int lastSlashIndex = decodedUrl.lastIndexOf('/');
624 | return decodedUrl.substring(lastSlashIndex + 1);
625 | }
626 |
627 | /**
628 | * Clones the Appdome API repository.
629 | * https://github.com/Appdome/appdome-api-bash.git
630 | *
631 | * @param listener the TaskListener to use for logging
632 | * @param appdomeWorkspace the working directory of the build
633 | * @param launcher used to launch commands.
634 | * @return the exit code of the process
635 | * @throws IOException if an I/O error occurs
636 | * @throws InterruptedException if the process is interrupted
637 | */
638 | private int CloneAppdomeApi(TaskListener listener, FilePath appdomeWorkspace, Launcher launcher) throws IOException, InterruptedException {
639 | listener
640 | .getLogger()
641 | .println("Updating Appdome Engine...");
642 |
643 | ArgumentListBuilder gitCloneCommand = new ArgumentListBuilder("git", "clone", "https://github.com/Appdome/appdome-api-bash.git");
644 | return launcher.launch()
645 | .cmds(gitCloneCommand)
646 | .pwd(appdomeWorkspace)
647 | .quiet(true)
648 | .join();
649 | }
650 |
651 | /**
652 | * This method deletes the contents and the workspace directory of an Appdome workspace.
653 | *
654 | * @param listener listener object to log messages
655 | * @param appdomeWorkspace the path to the Appdome workspace to delete
656 | * @throws IOException : if there is an error accessing the file system
657 | * @throws InterruptedException if the current thread is interrupted by another thread while
658 | * it is waiting for the workspace deletion to complete.
659 | */
660 | private static void deleteAppdomeWorkspacce(TaskListener listener, FilePath appdomeWorkspace) throws
661 | IOException, InterruptedException {
662 | listener
663 | .getLogger()
664 | .print("Deleting temporary files." + System.lineSeparator());
665 | appdomeWorkspace.deleteSuffixesRecursive();
666 | appdomeWorkspace.deleteContents();
667 | appdomeWorkspace.deleteRecursive();
668 | }
669 |
670 |
671 | public Platform getPlatform() {
672 | return platform;
673 | }
674 |
675 | public DescriptorExtensionList> getPlatformDescriptors() {
676 | return Jenkins.get().getDescriptorList(Platform.class);
677 | }
678 |
679 | public String getSecondOutput() {
680 | if (secondOutput != null) {
681 | return secondOutput.getSecondOutput();
682 | }
683 | return null;
684 | }
685 |
686 | @DataBoundSetter
687 | public void setSecondOutput(StringWarp secondOutput) {
688 | this.secondOutput = secondOutput;
689 | }
690 |
691 | @DataBoundSetter
692 | public void setDynamicCertificate(StringWarp dynamicCertificate) {
693 | this.dynamicCertificate = dynamicCertificate;
694 | }
695 |
696 | public String getDynamicCertificate() {
697 | if (dynamicCertificate != null) {
698 | return dynamicCertificate.getDynamicCertificate();
699 | }
700 | return null;
701 | }
702 |
703 |
704 | @Symbol("AppdomeBuilder")
705 | @Extension
706 | public static final class DescriptorImpl extends BuildStepDescriptor {
707 |
708 | @POST
709 | public FormValidation doCheckToken(@QueryParameter Secret token) {
710 | Jenkins.get().checkPermission(Jenkins.READ);
711 | if (token != null && Util.fixEmptyAndTrim(token.getPlainText()) == null) {
712 | return FormValidation.error("Token is required");
713 | } else if (token != null && token.getPlainText().contains(" ")) {
714 | return FormValidation.error("White spaces are not allowed in Token.");
715 | }
716 | // Perform any additional validation here
717 | return FormValidation.ok();
718 | }
719 |
720 | public ListBoxModel doFillSelectedVendorItems() {
721 | return VendorManager.getInstance().getVendors();
722 | }
723 |
724 |
725 | @POST
726 | public FormValidation doCheckTeamId(@QueryParameter String teamId) {
727 | Jenkins.get().checkPermission(Jenkins.READ);
728 | if (teamId != null && Util.fixEmptyAndTrim(teamId) == null) {
729 | return FormValidation.warning("Empty Team ID for personal workspace.");
730 | } else if (teamId != null && teamId.contains(" ")) {
731 | return FormValidation.error("White spaces are not allowed in Team ID.");
732 | }
733 | // Perform any additional validation here
734 | return FormValidation.ok("Working on TeamID: " + teamId);
735 | }
736 |
737 |
738 | @Override
739 | public boolean isApplicable(Class extends AbstractProject> aClass) {
740 | return true;
741 | }
742 |
743 | @Override
744 | public String getDisplayName() {
745 | return "Appdome Build-2secure";
746 | }
747 |
748 | }
749 |
750 | }
751 |
--------------------------------------------------------------------------------