Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f138c4c
MLE-32187: sync develop with master after 2.3.0 release
Sep 10, 2026
299ec9d
Merge pull request #484 from marklogic/MLE-32187_sync-master-to-develop
vitalykorolev Sep 10, 2026
3911928
MLE-32818: fix upgrade image tag and bump default MarkLogic 12 RPM ve…
Sep 22, 2026
281321b
Merge pull request #485 from marklogic/MLE-32818_fix-tagging-issue
vitalykorolev Sep 22, 2026
3adefed
MLE-32962: Fix ARM and rootless upgrade image handling
Sep 27, 2026
eaf39fa
MLE-32962: address PR review comment - stash/unstash upgrade image fo…
Sep 27, 2026
c5942e7
MLE-32962: always load upgrade image from archive to avoid stale tagg…
Sep 28, 2026
2dd9ba4
MLE-32821: Fix Docker pipeline issues
Sep 28, 2026
fa3d2a0
address PR review comments
Sep 29, 2026
3af801f
Merge pull request #487 from marklogic/MLE-32821_fix-docker-pipeline-…
vitalykorolev Sep 29, 2026
7f9ec40
Merge pull request #486 from marklogic/MLE-32962_fix-arm-rootless-upg…
vitalykorolev Sep 29, 2026
45847f1
MLE-32900: Exclude UBI packages from Docker NOTICE scan
Oct 2, 2026
b6f5558
MLE-33408: Update UBI base images to latest stable
Oct 7, 2026
a76c883
Merge pull request #488 from marklogic/MLE-32900_exclude-ubi-notice-p…
vitalykorolev Oct 8, 2026
da4c84a
Merge branch 'develop' into MLE-33408_update-ubi-base-images
vitalykorolev Oct 8, 2026
b142a5d
Merge pull request #490 from marklogic/MLE-33408_update-ubi-base-images
vitalykorolev Oct 8, 2026
61d2f44
MLE-32902: Fix SUID/SGID permissions on TPM eventlog
Oct 8, 2026
085b89c
Merge pull request #491 from marklogic/MLE-32902_fix-suid-sgid-permis…
vitalykorolev Oct 8, 2026
4320e36
MLE-33408: Align UBI9 glibc and libnsl versions
Oct 10, 2026
14ea16f
Merge pull request #492 from marklogic/MLE-33408-fix-ubi9-libnsl-283
vitalykorolev Oct 11, 2026
bf3ce26
fix SUID and SGID issue
rwinieski Oct 13, 2026
be0b42c
remove keystore SUID issue
rwinieski Oct 13, 2026
5a42e62
Merge pull request #493 from marklogic/MLE-33540/Fix-SUID-SGID
vitalykorolev Oct 13, 2026
6916e8f
MLE-33408: Update UBI8/UBI9 minimal base images and libnsl pin for EL8
Oct 13, 2026
5ab582b
Merge pull request #494 from marklogic/MLE-33408-update-ubi-base-libnsl
vitalykorolev Oct 14, 2026
673443d
MLE-33231: Release Docker 2.3.1
Oct 14, 2026
6c87268
MLE-33231: Add 2.3.1 SBOM files under SBOM folder
Oct 15, 2026
ddedc8d
MLE-33231: Update NOTICE.txt for Docker 2.3.1
Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ If you are using Copilot/AI to modify this repo, follow the **How Copilot Should
- Preserve the root vs rootless behavioral differences (sudo usage, config write mode, converter install).
- **Dockerfile templates (`dockerFiles/*`)**
- Keep the multi-stage + flattened final stage pattern (`COPY --from=builder / /`).
- UBI-repo (microdnf) installs belong in the `platform` stage of the deps Dockerfiles; non-UBI content (libnsl, MarkLogic rpm, tini, scripts) goes after it. The `marklogic-platform-<type>` image must stay an exact layer prefix of the server image (used for the Black Duck NOTICE scan), and `sudo` must never be installed in rootless images.
- Keep ownership/permissions correct for rootless (`marklogic_user:users`, UID 1000).
- If you add/remove files, update `test/structure-test.yaml` accordingly.
- **External RPM pinning**: When pinning external RPMs (e.g., libnsl from AlmaLinux), avoid broad `microdnf -y update` in the same RUN layer, as it can advance glibc and break version compatibility. Use targeted upgrades instead (e.g., `microdnf -y upgrade tzdata`). Test both the dependency image build AND downstream MarkLogic RPM installation.
Expand Down
84 changes: 57 additions & 27 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ SCAN_OUTPUT = ''
IMAGE_SIZE = 0
RPMversion = ''
GRAVITON3_IMAGE_ARCHIVE = 'marklogic-image.tar'
UPGRADE_IMAGE_ARCHIVE = 'marklogic-upgrade-image.tar'
builtImage = ''
platformBuiltImage = ''
platformLatestTag = ''
publishImage = ''
latestTag = ''
mlVerShort = ''
upgradeDockerImage = ''

// Define local funtions
Expand Down Expand Up @@ -169,7 +173,7 @@ def getReviewState() {
*/
void resultNotification(status) {
def paramEmailList = params.emailList?.trim()
def needSecList = params.SCAP_SCAN && BRANCH_NAME == 'develop'
def needSecList = params.SCAP_SCAN && env.BRANCH_NAME == 'develop'
def emailConfig = (!paramEmailList || needSecList) ? loadEmailConfig() : null
def baseEmailList = paramEmailList ?: emailConfig.emailList
def emailSecList = emailConfig?.emailSecList ?: ''
Expand Down Expand Up @@ -197,7 +201,7 @@ void resultNotification(status) {
}
if (params.SCAP_SCAN) {
email_body = "${email_body} <b><a href='${env.BUILD_URL}Open_20SCAP_20Report'>SCAP Scan Report</a></b><br/>"
if ( BRANCH_NAME == 'develop' ) {
if ( env.BRANCH_NAME == 'develop' ) {
emailList = emailList+','+emailSecList
}
} else {
Expand Down Expand Up @@ -244,7 +248,7 @@ void copyRPMs() {
else if (marklogicVersion == "12") {
RPMsuffix = ".nightly-rhel"
RPMbranch = "b12"
RPMversion = "12.1"
RPMversion = "12.2"
}
else {
error "Invalid value in marklogicVersion parameter."
Expand Down Expand Up @@ -303,14 +307,17 @@ void copyRPMs() {

/**
* Builds the Docker image using the 'make build' target.
* Sets various image tag variables (builtImage, publishImage, latestTag).
* Sets various image tag variables (builtImage, publishImage, latestTag, platformBuiltImage, platformLatestTag).
* Updates the Jenkins build display name.
*/
void buildDockerImage() {
builtImage="marklogic/marklogic-server-${dockerImageType}:${marklogicVersion}-${env.dockerImageType}-${env.dockerVersion}"
publishImage="marklogic/marklogic-server-${dockerImageType}:${marklogicVersion}-${env.dockerImageType}"
mlVerShort=marklogicVersion.split("\\.")[0]
latestTag="marklogic/marklogic-server-${dockerImageType}:latest-${mlVerShort}"
// platform image = UBI base + all UBI-repo packages; built by 'make build' as a layer prefix of the server image
platformBuiltImage="marklogic/marklogic-platform-${dockerImageType}:${marklogicVersion}-${env.dockerImageType}-${env.dockerVersion}"
platformLatestTag="marklogic/marklogic-platform-${dockerImageType}:latest-${mlVerShort}"
// Use Los Angeles time (same as ARM_DATE in copyRPMs) to ensure consistency across UTC/PST boundaries
timeStamp = sh(returnStdout: true, script: "TZ=America/Los_Angeles date +%Y%m%d").trim()
timestamptedTag = builtImage.replace('nightly', timeStamp)
Expand All @@ -322,17 +329,14 @@ void buildDockerImage() {

/**
* Pulls the Docker image required for upgrade testing.
* Uses the 'upgradeDockerImage' parameter or defaults to a corresponding 'ubi' image.
* Skips the pull if the target image is 'ubi-rootless' and DOCKER_TESTS is false.
* Uses the 'upgradeDockerImage' parameter or defaults to the last published 'latest-<majorVersion>'
* ubi image for x86 builds or matching ARM image type for ARM upgrade-from testing.
* Skips the pull for rootless image types when Docker tests are disabled.
*/
void pullUpgradeDockerImage() {
if (dockerImageType == "ubi-rootless" && params.DOCKER_TESTS != "true") {
if (dockerImageType.contains("rootless") && !params.DOCKER_TESTS) {
sh """
echo 'dockerImageType is set to ubi-rootless, skipping this stage and Docker upgrade test.'
"""
} else if (isArmImage()) {
sh """
echo 'ARM image type detected. Skipping upgrade test (no previous ARM images available for upgrade testing).'
echo 'dockerImageType is set to ${dockerImageType}, skipping this stage and Docker upgrade test because DOCKER_TESTS is false.'
"""
} else {
if (upgradeDockerImage != "" ) {
Expand All @@ -341,12 +345,22 @@ void pullUpgradeDockerImage() {
docker pull ${upgradeDockerImage}
"""
} else {
upgradeDockerImage = "${dockerRegistry}/marklogic/marklogic-server-ubi:${marklogicVersion}-ubi-${env.dockerVersion}"
def upgradeImageType = isArmImage() ? dockerImageType : "ubi"
upgradeDockerImage = "${dockerRegistry}/marklogic/marklogic-server-${upgradeImageType}:latest-${mlVerShort}"
Comment thread
vitalykorolev marked this conversation as resolved.
sh """
echo 'upgradeDockerImage is not specified, using ${upgradeDockerImage} for upgrade test.'
docker pull ${dockerRegistry}/marklogic/marklogic-server-ubi:${marklogicVersion}-ubi-${env.dockerVersion}
docker pull ${upgradeDockerImage}
"""
}
// Save and stash the pulled image so Docker-Run-Tests (which may run on a
// different agent, e.g. cld-docker-graviton) can load it without relying on
// another docker pull (which may fail against a private registry).
sh """
echo "Saving ${upgradeDockerImage} to ${WORKSPACE}/${UPGRADE_IMAGE_ARCHIVE}..."
docker image save ${upgradeDockerImage} -o ${WORKSPACE}/${UPGRADE_IMAGE_ARCHIVE}
ls -lh ${WORKSPACE}/${UPGRADE_IMAGE_ARCHIVE}
"""
stash name: 'upgrade-image-archive', includes: "${UPGRADE_IMAGE_ARCHIVE}", allowEmpty: false
}
}

Expand Down Expand Up @@ -434,9 +448,11 @@ void publishToInternalRegistry() {
docker tag ${imageToPublish} ${dockerRegistry}/${publishImage}
docker tag ${imageToPublish} ${dockerRegistry}/${latestTag}
docker tag ${imageToPublish} ${dockerRegistry}/${timestamptedTag}
docker tag ${platformBuiltImage} ${dockerRegistry}/${platformLatestTag}
docker push ${dockerRegistry}/${publishImage}
docker push ${dockerRegistry}/${latestTag}
docker push ${dockerRegistry}/${timestamptedTag}
docker push ${dockerRegistry}/${platformLatestTag}
"""

}
Expand Down Expand Up @@ -483,16 +499,13 @@ void publishToInternalRegistry() {
* Scans the rolling latest-<majorVersion> tag (not the per-build version tag) so each
* scan overwrites the same BlackDuck code location instead of accumulating a new one
* per MarkLogic minor version release.
* Passes the pinned UBI base image (read from the matching marklogic-deps Dockerfile's FROM
* line) so BlackDuck can run an additional scan excluding base image components.
* Passes the published marklogic-platform image (UBI base + all UBI-repo packages, an exact
* layer prefix of the server image) as BASE_IMAGE_TO_EXCLUDE so BlackDuck can run an additional
* scan excluding the UBI base and UBI-repo components. Non-UBI content (e.g. libnsl) is not excluded.
* Runs asynchronously (wait: false).
*/
void scanWithBlackDuck() {
def isUbi9 = params.dockerImageType.contains('ubi9')
def isArm = params.dockerImageType.contains('arm')
def depsDockerfile = (isUbi9 && isArm) ? 'dockerFiles/marklogic-deps-ubi9-arm:base' :
isUbi9 ? 'dockerFiles/marklogic-deps-ubi9:base' : 'dockerFiles/marklogic-deps-ubi:base'
def baseImageToExclude = sh(returnStdout: true, script: "grep -m1 '^FROM' ${depsDockerfile} | awk '{print \$2}'").trim()
def baseImageToExclude = "${dockerRegistry}/${platformLatestTag}"
build job: 'securityscans/Blackduck/KubeNinjas/docker', wait: false, parameters: [ string(name: 'BRANCH', value: "${env.BRANCH_NAME}"), string(name: 'CONTAINER_IMAGES', value: "${dockerRegistry}/${latestTag}"), string(name: 'ML_VER', value: "${params.marklogicVersion}"), string(name: 'DOCKER_TYPE', value: "${params.dockerImageType}"), string(name: 'BASE_IMAGE_TO_EXCLUDE', value: "${baseImageToExclude}") ]
}

Expand Down Expand Up @@ -569,9 +582,9 @@ pipeline {
}

parameters {
string(name: 'dockerVersion', defaultValue: '2.3.0', description: 'ML Docker version. This value is used as part of the Docker image tag, which is built as ${marklogicVersion}-${dockerImageType}-${dockerVersion}', trim: true)
string(name: 'dockerVersion', defaultValue: '2.3.1', description: 'ML Docker version. This value is used as part of the Docker image tag, which is built as ${marklogicVersion}-${dockerImageType}-${dockerVersion}', trim: true)
choice(name: 'dockerImageType', choices: 'ubi-rootless\nubi\nubi9-rootless\nubi9\nubi9-arm\nubi9-rootless-arm', description: 'Platform type for Docker image. Will be made part of the docker image tag')
string(name: 'upgradeDockerImage', defaultValue: '', description: 'Docker image for testing upgrades. Defaults to ubi image if left blank.\n Currently upgrading to ubi-rootless is not supported hence the test is skipped when ubi-rootless image is provided.', trim: true)
string(name: 'upgradeDockerImage', defaultValue: '', description: 'Docker image for testing upgrades. Defaults to the ubi image for x86 builds or matching ARM image type for ARM builds if left blank.\n Upgrade image pulls for rootless image types are skipped when DOCKER_TESTS is false.', trim: true)
choice(name: 'marklogicVersion', choices: '12\n11', description: 'MarkLogic Server Branch. used to pick appropriate rpm')
string(name: 'ML_RPM', defaultValue: '', description: 'URL for RPM to be used for Image creation. \n If left blank nightly ML rpm will be used.\n Please provide Jenkins accessible path e.g. /project/engineering or /project/qa', trim: true)
string(name: 'ML_CONVERTERS', defaultValue: '', description: 'URL for the converters RPM to be included in the image creation \n If left blank the nightly ML Converters Package will be used.', trim: true)
Expand Down Expand Up @@ -625,8 +638,8 @@ pipeline {
script {
// Always save image for cases where agents might differ
sh """
echo "Saving ${builtImage} to ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}..."
docker image save ${builtImage} -o ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}
echo "Saving ${builtImage} and ${platformBuiltImage} to ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}..."
docker image save ${builtImage} ${platformBuiltImage} -o ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}
ls -lh ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}
"""
stash name: 'built-image-archive', includes: "${GRAVITON3_IMAGE_ARCHIVE}", allowEmpty: false
Expand Down Expand Up @@ -765,6 +778,15 @@ pipeline {
echo "Image ${builtImage} already available locally"
fi
"""
unstash 'upgrade-image-archive'
// Always load from the archive: upgradeDockerImage defaults to the
// mutable 'latest-<majorVersion>' tag, which a shared agent may already
// have from a stale prior build, so a conditional skip could use it instead.
def upgradeImageSource = "${WORKSPACE}/${UPGRADE_IMAGE_ARCHIVE}"
sh """
echo "Loading image from ${upgradeImageSource} for Docker-Run-Tests..."
docker image load -i ${upgradeImageSource}
"""
}
dockerTests()
stash name: 'docker-test-results', includes: 'test/test_results/**', allowEmpty: true
Expand Down Expand Up @@ -793,13 +815,14 @@ pipeline {
// trust the exact, fully-qualified tag - never a loose repo/type match, which
// could resolve to a different build's image (e.g. a different marklogicVersion).
sh """
if ! docker image inspect ${builtImage} &>/dev/null; then
if ! docker image inspect ${builtImage} &>/dev/null || ! docker image inspect ${platformBuiltImage} &>/dev/null; then
echo "Image not found locally, loading from ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}..."
docker image load -i ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}
else
echo "Image ${builtImage} already available locally"
echo "Images ${builtImage} and ${platformBuiltImage} already available locally"
fi
docker image inspect ${builtImage} >/dev/null
docker image inspect ${platformBuiltImage} >/dev/null
"""

// Store for use in publishToInternalRegistry
Expand Down Expand Up @@ -857,10 +880,17 @@ pipeline {
rm -rf test/test_results scap container-structure-test.xml
# Remove ARM image tar archive
rm -f ${WORKSPACE}/${GRAVITON3_IMAGE_ARCHIVE}
# Remove upgrade image tar archive
rm -f ${WORKSPACE}/${UPGRADE_IMAGE_ARCHIVE}
# Remove ARM image if it was built
if [ -n "${builtImage}" ]; then
docker rmi ${builtImage} || true
fi
# Remove platform image and its pushed tag if they were built
if [ -n "${platformBuiltImage}" ]; then
docker rmi ${platformBuiltImage} || true
docker rmi ${dockerRegistry}/${platformLatestTag} || true
fi
# Clean up RPMs
if [ -d src ]; then
cd src
Expand Down
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ else
export DOCKER_PLATFORM=linux/amd64
endif

#***************************************************************************
# extra UBI-repo packages for the platform image (sudo must never be in rootless images)
#***************************************************************************
ifeq ($(findstring rootless,$(docker_image_type)),rootless)
platform_extra_packages=
else
platform_extra_packages=sudo
endif

#***************************************************************************
# build docker image
#***************************************************************************
Expand Down Expand Up @@ -64,7 +73,9 @@ endif


# build the image
cd src/; docker build ${docker_build_options} -t "${repo_dir}/marklogic-deps-${docker_image_type}:${dockerTag}" --build-arg ML_VERSION=${marklogicVersion} -f ../dockerFiles/marklogic-deps-${docker_image_type}:base .
# platform (UBI base + all UBI-repo packages) is an exact layer prefix of deps; build args must stay identical for both
cd src/; docker build ${docker_build_options} --target platform -t "${repo_dir}/marklogic-platform-${docker_image_type}:${dockerTag}" --build-arg ML_VERSION=${marklogicVersion} --build-arg PLATFORM_EXTRA_PACKAGES="${platform_extra_packages}" -f ../dockerFiles/marklogic-deps-${docker_image_type}:base .
cd src/; docker build ${docker_build_options} -t "${repo_dir}/marklogic-deps-${docker_image_type}:${dockerTag}" --build-arg ML_VERSION=${marklogicVersion} --build-arg PLATFORM_EXTRA_PACKAGES="${platform_extra_packages}" -f ../dockerFiles/marklogic-deps-${docker_image_type}:base .
cd src/; docker build ${docker_build_options} -t "${repo_dir}/marklogic-server-${docker_image_type}:${dockerTag}" --build-arg BASE_IMAGE=${repo_dir}/marklogic-deps-${docker_image_type}:${dockerTag} --build-arg ML_RPM=${package} --build-arg ML_USER=marklogic_user --build-arg ML_DOCKER_VERSION=${dockerVersion} --build-arg ML_VERSION=${marklogicVersion} --build-arg ML_CONVERTERS=${converters} --build-arg BUILD_BRANCH=${build_branch} --build-arg ML_DOCKER_TYPE=${docker_image_type} -f ../dockerFiles/marklogic-server-${docker_image_type}:base .

# remove temporary files
Expand Down Expand Up @@ -96,8 +107,8 @@ docker-test-ids:
@awk 'BEGIN{in_tests=0} /^\*\*\* Test Cases \*\*\*/{in_tests=1;next} /^\*\*\*/{if(in_tests)exit} in_tests && /^[DC][0-9][0-9] /{print " - " $$0}' ./test/docker-tests.robot

docker-tests:
cd test; \
$(MAKE) -s docker-test-ids; \
cd test; \
python3 -m venv python_env; \
source ./python_env/bin/activate; \
pip3 install -r requirements.txt; \
Expand Down
Loading
Loading