diff --git a/pipelines/monolithic.Jenkinsfile b/pipelines/monolithic.Jenkinsfile index 942d53c..af89512 100644 --- a/pipelines/monolithic.Jenkinsfile +++ b/pipelines/monolithic.Jenkinsfile @@ -323,6 +323,7 @@ or with paths relative to repo root: when { expression { params.BUILD_ISO } } steps { script { runPart ("build-iso") + runPart ("sign-iso") runPart ("publish-iso") sh ("BUILD_STATUS=success ${Constants.SCRIPTS_DIR}/create-latest-iso-symlinks.sh") } } diff --git a/pipelines/parts/build-iso.Jenkinsfile b/pipelines/parts/build-iso.Jenkinsfile index b5a07f1..6a0f74c 100644 --- a/pipelines/parts/build-iso.Jenkinsfile +++ b/pipelines/parts/build-iso.Jenkinsfile @@ -50,11 +50,6 @@ pipeline { sh ("${Constants.SCRIPTS_DIR}/build-iso.sh") } } - stage ("sign-iso") { - steps { - sh ("${Constants.SCRIPTS_DIR}/sign-iso.sh") - } - } } post { always { diff --git a/pipelines/parts/sign-iso.Jenkinsfile b/pipelines/parts/sign-iso.Jenkinsfile new file mode 100644 index 0000000..de6a1f4 --- /dev/null +++ b/pipelines/parts/sign-iso.Jenkinsfile @@ -0,0 +1,71 @@ +// vim: syn=groovy + +// +// Copyright (c) 2022 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +library "common@${params.JENKINS_SCRIPTS_BRANCH}" + +setBuildDescr() + +pipeline { + agent any + options { + timestamps() + } + parameters { + string ( + name: 'MASTER_JOB_NAME' + ) + string ( + name: 'MASTER_BUILD_NUMBER' + ) + string ( + name: 'JENKINS_SCRIPTS_BRANCH' + ) + string ( + name: 'BUILD_HOME' + ) + string ( + name: 'TIMESTAMP' + ) + string ( + name: 'PUBLISH_TIMESTAMP' + ) + booleanParam ( + name: 'DRY_RUN' + ) + booleanParam ( + name: 'SHELL_XTRACE' + ) + booleanParam ( + name: 'BUILD_ISO' + ) + } + stages { + stage ("signing-preflight") { + steps { + // Pre-flight checks before signing process + sh ("${Constants.SCRIPTS_DIR}/signing-preflight.sh") + } + } + stage ("sign-iso") { + steps { + sh ("${Constants.SCRIPTS_DIR}/sign-iso.sh") + } + } + } + post { + always { + notAborted { + sh ("${Constants.SCRIPTS_DIR}/archive-iso.sh") + } + } + cleanup { + cleanupPartJob() + } + } +} + diff --git a/scripts/build-iso.sh b/scripts/build-iso.sh index f089773..1554e11 100755 --- a/scripts/build-iso.sh +++ b/scripts/build-iso.sh @@ -30,12 +30,60 @@ build_img_args= # Job is configured to sign the ISO with official keys. if $SIGN_ISO_FORMAL ; then [[ -n "$SIGNING_SERVER" ]] || die "SIGN_ISO_FORMAL requires SIGNING_SERVER" - # Don't sign ISO with developer keys; we will sign it separately - # in sign-iso.sh + # Formal signing, task of the 'sign-iso.sh´ with official key build_img_args+=" --no-sign" +else + # Use developer key signing (default build-image behavior) + # build_img_args remains empty to enable default signing + notice "Using developer key signing" fi + notice "building STD ISO" stx_docker_cmd $DRY_RUN_ARG "build-image $build_img_args" python3 $(dirname "$0")/lib/packages_parser.py --input "$BUILD_HOME"/localdisk/workdir/starlingx/packages.yaml --csv-dest "$BUILD_HOME"/localdisk/deploy/iso-packages.csv || true # errors on the script are ignored + +# Create build information log +create_build_info_log() { + local build_info_file="$BUILD_HOME/localdisk/deploy/build_info.log" + + cat > "$build_info_file" << EOF +# StarlingX ISO Build Information (Build Stage) +Build Date: $(date -u) +Build Type: ISO Build (No Signing - separate sign-iso job) +Jenkins Job: ${JOB_NAME:-Unknown} +Build Number: ${BUILD_NUMBER:-Unknown} +Git Commit: ${GIT_COMMIT:-Unknown} +Git Branch: ${GIT_BRANCH:-Unknown} +Workspace: ${WORKSPACE:-Unknown} +Build Home: ${BUILD_HOME} +Timestamp: ${TIMESTAMP:-Unknown} +Secureboot Formal: ${SECUREBOOT_FORMAL:-false} +Sign ISO Formal: ${SIGN_ISO_FORMAL:-false} +Build Host: $(hostname) +Build User: $(whoami) + +# Build Configuration: +$(grep -E '^(BUILD_|SIGN_|SECUREBOOT_)' "$BUILD_HOME/build.conf" 2>/dev/null || echo "Configuration not available") + +# ISO Files Created: +$(find "$BUILD_HOME/localdisk/deploy" -name "*.iso" -type f 2>/dev/null | while read iso_file; do + echo "$iso_file ($(stat -c%s "$iso_file" 2>/dev/null | numfmt --to=iec 2>/dev/null || echo "unknown size"))" +done) + +# Build Command Used: +build-image --no-sign + +# Next Steps: +This build completed successfully without signing. +The ISO files are ready for the sign-iso stage. +Run 'sign-iso' job to complete the process. +EOF + + notice "Build info saved to: $build_info_file" +} + +create_build_info_log + +notice "ISO build completed successfully - ready for sign-iso stage" diff --git a/scripts/sign-iso.sh b/scripts/sign-iso.sh index 2d0a6b6..4f3970e 100755 --- a/scripts/sign-iso.sh +++ b/scripts/sign-iso.sh @@ -27,7 +27,7 @@ sign_iso() { # Job is configured to sign the ISO with formal keys if $SIGN_ISO_FORMAL ; then - [[ -n "$SIGNING_SERVER" ]] || die "SECUREBOOT_FORMAL requires SIGNING_SERVER" + [[ -n "$SIGNING_SERVER" ]] || die "SIGN_ISO_FORMAL requires SIGNING_SERVER" ( export MY_REPO=$REPO_ROOT/cgcs-root export MY_WORKSPACE=$WORKSPACE_ROOT diff --git a/scripts/signing-preflight.sh b/scripts/signing-preflight.sh new file mode 100644 index 0000000..6c9371e --- /dev/null +++ b/scripts/signing-preflight.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +# +# Copyright (c) 2022 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e +source $(dirname "$0")/lib/job_utils.sh + +require_job_env BUILD_HOME + +load_build_env + +notice "StarlingX Signing Pre-flight Checks" + +# Pre-flight validation: ISO artifacts + signing configuration + connectivity +# This script validates all conditions necessary for successful ISO signing +declare -a iso_files +iso_files+=($BUILD_HOME/localdisk/deploy/starlingx-intel-x86-64-cd.iso) + +validation_errors=0 + +for iso_file in "${iso_files[@]}" ; do + # Handle symlinks + if [[ -L "$iso_file" ]] ; then + iso_link_target="$(readlink "$iso_file")" || { + error "failed to read symlink $iso_file" + ((validation_errors++)) + continue + } + [[ -n "$iso_link_target" ]] || { + error "$iso_file: empty symlink target" + ((validation_errors++)) + continue + } + [[ ! "$iso_link_target" =~ / ]] || { + error "$iso_file: link target must not include slashes" + ((validation_errors++)) + continue + } + real_iso_file="$(dirname "$iso_file")/$iso_link_target" + info "ISO symlink: $iso_file -> $real_iso_file" + iso_file="$real_iso_file" + fi + + # Check if file exists and is readable + if [[ ! -f "$iso_file" ]]; then + error "ISO file not found: $iso_file" + ((validation_errors++)) + continue + fi + + if [[ ! -r "$iso_file" ]]; then + error "ISO file is not readable: $iso_file" + ((validation_errors++)) + continue + fi + + # Check file size (should be > 1MB for a valid ISO) + file_size=$(stat -c%s "$iso_file" 2>/dev/null || echo "0") + if [[ ${file_size} -lt 1048576 ]]; then + error "ISO file seems too small (${file_size} bytes): $iso_file" + ((validation_errors++)) + continue + fi + + info "✓ ISO file validated: $iso_file ($(numfmt --to=iec ${file_size}))" +done + +# Check for build info file +build_info_file="$BUILD_HOME/localdisk/deploy/build_info.log" +if [[ -f "$build_info_file" ]]; then + info "✓ Build info found: $build_info_file" +else + warn "Build info file not found: $build_info_file" +fi + +# Check for packages CSV +packages_csv="$BUILD_HOME/localdisk/deploy/iso-packages.csv" +if [[ -f "$packages_csv" ]]; then + info "✓ Packages CSV found: $packages_csv" +else + info "Packages CSV not found (optional): $packages_csv" +fi + +# Check signing configuration if formal signing is enabled +if [[ "${SIGN_ISO_FORMAL}" == "true" ]]; then + notice "Validating signing configuration for formal signing" + + missing_config=() + + if [[ -z "${SIGNING_SERVER}" ]]; then + missing_config+=("SIGNING_SERVER") + fi + + if [[ -z "${SIGNING_USER}" ]]; then + missing_config+=("SIGNING_USER") + fi + + if [[ ${#missing_config[@]} -gt 0 ]]; then + error "Missing signing configuration for formal signing:" + for config in "${missing_config[@]}"; do + error " - ${config}" + done + ((validation_errors++)) + else + info "✓ Signing configuration is complete" + info " - SIGNING_SERVER: ${SIGNING_SERVER}" + info " - SIGNING_USER: ${SIGNING_USER}" + if [[ -n "${SIGNING_KEY_NAME}" ]]; then + info "SIGNING_KEY_NAME: ${SIGNING_KEY_NAME}" + else + info "SIGNING_KEY_NAME not specified, using default" + fi + + # Test SSH connectivity to signing server (like actual signing process) + if command -v ssh >/dev/null 2>&1; then + info "Testing SSH connectivity to signing server..." + # Test actual SSH connection like sign_iso_formal.sh does + # Use same connection parameters as signing process + ssh_test_cmd="ssh -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no" + if [[ -n "${SIGNING_USER}" ]]; then + ssh_test_cmd+=" ${SIGNING_USER}@${SIGNING_SERVER}" + else + ssh_test_cmd+=" ${SIGNING_SERVER}" + fi + ssh_test_cmd+=" exit" + + # Execute SSH test with error handling + if eval "${ssh_test_cmd}" >/dev/null 2>&1 || true; then + if eval "${ssh_test_cmd}" >/dev/null 2>&1; then + info "✓ SSH connection successful to signing server: ${SIGNING_SERVER}" + else + warn "SSH connection failed to signing server: ${SIGNING_SERVER}" + warn "This may indicate authentication, network, or server issues" + warn "Signing process may fail - check SSH keys and server access" + fi + fi + else + info "SSH command not available - skipping connectivity test" + fi + fi +else + info "Formal ISO signing is disabled (SIGN_ISO_FORMAL != true)" +fi + +# Summary +if [[ ${validation_errors} -eq 0 ]]; then + notice "All pre-flight checks passed - ready for signing" + exit 0 +else + error "Found ${validation_errors} pre-flight check error(s)" + exit 1 +fi +