Compare commits

..

1 Commits

11 changed files with 75 additions and 444 deletions

View File

@ -27,8 +27,6 @@ https://letsencrypt.org/certs/lets-encrypt-r3.pem
https://letsencrypt.org/certs/lets-encrypt-e1.pem https://letsencrypt.org/certs/lets-encrypt-e1.pem
https://letsencrypt.org/certs/lets-encrypt-r4.pem https://letsencrypt.org/certs/lets-encrypt-r4.pem
https://letsencrypt.org/certs/lets-encrypt-e2.pem https://letsencrypt.org/certs/lets-encrypt-e2.pem
https://letsencrypt.org/certs/2024/r10.pem
https://letsencrypt.org/certs/2024/r11.pem
EOF EOF
)" )"

View File

@ -5,7 +5,6 @@ set -eo pipefail
GITEA_DOWNLOAD_PROJECT=${GITEA_DOWNLOAD_PROJECT} GITEA_DOWNLOAD_PROJECT=${GITEA_DOWNLOAD_PROJECT}
GITEA_DOWNLOAD_ORG=${GITEA_DOWNLOAD_ORG} GITEA_DOWNLOAD_ORG=${GITEA_DOWNLOAD_ORG}
GITEA_DOWNLOAD_BASE_URL=${GITEA_BASE_URL:-https://forge.cadoles.com} GITEA_DOWNLOAD_BASE_URL=${GITEA_BASE_URL:-https://forge.cadoles.com}
GITEA_DOWNLOAD_ANONYMOUS=${GITEA_DOWNLOAD_ANONYMOUS:-no}
GITEA_DOWNLOAD_USERNAME=${GITEA_DOWNLOAD_USERNAME} GITEA_DOWNLOAD_USERNAME=${GITEA_DOWNLOAD_USERNAME}
GITEA_DOWNLOAD_PASSWORD=${GITEA_DOWNLOAD_PASSWORD} GITEA_DOWNLOAD_PASSWORD=${GITEA_DOWNLOAD_PASSWORD}
GITEA_DOWNLOAD_RELEASE_NAME=${GITEA_DOWNLOAD_RELEASE_NAME:-latest} GITEA_DOWNLOAD_RELEASE_NAME=${GITEA_DOWNLOAD_RELEASE_NAME:-latest}
@ -53,10 +52,6 @@ function assert_environment {
} }
function ask_credentials { function ask_credentials {
if [ "${GITEA_DOWNLOAD_ANONYMOUS}" == "yes" ]; then
return
fi
if [ -z "$GITEA_DOWNLOAD_USERNAME" ]; then if [ -z "$GITEA_DOWNLOAD_USERNAME" ]; then
echo -n "Username: " echo -n "Username: "
read GITEA_DOWNLOAD_USERNAME read GITEA_DOWNLOAD_USERNAME
@ -109,14 +104,11 @@ function gitea_api {
local path=$1 local path=$1
local args=${@:2} local args=${@:2}
if [ "${GITEA_DOWNLOAD_ANONYMOUS}" != 'yes' ]; then
args="-u "$GITEA_DOWNLOAD_USERNAME:$GITEA_DOWNLOAD_PASSWORD" ${args}"
fi
curl -L \ curl -L \
--fail \ --fail \
--ipv4 \ --ipv4 \
-k \ -k \
-u "$GITEA_DOWNLOAD_USERNAME:$GITEA_DOWNLOAD_PASSWORD" \
${args} \ ${args} \
"$GITEA_DOWNLOAD_BASE_URL/api/v1$path" "$GITEA_DOWNLOAD_BASE_URL/api/v1$path"
} }
@ -125,14 +117,11 @@ function gitea_download {
local attachment_id=$1 local attachment_id=$1
local output=$2 local output=$2
if [ "${GITEA_DOWNLOAD_ANONYMOUS}" != 'yes' ]; then
GITEA_DOWNLOAD_CURL_ARGS="-u "$GITEA_DOWNLOAD_USERNAME:$GITEA_DOWNLOAD_PASSWORD" ${GITEA_DOWNLOAD_CURL_ARGS}"
fi
curl -L \ curl -L \
--fail \ --fail \
--ipv4 \ --ipv4 \
-k \ -k \
-u "$GITEA_DOWNLOAD_USERNAME:$GITEA_DOWNLOAD_PASSWORD" \
--output "$output" \ --output "$output" \
$GITEA_DOWNLOAD_CURL_ARGS \ $GITEA_DOWNLOAD_CURL_ARGS \
"$GITEA_DOWNLOAD_BASE_URL/attachments/$attachment_id" "$GITEA_DOWNLOAD_BASE_URL/attachments/$attachment_id"

View File

@ -1,124 +0,0 @@
#!/bin/bash
set -eo pipefail
GITEA_PACKAGE_ORG=${GITEA_PACKAGE_ORG}
GITEA_PACKAGE_BASE_URL=${GITEA_BASE_URL:-https://forge.cadoles.com}
GITEA_PACKAGE_USERNAME=${GITEA_PACKAGE_USERNAME}
GITEA_PACKAGE_PASSWORD=${GITEA_PACKAGE_PASSWORD}
GITEA_PACKAGE_CURL_MAX_RETRY=${GITEA_PACKAGE_CURL_MAX_RETRY:-3}
GITEA_PACKAGE_NAME_FILTER=${GITEA_PACKAGE_NAME_FILTER}
GITEA_PACKAGE_TYPE_FILTER=${GITEA_PACKAGE_TYPE_FILTER}
function check_dependencies {
assert_command_available 'curl'
assert_command_available 'jq'
}
function assert_command_available {
local command=$1
local command_path=$(which $command)
if [ -z "$command_path" ]; then
echo "The '$command' command could not be found. Please install it before using this script." 1>&2
exit 1
fi
}
function check_environment {
assert_environment GITEA_PACKAGE_ORG
assert_environment GITEA_PACKAGE_BASE_URL
}
function source_env_file {
if [ ! -f '.env' ]; then
return 0
fi
set -o allexport
source .env
set +o allexport
}
function assert_environment {
local name=$1
local value=${!name}
if [ -z "$value" ]; then
echo "The $"$name" environment variable is empty." 1>&2
exit 1
fi
}
function ask_credentials {
if [ -z "$GITEA_PACKAGE_USERNAME" ]; then
echo -n "Username: "
read GITEA_PACKAGE_USERNAME
fi
if [ -z "$GITEA_PACKAGE_PASSWORD" ]; then
echo -n "Password: "
stty -echo
read GITEA_PACKAGE_PASSWORD
stty echo
echo
fi
}
function gitea_api {
local path=$1
local args=${@:2}
curl -L \
--fail \
--ipv4 \
--progress-bar \
--retry "$GITEA_PACKAGE_CURL_MAX_RETRY" \
-u "$GITEA_PACKAGE_USERNAME:$GITEA_PACKAGE_PASSWORD" \
$GITEA_PACKAGE_CURL_ARGS \
${args} \
"$GITEA_PACKAGE_BASE_URL$path"
}
function delete_packages {
local page=1
local limit=100
while true; do
local result=$(gitea_api "/api/v1/packages/$GITEA_PACKAGE_ORG?page=$page&limit=$limit&type=all" -X GET -H 'accept:application/json')
local total_items=$(echo $result | jq -r '. | length')
for (( i = 0; i < $total_items; i++ )); do
local item=$(echo $result | jq --argjson index $i '.[$index]')
local package_name=$(echo $item | jq -r '.name')
local package_version=$(echo $item | jq -r '.version')
local package_type=$(echo $item | jq -r '.type')
if [ ! -z "$GITEA_PACKAGE_TYPE_FILTER" ]; then
[[ "$package_type" =~ $GITEA_PACKAGE_TYPE_FILTER ]] || continue
fi
if [ ! -z "$GITEA_PACKAGE_NAME_FILTER" ]; then
[[ "$package_name" =~ $GITEA_PACKAGE_NAME_FILTER ]] || continue
fi
echo "Deleting package $package_name (version: $package_version, type: $package_type)..."
gitea_api "/api/v1/packages/$GITEA_PACKAGE_ORG/$package_type/$package_name/$package_version" -X DELETE
done
if [[ "$total_items" == "0" ]]; then
break
fi
page=$(( $page + 1 ))
done
}
function main {
check_dependencies
source_env_file
check_environment
ask_credentials
delete_packages
}
main

121
resources/com/cadoles/gitea/gitea-package.sh Executable file → Normal file
View File

@ -1,29 +1,18 @@
#!/bin/bash #!/bin/bash
set -xeo pipefail set -eo pipefail
GITEA_PACKAGE_ORG=${GITEA_PACKAGE_ORG}
GITEA_PACKAGE_PROJECT=${GITEA_PACKAGE_PROJECT}
GITEA_PACKAGE_BASE_URL=${GITEA_BASE_URL:-https://forge.cadoles.com} GITEA_PACKAGE_BASE_URL=${GITEA_BASE_URL:-https://forge.cadoles.com}
GITEA_PACKAGE_USERNAME=${GITEA_PACKAGE_USERNAME} GITEA_PACKAGE_USERNAME=${GITEA_PACKAGE_USERNAME}
GITEA_PACKAGE_PASSWORD=${GITEA_PACKAGE_PASSWORD} GITEA_PACKAGE_PASSWORD=${GITEA_PACKAGE_PASSWORD}
GITEA_PACKAGE_FILE=${GITEA_PACKAGE_FILE} GITEA_PACKAGE_OWNER=${GITEA_PACKAGE_OWNER}
GITEA_PACKAGE_FILES=${GITEA_PACKAGE_FILES}
GITEA_PACKAGE_CURL_MAX_RETRY=${GITEA_PACKAGE_CURL_MAX_RETRY:-3} GITEA_PACKAGE_CURL_MAX_RETRY=${GITEA_PACKAGE_CURL_MAX_RETRY:-3}
GITEA_PACKAGE_FORCE_OVERWRITE=${GITEA_PACKAGE_FORCE_UPLOAD:-yes} GITEA_PACKAGE_TYPE=${GITEA_PACKAGE_TYPE:-generic}
GITEA_PACKAGE_RPM_GROUP=${GITEA_PACKAGE_RPM_GROUP:-main}
GITEA_PACKAGE_DEBIAN_DISTRIBUTION=${GITEA_PACKAGE_DEBIAN_DISTRIBUTION:-latest}
GITEA_PACKAGE_DEBIAN_COMPONENT=${GITEA_PACKAGE_DEBIAN_COMPONENT:-main}
GITEA_PACKAGE_ALPINE_BRANCH=${GITEA_PACKAGE_ALPINE_BRANCH:-latest}
GITEA_PACKAGE_ALPINE_REPOSITORY=${GITEA_PACKAGE_ALPINE_REPOSITORY:-main}
GITEA_PACKAGE_GENERIC_PACKAGE_NAME=${GITEA_PACKAGE_GENERIC_PACKAGE_NAME:-$GITEA_PACKAGE_PROJECT}
GITEA_PACKAGE_GENERIC_PACKAGE_VERSION=${GITEA_PACKAGE_GENERIC_PACKAGE_VERSION:-latest}
function check_dependencies { function check_dependencies {
assert_command_available 'curl' assert_command_available 'curl'
assert_command_available 'jq'
} }
function assert_command_available { function assert_command_available {
@ -37,9 +26,9 @@ function assert_command_available {
} }
function check_environment { function check_environment {
assert_environment GITEA_PACKAGE_ORG
assert_environment GITEA_PACKAGE_PROJECT
assert_environment GITEA_PACKAGE_BASE_URL assert_environment GITEA_PACKAGE_BASE_URL
assert_environment GITEA_PACKAGE_FILES
assert_environment GITEA_PACKAGE_OWNER
} }
function source_env_file { function source_env_file {
@ -76,52 +65,46 @@ function ask_credentials {
fi fi
} }
function ask_package_file { function upload_package {
while [ ! -f "$GITEA_PACKAGE_FILE" ]; do echo "Uploading package(s)..."
echo -n "Package file (must be a valid path to a supported package file): " case "$GITEA_PACKAGE_TYPE" in
read GITEA_PACKAGE_FILE generic)
done upload_generic_package
if [ -z $GITEA_PACKAGE_TYPE ]; then
local filename=$(basename -- "$GITEA_PACKAGE_FILE")
local extension="${filename##*.}"
case $extension in
deb)
GITEA_PACKAGE_TYPE=debian
;; ;;
apk) alpine)
GITEA_PACKAGE_TYPE=alpine upload_alpine_package
;; ;;
rpm) *)
GITEA_PACKAGE_TYPE=redhat echo "Unknown package type '$GITEA_PACKAGE_TYPE'. Please check $"$GITEA_PACKAGE_TYPE" environment variable value." 1>&2
;; exit 1
*) esac
GITEA_PACKAGE_TYPE=generic echo "Done"
;;
esac
fi
}
function upload_debian_package {
gitea_api "/api/packages/$GITEA_PACKAGE_ORG/debian/pool/$GITEA_PACKAGE_DEBIAN_DISTRIBUTION/$GITEA_PACKAGE_DEBIAN_COMPONENT/upload" \
--upload-file "$GITEA_PACKAGE_FILE"
}
function upload_alpine_package {
gitea_api "/api/packages/$GITEA_PACKAGE_ORG/alpine/$GITEA_PACKAGE_ALPINE_BRANCH/$GITEA_PACKAGE_ALPINE_REPOSITORY" \
--upload-file "$GITEA_PACKAGE_FILE"
}
function upload_redhat_package {
gitea_api "/api/packages/$GITEA_PACKAGE_ORG/rpm/${GITEA_PACKAGE_RPM_GROUP}/upload" \
--upload-file "$GITEA_PACKAGE_FILE"
} }
function upload_generic_package { function upload_generic_package {
local filename=$(basename $GITEA_PACKAGE_FILE) assert_environment GITEA_PACKAGE_GENERIC_PACKAGE_NAME
gitea_api "/api/packages/$GITEA_PACKAGE_ORG/generic/$GITEA_PACKAGE_GENERIC_PACKAGE_NAME/$GITEA_PACKAGE_GENERIC_PACKAGE_VERSION/$filename" \ assert_environment GITEA_PACKAGE_GENERIC_PACKAGE_VERSION
--upload-file "$GITEA_PACKAGE_FILE"
for f in $GITEA_PACKAGE_FILES; do
local filename=$(basename $f)
echo "Uploading file '$f' as generic package $GITEA_PACKAGE_OWNER/$GITEA_PACKAGE_GENERIC_PACKAGE_NAME/$GITEA_PACKAGE_GENERIC_PACKAGE_VERSION..."
gitea_api "/api/packages/$GITEA_PACKAGE_OWNER/generic/$GITEA_PACKAGE_GENERIC_PACKAGE_NAME/$GITEA_PACKAGE_GENERIC_PACKAGE_VERSION/$filename" \
-X PUT \
--upload-file "$f"
done
}
function upload_alpine_package {
assert_environment GITEA_PACKAGE_ALPINE_PACKAGE_BRANCH
assert_environment GITEA_PACKAGE_ALPINE_PACKAGE_REPOSITORY
for f in $GITEA_PACKAGE_FILES; do
local filename=$(basename $f)
echo "Uploading file '$f' as alpine package $GITEA_PACKAGE_OWNER/$GITEA_PACKAGE_ALPINE_PACKAGE_BRANCH/$GITEA_PACKAGE_ALPINE_PACKAGE_REPOSITORY..."
gitea_api "/api/packages/$GITEA_PACKAGE_OWNER/alpine/$GITEA_PACKAGE_ALPINE_PACKAGE_BRANCH/$GITEA_PACKAGE_ALPINE_PACKAGE_REPOSITORY" \
-X PUT \
--upload-file "$f"
done
} }
function gitea_api { function gitea_api {
@ -144,25 +127,7 @@ function main {
source_env_file source_env_file
check_environment check_environment
ask_credentials ask_credentials
ask_package_file upload_package
case $GITEA_PACKAGE_TYPE in
debian)
upload_debian_package
;;
alpine)
upload_alpine_package
;;
redhat)
upload_redhat_package
;;
generic)
upload_generic_package
;;
*)
echo "Package type '$GITEA_PACKAGE_TYPE' is not yet supported" 1>&2
exit 1
;;
esac
} }
main main

View File

@ -1,4 +1,4 @@
FROM reg.cadoles.com/proxy_cache/library/alpine:3.20 FROM reg.cadoles.com/proxy_cache/library/alpine:3.12
ARG HTTP_PROXY= ARG HTTP_PROXY=
ARG HTTPS_PROXY= ARG HTTPS_PROXY=
@ -11,7 +11,7 @@ RUN apk add --no-cache git docker python3 bash openssl curl
RUN curl -k https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/common/add-letsencrypt-ca.sh | bash RUN curl -k https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/common/add-letsencrypt-ca.sh | bash
RUN git clone https://forge.cadoles.com/Cadoles/Tamarin /tamarin\ RUN git clone http://forge.cadoles.com/Cadoles/Tamarin /tamarin\
&& cd /tamarin\ && cd /tamarin\
&& git checkout ${TAMARIN_VERSION} && git checkout ${TAMARIN_VERSION}

View File

@ -1,56 +0,0 @@
{{- if . }}
{{- range . }}
<h3>Target <code>{{ escapeXML .Target }}</code></h3>
{{- if (eq (len .Vulnerabilities) 0) }}
<h4>No Vulnerabilities found</h4>
{{- else }}
<h4>Vulnerabilities ({{ len .Vulnerabilities }})</h4>
<table>
<tr>
<th>Package</th>
<th>ID</th>
<th>Severity</th>
<th>Installed Version</th>
<th>Fixed Version</th>
</tr>
{{- range .Vulnerabilities }}
<tr>
<td><code>{{ escapeXML .PkgName }}</code></td>
<td>{{ escapeXML .VulnerabilityID }}</td>
<td>{{ escapeXML .Severity }}</td>
<td>{{ escapeXML .InstalledVersion }}</td>
<td>{{ escapeXML .FixedVersion }}</td>
</tr>
{{- end }}
</table>
{{- end }}
{{- if (eq (len .Misconfigurations ) 0) }}
<h4>No Misconfigurations found</h4>
{{- else }}
<h4>Misconfigurations</h4>
<table>
<tr>
<th>Type</th>
<th>ID</th>
<th>Check</th>
<th>Severity</th>
<th>Message</th>
</tr>
{{- range .Misconfigurations }}
<tr>
<td>{{ escapeXML .Type }}</td>
<td>{{ escapeXML .ID }}</td>
<td>{{ escapeXML .Title }}</td>
<td>{{ escapeXML .Severity }}</td>
<td>
{{ escapeXML .Message }}
<br><a href={{ escapeXML .PrimaryURL | printf "%q" }}>{{ escapeXML .PrimaryURL }}</a></br>
</td>
</tr>
{{- end }}
</table>
{{- end }}
{{- end }}
{{- else }}
<h3>Trivy Returned Empty Report</h3>
{{- end }}

View File

@ -6,7 +6,7 @@
* - dockerfile - String - Chemin vers le fichier Dockerfile à utiliser pour construire l'image, par défaut "./Dockerfile" * - dockerfile - String - Chemin vers le fichier Dockerfile à utiliser pour construire l'image, par défaut "./Dockerfile"
* - contextDir - String - Répertoire servant de "contexte" pour la construction de l'image, par défault "./" * - contextDir - String - Répertoire servant de "contexte" pour la construction de l'image, par défault "./"
* - imageName - String - Nom de l'image à construire, par défaut "" * - imageName - String - Nom de l'image à construire, par défaut ""
* - imageTags - String - Tag(s) apposé(s) sur l'image après construction, par défaut tags générés par la méthode utils.getProjectVersionTags() * - imageTag - String - Tag apposé sur l'image après construction, par défaut résultat de la commande `git describe --always`
* - gitCredentialsId - String - Identifiant des "credentials" Jenkins utilisés pour cloner le dépôt Git, par défaut "forge-jenkins" * - gitCredentialsId - String - Identifiant des "credentials" Jenkins utilisés pour cloner le dépôt Git, par défaut "forge-jenkins"
* - dockerRepository - String - Nom d'hôte du registre Docker sur lequel publier l'image, par défaut "reg.cadoles.com" * - dockerRepository - String - Nom d'hôte du registre Docker sur lequel publier l'image, par défaut "reg.cadoles.com"
* - dockerRepositoryCredentialsId - String - Identifiant des "credentials" Jenkins utilisés pour déployer l'image sur le registre Docker, par défault "reg.cadoles.com-jenkins" * - dockerRepositoryCredentialsId - String - Identifiant des "credentials" Jenkins utilisés pour déployer l'image sur le registre Docker, par défault "reg.cadoles.com-jenkins"
@ -18,14 +18,7 @@ String buildAndPublishImage(Map options = [:]) {
String contextDir = options.get('contextDir', '.') String contextDir = options.get('contextDir', '.')
String imageName = options.get('imageName', '') String imageName = options.get('imageName', '')
String gitRef = sh(returnStdout: true, script: 'git describe --always').trim() String gitRef = sh(returnStdout: true, script: 'git describe --always').trim()
String imageTag = options.get('imageTag', gitRef)
List<String> defaultImageTags = utils.getProjectVersionTags() + [ "${utils.getProjectVersionDefaultChannel()}-latest" ]
List<String> imageTags = options.get('imageTags', defaultImageTags)
// Handle legacy imageTag parameter
if (options.containsKey('imageTag')) {
imageTags = [ options.get("imageTag", gitRef) ]
}
String gitCredentialsId = options.get('gitCredentialsId', 'forge-jenkins') String gitCredentialsId = options.get('gitCredentialsId', 'forge-jenkins')
String dockerRepository = options.get('dockerRepository', 'reg.cadoles.com') String dockerRepository = options.get('dockerRepository', 'reg.cadoles.com')
String dockerRepositoryCredentialsId = options.get('dockerRepositoryCredentialsId', 'reg.cadoles.com-jenkins') String dockerRepositoryCredentialsId = options.get('dockerRepositoryCredentialsId', 'reg.cadoles.com-jenkins')
@ -51,15 +44,13 @@ String buildAndPublishImage(Map options = [:]) {
} }
} }
String primaryImageTag = imageTags[0] stage("Build image '${imageName}:${imageTag}'") {
stage("Build image '${imageName}:${primaryImageTag}'") {
git.withHTTPCredentials(gitCredentialsId) { git.withHTTPCredentials(gitCredentialsId) {
sh """ sh """
docker build \ docker build \
--build-arg="GIT_USERNAME=${env.GIT_USERNAME}" \ --build-arg="GIT_USERNAME=${env.GIT_USERNAME}" \
--build-arg="GIT_PASSWORD=${env.GIT_PASSWORD}" \ --build-arg="GIT_PASSWORD=${env.GIT_PASSWORD}" \
-t '${imageName}:${primaryImageTag}' \ -t '${imageName}:${imageTag}' \
-f '${dockerfile}' \ -f '${dockerfile}' \
'${contextDir}' '${contextDir}'
""" """
@ -68,33 +59,20 @@ String buildAndPublishImage(Map options = [:]) {
stage('Validate image with Trivy') { stage('Validate image with Trivy') {
utils.when(!skipVerifications) { utils.when(!skipVerifications) {
runTrivyCheck("${imageName}:${primaryImageTag}", projectRepository) runTrivyCheck("${imageName}:${imageTag}", projectRepository)
} }
} }
stage("Login with image repository") { stage("Publish image '${imageName}:${imageTag}'") {
utils.when(!dryRun) { utils.when(!dryRun) {
sh """ retry(2) {
echo ${env.HUB_PASSWORD} | docker login -u '${env.HUB_USERNAME}' --password-stdin '${dockerRepository}'
"""
}
}
imageTags.each { imageTag ->
stage("Publish image '${imageName}:${imageTag}'") {
utils.when(!dryRun) {
sh """ sh """
docker tag "${imageName}:${primaryImageTag}" "${imageName}:${imageTag}" echo ${env.HUB_PASSWORD} | docker login -u '${env.HUB_USERNAME}' --password-stdin '${dockerRepository}'
"""
retry(2) {
sh """
docker push '${imageName}:${imageTag}' docker push '${imageName}:${imageTag}'
""" """
}
} }
} }
} }
} }
} }
@ -109,12 +87,10 @@ void runHadolintCheck(String dockerfile, String projectRepository) {
String lintReport = '' String lintReport = ''
if (fileExists(reportFile)) { if (fileExists(reportFile)) {
String report = readFile(reportFile)
lintReport = """${lintReport} lintReport = """${lintReport}
| |
|``` |```
|${report.trim() ? report : "Rien à signaler."} |${readFile(reportFile)}
|```""" |```"""
} else { } else {
lintReport = """${lintReport} lintReport = """${lintReport}
@ -123,7 +99,7 @@ void runHadolintCheck(String dockerfile, String projectRepository) {
} }
String defaultReport = '_Rien à signaler !_ :thumbsup:' String defaultReport = '_Rien à signaler !_ :thumbsup:'
String report = """## Rapport d'analyse du fichier `${dockerfile}` avec [Hadolint](https://github.com/hadolint/hadolint) String report = """## Validation du Dockerfile `${dockerfile}`
| |
|${lintReport ?: defaultReport} |${lintReport ?: defaultReport}
""".stripMargin() """.stripMargin()
@ -162,8 +138,9 @@ void runTrivyCheck(String imageName, String projectRepository, Map options = [:]
if (fileExists(reportFile)) { if (fileExists(reportFile)) {
lintReport = """${lintReport} lintReport = """${lintReport}
| |
|```
|${readFile(reportFile)} |${readFile(reportFile)}
|""" |```"""
} else { } else {
lintReport = """${lintReport} lintReport = """${lintReport}
| |
@ -171,7 +148,7 @@ void runTrivyCheck(String imageName, String projectRepository, Map options = [:]
} }
String defaultReport = '_Rien à signaler !_ :thumbsup:' String defaultReport = '_Rien à signaler !_ :thumbsup:'
String report = """## Rapport d'analyse de l'image avec [Trivy](https://github.com/aquasecurity/trivy) String report = """## Validation de l'image `${imageName}`
| |
|${lintReport ?: defaultReport} |${lintReport ?: defaultReport}
""".stripMargin() """.stripMargin()
@ -191,14 +168,11 @@ String validateImageWithTrivy(String imageName, Map options = [:]) {
String cacheDefaultBranch = options.get('cacheDefaultBranch', 'develop') String cacheDefaultBranch = options.get('cacheDefaultBranch', 'develop')
Integer cacheMaxSize = options.get('cacheMaxSize', 250) Integer cacheMaxSize = options.get('cacheMaxSize', 250)
String reportFile = options.get('reportFile', ".trivy-report-${currentBuild.startTimeInMillis}.txt") String reportFile = options.get('reportFile', ".trivy-report-${currentBuild.startTimeInMillis}.txt")
String markdownTemplate = libraryResource 'com/cadoles/trivy/templates/markdown.tpl'
writeFile file:'.trivy-markdown.tpl', text: markdownTemplate
cache(maxCacheSize: cacheMaxSize, defaultBranch: cacheDefaultBranch, caches: [ cache(maxCacheSize: cacheMaxSize, defaultBranch: cacheDefaultBranch, caches: [
[$class: 'ArbitraryFileCache', path: cacheDirectory, compressionMethod: 'TARGZ'] [$class: 'ArbitraryFileCache', path: cacheDirectory, compressionMethod: 'TARGZ']
]) { ]) {
sh("'${trivyBin}' --cache-dir '${cacheDirectory}' image --ignorefile .trivyignore.yaml --format template --template '@.trivy-markdown.tpl' -o '${reportFile}' ${trivyArgs} '${imageName}'") sh("'${trivyBin}' --cache-dir '${cacheDirectory}' image -o '${reportFile}' ${trivyArgs} '${imageName}'")
} }
return reportFile return reportFile
@ -206,7 +180,7 @@ String validateImageWithTrivy(String imageName, Map options = [:]) {
String getOrInstallHadolint(Map options = [:]) { String getOrInstallHadolint(Map options = [:]) {
String installDir = options.get('installDir', '/usr/local/bin') String installDir = options.get('installDir', '/usr/local/bin')
String version = options.get('version', '2.12.0') String version = options.get('version', '2.10.0')
String forceDownload = options.get('forceDownload', false) String forceDownload = options.get('forceDownload', false)
String downloadUrl = options.get('downloadUrl', "https://github.com/hadolint/hadolint/releases/download/v${version}/hadolint-Linux-x86_64") String downloadUrl = options.get('downloadUrl', "https://github.com/hadolint/hadolint/releases/download/v${version}/hadolint-Linux-x86_64")
@ -226,7 +200,7 @@ String getOrInstallHadolint(Map options = [:]) {
String getOrInstallTrivy(Map options = [:]) { String getOrInstallTrivy(Map options = [:]) {
String installDir = options.get('installDir', '/usr/local/bin') String installDir = options.get('installDir', '/usr/local/bin')
String version = options.get('version', '0.47.0') String version = options.get('version', '0.27.1')
String forceDownload = options.get('forceDownload', false) String forceDownload = options.get('forceDownload', false)
String installScriptDownloadUrl = options.get('downloadUrl', 'https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh') String installScriptDownloadUrl = options.get('downloadUrl', 'https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh')

View File

@ -52,7 +52,7 @@ def listRepoPackages(Map params = [:]) {
def type = params.type ? params.type : 'binary' def type = params.type ? params.type : 'binary'
def arch = params.arch ? params.arch : 'amd64' def arch = params.arch ? params.arch : 'amd64'
def response = httpRequest(ignoreSslErrors: true, url: "${baseURL}/dists/${distrib}/${component}/${type}-${arch}/Packages") def response = httpRequest(url: "${baseURL}/dists/${distrib}/${component}/${type}-${arch}/Packages")
def packages = [:] def packages = [:]
def lines = response.content.split('\n') def lines = response.content.split('\n')

View File

@ -1,5 +1,3 @@
import java.io.File
def commentPullRequest(String repo, String issueId, String comment, Integer commentIndex = -1) { def commentPullRequest(String repo, String issueId, String comment, Integer commentIndex = -1) {
comment = comment.replaceAll('"', '\\"') comment = comment.replaceAll('"', '\\"')
withCredentials([ withCredentials([
@ -105,6 +103,7 @@ void release(String credentialsId, String org, String project, Map options = [:]
} }
rocketSend( rocketSend(
avatar: 'https://jenkins.cadol.es/static/b5f67753/images/headshot.png',
message: """ message: """
Nouvelle version publiée pour le projet `${org}/${project}`: [${releaseName}](${baseUrl}/${org}/${project}/releases/tag/${releaseVersion}) Nouvelle version publiée pour le projet `${org}/${project}`: [${releaseName}](${baseUrl}/${org}/${project}/releases/tag/${releaseVersion})
@ -116,70 +115,6 @@ void release(String credentialsId, String org, String project, Map options = [:]
) )
} }
// Téléverse une liste de paquets sur Gitea pour le <ORG>/<PROJET> donné.
void uploadPackages(String credentialsId, String org, String project, List<String> packageFiles, Map options = [:]) {
String baseUrl = options.get('baseUrl', 'https://forge.cadoles.com')
String debianDistribution = options.get('debianDistribution', 'latest')
String debianComponent = options.get('debianComponent', 'main')
String rpmGroup = options.get('rpmGroup', 'main')
String alpineBranch = options.get('alpineBranch', 'latest')
String alpineRepository = options.get('alpineRepository', 'main')
String scriptTempDir = ".gitea-package-script-${System.currentTimeMillis()}"
sh("mkdir -p '${scriptTempDir}'")
String giteaPackageScript = "${scriptTempDir}/gitea-package.sh"
String giteaPackageScriptContent = libraryResource 'com/cadoles/gitea/gitea-package.sh'
writeFile file: giteaPackageScript, text:giteaPackageScriptContent
sh("chmod +x '${giteaPackageScript}'")
try {
withCredentials([
usernamePassword(
credentialsId: credentialsId,
usernameVariable: 'GITEA_PACKAGE_USERNAME',
passwordVariable: 'GITEA_PACKAGE_PASSWORD'
)
]) {
packageFiles.each { file ->
sh """
export GITEA_PACKAGE_PROJECT="${project}"
export GITEA_PACKAGE_ORG="${org}"
export GITEA_PACKAGE_FILE="${file}"
export GITEA_PACKAGE_RPM_GROUP="${rpmGroup}"
export GITEA_PACKAGE_DEBIAN_DISTRIBUTION="${debianDistribution}"
export GITEA_PACKAGE_DEBIAN_COMPONENT="${debianComponent}"
export GITEA_PACKAGE_ALPINE_BRANCH="${alpineBranch}"
export GITEA_PACKAGE_ALPINE_REPOSITORY="${alpineRepository}"
${giteaPackageScript}
"""
}
}
} finally {
dir(scriptTempDir) {
deleteDir()
}
}
rocketSend(
message: """
| Nouveau(x) paquet(s) publié(s) pour le projet [${org}/${project}](${baseUrl}/${org}/-/packages):
|
${ (packageFiles.collect{ "| - `${ new File(it).name }`" }).join('\n') }
|
| [Visualiser le job](${env.RUN_DISPLAY_URL})
|
| @${utils.getBuildUser()}
""".stripIndent().stripMargin(),
rawMessage: true
)
}
// Télécharge les fichiers associés à une "version" publiée sur un projet Gitea // Télécharge les fichiers associés à une "version" publiée sur un projet Gitea
void download(String credentialsId, String org, String project, Map options = [:]) { void download(String credentialsId, String org, String project, Map options = [:]) {
String baseUrl = options.get('baseUrl', 'https://forge.cadoles.com') String baseUrl = options.get('baseUrl', 'https://forge.cadoles.com')

View File

@ -27,19 +27,13 @@ void call(Map options = [:]) {
String dockerfileExtension = options.get('dockerfileExtension', '') String dockerfileExtension = options.get('dockerfileExtension', '')
List credentials = options.get('credentials', []) List credentials = options.get('credentials', [])
List<String> releaseBranches = options.get('releaseBranches', ['develop', 'testing', 'stable', 'staging', 'master']) List<String> releaseBranches = options.get('releaseBranches', ['develop', 'testing', 'stable'])
node { node {
properties([ properties([
buildDiscarder(logRotator(daysToKeepStr: jobHistory, numToKeepStr: jobHistory)), buildDiscarder(logRotator(daysToKeepStr: jobHistory, numToKeepStr: jobHistory)),
]) ])
environment {
// Set MKT_PROJECT_VERSION_BRANCH_NAME to Jenkins current branch name by default
// See https://forge.cadoles.com/Cadoles/mktools project
MKT_PROJECT_VERSION_BRANCH_NAME = env.BRANCH_NAME
}
stage('Cancel older jobs') { stage('Cancel older jobs') {
int buildNumber = env.BUILD_NUMBER as int int buildNumber = env.BUILD_NUMBER as int
if (buildNumber > 1) { if (buildNumber > 1) {
@ -55,7 +49,7 @@ void call(Map options = [:]) {
try { try {
def containerImage = buildContainerImage(baseImage, baseDockerfile, dockerfileExtension) def containerImage = buildContainerImage(baseImage, baseDockerfile, dockerfileExtension)
containerImage.inside('-v /var/run/docker.sock:/var/run/docker.sock --network host') { containerImage.inside('-v /var/run/docker.sock:/var/run/docker.sock') {
String repo = env.JOB_NAME String repo = env.JOB_NAME
if (env.BRANCH_NAME ==~ /^PR-.*$/) { if (env.BRANCH_NAME ==~ /^PR-.*$/) {
repo = env.JOB_NAME - "/${env.JOB_BASE_NAME}" repo = env.JOB_NAME - "/${env.JOB_BASE_NAME}"
@ -84,15 +78,9 @@ void call(Map options = [:]) {
String report = """ String report = """
|# Test report for ${gitCommit} |# Test report for ${gitCommit}
| |
|<details ${output.count('\n') <= 10 ? 'open' : ''}>
|
|<summary>Output</summary>
|
|``` |```
|${output} |${output}
|``` |```
|
|</details>
|""".trim().stripMargin() |""".trim().stripMargin()
gitea.commentPullRequest(repo, env.CHANGE_ID, report) gitea.commentPullRequest(repo, env.CHANGE_ID, report)
@ -117,7 +105,7 @@ void call(Map options = [:]) {
message: """ message: """
|:warning: Une erreur est survenue lors de la publication de [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}): |:warning: Une erreur est survenue lors de la publication de [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}):
| |
| - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}/commit/${env.GIT_COMMIT}) | - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}commit/${env.GIT_COMMIT})
| - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}` | - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}`
| |
| **Erreur** | **Erreur**
@ -139,7 +127,7 @@ void call(Map options = [:]) {
message: """ message: """
|:white_check_mark: Nouvelle publication terminée pour [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}): |:white_check_mark: Nouvelle publication terminée pour [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}):
| |
| - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}/commit/${env.GIT_COMMIT}) | - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}commit/${env.GIT_COMMIT})
| - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}` | - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}`
| |
|[Visualiser le job](${env.RUN_DISPLAY_URL}) |[Visualiser le job](${env.RUN_DISPLAY_URL})

View File

@ -1,5 +1,4 @@
import org.jenkinsci.plugins.pipeline.modeldefinition.Utils import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
import org.jenkinsci.plugins.pipeline.modeldefinition.when.impl.ChangeSetConditional
void when(Boolean condition, body) { void when(Boolean condition, body) {
Map config = [:] Map config = [:]
@ -45,36 +44,17 @@ String getBuildUser() {
} }
String getProjectVersionDefaultChannel() { String getProjectVersionDefaultChannel() {
switch (env.BRANCH_NAME) { return env.BRANCH_NAME.toLowerCase().replaceAll('(_|-| )+', '')
case 'develop':
return 'develop'
case 'testing':
case 'staging':
return 'testing'
case 'stable':
case 'master':
return 'stable'
default:
return env.BRANCH_NAME.toLowerCase().replaceAll('(_|-| )+', '')
}
} }
String getProjectVersionShortChannel(String channel) { String getProjectVersionShortChannel(String channel) {
switch (channel) { switch (channel) {
case 'develop': case 'develop':
return 'dev' return 'dev'
case 'testing': case 'testing':
case 'staging':
return 'tst' return 'tst'
case 'stable': case 'stable':
case 'master':
return 'stb' return 'stb'
default: default:
return channel.toLowerCase().replaceAll('(a|e|i|o|u|y_|-| )+', '').take(3) return channel.toLowerCase().replaceAll('(a|e|i|o|u|y_|-| )+', '').take(3)
} }
@ -84,9 +64,8 @@ List<String> getProjectVersionTags(String overrideChannel = '') {
String channel = overrideChannel ? overrideChannel : getProjectVersionDefaultChannel() String channel = overrideChannel ? overrideChannel : getProjectVersionDefaultChannel()
String shortChannel = getProjectVersionShortChannel(channel) String shortChannel = getProjectVersionShortChannel(channel)
String currrentCommitDate = sh(script: 'git show -s --format=%ct', returnStdout: true).trim() String dateVersion = sh(script: 'date +%Y.%-m.%-d', returnStdout: true).trim()
String dateVersion = sh(script: "TZ=Europe/Paris date -d '@${currrentCommitDate}' +%Y.%-m.%-d", returnStdout: true).trim() String timestamp = sh(script: 'date +%-H%M', returnStdout: true).trim()
String timestamp = sh(script: "TZ=Europe/Paris date -d '@${currrentCommitDate}' +%-H%M", returnStdout: true).trim()
String shortCommit = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() String shortCommit = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
String longTag = "${dateVersion}-${channel}.${timestamp}.${shortCommit}" String longTag = "${dateVersion}-${channel}.${timestamp}.${shortCommit}"
@ -98,20 +77,3 @@ List<String> getProjectVersionTags(String overrideChannel = '') {
Boolean isPR() { Boolean isPR() {
return env.BRANCH_NAME ==~ /^PR-.*$/ return env.BRANCH_NAME ==~ /^PR-.*$/
} }
def hasChanges(String pattern) {
def changeLogSets = currentBuild.changeSets
def conditional = new ChangeSetConditional(pattern)
for (set in changeLogSets) {
def entries = set.items
for (entry in entries) {
if (conditional.changeSetMatches(entry, pattern, true)) {
return true;
}
}
}
return false;
}