diff --git a/MODULE.bazel b/MODULE.bazel index ae437a166d6..92c788bed8e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -44,6 +44,24 @@ include("//bazel_common:score_modules_target_sw.MODULE.bazel") # Score test images include("//bazel_common:score_images.MODULE.bazel") +# The release tag includes the KAS/Isar sources; no delivery images are needed. +new_git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") + +new_git_repository( + name = "eb_corbos_toolkit", + build_file_content = """ +exports_files(["BUILD.bazel"]) + +filegroup( + name = "sources", + srcs = glob(["kas/**", "layers/**", ".devcontainer/**"]), + visibility = ["//visibility:public"], +) +""", + commit = "2b0a6c88dd12f892de830ffdabc5dabda275838c", # v2.0.0-beta2 + remote = "https://github.com/Elektrobit/eb_corbos_toolkit.git", +) + # Single-version locks for the deps Stage 2 collects test artifacts from (GTest, the Rust # test rules, the ferrocene coverage tooling). Read after the includes above so it pins the # versions they bring in transitively. diff --git a/images/ebclfsa_aarch64/README.md b/images/ebclfsa_aarch64/README.md index 1984b120c2e..5d5ea310190 100644 --- a/images/ebclfsa_aarch64/README.md +++ b/images/ebclfsa_aarch64/README.md @@ -5,6 +5,9 @@ This is an `aarch64`-based, pre-built image, capable of demonstraing the executi The example can be executed using QEMU. In the [related CI workflow](../.github/workflows/build_and_test_ebclfsa.yml), all these steps are performed, and the resulting log files are stored and made available for download. +For a new image assembled from Debian packages with KAS, instead of deploying +onto this prebuilt image, see the [from-scratch build](../ebclfsa_aarch64_from_scratch/README.md). + > [!TIP] > **Quick Start** > diff --git a/images/ebclfsa_aarch64_from_scratch/BUILD b/images/ebclfsa_aarch64_from_scratch/BUILD new file mode 100644 index 00000000000..3ba6057ca86 --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/BUILD @@ -0,0 +1,73 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +genrule( + name = "image", + srcs = [ + "kas.yml", + "@eb_corbos_toolkit//:BUILD.bazel", + "@eb_corbos_toolkit//:sources", + "//showcases:showcases_deb", + "//images/ebclfsa_aarch64/build/config-overlay:etc/crinit/crinit.d/getty-console.crinit", + "//images/ebclfsa_aarch64/build/config-overlay:usr/bin/delayed-start.sh", + ] + glob(["meta-score/**"]), + outs = [ + "fastdev-trixie-ebclfsa-ebcl-qemuarm64-vmlinux", + "fastdev-trixie-ebclfsa-ebcl-qemuarm64.wic", + ], + cmd = "bash $(location build_image.sh) " + + "$$(dirname $(location @eb_corbos_toolkit//:BUILD.bazel)) " + + "$(location //showcases:showcases_deb) " + + "$(location kas.yml) " + + "$(location //images/ebclfsa_aarch64/build/config-overlay:etc/crinit/crinit.d/getty-console.crinit) " + + "$(location //images/ebclfsa_aarch64/build/config-overlay:usr/bin/delayed-start.sh) " + + "$(RULEDIR)", + local = True, + tags = ["manual"], + tools = ["build_image.sh"], + visibility = ["//visibility:public"], +) + +sh_binary( + name = "run", + srcs = ["//runners/qemu_aarch64/scripts:run_qemu.sh"], + args = [ + "$(location :fastdev-trixie-ebclfsa-ebcl-qemuarm64-vmlinux)", + "$(location :fastdev-trixie-ebclfsa-ebcl-qemuarm64.wic)", + "-append", + "'root=/dev/vda1 sdk_enable lisa_syscall_whitelist=2026 rw sharedmem.enable_sharedmem=0 init=/usr/bin/ebclfsa-cflinit'", + "-snapshot", + ], + data = [ + ":fastdev-trixie-ebclfsa-ebcl-qemuarm64.wic", + ":fastdev-trixie-ebclfsa-ebcl-qemuarm64-vmlinux", + ], + tags = ["manual"], + use_bash_launcher = True, + visibility = ["//visibility:public"], +) + +sh_test( + name = "build_image_test", + size = "small", + srcs = ["build_image_test.sh"], + data = [ + "build_image.sh", + "kas.yml", + "//images/ebclfsa_aarch64/build/config-overlay:etc/crinit/crinit.d/getty-console.crinit", + "//images/ebclfsa_aarch64/build/config-overlay:usr/bin/delayed-start.sh", + ] + glob(["meta-score/**"]), +) diff --git a/images/ebclfsa_aarch64_from_scratch/README.md b/images/ebclfsa_aarch64_from_scratch/README.md new file mode 100644 index 00000000000..00cc85fe11d --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/README.md @@ -0,0 +1,68 @@ +# EB corbos Linux for Safety Applications: image from scratch + +```bash +bazel run --config=eb-aarch64 //images/ebclfsa_aarch64_from_scratch:run +``` + +This cross-compiles the showcases with the EB aarch64 toolchains, packages +[`//showcases:showcases_pkg_tar`](../../showcases/BUILD) as the `score-showcases` +arm64 Debian package, and builds a new `fastdev` disk image with KAS/Isar. +The image is assembled from Debian packages using a Git checkout of the +[EB corbos Toolkit v2.0.0-beta2 tag](https://github.com/Elektrobit/eb_corbos_toolkit/tree/v2.0.0-beta2), +pinned to its commit in `MODULE.bazel`. Only the KAS configuration, bundled Isar +layers and development-container setup are copied into the build workspace. +The large delivery archive, including its prebuilt container and disk images, +is not downloaded. The build container is pulled separately from GHCR. +It does **not** boot or modify the toolkit's prebuilt disk image. +The toolkit still supplies precompiled system packages, including the kernel; +this is an image build from packages, not a source rebuild of the entire OS. + +## Requirements + +- An x86_64 Linux host with Docker and permission to run privileged containers. + The Docker daemon must see the Bazel output directory at the same absolute + path as the build process (not a remote Docker daemon). +- Network access to GitHub, GHCR, and the package repositories referenced by the + toolkit; substantial free disk space for the Isar build. +- `qemu-system-aarch64` and passwordless `sudo`, as required by the existing + [QEMU runner](../../runners/qemu_aarch64/scripts/run_qemu.sh). + +The local image-building action runs the toolkit's digest-pinned v18 development +container. It registers its aarch64 binfmt interpreter if none is registered; +this requires privileged access and affects the host kernel's binfmt registry. +Existing aarch64 registrations are left untouched. KAS/Isar needs privileges +for chroots and mounts, so this action cannot run in a Bazel sandbox or on a +remote executor. + +## Outputs and boot + +To build without starting QEMU: + +```bash +bazel build --config=eb-aarch64 //images/ebclfsa_aarch64_from_scratch:image +``` + +The kernel and `.wic` disk image are written to +`bazel-bin/images/ebclfsa_aarch64_from_scratch/`. The temporary KAS workspace +is removed after the build. The showcases are installed at `/showcases`. +The existing console configuration starts the showcase CLI automatically. +QEMU uses a temporary disk snapshot so running it does not modify Bazel's +image output. Exit QEMU with `Ctrl-a x`. + +The Debian package can also be built separately: + +```bash +bazel build --config=eb-aarch64 //showcases:showcases_deb +``` + +The original [prebuilt-image integration](../ebclfsa_aarch64/README.md) remains +available unchanged. + +## Tests + +The staging test checks package and console configuration placement, excludes +prebuilt images, and verifies cleanup and failure propagation without Docker: + +```bash +bazel test --config=eb-aarch64 //images/ebclfsa_aarch64_from_scratch:build_image_test +``` diff --git a/images/ebclfsa_aarch64_from_scratch/build_image.sh b/images/ebclfsa_aarch64_from_scratch/build_image.sh new file mode 100755 index 00000000000..d65c9d9fc84 --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/build_image.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set -euo pipefail + +if [[ $# != 6 ]]; then + echo "Usage: $0 TOOLKIT_SOURCE_DIR DEB KAS_CONFIG GETTY_CONFIG START_SCRIPT OUTPUT_DIR" >&2 + exit 1 +fi + +for tool in docker realpath; do + if ! command -v "$tool" >/dev/null; then + echo "Error: required image build tool is missing: $tool" >&2 + exit 1 + fi +done +docker info >/dev/null + +toolkit=$(realpath "$1") +deb=$(realpath "$2") +config=$(realpath "$3") +getty=$(realpath "$4") +start=$(realpath "$5") +output=$(realpath "$6") +sources=$(dirname "$config") +# Keep the workspace on the same filesystem visible to the Docker daemon. +work=$(mktemp -d "$output/kas-work.XXXXXXXX") +trap 'rm -rf -- "$work"' EXIT + +cp -R "$toolkit/kas" "$toolkit/layers" "$toolkit/.devcontainer" "$work/" +cp -R "$sources/meta-score" "$work/meta-score" +cp "$config" "$work/kas/score.yml" +packages="$work/meta-score/recipes-score/score-showcases/files" +console="$work/meta-score/recipes-crinit/fastdev/files" +mkdir -p "$packages" "$console" +cp "$deb" "$packages/score-showcases_1.0_arm64.deb" +cp "$getty" "$console/getty-console.crinit" +cp "$start" "$console/delayed-start.sh" + +# Match the toolkit's v18 container, pinned independently of its mutable tag. +container=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd64@sha256:10f487469c03fb2b5be1c804ec0b0c911d3903a9dd9a8fcbb8b8f401d43b158c +docker run --rm --init --privileged --user root \ + --mount "type=bind,src=$work,dst=/workspace" \ + --workdir /workspace "$container" \ + bash -euo pipefail -c ' + uid=$1 + gid=$2 + if ! getent group "$gid" >/dev/null; then + groupmod -g "$gid" developer + fi + usermod -u "$uid" -g "$gid" developer + trap '\''chown -R "$uid:$gid" /workspace'\'' EXIT + if [[ ! -e /proc/sys/fs/binfmt_misc/qemu-aarch64 ]]; then + mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc + update-binfmts --import /workspace/.devcontainer/binfmt-config/qemu-aarch64 + fi + # KAS resolves includes relative to the enclosing Git repository. + runuser -u developer -- git init --quiet /workspace + # The release checkout already includes the patched Isar tree; its internal + # patch sources are not shipped. + runuser -u developer -- kas build \ + --skip repos_checkout --skip repos_apply_patches \ + kas/public.yml:kas/score.yml + ' bash "$(id -u)" "$(id -g)" + +deploy="$work/build/tmp/deploy/images/ebcl-qemuarm64" +for artifact in fastdev-trixie-ebclfsa-ebcl-qemuarm64{.wic,-vmlinux}; do + if [[ ! -f "$deploy/$artifact" ]]; then + echo "Error: KAS did not produce the expected artifact: $deploy/$artifact" >&2 + exit 1 + fi + cp --sparse=always -L "$deploy/$artifact" "$output/$artifact" +done diff --git a/images/ebclfsa_aarch64_from_scratch/build_image_test.sh b/images/ebclfsa_aarch64_from_scratch/build_image_test.sh new file mode 100755 index 00000000000..984f379797c --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/build_image_test.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set -euo pipefail + +sources="$TEST_SRCDIR/_main/images/ebclfsa_aarch64_from_scratch" +overlay="$TEST_SRCDIR/_main/images/ebclfsa_aarch64/build/config-overlay" +fixture="$TEST_TMPDIR/fixture" +output="$TEST_TMPDIR/output" +mkdir -p "$fixture/"{kas,layers/isar,.devcontainer,prebuilt} "$output" +echo "must not use a prebuilt image" > "$fixture/prebuilt/image.wic" +echo "KAS configuration" > "$fixture/kas/public.yml" +echo "bundled Isar" > "$fixture/layers/isar/isar-init-build-env" +echo "container configuration" > "$fixture/.devcontainer/devcontainer.json" +echo "Debian package fixture" > "$TEST_TMPDIR/showcases.deb" + +# Exercise staging, artifact export and error propagation without a privileged +# container or network access. +docker() { + if [[ $1 == info ]]; then + return 0 + fi + local mount work deploy + while [[ $# -gt 0 ]]; do + if [[ $1 == --mount ]]; then + mount=$2 + break + fi + shift + done + work=${mount#type=bind,src=} + work=${work%,dst=/workspace} + [[ ! -e "$work/prebuilt" ]] + cmp "$TEST_TMPDIR/fixture/kas/public.yml" "$work/kas/public.yml" + cmp "$TEST_TMPDIR/fixture/layers/isar/isar-init-build-env" "$work/layers/isar/isar-init-build-env" + cmp "$TEST_TMPDIR/fixture/.devcontainer/devcontainer.json" "$work/.devcontainer/devcontainer.json" + cmp "$TEST_TMPDIR/showcases.deb" \ + "$work/meta-score/recipes-score/score-showcases/files/score-showcases_1.0_arm64.deb" + cmp "$TEST_SRCDIR/_main/images/ebclfsa_aarch64_from_scratch/kas.yml" "$work/kas/score.yml" + cmp "$TEST_SRCDIR/_main/images/ebclfsa_aarch64/build/config-overlay/etc/crinit/crinit.d/getty-console.crinit" \ + "$work/meta-score/recipes-crinit/fastdev/files/getty-console.crinit" + cmp "$TEST_SRCDIR/_main/images/ebclfsa_aarch64/build/config-overlay/usr/bin/delayed-start.sh" \ + "$work/meta-score/recipes-crinit/fastdev/files/delayed-start.sh" + if [[ ${MOCK_DOCKER_FAIL:-0} == 1 ]]; then + return 17 + fi + deploy="$work/build/tmp/deploy/images/ebcl-qemuarm64" + mkdir -p "$deploy" + echo kernel > "$deploy/fastdev-trixie-ebclfsa-ebcl-qemuarm64-vmlinux" + if [[ ${MOCK_MISSING_IMAGE:-0} != 1 ]]; then + echo disk > "$deploy/fastdev-trixie-ebclfsa-ebcl-qemuarm64.wic" + fi +} +export -f docker + +build_image() { + bash "$sources/build_image.sh" "$fixture" \ + "$TEST_TMPDIR/showcases.deb" "$sources/kas.yml" \ + "$overlay/etc/crinit/crinit.d/getty-console.crinit" \ + "$overlay/usr/bin/delayed-start.sh" "$output" +} + +build_image +[[ ! -e "$fixture/kas/score.yml" ]] +[[ ! -e "$fixture/meta-score" ]] +[[ $(cat "$output/fastdev-trixie-ebclfsa-ebcl-qemuarm64-vmlinux") == kernel ]] +[[ $(cat "$output/fastdev-trixie-ebclfsa-ebcl-qemuarm64.wic") == disk ]] + +export MOCK_DOCKER_FAIL=1 +if build_image; then + echo "Error: container failure was not propagated" >&2 + exit 1 +fi +export MOCK_DOCKER_FAIL=0 MOCK_MISSING_IMAGE=1 +if build_image; then + echo "Error: missing image artifact was not rejected" >&2 + exit 1 +fi +if find "$output" -maxdepth 1 -name 'kas-work.*' | grep -q .; then + echo "Error: temporary KAS workspace was not cleaned up" >&2 + exit 1 +fi diff --git a/images/ebclfsa_aarch64_from_scratch/kas.yml b/images/ebclfsa_aarch64_from_scratch/kas.yml new file mode 100644 index 00000000000..de9df9fa3c2 --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/kas.yml @@ -0,0 +1,25 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +header: + version: 18 + +repos: + meta-score: + path: meta-score + layers: + .: + +local_conf_header: + score_showcases: | + IMAGE_INSTALL:append = " score-showcases" diff --git a/images/ebclfsa_aarch64_from_scratch/meta-score/conf/layer.conf b/images/ebclfsa_aarch64_from_scratch/meta-score/conf/layer.conf new file mode 100644 index 00000000000..7a169dd3e2d --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/meta-score/conf/layer.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# SPDX-License-Identifier: Apache-2.0 + +BBPATH .= ":${LAYERDIR}" +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend" +BBFILE_COLLECTIONS += "score" +BBFILE_PATTERN_score = "^${LAYERDIR}/" +BBFILE_PRIORITY_score = "10" +LAYERSERIES_COMPAT_score = "next" diff --git a/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-crinit/fastdev/ebclfsa-fastdev-crinit-getty_%.bbappend b/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-crinit/fastdev/ebclfsa-fastdev-crinit-getty_%.bbappend new file mode 100644 index 00000000000..acf08121340 --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-crinit/fastdev/ebclfsa-fastdev-crinit-getty_%.bbappend @@ -0,0 +1,10 @@ +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# SPDX-License-Identifier: Apache-2.0 + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" +SRC_URI += "file://delayed-start.sh" + +do_install:append() { + install -d ${D}/usr/bin + install -m 0755 ${WORKDIR}/delayed-start.sh ${D}/usr/bin/delayed-start.sh +} diff --git a/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-score/score-showcases/score-showcases_1.0.bb b/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-score/score-showcases/score-showcases_1.0.bb new file mode 100644 index 00000000000..1d6fc0a1322 --- /dev/null +++ b/images/ebclfsa_aarch64_from_scratch/meta-score/recipes-score/score-showcases/score-showcases_1.0.bb @@ -0,0 +1,10 @@ +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# SPDX-License-Identifier: Apache-2.0 + +SUMMARY = "Bazel-built Eclipse S-CORE showcases" +LICENSE = "Apache-2.0" + +inherit dpkg-prebuilt + +SRC_URI = "file://score-showcases_1.0_arm64.deb" +COMPATIBLE_MACHINE = "ebcl-qemuarm64" diff --git a/showcases/BUILD b/showcases/BUILD index 7f5f081dedd..4a6f8e986bb 100644 --- a/showcases/BUILD +++ b/showcases/BUILD @@ -10,6 +10,7 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* +load("@rules_pkg//pkg:deb.bzl", "pkg_deb") load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup") load("//bazel_common:bundlers.bzl", "score_pkg_bundle") @@ -27,6 +28,27 @@ score_pkg_bundle( package_dir = "showcases", ) +pkg_deb( + name = "showcases_deb", + architecture = "arm64", + data = ":showcases_pkg_tar", + depends = [ + "libc6", + "libgcc-s1", + "libstdc++6", + ], + description = "Eclipse S-CORE showcases for EB corbos Linux for Safety Applications", + homepage = "https://github.com/eclipse-score/reference_integration", + maintainer = "Eclipse S-CORE contributors ", + package = "score-showcases", + target_compatible_with = [ + "@platforms//cpu:aarch64", + "@platforms//os:linux", + ], + version = "1.0", + visibility = ["//visibility:public"], +) + # rules_pkg provider view of the showcases bundle for consumers that need a # pkg_filegroup (e.g. qnx_ifs in score_rules_imagefs >= 0.1.0) instead of the # untarred tree. Mirrors the "showcases" pkg_tar content 1:1 (same members, same