String GITHUB_REPOSITORY = 'jenkins'
String SHARED_ACCOUNT_ID = '086679231553'
String SHARED_DEPLOYMENT_ROLE = 'shared-jenkins-pipeline-deploy-role'
List<String> AWS_REGIONS = ['us-east-1']
String SLACK_NOTIFICATIONS_CHANNEL = '#devops'

SERVICES = [
    scheduler: [
        environment: 'shared',
        serviceName: 'scheduler-jenkins'
    ],
    pipeline: [
        environment: 'shared',
        serviceName: 'pipeline-jenkins'
    ],
]

pipeline {
    agent any

    options {
        ansiColor('xterm')
        disableConcurrentBuilds()
        timestamps()
    }

    parameters {
        string(name: 'SHARED_LIBRARIES_VERSION', defaultValue: 'master', description: 'The version of the Jenkins shared libraries to use. Can be a branch, tag, Git revision or PR ref (e.g. pull/PR_NUMBER/merge).')
    }

    triggers {
        issueCommentTrigger('.*retest this please.*')
    }

    stages {
        stage('Load Shared Libraries') {
            steps {
                library "jenkins-global-libraries@${params.SHARED_LIBRARIES_VERSION}"
            }
        }
        stage('Compliance Checks') {
            steps {
                complianceChecks()
            }
        }
        stage('Static Application Security Tests') {
            steps {
                sastTests()
            }
        }
        stage('Validate Software Catalog Definitions') {
            steps {
                script {
                    parallel(SERVICES.collectEntries { service, config ->
                        [
                            (service): {
                                echo "Validating Software Catalog definition for ${config['serviceName']}"
                                datadogSoftwareCatalogValidate(serviceDefinitionFilePath: "software_catalog/${config['serviceName']}.yaml")
                            }
                        ]
                    })
                }
            }
        }
        stage('Create a Release') {
            steps {
                dockerToEcr awsRegions: AWS_REGIONS,
                    ecrAccountId: SHARED_ACCOUNT_ID,
                    imageName: GITHUB_REPOSITORY,
                    imageTag: env.GIT_COMMIT,
                    pushLatest: (env.BRANCH_NAME == 'master'),
                    dockerBuildTarget: 'deploy'
            }
        }
        stage('Scan Docker Image') {
            steps {
                dockerScan awsRegion: AWS_REGIONS[0],
                    ecrAccountId: SHARED_ACCOUNT_ID,
                    imageName: GITHUB_REPOSITORY,
                    imageTag: env.GIT_COMMIT,
                    vulnerabilitiesToIgnore: [
                        'CVE-2014-0114',
                        'CVE-2020-10683',
                        'CVE-2018-1000632',
                        'CVE-2019-10086',
                        'CVE-2025-48734',
                        'CVE-2024-12801',
                        'CVE-2024-12798',
                        'CVE-2025-61729',
                        'CVE-2025-47913',
                        'CVE-2025-68121', // go_toolchain CVE. May fix in final release that is scheduled for February 18, 2026
                        'CVE-2025-61726', // go_toolchain CVE. May fix in final release that is scheduled for February 18, 2026
                        'CVE-2026-25679', // no fix available in jenkins
                        'CVE-2026-32280', // go_toolchain embedded in git-lfs binary from Jenkins base image; requires upstream Jenkins image rebuild with go 1.25.9
                        'CVE-2026-32281', // go_toolchain embedded in git-lfs binary from Jenkins base image; requires upstream Jenkins image rebuild with go 1.25.9
                        'CVE-2026-32283', // go_toolchain embedded in git-lfs binary from Jenkins base image; requires upstream Jenkins image rebuild with go 1.25.9
                        'CVE-2026-39821', // pkg:golang/golang.org/x/net@v0.38.0
                        'CVE-2026-39830', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-39831', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-39832', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-39833', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-39834', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-42508', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-46595', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-5598', // pkg:maven/org.bouncycastle/bcprov-jdk18on@1.83?optional=true&scope=compile
                        'CVE-2025-11226', // pkg:maven/ch.qos.logback/logback-core@1.3.14?scope=test
                        'CVE-2026-33811', // pkg:generic/git-lfs?go_toolchain=1.25.3
                        'CVE-2026-33814', //  pkg:golang/golang.org/x/net@v0.38.0
                        'CVE-2026-34478', // pkg:maven/org.apache.logging.log4j/log4j-core@2.24.3?scope=test
                        'CVE-2026-34479', // pkg:maven/org.apache.logging.log4j/log4j-1.2-api@2.24.3?optional=true
                        'CVE-2026-34480', // pkg:maven/org.apache.logging.log4j/log4j-core@2.24.3?scope=test
                        'CVE-2026-39820', // pkg:generic/git-lfs?go_toolchain=1.25.3
                        'CVE-2026-39829', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-39836', // pkg:generic/git-lfs?go_toolchain=1.25.3
                        'CVE-2026-42499', // pkg:generic/git-lfs?go_toolchain=1.25.3
                        'CVE-2026-42504', // pkg:generic/git-lfs?go_toolchain=1.25.3
                        'CVE-2026-46597', // pkg:golang/golang.org/x/crypto@v0.36.0
                        'CVE-2026-53441', // pkg:maven/org.jenkins-ci.main/jenkins-core@2.555.3
                    ]
            }
        }
        // We don't automatically deploy to the services, to ensure that Jenkins can be shut down cleanly
        // (and also prevent the deployment from taking down the Jenkins service that is running this pipeline!)
        // Instead, we just create new task definitions.
        stage('Create Task Definitions') {
            when {
                branch 'master'
            }
            steps {
                script {
                    parallel(SERVICES.collectEntries { service, config ->
                        [
                            (service): {
                                fargateDeploy environment: config['environment'],
                                    awsRegions: AWS_REGIONS,
                                    gitCommit: env.GIT_COMMIT,
                                    serviceName: config['serviceName'],
                                    ecrRegistryAccountId: SHARED_ACCOUNT_ID,
                                    awsDeploymentTargetAccountId: SHARED_ACCOUNT_ID,
                                    awsDeploymentRoleName: SHARED_DEPLOYMENT_ROLE,
                                    deployType: 'CREATE_TASK_DEFINITION',
                                    imageNameOverride: GITHUB_REPOSITORY
                            }
                        ]
                    })
                }
            }
        }
        stage('Publish Software Catalog Definitions') {
            when {
                branch 'master'
            }
            steps {
                script {
                    parallel(SERVICES.collectEntries { service, config ->
                        [
                            (service): {
                                echo "Publishing Software Catalog definition for ${config['serviceName']}"
                                datadogSoftwareCatalogPublish(serviceDefinitionFilePath: "software_catalog/${config['serviceName']}.yaml")
                            }
                        ]
                    })
                }
            }
        }
    }

    post {
        regression {
            script {
                if (env.BRANCH_NAME == 'master') {
                    slackNotify channel: SLACK_NOTIFICATIONS_CHANNEL
                }
            }
        }
        fixed {
            script {
                if (env.BRANCH_NAME == 'master') {
                    slackNotify channel: SLACK_NOTIFICATIONS_CHANNEL
                }
            }
        }
        cleanup {
            cleanWs()
        }
    }
}
