Jenkinsfile
#!/usr/bin/env groovy
@Library("product-pipelines-shared-library") _
// Automated release, promotion and dependencies
properties([
// Include the automated release parameters for the build
release.addParams(),
// Dependencies of the project that should trigger builds
dependencies([
'conjur-enterprise/conjur-opentelemetry-tracer',
'conjur-enterprise/conjur-api-go',
'conjur-enterprise/conjur-authn-k8s-client',
'conjur-enterprise/summon'
])
])
// Performs release promotion. No other stages will be run
if (params.MODE == "PROMOTE") {
release.promote(params.VERSION_TO_PROMOTE) { infrapool, sourceVersion, targetVersion, assetDirectory ->
// Any assets from sourceVersion Github release are available in assetDirectory
// Any version number updates from sourceVersion to targetVersion occur here
// Any publishing of targetVersion artifacts occur here
// Anything added to assetDirectory will be attached to the Github Release
// Pull existing images from internal registry in order to promote
infrapool.agentSh """
export PATH="release-tools/bin:${PATH}"
docker pull registry.tld/secretless-broker:${sourceVersion}
docker pull registry.tld/secretless-broker-quickstart:${sourceVersion}
docker pull registry.tld/secretless-broker-redhat:${sourceVersion}
#Promote source version to target version.
summon -e common ./bin/publish --promote --source ${sourceVersion} --target ${targetVersion}
"""
}
// Copy Github Enterprise release to Github
release.copyEnterpriseRelease(params.VERSION_TO_PROMOTE)
return
}
pipeline {
agent { label 'conjur-enterprise-common-agent' }
options {
timestamps()
buildDiscarder(logRotator(numToKeepStr: '30'))
}
triggers {
cron(getDailyCronString())
}
environment {
// Sets the MODE to the specified or autocalculated value as appropriate
MODE = release.canonicalizeMode()
}
stages {
// Aborts any builds triggered by another project that wouldn't include any changes
stage ("Skip build if triggering job didn't create a release") {
when {
expression {
MODE == "SKIP"
}
}
steps {
script {
currentBuild.result = 'ABORTED'
error("Aborting build because this build was triggered from upstream, but no release was built")
}
}
}
stage('Scan for internal URLs') {
steps {
script {
detectInternalUrls()
}
}
}
stage('Get InfraPool ExecutorV2 Agent') {
steps {
script {
// Request ExecutorV2 agents for 1 hour(s)
INFRAPOOL_EXECUTORV2_AGENTS = getInfraPoolAgent(type: "ExecutorV2", quantity: 1, duration: 5)
INFRAPOOL_EXECUTORV2_AGENT_0 = INFRAPOOL_EXECUTORV2_AGENTS[0]
}
}
}
stage('Validate Changelog') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/parse-changelog'
}
}
}
}
// Generates a VERSION file based on the current build number and latest version in CHANGELOG.md
stage('Validate Changelog and set version') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
updateVersion(infrapool, "CHANGELOG.md", "${BUILD_NUMBER}")
}
}
}
}
stage('Update Submodules') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'git submodule update --init --recursive'
}
}
}
}
stage('Get latest upstream dependencies') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
updateGoDependencies(infrapool, "${WORKSPACE}/go.mod")
}
}
}
}
stage('Build and Unit tests') {
parallel {
stage('Build Images') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/build'
}
}
}
}
stage('Unit tests') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/test_unit'
}
}
}
post {
always {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/coverage'
infrapool.agentSh 'cp ./test/unit-test-output/c.out ./c.out'
infrapool.agentStash name: 'junit-report', includes: 'test/unit-test-output/junit.xml'
}
}
unstash 'junit-report'
junit 'test/unit-test-output/junit.xml'
}
}
}
}
}
stage('Scan Secretless') {
parallel {
stage('Scan Secretless Image for fixable issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
scanAndReport(infrapool, "secretless-broker:latest", "HIGH", false)
}
}
}
}
stage('Scan Secretless Image for all issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
scanAndReport(infrapool, "secretless-broker:latest", "NONE", true)
}
}
}
}
stage('Scan Secretless Quickstart for fixable issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
scanAndReport(infrapool, "secretless-broker-quickstart:latest", "HIGH", false)
}
}
}
}
stage('Scan Secretless Quickstart for all issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
scanAndReport(infrapool, "secretless-broker-quickstart:latest", "NONE", true)
}
}
}
}
stage('Scan Secretless RedHat for fixable issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
TAG = infrapool.agentSh(returnStdout: true, script: '. bin/build_utils && full_version_tag')
scanAndReport(infrapool, "secretless-broker-redhat:${TAG}", "HIGH", false)
}
}
}
}
stage('Scan Secretless RedHat for all issues') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
TAG = infrapool.agentSh(returnStdout: true, script: '. bin/build_utils && full_version_tag')
scanAndReport(infrapool, "secretless-broker-redhat:${TAG}", "NONE", true)
}
}
}
}
stage('Scan For Security with Gosec') {
//Gosec only works on branch builds
when {
not { buildingTag() }
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentGet from: "${WORKSPACE}", to: "${WORKSPACE}"
}
sh "./bin/check_golang_security -s High -c Medium -b ${env.BRANCH_NAME}"
}
junit(allowEmptyResults: true, testResults: 'gosec.output')
}
}
}
}
stage('Integration Tests') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
def directories = infrapool.agentSh (
returnStdout: true,
// We run the 'find' directive first on all directories with test files, then run a 'find' directive
// to make sure they also contain start files. We then take the dirname, and basename respectively.
script:
'''
find $(find ./test -name test) -name 'start' -exec dirname {} \\; | xargs -n1 basename
'''
).trim().split()
def integrationStages = [:]
// Create an integration test stage for each directory we collected previously.
// We want to be sure to skip any tests, such as keychain tests, that can only be run manually.
directories.each { name ->
if (name == "keychain") return
integrationStages["Integration: ${name}"] = {
stage("${name}") {
script {
infrapool.agentSh "./bin/run_integration ${name}"
infrapool.agentStash name: 'integration-junit-report', includes: '**/test/**/junit.xml'
}
}
}
}
parallel integrationStages
}
}
unstash 'integration-junit-report'
junit "**/test/**/junit.xml"
}
}
stage('Combine Integration and Unit Test Coverage') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh "./bin/merge_integration_coverage"
infrapool.agentArchiveArtifacts artifacts: 'test/test-coverage/integ-and-ut-cover.html'
}
}
}
}
stage('Cobertura') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
cobertura(
autoUpdateHealth: false,
autoUpdateStability: false,
coberturaReportFile: 'test/test-coverage/coverage.xml',
conditionalCoverageTargets: '70, 0, 70',
failUnhealthy: true,
failUnstable: true,
lineCoverageTargets: '70, 70, 70',
maxNumberOfBuilds: 0,
methodCoverageTargets: '70, 0, 70',
onlyStable: false,
sourceEncoding: 'ASCII',
zoomCoverageChart: false
)
infrapool.agentSh 'cp test/test-coverage/integ-and-ut-cover.out ./c.out'
infrapool.agentStash name: 'coverage-report', includes: 'test/test-coverage/coverage.xml'
}
codacy action: 'reportCoverage', filePath: "test/test-coverage/coverage.xml"
}
}
}
stage('Functional Tests') {
parallel {
stage('Quick start') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/test_demo'
}
}
}
}
stage('K8s Demo') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'summon -f ./k8s-ci/secrets.yml ./k8s-ci/test demos/k8s-demo'
}
}
}
}
stage('CRD test') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'summon -f ./k8s-ci/secrets.yml ./k8s-ci/test k8s-ci/k8s_crds'
}
}
}
}
}
}
stage('Push Images Internally') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh'./bin/publish --internal'
}
}
}
}
stage('Build Release Artifacts') {
when {
expression {
MODE == "RELEASE"
}
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/build_release --snapshot'
infrapool.agentArchiveArtifacts artifacts: 'dist/goreleaser/'
}
}
}
}
stage('Create Release Assets') {
when {
expression {
MODE == "RELEASE"
}
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
dir('./pristine-checkout') {
// Go releaser requires a pristine checkout
checkout scm
infrapool.agentPut from: """${WORKSPACE}/pristine-checkout""", to: """$WORKSPACE/"""
infrapool.agentSh 'git submodule update --init --recursive'
// Create release packages without releasing to Github
infrapool.agentSh "./bin/build_release --skip-validate"
infrapool.agentArchiveArtifacts artifacts: 'dist/goreleaser/'
}
}
}
}
}
stage('Release') {
when {
expression {
MODE == "RELEASE"
}
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
release(infrapool) { billOfMaterialsDirectory, assetDirectory, toolsDirectory ->
// Publish release artifacts to all the appropriate locations
// Copy any artifacts to assetDirectory to attach them to the Github release
// Copy assets to be published in Github release.
infrapool.agentSh "./bin/copy_release_assets ${assetDirectory}"
// Create Go application SBOM using the go.mod version for the golang container image
infrapool.agentSh """export PATH="${toolsDirectory}/bin:${PATH}" && go-bom --tools "${toolsDirectory}" --go-mod ./go.mod --image "golang" --main "cmd/secretless-broker/" --output "${billOfMaterialsDirectory}/go-app-bom.json" """
// Create Go module SBOM
infrapool.agentSh """export PATH="${toolsDirectory}/bin:${PATH}" && go-bom --tools "${toolsDirectory}" --go-mod ./go.mod --image "golang" --output "${billOfMaterialsDirectory}/go-mod-bom.json" """
infrapool.agentSh """export PATH="${toolsDirectory}/bin:${PATH}" && summon -e production ./bin/publish --edge"""
}
}
}
}
}
stage('Fix Website Flags (staging)') {
when {
branch 'staging'
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'sed -i "s#^is_maintenance_mode:.*#is_maintenance_mode: false#" docs/_config.yml'
}
}
}
}
stage('Build Website') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/build_website'
}
}
}
}
stage('Check Links') {
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh './bin/check_website_links'
}
}
}
}
stage('Publish') {
parallel {
stage('Publish Website (staging)') {
when {
branch 'staging'
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'summon -e staging bin/publish_website'
infrapool.agentArchiveArtifacts artifacts: 'docs/_site/'
}
}
}
}
stage('Publish Website (production)') {
when {
branch 'main'
}
steps {
script {
infraPoolConnect(INFRAPOOL_EXECUTORV2_AGENT_0) { infrapool ->
infrapool.agentSh 'summon -e production bin/publish_website'
infrapool.agentArchiveArtifacts artifacts: 'docs/_site/'
}
}
}
}
}
}
}
post {
always {
releaseInfraPoolAgent(".infrapool/release_agents")
}
}
}