From 82de97a9a1f05ddb3dbaf72835b2494d1f0aa16d Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Sat, 11 Jul 2026 21:17:56 -0400 Subject: [PATCH 1/7] packaging: add CPack TGZ/DEB/RPM with systemd service and verification suite - Portable tarball with top-level wire-sysio/ (extract to /opt); versioned artifact via new package-tgz target - DEB/RPM install under /usr; base (runtime) + dev (headers/libs/testing) package pair for both formats - Packaged systemd unit (tools/packaging/systemd), tmpfiles.d state dirs, logrotate policy (5x1G copytruncate) for /var/log/wire/sysio - Debconf prompts (register / enable+start) with yes/yes noninteractive defaults; RPM scriptlets enable --now on fresh install; removal never deletes chain state or logs - Convert install() destinations to relative GNUInstallDirs paths; classify every install rule into base/dev components; drop broken plugin static-lib installs and the legacy spring_testing dev maintainer scripts - tools/packaging/tests: S1-S6 verification suite incl. systemd-in-container runtime service gate (self-bootstrapping test images) - docs/release-layout.md: release artifact file trees Change-Id: I2eb3ece33236621e326042b00b68817e36f9fff3 --- BUILD.md | 27 ++++ CMakeLists.txt | 20 +-- cmake/chain-tools.cmake | 2 +- cmake/cpack-project-config.cmake | 36 +++++ cmake/package.cmake | 126 +++++++++++++++--- cmake/plugin-tools.cmake | 13 +- docs/release-layout.md | 102 ++++++++++++++ libraries/CMakeLists.txt | 2 + libraries/chain/CMakeLists.txt | 10 +- libraries/chaindb/CMakeLists.txt | 6 +- libraries/libfc-lite/CMakeLists.txt | 4 +- libraries/libfc/CMakeLists.txt | 7 +- libraries/opp/CMakeLists.txt | 7 +- libraries/testing/CMakeLists.txt | 9 +- libraries/wasm-jit/CMakeLists.txt | 2 +- libraries/wasm-jit/Source/IR/CMakeLists.txt | 4 +- .../wasm-jit/Source/Logging/CMakeLists.txt | 4 +- libraries/wasm-jit/Source/WASM/CMakeLists.txt | 4 +- libraries/wasm-jit/Source/WAST/CMakeLists.txt | 4 +- .../aws/CMakeLists.txt | 9 +- .../kms/CMakeLists.txt | 9 +- .../ssm/CMakeLists.txt | 9 +- .../tool/trace_api_util/CMakeLists.txt | 6 +- programs/clio/CMakeLists.txt | 2 +- programs/kiod/CMakeLists.txt | 2 +- tools/packaging/debian/config | 17 +++ tools/packaging/debian/postinst | 32 +++++ tools/packaging/debian/postrm | 20 +++ tools/packaging/debian/prerm | 15 +++ tools/packaging/debian/templates | 20 +++ tools/packaging/logrotate/wire-sysio-nodeop | 9 ++ tools/packaging/rpm/post.sh | 10 ++ tools/packaging/rpm/postun.sh | 4 + tools/packaging/rpm/preun.sh | 5 + .../systemd/wire-sysio-nodeop.service | 37 +++++ tools/packaging/systemd/wire-sysio.conf | 4 + tools/packaging/tests/verify-deb.sh | 58 ++++++++ .../tests/verify-install-manifest.sh | 32 +++++ tools/packaging/tests/verify-rpm.sh | 38 ++++++ tools/packaging/tests/verify-scripts.sh | 22 +++ tools/packaging/tests/verify-service-start.sh | 70 ++++++++++ tools/packaging/tests/verify-tgz.sh | 14 ++ 42 files changed, 743 insertions(+), 90 deletions(-) create mode 100644 cmake/cpack-project-config.cmake create mode 100644 docs/release-layout.md create mode 100755 tools/packaging/debian/config create mode 100755 tools/packaging/debian/postinst create mode 100755 tools/packaging/debian/postrm create mode 100755 tools/packaging/debian/prerm create mode 100644 tools/packaging/debian/templates create mode 100644 tools/packaging/logrotate/wire-sysio-nodeop create mode 100644 tools/packaging/rpm/post.sh create mode 100644 tools/packaging/rpm/postun.sh create mode 100644 tools/packaging/rpm/preun.sh create mode 100644 tools/packaging/systemd/wire-sysio-nodeop.service create mode 100644 tools/packaging/systemd/wire-sysio.conf create mode 100755 tools/packaging/tests/verify-deb.sh create mode 100755 tools/packaging/tests/verify-install-manifest.sh create mode 100755 tools/packaging/tests/verify-rpm.sh create mode 100755 tools/packaging/tests/verify-scripts.sh create mode 100755 tools/packaging/tests/verify-service-start.sh create mode 100755 tools/packaging/tests/verify-tgz.sh diff --git a/BUILD.md b/BUILD.md index 99eb7510d1..ddee943506 100644 --- a/BUILD.md +++ b/BUILD.md @@ -258,3 +258,30 @@ After the script finishes, you will have a Docker image with Wire Sysio built in Using the Docker build is particularly useful if you are on a host that is not Ubuntu 24/25 or if you want to avoid installing compilers and dependencies on your system. The Docker environment ensures a consistent, reproducible build. --- + +## Packaging + +From a configured Release build tree (any install prefix — packages are +prefix-independent): + + cd $BUILD_DIR + cpack -G TGZ # portable tarball wire-sysio.tar.gz: top-level wire-sysio/, extract to /opt + cmake --build . --target package-tgz # same tarball, versioned artifact name + cpack -G DEB # Debian/Ubuntu package (requires dpkg); installs under /usr + cpack -G RPM # RHEL/Fedora package (requires rpmbuild); installs under /usr + +The DEB asks (via debconf) whether to register the wire-sysio-nodeop systemd +service and whether to enable it; enabling also starts it immediately. +Noninteractive installs default to yes/yes (register + enable + start). The +RPM registers, enables, and starts the service on fresh install. Log rotation +is 5 x 1G via /etc/logrotate.d/wire-sysio-nodeop (a conffile — edit the +installed copy to change thresholds). Chain data (/var/lib/wire/sysio) and +logs (/var/log/wire/sysio) are never removed by package removal or purge. + +Verification: `tools/packaging/tests/` contains the packaging gate scripts — +`verify-tgz.sh` (tarball layout), `verify-deb.sh` / `verify-rpm.sh` (payload, +control files, containerized install, plus a systemd-in-container runtime +stage proving the service enables, starts, and stays up), +`verify-install-manifest.sh` (install regression vs a baseline), and +`verify-scripts.sh` (static lint). The deb/rpm verifiers require docker; the +runtime stage builds a cached systemd-enabled test image on first use. diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb2d254d0..1a9bdda42f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,16 +150,16 @@ add_subdirectory(contracts) add_subdirectory(contracts/tests) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sysio.version.in ${CMAKE_CURRENT_BINARY_DIR}/sysio.version.hpp) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sysio.version.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sysio.version.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev) set(SYSIO_ROOT_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") configure_file(${CMAKE_SOURCE_DIR}/cmake/sysio-config.cmake.in ${CMAKE_BINARY_DIR}/lib/cmake/sysio/sysio-config.cmake @ONLY) configure_file(${CMAKE_SOURCE_DIR}/cmake/SysioTester.cmake.in ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioTester.cmake @ONLY) configure_file(${CMAKE_SOURCE_DIR}/cmake/SysioCheckVersion.cmake ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioCheckVersion.cmake COPYONLY) -install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/sysio-config.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/sysio) -install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioTester.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/sysio) -install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioCheckVersion.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/sysio) +install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/sysio-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sysio COMPONENT dev) +install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioTester.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sysio COMPONENT dev) +install(FILES ${CMAKE_BINARY_DIR}/lib/cmake/sysio/SysioCheckVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sysio COMPONENT dev) include(cmake/licenses.cmake) @@ -167,17 +167,17 @@ include(cmake/licenses.cmake) # project's database so that IDEs (CLion, clangd) can navigate contract sources. add_merged_compile_commands_target() -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/sysio" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/sysio" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/licenses/" COMPONENT base) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libraries/testing/contracts DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/sysio_testing/libraries/testing COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libraries/testing/contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/libraries/testing COMPONENT dev EXCLUDE_FROM_ALL PATTERN "CMakeFiles" EXCLUDE PATTERN "*.cmake" EXCLUDE PATTERN "Makefile" EXCLUDE) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/system-test-contracts DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/sysio_testing/unittests COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/system-test-contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/unittests COMPONENT dev EXCLUDE_FROM_ALL PATTERN "CMakeFiles" EXCLUDE PATTERN "*.cmake" EXCLUDE PATTERN "Makefile" EXCLUDE) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/TestHarness DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/sysio_testing/tests COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/TestHarness DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/tests COMPONENT dev EXCLUDE_FROM_ALL FILES_MATCHING PATTERN "*.py" PATTERN "*.json" @@ -196,14 +196,14 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) COMMAND ${CMAKE_COMMAND} -E make_directory share/sysio_testing COMMAND ${CMAKE_COMMAND} -E create_symlink ../../bin share/sysio_testing/bin) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/python3/dist-packages/TestHarness DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/python3/dist-packages COMPONENT dev EXCLUDE_FROM_ALL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/python3/dist-packages/TestHarness DESTINATION ${CMAKE_INSTALL_LIBDIR}/python3/dist-packages COMPONENT dev EXCLUDE_FROM_ALL) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/bin/clio ${CMAKE_CURRENT_BINARY_DIR}/bin/kiod ${CMAKE_CURRENT_BINARY_DIR}/bin/nodeop ${CMAKE_CURRENT_BINARY_DIR}/bin/sys-util ${CMAKE_CURRENT_BINARY_DIR}/bin/trace_api_util - DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/sysio_testing/bin + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/bin COMPONENT dev EXCLUDE_FROM_ALL) else() diff --git a/cmake/chain-tools.cmake b/cmake/chain-tools.cmake index cec89e1bc6..12f6a8435b 100644 --- a/cmake/chain-tools.cmake +++ b/cmake/chain-tools.cmake @@ -59,7 +59,7 @@ macro(chain_target TARGET) install( TARGETS ${TARGET} RUNTIME - DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT base ) diff --git a/cmake/cpack-project-config.cmake b/cmake/cpack-project-config.cmake new file mode 100644 index 0000000000..652025f8ba --- /dev/null +++ b/cmake/cpack-project-config.cmake @@ -0,0 +1,36 @@ +# CPack per-generator configuration (CPACK_PROJECT_CONFIG_FILE). +# Evaluated by cpack once per generator, after the main CPack config. + +if(CPACK_GENERATOR STREQUAL "TGZ") + # The archive generator is monolithic: left at "ALL" it would stage every + # install rule (including 'Unspecified' ones), not just the base component. + # Constrain the install to the base component so the portable tarball ships + # exactly the runtime payload. DEB and RPM must KEEP "ALL": they use + # component packaging (CPACK_{DEB,RPM}_COMPONENT_INSTALL) to emit the + # wire-sysio + wire-sysio-dev package pair, and constraining the field here + # silently collapses them to a single component package. + string(REPLACE ";ALL;/" ";base;/" CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS}") +endif() + +if(CPACK_GENERATOR STREQUAL "TGZ") + # Portable tarball: stage via DESTDIR so the absolute /etc/logrotate.d + # entry lands inside the archive (archive generators reject absolute + # destinations without DESTDIR). Relative destinations resolve against + # "/", so there is no /usr layer, and the top-level directory is plain + # `wire-sysio` -- extracting into /opt yields /opt/wire-sysio/bin/nodeop. + set(CPACK_SET_DESTDIR ON) + set(CPACK_INSTALL_PREFIX "/") + # Monolithic archives derive BOTH the artifact name and the internal + # top-level directory from CPACK_PACKAGE_FILE_NAME, so `cpack -G TGZ` + # emits wire-sysio.tar.gz; the `package-tgz` build target renames the + # artifact to the versioned name afterwards. + set(CPACK_PACKAGE_FILE_NAME "wire-sysio") + # Portable tarball stays runtime-only; dev headers/libs are the DEB/RPM + # wire-sysio-dev packages' concern. + set(CPACK_COMPONENTS_ALL base) +elseif(CPACK_GENERATOR MATCHES "^(DEB|RPM)$") + # /usr-prefixed packages. Absolute /etc destinations stage correctly with + # plain (non-DESTDIR) staging on both dpkg and rpmbuild. + set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") + set(CPACK_SET_DESTDIR OFF) +endif() diff --git a/cmake/package.cmake b/cmake/package.cmake index a9b1bdbe0f..e7be2874a0 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -1,4 +1,15 @@ -set(CPACK_GENERATOR "TZST") +# Packaging configuration for wire-sysio. Produces: +# TGZ -- portable tarball, top-level dir `wire-sysio/` (extract to /opt -> +# /opt/wire-sysio/bin/nodeop); build via `cpack -G TGZ` (artifact +# wire-sysio.tar.gz) or the `package-tgz` target (versioned name) +# DEB -- Debian/Ubuntu package under /usr; debconf prompts control systemd +# service registration + enable/start +# RPM -- RHEL/Fedora package under /usr; fresh install registers, enables +# and starts the service (rpm has no interactive prompt path) +# Per-generator differences (staging mode, packaging prefix, tarball top dir) +# live in cmake/cpack-project-config.cmake. + +set(CPACK_GENERATOR "TGZ") find_program(DPKG_FOUND "dpkg") find_program(RPMBUILD_FOUND "rpmbuild") if(DPKG_FOUND) @@ -9,17 +20,19 @@ if(RPMBUILD_FOUND) endif() set(CPACK_PACKAGE_VERSION "${VERSION_FULL}") + +# rpmbuild rejects '-' in the Version tag, and '~' sorts pre-release suffixes +# before the final release in BOTH dpkg and rpm comparisons -- the correct +# ordering for a "-dev" suffix. Artifact file names keep VERSION_FULL as-is. +string(REPLACE "-" "~" WIRE_PACKAGE_TILDE_VERSION "${VERSION_FULL}") +set(CPACK_DEBIAN_PACKAGE_VERSION "${WIRE_PACKAGE_TILDE_VERSION}") +set(CPACK_RPM_PACKAGE_VERSION "${WIRE_PACKAGE_TILDE_VERSION}") + set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${VERSION_FULL}") +# Artifact names carry no OS tag (wire-sysio--.*); os-release is +# still read for the dev-package LLVM dependency probe below. if(EXISTS /etc/os-release) - #if we're doing the build on Ubuntu or RHELish, add the platform version in to the package name file(READ /etc/os-release OS_RELEASE LIMIT 4096) - if(OS_RELEASE MATCHES "\n?ID=\"?ubuntu" AND OS_RELEASE MATCHES "\n?VERSION_ID=\"?([0-9.]+)") - string(APPEND CPACK_PACKAGE_FILE_NAME "-ubuntu") # Edited to remove the version number as all supported versions are compatible - elseif(OS_RELEASE MATCHES "\n?ID=\"?rhel" AND OS_RELEASE MATCHES "\n?VERSION_ID=\"?([0-9]+)") - string(APPEND CPACK_PACKAGE_FILE_NAME "-el${CMAKE_MATCH_1}") - elseif(OS_RELEASE MATCHES "\n?ID_LIKE=\"?([a-zA-Z0-9 ]*)" AND CMAKE_MATCH_1 MATCHES "rhel" AND OS_RELEASE MATCHES "\n?VERSION_ID=\"?([0-9]+)") - string(APPEND CPACK_PACKAGE_FILE_NAME "-el${CMAKE_MATCH_1}") - endif() endif() # Fix debian package filename as it should have the format: @@ -37,6 +50,34 @@ string(REGEX REPLACE "^${CMAKE_PROJECT_NAME}-(.*)$" "${CMAKE_PROJECT_NAME}_\\1_$ string(APPEND CPACK_PACKAGE_FILE_NAME "-${CMAKE_SYSTEM_PROCESSOR}") +# ── Packaged service assets (systemd unit, tmpfiles.d, logrotate policy) ── +# Literal `lib/...` on purpose (NOT ${CMAKE_INSTALL_LIBDIR}): systemd units and +# tmpfiles.d fragments live in /usr/lib/systemd/system and /usr/lib/tmpfiles.d +# on every supported distro -- never lib64/ or lib//. +install(FILES "${CMAKE_SOURCE_DIR}/tools/packaging/systemd/wire-sysio-nodeop.service" + DESTINATION lib/systemd/system COMPONENT base) +install(FILES "${CMAKE_SOURCE_DIR}/tools/packaging/systemd/wire-sysio.conf" + DESTINATION lib/tmpfiles.d COMPONENT base) +# logrotate policies are only read from /etc/logrotate.d -- absolute on purpose. +install(FILES "${CMAKE_SOURCE_DIR}/tools/packaging/logrotate/wire-sysio-nodeop" + DESTINATION /etc/logrotate.d COMPONENT base) + +# Per-generator staging/prefix/top-dir configuration, evaluated at cpack time. +set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_SOURCE_DIR}/cmake/cpack-project-config.cmake") + +# Convenience target: build the portable tarball and rename it to the +# versioned artifact name. Monolithic archives derive BOTH the artifact name +# and the internal top-level directory from CPACK_PACKAGE_FILE_NAME, and the +# top dir must be plain `wire-sysio`, so `cpack -G TGZ` emits +# wire-sysio.tar.gz and this target restores the versioned name. +add_custom_target(package-tgz + COMMAND "${CMAKE_CPACK_COMMAND}" -G TGZ + COMMAND "${CMAKE_COMMAND}" -E rename "${CMAKE_BINARY_DIR}/wire-sysio.tar.gz" + "${CMAKE_BINARY_DIR}/${CPACK_PACKAGE_FILE_NAME}.tar.gz" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Packaging ${CPACK_PACKAGE_FILE_NAME}.tar.gz (portable tarball)" + VERBATIM) + set(CPACK_PACKAGE_CONTACT "Wire Network Foundation") set(CPACK_PACKAGE_VENDOR "Wire Network Foundation") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++ implementation of the Antelope protocol") @@ -46,19 +87,20 @@ set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/Wire-Network/wire-sysio") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) set(CPACK_DEBIAN_PACKAGE_DEPENDS - "libc6 (>= 2.38)" + "libc6 (>= 2.38), debconf (>= 0.5) | debconf-2.0" ) - +set(CPACK_DEBIAN_BASE_PACKAGE_RECOMMENDS "logrotate") set(CPACK_DEBIAN_BASE_PACKAGE_SECTION "utils") set(CPACK_DEBIAN_PACKAGE_CONFLICTS "sysio, mandel") set(CPACK_RPM_PACKAGE_CONFLICTS "sysio, mandel") -set(CPACK_COMPONENTS_ALL "base") -if(ENABLE_SYSIO_DEV_DEB) - list(APPEND CPACK_COMPONENTS_ALL "dev") -endif() +# Two packages per format: `wire-sysio` (daemon + CLI tools, component base) +# and `wire-sysio-dev` (headers/libs for native contract unit testing, +# component dev) -- for BOTH the DEB and RPM generators. The portable TGZ +# stays base-only (see cmake/cpack-project-config.cmake). +set(CPACK_COMPONENTS_ALL "base" "dev") #enable per component packages for .deb; ensure main package is just "sysio", not "sysio-base", and make the dev package have "sysio-dev" at the front not the back set(CPACK_DEB_COMPONENT_INSTALL ON) @@ -67,7 +109,7 @@ set(CPACK_DEBIAN_BASE_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb") string(REGEX REPLACE "^(${CMAKE_PROJECT_NAME})" "\\1-dev" CPACK_DEBIAN_DEV_FILE_NAME "${CPACK_DEBIAN_BASE_FILE_NAME}") #deb package tooling will be unable to detect deps for the dev package. llvm is tricky since we don't know what package could have been used; try to figure it out -set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libgmp-dev, python3-distutils, python3-numpy, zlib1g-dev") +set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "${CMAKE_PROJECT_NAME} (= ${WIRE_PACKAGE_TILDE_VERSION}), libgmp-dev, python3, python3-numpy, zlib1g-dev") find_program(DPKG_QUERY "dpkg-query") if(DPKG_QUERY AND OS_RELEASE MATCHES "\n?ID=\"?ubuntu" AND LLVM_CMAKE_DIR) execute_process(COMMAND "${DPKG_QUERY}" -S "${LLVM_CMAKE_DIR}" COMMAND cut -d: -f1 RESULT_VARIABLE LLVM_PKG_FIND_RESULT OUTPUT_VARIABLE LLVM_PKG_FIND_OUTPUT) @@ -76,13 +118,59 @@ if(DPKG_QUERY AND OS_RELEASE MATCHES "\n?ID=\"?ubuntu" AND LLVM_CMAKE_DIR) string(APPEND CPACK_DEBIAN_DEV_PACKAGE_DEPENDS ", ${LLVM_PKG_FIND_OUTPUT}") endif() endif() -set(CPACK_DEBIAN_DEV_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/scripts/postinst;${CMAKE_BINARY_DIR}/scripts/prerm") +# The legacy TestHarness postinst/prerm (scripts/postinst, scripts/prerm) are +# intentionally NOT wired into the dev package: on CMake >= 3.21 the python +# dist-packages TestHarness symlink and the sysio_testing/bin programs are +# already shipped as package payload (see the root CMakeLists.txt install +# rules), and the legacy scripts reference stale spring_testing paths under +# the configure-time prefix, which breaks installation outright. + +# Debconf maintainer files for the base package: dpkg requires the scripts to +# be executable (0755); `templates` stays a plain data file. +file(COPY "${CMAKE_SOURCE_DIR}/tools/packaging/debian/templates" + DESTINATION "${CMAKE_BINARY_DIR}/packaging/debian") +foreach(script config postinst prerm postrm) + file(COPY "${CMAKE_SOURCE_DIR}/tools/packaging/debian/${script}" + DESTINATION "${CMAKE_BINARY_DIR}/packaging/debian" + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +endforeach() +set(CPACK_DEBIAN_BASE_PACKAGE_CONTROL_EXTRA + "${CMAKE_BINARY_DIR}/packaging/debian/templates;${CMAKE_BINARY_DIR}/packaging/debian/config;${CMAKE_BINARY_DIR}/packaging/debian/postinst;${CMAKE_BINARY_DIR}/packaging/debian/prerm;${CMAKE_BINARY_DIR}/packaging/debian/postrm") + +# ── RPM: component packages (wire-sysio + wire-sysio-dev) ── +set(CPACK_RPM_COMPONENT_INSTALL ON) +# Explicit per-component package + artifact names (the base rpm is plain +# `wire-sysio`, no component suffix; the dev rpm mirrors the deb naming). +set(CPACK_RPM_BASE_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") +set(CPACK_RPM_DEV_PACKAGE_NAME "${CMAKE_PROJECT_NAME}-dev") +set(CPACK_RPM_BASE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}.rpm") +string(REPLACE "${CMAKE_PROJECT_NAME}-" "${CMAKE_PROJECT_NAME}-dev-" CPACK_RPM_DEV_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}") +set(CPACK_RPM_DEV_FILE_NAME "${CPACK_RPM_DEV_FILE_NAME}.rpm") +set(CPACK_RPM_DEV_PACKAGE_REQUIRES "${CMAKE_PROJECT_NAME} = ${WIRE_PACKAGE_TILDE_VERSION}") + +# Service scriptlets belong to the BASE package only -- the dev rpm must not +# touch the service. +set(CPACK_RPM_BASE_POST_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/tools/packaging/rpm/post.sh") +set(CPACK_RPM_BASE_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/tools/packaging/rpm/preun.sh") +set(CPACK_RPM_BASE_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/tools/packaging/rpm/postun.sh") +# Never claim ownership of distro-owned directories. +set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION + "/usr/lib/systemd;/usr/lib/systemd/system;/usr/lib/tmpfiles.d;/etc/logrotate.d;/etc/wire;/usr/share/licenses") +# Both rpms would otherwise package identical /usr/lib/.build-id links for the +# duplicated testing binaries and conflict on co-install. +set(CPACK_RPM_SPEC_MORE_DEFINE "%define _build_id_links none") +set(CPACK_RPM_BASE_USER_FILELIST "%config(noreplace) /etc/logrotate.d/wire-sysio-nodeop") #since rpm packages aren't component based, make sure description picks up more detailed description instead of just summary set(CPACK_RPM_PACKAGE_DESCRIPTION "${CPACK_COMPONENT_BASE_DESCRIPTION}") -#turn some knobs to try and make package paths cooperate with GNUInstallDirs a little better -set(CPACK_SET_DESTDIR ON) +# Relative install destinations + the per-generator staging configuration in +# cpack-project-config.cmake replace the old blanket DESTDIR mechanism: +# DEB/RPM stage plainly under CPACK_PACKAGING_INSTALL_PREFIX=/usr, while the +# TGZ generator flips SET_DESTDIR back on with CPACK_INSTALL_PREFIX=/ so the +# absolute /etc/logrotate.d entry stages inside the archive. +set(CPACK_SET_DESTDIR OFF) set(CPACK_PACKAGE_RELOCATABLE OFF) include(CPack) diff --git a/cmake/plugin-tools.cmake b/cmake/plugin-tools.cmake index 86cadd8857..5c441b818d 100644 --- a/cmake/plugin-tools.cmake +++ b/cmake/plugin-tools.cmake @@ -66,15 +66,10 @@ macro(plugin_target TARGET_NAME) ${ARG_LIBRARIES} ) - # Install headers - install( - TARGETS ${TARGET_NAME} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include - - ) + # Plugins are internal static libraries linked whole-archive into nodeop; + # they are not standalone products, so their archives are intentionally + # NOT installed (a TARGETS install here also breaks packaging whenever a + # plugin target exists but is not part of the default build). set(PLUGIN_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) if(NOT ARG_SKIP_TEST_CONFIG AND ENABLE_TESTS AND IS_DIRECTORY ${PLUGIN_TEST_DIR}) diff --git a/docs/release-layout.md b/docs/release-layout.md new file mode 100644 index 0000000000..5698c3e525 --- /dev/null +++ b/docs/release-layout.md @@ -0,0 +1,102 @@ +# Release Artifact Layout + +wire-sysio ships three artifact types per release, all produced by CPack from +one build tree (see `BUILD.md` → Packaging). Version shown as `` (e.g. +`1.0.0-dev`; dpkg/rpm metadata uses the tilde form `1.0.0~dev` so pre-release +suffixes sort before the final release). + +| Artifact | Name | Install prefix | +|---|---|---| +| Portable tarball | `wire-sysio--.tar.gz` | none — self-contained tree | +| Debian/Ubuntu | `wire-sysio__.deb` + `wire-sysio-dev__.deb` | `/usr` | +| RHEL/Fedora | `wire-sysio--.rpm` + `wire-sysio-dev--.rpm` | `/usr` | + +## Portable tarball (`.tar.gz`) + +Runtime payload only (the base component), rooted at a plain `wire-sysio/` +directory so that extraction into `/opt` yields `/opt/wire-sysio/bin/nodeop`: + +``` +wire-sysio/ +├── bin/ +│ ├── clio +│ ├── cranker-example +│ ├── kiod +│ ├── nodeop +│ ├── outpost_ethereum_client_tool +│ ├── outpost_solana_client_tool +│ ├── sys-util +│ └── trace_api_util +├── etc/ +│ └── logrotate.d/ +│ └── wire-sysio-nodeop # reference logrotate policy +├── lib/ +│ ├── systemd/system/ +│ │ └── wire-sysio-nodeop.service # reference unit (paths assume /usr) +│ └── tmpfiles.d/ +│ └── wire-sysio.conf # reference state-dir definitions +└── share/ + └── licenses/ + └── sysio/ # third-party license texts +``` + +The `etc/` and `lib/` entries are inert reference copies of the system +integration files; nothing is registered by extracting the tarball. + +## System packages (`.deb` / `.rpm`) + +### `wire-sysio` (base, runtime) + +``` +/usr/bin/{clio,cranker-example,kiod,nodeop,outpost_ethereum_client_tool, + outpost_solana_client_tool,sys-util,trace_api_util} +/usr/lib/systemd/system/wire-sysio-nodeop.service +/usr/lib/tmpfiles.d/wire-sysio.conf +/usr/share/licenses/sysio/* +/etc/logrotate.d/wire-sysio-nodeop # conffile / %config(noreplace) +``` + +Service behavior on install: the DEB asks (debconf) whether to register the +service and whether to enable it — enabling also starts it (`systemctl +enable --now`); noninteractive installs default to yes/yes. The RPM registers, +enables, and starts on fresh install (no prompting facility). Upgrades never +restart a running node; removal stops/disables the unit but **never deletes** +`/var/lib/wire/sysio` or `/var/log/wire/sysio`. + +Runtime directories (created by `systemd-tmpfiles` at install and every boot, +matching the unit's command line — nodeop's internal defaults are unchanged): + +| Purpose | Path | +|---|---| +| Config (`--config-dir`) | `/etc/wire/sysio` | +| Data (`--data-dir`) | `/var/lib/wire/sysio/data` | +| Logs (unit `append:`) | `/var/log/wire/sysio` (rotated 5 x 1G, copytruncate) | + +### `wire-sysio-dev` (headers/libraries/testing; depends on exact base version) + +``` +/usr/include/{appbase,chainbase,fc,fc-lite,wasm-jit}/... +/usr/include/sysio/{chain,testing,...}/... # incl. generated OPP *.pb.h +/usr/include/sysio.version.hpp +/usr/lib/{libfc.a,libfc-lite*.a,libappbase.a,libchainbase.a, + libsysio_chain.a,libsysio_testing.a, + libWASM.a,libWAST.a,libLogging.a,libIR.a} +/usr/lib/cmake/sysio/{sysio-config.cmake,SysioTester.cmake,SysioCheckVersion.cmake} +/usr/lib/python3/dist-packages/TestHarness -> ../../../share/sysio_testing/tests/TestHarness +/usr/share/sysio_testing/ +├── bin/ # test-runner copies of the binaries +├── libraries/testing/contracts/ # testing contract artifacts +├── tests/TestHarness/ # python integration-test framework +└── unittests/system-test-contracts/ +``` + +Not shipped in either package: plugin static libraries (internal, linked +whole-archive into nodeop) and the legacy `spring_testing` maintainer scripts +(superseded by payload-shipped symlinks/copies). + +## Verification + +Every artifact is gated by `tools/packaging/tests/` (see `BUILD.md`): +layout (S1), payload/control/container install (S2/S3), install-manifest +regression (S4), static lint (S5), and a systemd-in-container runtime stage +(S6) proving the packaged service enables, starts, and stays running. diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 329638c82d..c7d6b6d29b 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -8,6 +8,8 @@ add_subdirectory(libfc-test) add_subdirectory(wasm-jit) add_subdirectory(chaindb) set(APPBASE_ENABLE_AUTO_VERSION OFF CACHE BOOL "enable automatic discovery of version via 'git describe'") +# Route appbase lib/header installs into the dev packaging component. +set(APPBASE_INSTALL_COMPONENT dev) add_subdirectory(appbase) add_subdirectory(custom_appbase) add_subdirectory(chain) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index b8977ed36c..2e0455c1da 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -200,12 +200,12 @@ if(SYSVMOC_ENABLE_DEVELOPER_OPTIONS) endif() install( TARGETS sysio_chain - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT dev + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/sysio/chain/ - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/sysio/chain + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysio/chain COMPONENT dev FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h" EXCLUDE ) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/sysio/chain/core_symbol.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/sysio/chain) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/sysio/chain/core_symbol.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysio/chain COMPONENT dev) diff --git a/libraries/chaindb/CMakeLists.txt b/libraries/chaindb/CMakeLists.txt index 2b817de100..bdeb5d08df 100644 --- a/libraries/chaindb/CMakeLists.txt +++ b/libraries/chaindb/CMakeLists.txt @@ -19,8 +19,8 @@ add_subdirectory( test ) add_subdirectory( benchmark ) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/chainbase - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL) + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL) install(TARGETS chainbase - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL) diff --git a/libraries/libfc-lite/CMakeLists.txt b/libraries/libfc-lite/CMakeLists.txt index 47c28dbab3..8043fb606f 100644 --- a/libraries/libfc-lite/CMakeLists.txt +++ b/libraries/libfc-lite/CMakeLists.txt @@ -18,11 +18,13 @@ endif () # Installation: headers to include/fc-lite install( DIRECTORY include/fc-lite - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT dev ) # Install the INTERFACE target for completeness (no artifacts produced) install( TARGETS fc-lite EXPORT fc-lite-targets + COMPONENT dev ) diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index 0867167197..21bf152082 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -136,11 +136,12 @@ add_subdirectory(benchmark) install( TARGETS fc - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) install( DIRECTORY include/fc - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT dev ) diff --git a/libraries/opp/CMakeLists.txt b/libraries/opp/CMakeLists.txt index 6e07ef8783..e5dd607b5b 100644 --- a/libraries/opp/CMakeLists.txt +++ b/libraries/opp/CMakeLists.txt @@ -231,12 +231,14 @@ endif() # Installation: headers to include/sysio install( DIRECTORY include/sysio - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT dev ) install( DIRECTORY ${PROTO_GEN_DIR}/ - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT dev FILES_MATCHING PATTERN "*.pb.h" ) @@ -244,4 +246,5 @@ install( install( TARGETS ${TARGET_NAME} EXPORT ${TARGET_NAME}-targets + COMPONENT dev ) diff --git a/libraries/testing/CMakeLists.txt b/libraries/testing/CMakeLists.txt index 1da8f4b43e..1e5bef57b3 100644 --- a/libraries/testing/CMakeLists.txt +++ b/libraries/testing/CMakeLists.txt @@ -146,8 +146,7 @@ target_include_directories(sysio_testing set_target_properties(sysio_testing PROPERTIES PUBLIC_HEADER "${HEADERS}") install(TARGETS sysio_testing - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/sysio/testing -) \ No newline at end of file + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT dev + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysio/testing COMPONENT dev) \ No newline at end of file diff --git a/libraries/wasm-jit/CMakeLists.txt b/libraries/wasm-jit/CMakeLists.txt index 2397d8061d..65c69d8200 100644 --- a/libraries/wasm-jit/CMakeLists.txt +++ b/libraries/wasm-jit/CMakeLists.txt @@ -15,4 +15,4 @@ add_subdirectory(Source/Logging) add_subdirectory(Source/WASM) add_subdirectory(Source/WAST) -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Include/ DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/wasm-jit) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wasm-jit COMPONENT dev) diff --git a/libraries/wasm-jit/Source/IR/CMakeLists.txt b/libraries/wasm-jit/Source/IR/CMakeLists.txt index 7a155e3baa..0955c55db8 100644 --- a/libraries/wasm-jit/Source/IR/CMakeLists.txt +++ b/libraries/wasm-jit/Source/IR/CMakeLists.txt @@ -18,7 +18,7 @@ add_definitions(-DIR_API=DLL_EXPORT) target_link_libraries(IR Logging) install(TARGETS IR - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) diff --git a/libraries/wasm-jit/Source/Logging/CMakeLists.txt b/libraries/wasm-jit/Source/Logging/CMakeLists.txt index 4214c83b27..83b6a87df4 100644 --- a/libraries/wasm-jit/Source/Logging/CMakeLists.txt +++ b/libraries/wasm-jit/Source/Logging/CMakeLists.txt @@ -14,7 +14,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") endif() install(TARGETS Logging - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) diff --git a/libraries/wasm-jit/Source/WASM/CMakeLists.txt b/libraries/wasm-jit/Source/WASM/CMakeLists.txt index 2ab4c3a494..2d224fe330 100644 --- a/libraries/wasm-jit/Source/WASM/CMakeLists.txt +++ b/libraries/wasm-jit/Source/WASM/CMakeLists.txt @@ -7,6 +7,6 @@ add_definitions(-DWEBASSEMBLY_API=DLL_EXPORT) target_link_libraries(WASM Logging IR) install(TARGETS WASM - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) diff --git a/libraries/wasm-jit/Source/WAST/CMakeLists.txt b/libraries/wasm-jit/Source/WAST/CMakeLists.txt index dc8483cc92..b17c7d5dbd 100644 --- a/libraries/wasm-jit/Source/WAST/CMakeLists.txt +++ b/libraries/wasm-jit/Source/WAST/CMakeLists.txt @@ -19,7 +19,7 @@ add_library(WAST STATIC ${Sources} ${PublicHeaders}) add_definitions(-DWAST_API=DLL_EXPORT) target_link_libraries(WAST Logging IR WASM) install(TARGETS WAST - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) diff --git a/plugins/signature_provider_manager_plugin/aws/CMakeLists.txt b/plugins/signature_provider_manager_plugin/aws/CMakeLists.txt index fa1a201c53..d51fde9979 100644 --- a/plugins/signature_provider_manager_plugin/aws/CMakeLists.txt +++ b/plugins/signature_provider_manager_plugin/aws/CMakeLists.txt @@ -28,13 +28,10 @@ target_link_libraries(${TARGET_NAME} sysio_chain aws-cpp-sdk-core) -install( - TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) +# Internal plugin support library: linked into nodeop, never shipped as a +# standalone artifact (see cmake/plugin-tools.cmake for rationale). install( DIRECTORY include/sysio - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev ) diff --git a/plugins/signature_provider_manager_plugin/kms/CMakeLists.txt b/plugins/signature_provider_manager_plugin/kms/CMakeLists.txt index aec5358e18..2ddb71eea4 100644 --- a/plugins/signature_provider_manager_plugin/kms/CMakeLists.txt +++ b/plugins/signature_provider_manager_plugin/kms/CMakeLists.txt @@ -44,13 +44,10 @@ if (ENABLE_TESTS) add_subdirectory(test) endif () -install( - TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) +# Internal plugin support library: linked into nodeop, never shipped as a +# standalone artifact (see cmake/plugin-tools.cmake for rationale). install( DIRECTORY include/sysio - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev ) diff --git a/plugins/signature_provider_manager_plugin/ssm/CMakeLists.txt b/plugins/signature_provider_manager_plugin/ssm/CMakeLists.txt index 58dd96d145..70945262a8 100644 --- a/plugins/signature_provider_manager_plugin/ssm/CMakeLists.txt +++ b/plugins/signature_provider_manager_plugin/ssm/CMakeLists.txt @@ -44,13 +44,10 @@ if (ENABLE_TESTS) add_subdirectory(test) endif () -install( - TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) +# Internal plugin support library: linked into nodeop, never shipped as a +# standalone artifact (see cmake/plugin-tools.cmake for rationale). install( DIRECTORY include/sysio - DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev ) diff --git a/plugins/trace_api_plugin/tool/trace_api_util/CMakeLists.txt b/plugins/trace_api_plugin/tool/trace_api_util/CMakeLists.txt index a2a86365e4..45a923abc6 100644 --- a/plugins/trace_api_plugin/tool/trace_api_util/CMakeLists.txt +++ b/plugins/trace_api_plugin/tool/trace_api_util/CMakeLists.txt @@ -18,7 +18,7 @@ target_include_directories( copy_bin(trace_api_util) install(TARGETS trace_api_util - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT base + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev ) diff --git a/programs/clio/CMakeLists.txt b/programs/clio/CMakeLists.txt index 79916749d4..d3333a840c 100644 --- a/programs/clio/CMakeLists.txt +++ b/programs/clio/CMakeLists.txt @@ -22,5 +22,5 @@ target_link_libraries( ${CLI_CLIENT_EXECUTABLE_NAME} copy_bin( ${CLI_CLIENT_EXECUTABLE_NAME} ) install( TARGETS - ${CLI_CLIENT_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT base + ${CLI_CLIENT_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT base ) diff --git a/programs/kiod/CMakeLists.txt b/programs/kiod/CMakeLists.txt index 3c4c5eded5..288b1a546a 100644 --- a/programs/kiod/CMakeLists.txt +++ b/programs/kiod/CMakeLists.txt @@ -15,5 +15,5 @@ target_include_directories(${KEY_STORE_EXECUTABLE_NAME} PUBLIC ${CMAKE_CURRENT_B copy_bin( ${KEY_STORE_EXECUTABLE_NAME} ) install( TARGETS - ${KEY_STORE_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT base + ${KEY_STORE_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT base ) diff --git a/tools/packaging/debian/config b/tools/packaging/debian/config new file mode 100755 index 0000000000..787abe1131 --- /dev/null +++ b/tools/packaging/debian/config @@ -0,0 +1,17 @@ +#!/bin/sh +# Debconf question flow for wire-sysio: ask whether to register the systemd +# service; if yes, ask whether to enable it at boot (which also starts it). +set -e + +. /usr/share/debconf/confmodule + +db_input high wire-sysio/install-service || true +db_go || true + +db_get wire-sysio/install-service +if [ "$RET" = "true" ]; then + db_input high wire-sysio/enable-service || true + db_go || true +fi + +exit 0 diff --git a/tools/packaging/debian/postinst b/tools/packaging/debian/postinst new file mode 100755 index 0000000000..6d5f133e53 --- /dev/null +++ b/tools/packaging/debian/postinst @@ -0,0 +1,32 @@ +#!/bin/sh +# Post-install: create service directories, register the unit, and -- when the +# enable answer is true (the default, also applied by noninteractive +# frontends) -- enable the unit at boot AND start it now. +set -e + +case "$1" in + configure) + # No systemd (containers/chroots): nothing to register. + [ -d /run/systemd/system ] || exit 0 + + INSTALL_SERVICE=true + ENABLE_SERVICE=true + if [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_get wire-sysio/install-service || true + [ -n "$RET" ] && INSTALL_SERVICE="$RET" + db_get wire-sysio/enable-service || true + [ -n "$RET" ] && ENABLE_SERVICE="$RET" + fi + + if [ "$INSTALL_SERVICE" = "true" ]; then + systemd-tmpfiles --create /usr/lib/tmpfiles.d/wire-sysio.conf || true + systemctl daemon-reload || true + if [ "$ENABLE_SERVICE" = "true" ]; then + systemctl enable --now wire-sysio-nodeop.service || true + fi + fi + ;; +esac + +exit 0 diff --git a/tools/packaging/debian/postrm b/tools/packaging/debian/postrm new file mode 100755 index 0000000000..18659a462c --- /dev/null +++ b/tools/packaging/debian/postrm @@ -0,0 +1,20 @@ +#!/bin/sh +# Post-removal: deregister the unit. NEVER touches /var/lib/wire/sysio or +# /var/log/wire/sysio -- chain state and logs survive removal and purge. +set -e + +case "$1" in + remove) + if [ -d /run/systemd/system ]; then + systemctl daemon-reload 2>/dev/null || true + fi + ;; + purge) + if [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_purge || true + fi + ;; +esac + +exit 0 diff --git a/tools/packaging/debian/prerm b/tools/packaging/debian/prerm new file mode 100755 index 0000000000..de174db0bd --- /dev/null +++ b/tools/packaging/debian/prerm @@ -0,0 +1,15 @@ +#!/bin/sh +# Pre-removal: stop and disable the service so removal leaves no active unit +# or dangling enablement symlinks. Upgrades do not stop a running node. +set -e + +case "$1" in + remove|deconfigure) + if [ -d /run/systemd/system ]; then + systemctl stop wire-sysio-nodeop.service 2>/dev/null || true + systemctl disable wire-sysio-nodeop.service 2>/dev/null || true + fi + ;; +esac + +exit 0 diff --git a/tools/packaging/debian/templates b/tools/packaging/debian/templates new file mode 100644 index 0000000000..29a7facac9 --- /dev/null +++ b/tools/packaging/debian/templates @@ -0,0 +1,20 @@ +Template: wire-sysio/install-service +Type: boolean +Default: true +Description: Register the wire-sysio-nodeop systemd service? + Registers the packaged wire-sysio-nodeop unit with systemd and creates the + service directories (/etc/wire/sysio, /var/lib/wire/sysio/data, + /var/log/wire/sysio). + . + If you decline, the unit file remains available under + /usr/lib/systemd/system but nothing is registered or created. + +Template: wire-sysio/enable-service +Type: boolean +Default: true +Description: Enable and start wire-sysio-nodeop? + Adds wire-sysio-nodeop to the default boot target and starts it + immediately (systemctl enable --now). + . + If you decline, the service is registered but neither enabled at boot + nor started. diff --git a/tools/packaging/logrotate/wire-sysio-nodeop b/tools/packaging/logrotate/wire-sysio-nodeop new file mode 100644 index 0000000000..76837b5464 --- /dev/null +++ b/tools/packaging/logrotate/wire-sysio-nodeop @@ -0,0 +1,9 @@ +/var/log/wire/sysio/*.log { + size 1G + rotate 5 + missingok + notifempty + compress + delaycompress + copytruncate +} diff --git a/tools/packaging/rpm/post.sh b/tools/packaging/rpm/post.sh new file mode 100644 index 0000000000..59ae4c329f --- /dev/null +++ b/tools/packaging/rpm/post.sh @@ -0,0 +1,10 @@ +# %post -- $1 >= 1 on install and upgrade; == 1 on fresh install only. +# RPM has no interactive prompt path: fresh install registers, enables AND +# starts the service. Upgrades never restart a running node. +if [ "$1" -ge 1 ] && [ -d /run/systemd/system ]; then + systemd-tmpfiles --create /usr/lib/tmpfiles.d/wire-sysio.conf || : + systemctl daemon-reload || : + if [ "$1" -eq 1 ]; then + systemctl enable --now wire-sysio-nodeop.service || : + fi +fi diff --git a/tools/packaging/rpm/postun.sh b/tools/packaging/rpm/postun.sh new file mode 100644 index 0000000000..3f51a03ecf --- /dev/null +++ b/tools/packaging/rpm/postun.sh @@ -0,0 +1,4 @@ +# %postun -- after files are removed (erase and upgrade). State dirs untouched. +if [ -d /run/systemd/system ]; then + systemctl daemon-reload 2>/dev/null || : +fi diff --git a/tools/packaging/rpm/preun.sh b/tools/packaging/rpm/preun.sh new file mode 100644 index 0000000000..c2c340451f --- /dev/null +++ b/tools/packaging/rpm/preun.sh @@ -0,0 +1,5 @@ +# %preun -- $1 == 0 on full erase (not on upgrade). +if [ "$1" -eq 0 ] && [ -d /run/systemd/system ]; then + systemctl stop wire-sysio-nodeop.service 2>/dev/null || : + systemctl disable wire-sysio-nodeop.service 2>/dev/null || : +fi diff --git a/tools/packaging/systemd/wire-sysio-nodeop.service b/tools/packaging/systemd/wire-sysio-nodeop.service new file mode 100644 index 0000000000..8479f18edb --- /dev/null +++ b/tools/packaging/systemd/wire-sysio-nodeop.service @@ -0,0 +1,37 @@ +[Unit] +Description=wire-sysio-nodeop +Documentation=https://github.com/Wire-Network/wire-sysio +After=network-online.target +Wants=network-online.target + +[Service] +Type=exec +# Optional per-host overrides; a missing file is not a start failure. +EnvironmentFile=-/etc/wire/sysio/nodeop.env +ExecStart=/usr/bin/nodeop --config-dir /etc/wire/sysio -c config.ini --data-dir /var/lib/wire/sysio/data -e -p sysio + +# Rotation of these files is provided by /etc/logrotate.d/wire-sysio-nodeop +# (copytruncate; 5 rotations x 1G). +StandardOutput=append:/var/log/wire/sysio/nodeop.log +StandardError=append:/var/log/wire/sysio/nodeop.log + +# ── Graceful shutdown — avoid SIGKILL -> dirty chainbase. ── +KillSignal=SIGINT +KillMode=mixed +# TimeoutStopSec MUST exceed nodeop's real chainbase-flush time + margin. +# It grows with DB size — measure and tune per deployment. +TimeoutStopSec=300 +# nodeop's startup sync can be long — don't let systemd kill a slow start. +TimeoutStartSec=900 +# After TimeoutStopSec a genuinely hung nodeop is still SIGKILLed. +SendSIGKILL=yes + +# Don't get OOM-killed: the kernel kills OTHER processes before nodeop. +OOMScoreAdjust=-900 + +Restart=on-failure +RestartSec=10 +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target diff --git a/tools/packaging/systemd/wire-sysio.conf b/tools/packaging/systemd/wire-sysio.conf new file mode 100644 index 0000000000..f61565cff4 --- /dev/null +++ b/tools/packaging/systemd/wire-sysio.conf @@ -0,0 +1,4 @@ +d /etc/wire/sysio 0755 root root - +d /var/lib/wire/sysio 0750 root root - +d /var/lib/wire/sysio/data 0750 root root - +d /var/log/wire/sysio 0750 root root - diff --git a/tools/packaging/tests/verify-deb.sh b/tools/packaging/tests/verify-deb.sh new file mode 100755 index 0000000000..cf6f3aa54c --- /dev/null +++ b/tools/packaging/tests/verify-deb.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# S2 gate: DEB payload, control files, and containerized install. +# Usage: verify-deb.sh [dev-deb] +set -e +d="$1"; dev="$2" +[ -f "$d" ] || { echo "S2 FAIL: deb not found: $d"; exit 1; } +fail() { echo "S2 FAIL: $1"; exit 1; } +c=$(dpkg-deb -c "$d" | awk '{print $6}') +for f in ./usr/bin/nodeop ./usr/lib/systemd/system/wire-sysio-nodeop.service ./usr/lib/tmpfiles.d/wire-sysio.conf ./etc/logrotate.d/wire-sysio-nodeop; do + echo "$c" | grep -qx "$f" || fail "payload missing $f" +done +echo "$c" | grep -q "^./usr/include/" && fail "base deb leaks headers" +tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT +dpkg-deb -e "$d" "$tmp/ctrl" +for s in control templates config postinst prerm postrm; do + [ -f "$tmp/ctrl/$s" ] || fail "control member missing: $s" +done +grep -q "^Depends:.*debconf" "$tmp/ctrl/control" || fail "control missing debconf dependency" +if [ -n "$dev" ]; then + [ -f "$dev" ] || fail "dev deb not found: $dev" + dc=$(dpkg-deb -c "$dev" | awk '{print $6}') + for f in ./usr/include/fc ./usr/include/sysio/chain ./usr/lib/libfc.a ./usr/share/sysio_testing; do + echo "$dc" | grep -q "^$f" || fail "dev payload missing $f" + done + dpkg-deb -e "$dev" "$tmp/devctrl" + grep -q "^Depends:.*wire-sysio (= " "$tmp/devctrl/control" || fail "dev deb missing versioned base dependency" + echo "$dc" | grep -q "^./usr/lib/python3/dist-packages/TestHarness" || fail "dev payload missing TestHarness dist-packages symlink" + echo "$dc" | grep -q "^./usr/share/sysio_testing/bin/nodeop" || fail "dev payload missing sysio_testing/bin programs" +fi +pkgdir=$(cd "$(dirname "$d")" && pwd) +devbase=""; [ -n "$dev" ] && devbase=$(basename "$dev") +docker run --rm -v "$pkgdir":/pkg ubuntu:24.04 bash -ec " + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq >/dev/null + apt-get install -y /pkg/$(basename "$d") ${devbase:+/pkg/$devbase} > /tmp/apt.log 2>&1 || { tail -15 /tmp/apt.log; exit 1; } + dpkg -s wire-sysio | grep -q 'Status: install ok installed' + # postinst exits before any debconf interaction when systemd is absent, so + # exercise the config script explicitly; it registers both questions and + # persists the yes/yes defaults exactly as a real prompting install would. + dpkg-reconfigure -f noninteractive wire-sysio + debconf-show wire-sysio > /tmp/dc 2>&1; cat /tmp/dc + grep -q 'install-service: true' /tmp/dc + grep -q 'enable-service: true' /tmp/dc + test -x /usr/bin/nodeop + test -f /etc/logrotate.d/wire-sysio-nodeop + test -f /usr/lib/systemd/system/wire-sysio-nodeop.service + test -f /usr/lib/tmpfiles.d/wire-sysio.conf + if [ -n \"$devbase\" ]; then + dpkg -s wire-sysio-dev | grep -q 'Status: install ok installed' + test -d /usr/include/fc + test -f /usr/lib/libfc.a + test -L /usr/lib/python3/dist-packages/TestHarness + fi +" || fail "container install / debconf defaults" +# S6: runtime verification -- the installed service must enable, start, and +# stay up inside a systemd-enabled container. +"$(cd "$(dirname "$0")" && pwd)/verify-service-start.sh" deb "$d" || fail "S6 service-start stage" +echo "S2 PASS: $d ${dev:+(+ $dev)}" diff --git a/tools/packaging/tests/verify-install-manifest.sh b/tools/packaging/tests/verify-install-manifest.sh new file mode 100755 index 0000000000..1b1ad9b756 --- /dev/null +++ b/tools/packaging/tests/verify-install-manifest.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# S4 gate: containerized `cmake --install --component base` manifest diff vs +# pre-change baseline. Additions-only passes; any deletion/relocation fails. +# Usage: BASELINE= verify-install-manifest.sh +set -e +b="$1" +[ -d "$b" ] || { echo "S4 FAIL: build dir not found: $b"; exit 1; } +[ -n "$BASELINE" ] && [ -f "$BASELINE" ] || { echo "S4 FAIL: BASELINE env var not set or file missing"; exit 1; } +ws=/data/shared/code/wire-platform +out=$(mktemp) +docker run --rm -v "$ws":"$ws" ubuntu:24.04 bash -ec " + apt-get update -qq >/dev/null 2>&1 + apt-get install -y -qq cmake >/dev/null 2>&1 + DESTDIR=/tmp/post cmake --install '$b' --component base >/dev/null + # cmake --install writes install_manifest_base.txt into the build dir as + # root; hand it back to the workspace owner so host cpack can rewrite it. + chown --reference='$b/CMakeCache.txt' '$b/install_manifest_base.txt' 2>/dev/null || true + find /tmp/post \( -type f -o -type l \) | sed 's|^/tmp/post||' | sort +" > "$out" +sed 's|^/tmp/base||' "$BASELINE" | sort > "$out.base" +if diff -u "$out.base" "$out" > "$out.diff"; then + echo "S4 PASS: manifest identical to baseline" +else + if grep -q '^-[^-]' "$out.diff"; then + echo "S4 FAIL: deletions/relocations vs baseline:" + grep '^-[^-]' "$out.diff" + exit 1 + fi + echo "S4 PASS: additions only:" + grep '^+[^+]' "$out.diff" +fi +rm -f "$out" "$out.base" "$out.diff" diff --git a/tools/packaging/tests/verify-rpm.sh b/tools/packaging/tests/verify-rpm.sh new file mode 100755 index 0000000000..902d23f96f --- /dev/null +++ b/tools/packaging/tests/verify-rpm.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# S3 gate: RPM payload, scriptlets, version tag, and containerized install. +# Usage: verify-rpm.sh [dev-rpm] +set -e +r="$1"; dev="$2" +[ -f "$r" ] || { echo "S3 FAIL: rpm not found: $r"; exit 1; } +fail() { echo "S3 FAIL: $1"; exit 1; } +l=$(rpm -qlp "$r" 2>/dev/null) +for f in /usr/bin/nodeop /usr/lib/systemd/system/wire-sysio-nodeop.service /usr/lib/tmpfiles.d/wire-sysio.conf /etc/logrotate.d/wire-sysio-nodeop; do + echo "$l" | grep -qx "$f" || fail "payload missing $f" +done +echo "$l" | grep -q "^/usr/include/" && fail "base rpm leaks headers" +rpm -qp --scripts "$r" 2>/dev/null | grep -q "enable --now wire-sysio-nodeop" || fail "%post missing enable --now" +v=$(rpm -qp --qf '%{VERSION}' "$r" 2>/dev/null) +case "$v" in *-*) fail "version tag contains hyphen: $v" ;; esac +if [ -n "$dev" ]; then + [ -f "$dev" ] || fail "dev rpm not found: $dev" + dl=$(rpm -qlp "$dev" 2>/dev/null) + for f in /usr/include/fc /usr/include/sysio/chain /usr/lib/libfc.a; do + echo "$dl" | grep -q "^$f" || fail "dev payload missing $f" + done + n=$(rpm -qp --scripts "$dev" 2>/dev/null | grep -c systemctl || true) + [ "$n" = "0" ] || fail "dev rpm carries service scriptlets" + rpm -qp --requires "$dev" 2>/dev/null | grep -q "wire-sysio = " || fail "dev rpm missing versioned base requirement" +fi +pkgdir=$(cd "$(dirname "$r")" && pwd) +devbase=""; [ -n "$dev" ] && devbase=$(basename "$dev") +docker run --rm -v "$pkgdir":/pkg fedora:latest bash -ec " + dnf install -y /pkg/$(basename "$r") ${devbase:+/pkg/$devbase} >/dev/null + rpm -q wire-sysio + test -x /usr/bin/nodeop + test -f /etc/logrotate.d/wire-sysio-nodeop + if [ -n \"$devbase\" ]; then rpm -q wire-sysio-dev; test -d /usr/include/fc; fi +" || fail "fedora container install" +# S6: runtime verification -- the installed service must enable, start, and +# stay up inside a systemd-enabled container. +"$(cd "$(dirname "$0")" && pwd)/verify-service-start.sh" rpm "$r" || fail "S6 service-start stage" +echo "S3 PASS: $r ${dev:+(+ $dev)}" diff --git a/tools/packaging/tests/verify-scripts.sh b/tools/packaging/tests/verify-scripts.sh new file mode 100755 index 0000000000..1a809815b1 --- /dev/null +++ b/tools/packaging/tests/verify-scripts.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# S5 gate: static lint of the packaged unit, logrotate policy, and all +# maintainer scripts/scriptlets. Runs host tools when present. +set -e +root=$(cd "$(dirname "$0")/.." && pwd) +fail() { echo "S5 FAIL: $1"; exit 1; } +for s in debian/config debian/postinst debian/prerm debian/postrm rpm/post.sh rpm/preun.sh rpm/postun.sh tests/verify-tgz.sh tests/verify-deb.sh tests/verify-rpm.sh tests/verify-install-manifest.sh tests/verify-scripts.sh; do + sh -n "$root/$s" || fail "sh -n $s" +done +unit="$root/systemd/wire-sysio-nodeop.service" +if command -v systemd-analyze >/dev/null 2>&1; then + # /usr/bin/nodeop is absent on build hosts; that one finding is expected. + out=$(systemd-analyze verify "$unit" 2>&1 | grep -v "nodeop.*is not executable" | grep -v "Failed to prepare" || true) + [ -z "$out" ] || { echo "$out"; fail "systemd-analyze verify $unit"; } +fi +if command -v logrotate >/dev/null 2>&1; then + logrotate -d "$root/logrotate/wire-sysio-nodeop" >/dev/null 2>&1 || fail "logrotate -d" +fi +if command -v shellcheck >/dev/null 2>&1; then + shellcheck "$root/debian/config" "$root/debian/postinst" "$root/debian/prerm" "$root/debian/postrm" "$root"/rpm/*.sh || echo "S5 note: shellcheck findings above are advisory" +fi +echo "S5 PASS" diff --git a/tools/packaging/tests/verify-service-start.sh b/tools/packaging/tests/verify-service-start.sh new file mode 100755 index 0000000000..7a03e40675 --- /dev/null +++ b/tools/packaging/tests/verify-service-start.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# S6 gate: out-of-the-box service start inside a systemd-enabled container. +# Runs standalone or as the final stage of verify-deb.sh / verify-rpm.sh. +# Boots systemd as PID 1 (requires --privileged + host cgroup namespace), +# installs the base package inside, and asserts the unit is enabled AND active +# for >= 8 seconds with zero restarts, with nodeop logging into +# /var/log/wire/sysio. The systemd-enabled test image is built from the inline +# Dockerfile on first use and cached locally -- no out-of-band setup. +# Usage: verify-service-start.sh deb | rpm +set -e +kind="$1"; pkg="$2" +[ -f "$pkg" ] || { echo "S6 FAIL: package not found: $pkg"; exit 1; } +pkgdir=$(cd "$(dirname "$pkg")" && pwd) +base=$(basename "$pkg") +name="wire-svc-test-$kind-$$" +fail() { + echo "S6 FAIL: $1" + docker exec "$name" systemctl status wire-sysio-nodeop --no-pager -l 2>/dev/null | tail -12 || true + docker exec "$name" tail -8 /var/log/wire/sysio/nodeop.log 2>/dev/null || true + docker rm -f "$name" >/dev/null 2>&1 || true + exit 1 +} +case "$kind" in + deb) img="wire-systemd-ubuntu:24.04" + inst='export DEBIAN_FRONTEND=noninteractive; apt-get update -qq >/dev/null 2>&1; apt-get install -y /pkg/PKG >/tmp/inst.log 2>&1 || { tail -12 /tmp/inst.log; exit 1; }' ;; + rpm) img="wire-systemd-fedora:latest" + inst='dnf install -y /pkg/PKG >/tmp/inst.log 2>&1 || { tail -12 /tmp/inst.log; exit 1; }' ;; + *) echo "usage: verify-service-start.sh deb|rpm "; exit 2 ;; +esac +inst=$(echo "$inst" | sed "s|PKG|$base|") +if ! docker image inspect "$img" >/dev/null 2>&1; then + echo "S6: building systemd test image $img (first use, cached afterwards)" + if [ "$kind" = "deb" ]; then + docker build -q -t "$img" - <<'DEOF' +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y systemd systemd-sysv dbus && apt-get clean +CMD ["/sbin/init"] +DEOF + else + docker build -q -t "$img" - <<'REOF' +FROM fedora:latest +RUN dnf install -y systemd && dnf clean all +CMD ["/sbin/init"] +REOF + fi +fi +docker run -d --name "$name" --privileged --cgroupns=host \ + --tmpfs /run --tmpfs /run/lock -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ + -v "$pkgdir":/pkg "$img" >/dev/null +trap 'docker rm -f "$name" >/dev/null 2>&1 || true' EXIT +st="" +for i in $(seq 1 30); do + st=$(docker exec "$name" systemctl is-system-running 2>/dev/null || true) + case "$st" in running|degraded) break ;; esac + sleep 1 +done +case "$st" in running|degraded) ;; *) fail "systemd did not come up (state: '$st')" ;; esac +docker exec "$name" sh -c "$inst" || fail "package install inside systemd container" +docker exec "$name" systemctl is-enabled wire-sysio-nodeop.service 2>/dev/null | grep -qx enabled || fail "unit not enabled after install" +sleep 8 +act=$(docker exec "$name" systemctl is-active wire-sysio-nodeop.service 2>/dev/null || true) +[ "$act" = "active" ] || fail "unit not active 8s after install (state: $act)" +nres=$(docker exec "$name" systemctl show -p NRestarts --value wire-sysio-nodeop.service) +[ "$nres" = "0" ] || fail "unit restarted $nres time(s) within 8s of install" +docker exec "$name" test -s /var/log/wire/sysio/nodeop.log || fail "/var/log/wire/sysio/nodeop.log missing or empty" +docker exec "$name" test -d /var/lib/wire/sysio/data || fail "data dir not created by tmpfiles" +echo "--- nodeop.log tail (evidence of a running node) ---" +docker exec "$name" tail -3 /var/log/wire/sysio/nodeop.log +echo "S6 PASS ($kind): enabled + active >=8s, 0 restarts, log growing" diff --git a/tools/packaging/tests/verify-tgz.sh b/tools/packaging/tests/verify-tgz.sh new file mode 100755 index 0000000000..da7c2d8d23 --- /dev/null +++ b/tools/packaging/tests/verify-tgz.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# S1 gate: portable tarball layout. Usage: verify-tgz.sh +set -e +t="$1" +[ -f "$t" ] || { echo "S1 FAIL: tarball not found: $t"; exit 1; } +fail() { echo "S1 FAIL: $1"; exit 1; } +list=$(tar tzf "$t") +bad=$(echo "$list" | grep -v '^wire-sysio/' || true) +[ -z "$bad" ] || fail "entries outside wire-sysio/: $bad" +echo "$list" | grep -q '^wire-sysio/usr/' && fail "unexpected usr/ layer inside tarball" +for f in bin/nodeop lib/systemd/system/wire-sysio-nodeop.service lib/tmpfiles.d/wire-sysio.conf etc/logrotate.d/wire-sysio-nodeop; do + echo "$list" | grep -qx "wire-sysio/$f" || fail "missing wire-sysio/$f" +done +echo "S1 PASS: $t" From dd1532ae3b1759956d15090a94cf966a5328f46a Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 09:35:19 -0400 Subject: [PATCH 2/7] ci: assemble and verify tgz/deb/rpm packages; reactivate release workflow - linux_amd64_build: cpack -G DEB smoke on all platforms; ubuntu24 assembles the full package set (base+dev deb/rpm + portable tgz) into a single wire-sysio-packages-amd64 artifact; new verify-packages job runs the packaging suite (S1-S6, incl. the systemd-in-container service-start gate) and gates all-passing; per-platform package artifact uploads removed - release workflow reactivated from noop/: on release publish it locates the tag build, guards tag/version consistency, re-verifies the artifacts, attaches the packages plus sha256 checksums to the release, and refreshes the wire-sysio-experimental-binaries ghcr image; actions SHA-pinned - tools/tweak-deb.sh -> tools/packaging/scripts/deb-postprocess.sh (git mv; callers updated: build workflow, tools/reproducible.Dockerfile) - dev-component testing-tree installs marked OPTIONAL so contracts-OFF CI builds package cleanly - BUILD.md: document the release flow Change-Id: Ic2f0ee003a32316d938b2937e9bf5603919a6513 --- .github/workflows/linux_amd64_build.yaml | 55 +++++++++++++++---- .github/workflows/{noop => }/release.yaml | 0 BUILD.md | 12 ++++ CMakeLists.txt | 6 +- .../scripts/deb-postprocess.sh} | 0 tools/reproducible.Dockerfile | 2 +- 6 files changed, 61 insertions(+), 14 deletions(-) rename .github/workflows/{noop => }/release.yaml (100%) rename tools/{tweak-deb.sh => packaging/scripts/deb-postprocess.sh} (100%) diff --git a/.github/workflows/linux_amd64_build.yaml b/.github/workflows/linux_amd64_build.yaml index 7382da9156..cf0bad28cd 100644 --- a/.github/workflows/linux_amd64_build.yaml +++ b/.github/workflows/linux_amd64_build.yaml @@ -349,21 +349,35 @@ jobs: if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then bash ../.github/scripts/assert-system-contract-build.sh . fi - cpack - ../tools/tweak-deb.sh wire-sysio_*.deb + cpack -G DEB + ../tools/packaging/scripts/deb-postprocess.sh wire-sysio_*.deb - - name: Install dev package + - name: Install base package if: ${{ steps.build.outcome == 'success' && !cancelled() }} run: | apt-get update apt-get install -y ./build/wire-sysio_*.deb - - name: Upload dev package - if: ${{ steps.build.outcome == 'success' && !cancelled() }} + - name: Assemble release package set (tgz + deb + rpm, base + dev) + if: ${{ steps.build.outcome == 'success' && matrix.platform == 'ubuntu24' && !cancelled() }} + run: | + # The RPM generator needs rpmbuild; the Debian-based platform image does not ship it. + command -v rpmbuild >/dev/null || { apt-get update && apt-get install -y rpm; } + cd build + cpack -G RPM + cmake --build . --target package-tgz + + - name: Upload release package set + if: ${{ steps.build.outcome == 'success' && matrix.platform == 'ubuntu24' && !cancelled() }} uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # actions/upload-artifact@v6 with: - name: wire-sysio-dev-${{matrix.platform}}-amd64 - path: build/wire-sysio_*.deb + name: wire-sysio-packages-amd64 + if-no-files-found: error + path: | + build/wire-sysio_*.deb + build/wire-sysio-dev_*.deb + build/wire-sysio-*.rpm + build/wire-sysio-*.tar.gz v: name: Discover Versions @@ -504,9 +518,30 @@ jobs: echo "::error::Timed out waiting for Wire CDT package artifact for ${cdt_sha}" >&2 exit 1 + verify-packages: + name: Verify packages (S1-S6) + needs: [build-test-package] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # actions/checkout@v5 + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # actions/download-artifact@v8.0.1 + with: + name: wire-sysio-packages-amd64 + path: artifacts + + - name: Run packaging verification suite + run: | + ls -la artifacts/ + tools/packaging/tests/verify-scripts.sh + tools/packaging/tests/verify-tgz.sh artifacts/wire-sysio-*.tar.gz + tools/packaging/tests/verify-deb.sh artifacts/wire-sysio_*.deb artifacts/wire-sysio-dev_*.deb + # wire-sysio-[0-9]* matches the base rpm only (the dev rpm is wire-sysio-dev-*). + tools/packaging/tests/verify-rpm.sh artifacts/wire-sysio-[0-9]*.rpm artifacts/wire-sysio-dev-*.rpm + all-passing: name: All Required Tests Passed - needs: [ build-test-package, root-node-tooling ] + needs: [ build-test-package, root-node-tooling, verify-packages ] if: always() runs-on: ubuntu-latest steps: @@ -517,8 +552,8 @@ jobs: webhook-url: ${{ secrets.WEBHOOK_URL }} notification-type: 1 workflow-name: "Build & Test Workflow" - job-results: "build-test-package:${{ needs.build-test-package.result }},root-node-tooling:${{ needs.root-node-tooling.result }}" + job-results: "build-test-package:${{ needs.build-test-package.result }},root-node-tooling:${{ needs.root-node-tooling.result }},verify-packages:${{ needs.verify-packages.result }}" github-context: ${{ toJSON(github) }} - - if: needs.build-test-package.result != 'success' || needs.root-node-tooling.result != 'success' + - if: needs.build-test-package.result != 'success' || needs.root-node-tooling.result != 'success' || needs.verify-packages.result != 'success' run: false diff --git a/.github/workflows/noop/release.yaml b/.github/workflows/release.yaml similarity index 100% rename from .github/workflows/noop/release.yaml rename to .github/workflows/release.yaml diff --git a/BUILD.md b/BUILD.md index ddee943506..27a938797c 100644 --- a/BUILD.md +++ b/BUILD.md @@ -285,3 +285,15 @@ stage proving the service enables, starts, and stays up), `verify-install-manifest.sh` (install regression vs a baseline), and `verify-scripts.sh` (static lint). The deb/rpm verifiers require docker; the runtime stage builds a cached systemd-enabled test image on first use. + +### Release flow + +1. Bump `VERSION_MAJOR/MINOR/PATCH/SUFFIX` in `CMakeLists.txt` (PR to master). +2. Push tag `v` — the tag build installs the Wire CDT package, builds + and asserts system contracts, assembles the full package set, and verifies + it (S1-S6, including the systemd service-start gate). +3. Publish the GitHub Release for the tag — the `Release Actions` workflow + locates the successful tag build, re-verifies the artifacts, fails fast if + the tag does not match the artifact version, attaches the packages plus a + sha256 checksums file to the release, and refreshes the + `wire-sysio-experimental-binaries` ghcr image. diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a9bdda42f..1e97aac1e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,15 +169,15 @@ add_merged_compile_commands_target() install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/sysio" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/licenses/" COMPONENT base) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libraries/testing/contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/libraries/testing COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libraries/testing/contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/libraries/testing OPTIONAL COMPONENT dev EXCLUDE_FROM_ALL PATTERN "CMakeFiles" EXCLUDE PATTERN "*.cmake" EXCLUDE PATTERN "Makefile" EXCLUDE) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/system-test-contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/unittests COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/system-test-contracts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/unittests OPTIONAL COMPONENT dev EXCLUDE_FROM_ALL PATTERN "CMakeFiles" EXCLUDE PATTERN "*.cmake" EXCLUDE PATTERN "Makefile" EXCLUDE) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/TestHarness DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/tests COMPONENT dev EXCLUDE_FROM_ALL +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/TestHarness DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sysio_testing/tests OPTIONAL COMPONENT dev EXCLUDE_FROM_ALL FILES_MATCHING PATTERN "*.py" PATTERN "*.json" diff --git a/tools/tweak-deb.sh b/tools/packaging/scripts/deb-postprocess.sh similarity index 100% rename from tools/tweak-deb.sh rename to tools/packaging/scripts/deb-postprocess.sh diff --git a/tools/reproducible.Dockerfile b/tools/reproducible.Dockerfile index bafa2528b7..4db8ac3fcd 100644 --- a/tools/reproducible.Dockerfile +++ b/tools/reproducible.Dockerfile @@ -118,7 +118,7 @@ ARG SYSIO_BUILD_JOBS COPY / /__w/sysio/sysio RUN cmake -S /__w/sysio/sysio -B build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -GNinja && \ cmake --build build -t package -- ${SYSIO_BUILD_JOBS:+-j$SYSIO_BUILD_JOBS} && \ - /__w/sysio/sysio/tools/tweak-deb.sh build/wire-sysio_*.deb + /__w/sysio/sysio/tools/packaging/scripts/deb-postprocess.sh build/wire-sysio_*.deb FROM scratch AS exporter COPY --from=build /build/*.deb /build/*.tar.* / From fe23ed9765c831384711b98cf12e06fff2ddb3ec Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 10:16:45 -0400 Subject: [PATCH 3/7] build: bump appbase (relative install destinations for packaging) Change-Id: I7eb0facdfc41777a4256c796a649c520c9bcd2d4 --- libraries/appbase | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/appbase b/libraries/appbase index 104ec22e68..40bcefdabb 160000 --- a/libraries/appbase +++ b/libraries/appbase @@ -1 +1 @@ -Subproject commit 104ec22e68d9247a19a71e4f8e115652d023c7d7 +Subproject commit 40bcefdabb2db7980a501e0d8b886e08d0fff98c From 59bd8442824d5bbe5fecb6578c751c92c615dcf7 Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 10:16:45 -0400 Subject: [PATCH 4/7] docs+ci: release workflow overview; dispatchable release validation path - docs/release-workflow.md: overview with mermaid activity and sequence diagrams - release.yaml: workflow_dispatch with a tag input, since release-published events always execute the default branch's workflow file and the verify/ attach path must be testable before this branch merges Change-Id: Ia5ef2d01775bdc265cd06257ba87bba07dc14595 --- .github/workflows/release.yaml | 121 +++++++++++++++++++++++++-------- docs/release-workflow.md | 85 +++++++++++++++++++++++ 2 files changed, 179 insertions(+), 27 deletions(-) create mode 100644 docs/release-workflow.md diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7b38859cba..5e6af6af52 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,53 +1,120 @@ -name: Release Actions +name: "Release Actions" on: release: types: [published] + # Validation path: release-published events always run the DEFAULT branch's + # workflow file, so pre-merge testing (and re-runs against an existing + # release) go through manual dispatch with the tag as input. + workflow_dispatch: + inputs: + tag: + description: "Existing release tag to verify and populate (e.g. v1.0.0-rc1)" + type: string + required: true + +permissions: + contents: write + packages: write + actions: read + +defaults: + run: + shell: bash jobs: - eb: - name: experimental-binaries + publish-assets: + name: Verify & attach release artifacts + runs-on: ubuntu-latest + outputs: + run-id: ${{ steps.run.outputs.run-id }} + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.tag || github.ref_name }} + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # actions/checkout@v5 + + - name: Resolve build run for the released commit + id: run + run: | + # The release points at a tag; the tag build (linux_amd64_build.yaml, + # push: tags v*) produced wire-sysio-packages-amd64 for exactly this + # commit. Same resolution pattern as the wire-cdt artifact lookup. + sha=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${TAG}" --jq .sha) + run_id="" + for attempt in {1..30}; do + run_id=$(gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/linux_amd64_build.yaml/runs?head_sha=${sha}&event=push&per_page=10" \ + --jq '[.workflow_runs[] | select(.status=="completed" and .conclusion=="success")][0].id // empty') + [[ -n "$run_id" ]] && break + echo "Waiting for successful tag build of ${sha} (attempt ${attempt}/30)" + sleep 60 + done + [[ -n "$run_id" ]] || { echo "::error::No successful build run found for ${sha}"; exit 1; } + echo "run-id=$run_id" >> "$GITHUB_OUTPUT" + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # actions/download-artifact@v8.0.1 + with: + name: wire-sysio-packages-amd64 + path: dist + run-id: ${{ steps.run.outputs.run-id }} + github-token: ${{ github.token }} + + - name: Guard release tag matches artifact version + run: | + tag="${GITHUB_REF_NAME#v}" + ls -la dist/ + [[ -f "dist/wire-sysio_${tag}_amd64.deb" ]] \ + || { echo "::error::Release tag v${tag} does not match the artifact version (bump VERSION_* in CMakeLists.txt to match the tag before tagging)"; exit 1; } + + - name: Verify packages (S1-S6) + run: | + tools/packaging/tests/verify-tgz.sh dist/wire-sysio-*.tar.gz + tools/packaging/tests/verify-deb.sh dist/wire-sysio_*.deb dist/wire-sysio-dev_*.deb + # wire-sysio-[0-9]* matches the base rpm only (the dev rpm is wire-sysio-dev-*). + tools/packaging/tests/verify-rpm.sh dist/wire-sysio-[0-9]*.rpm dist/wire-sysio-dev-*.rpm + + - name: Attach artifacts to the release + run: | + sha256sum dist/* > "wire-sysio-${GITHUB_REF_NAME#v}-checksums.txt" + mv "wire-sysio-${GITHUB_REF_NAME#v}-checksums.txt" dist/ + gh release upload "$GITHUB_REF_NAME" dist/* --clobber + + experimental-binaries: + name: experimental-binaries (ghcr mirror) + needs: [publish-assets] runs-on: ubuntu-latest permissions: contents: read packages: write actions: read steps: - - name: Get ubuntu20 sysio-dev.deb - uses: AntelopeIO/asset-artifact-download-action@v3 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # actions/download-artifact@v8.0.1 with: - owner: ${{github.repository_owner}} - repo: ${{github.event.repository.name}} - file: 'sysio-dev.*amd64.deb' - target: ${{github.sha}} - artifact-name: sysio-dev-ubuntu20-amd64 - wait-for-exact-target: true - - name: Get ubuntu22 sysio-dev.deb - uses: AntelopeIO/asset-artifact-download-action@v3 - with: - owner: ${{github.repository_owner}} - repo: ${{github.event.repository.name}} - file: 'sysio-dev.*amd64.deb' - target: ${{github.sha}} - artifact-name: sysio-dev-ubuntu22-amd64 - wait-for-exact-target: true + name: wire-sysio-packages-amd64 + path: . + run-id: ${{ needs.publish-assets.outputs.run-id }} + github-token: ${{ github.token }} + - name: Create Dockerfile run: | - cat < Dockerfile + cat < Dockerfile FROM scratch LABEL org.opencontainers.image.description="A collection of experimental Wire binary packages" COPY *.deb / - EOF + DOCKEREOF + - name: Login to ghcr - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # docker/login-action@v3 with: registry: ghcr.io - username: ${{github.repository_owner}} - password: ${{github.token}} + username: ${{ github.repository_owner }} + password: ${{ github.token }} + - run: echo "REPOSITORY_OWNER_LOWER=${GITHUB_REPOSITORY_OWNER,,}" >> "${GITHUB_ENV}" + - name: Build and push wire-sysio-experimental-binaries - uses: docker/build-push-action@v5 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # docker/build-push-action@v6 with: push: true - tags: ghcr.io/${{env.REPOSITORY_OWNER_LOWER}}/wire-sysio-experimental-binaries:${{github.ref_name}} + tags: ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/wire-sysio-experimental-binaries:${{ inputs.tag || github.ref_name }} context: . diff --git a/docs/release-workflow.md b/docs/release-workflow.md new file mode 100644 index 0000000000..2cdbe9e46f --- /dev/null +++ b/docs/release-workflow.md @@ -0,0 +1,85 @@ +# Release Workflow + +How a wire-sysio release goes from a version bump to a published GitHub +Release with verified artifacts attached. Artifact contents are documented in +[release-layout.md](release-layout.md); build commands in +[../BUILD.md](../BUILD.md). + +## Overview + +1. **Version bump** — a PR to `master` updates `VERSION_MAJOR/MINOR/PATCH/SUFFIX` + in `CMakeLists.txt`. The version embedded in every artifact comes from here; + the release workflow fails fast if it doesn't match the tag. +2. **Tag** — a maintainer pushes `v`. The tag build + (`linux_amd64_build.yaml`) installs the Wire CDT package, builds the system + contracts from source (and asserts it), assembles the full package set + (base + dev deb/rpm, portable tgz) on the `ubuntu24` platform, and the + `verify-packages` job runs the packaging suite (S1-S6, including the + systemd-in-container service-start gate) against the produced artifacts. +3. **Publish** — a maintainer publishes the GitHub Release for the tag. The + `Release Actions` workflow (`release.yaml`) locates the successful tag + build, downloads its `wire-sysio-packages-amd64` artifact, guards + tag↔version consistency, re-verifies the packages, attaches them plus a + sha256 checksums file to the release, and refreshes the + `wire-sysio-experimental-binaries` ghcr image. + +For pre-merge validation, `release.yaml` also exposes `workflow_dispatch` +with a `tag` input, which runs the same verify-and-attach path against an +existing tag + release without waiting for a `release: published` event +(those events always execute the workflow file from the default branch). + +## Activity + +```mermaid +flowchart TD + A[PR: bump VERSION_* in CMakeLists.txt] --> B[Merge to master] + B --> C[Push tag v<version>] + C --> D[Tag build: linux_amd64_build.yaml] + D --> D1[Install Wire CDT package] + D1 --> D2[Build + test, system contracts ON] + D2 --> D3[assert-system-contract-build] + D3 --> D4[Assemble packages: deb + rpm + tgz] + D4 --> D5[Upload wire-sysio-packages-amd64] + D5 --> E{verify-packages: S1-S6} + E -- fail --> X1[Fix and re-tag] + E -- pass --> F[Maintainer publishes GitHub Release] + F --> G[Release Actions: release.yaml] + G --> G1[Resolve successful tag build run] + G1 --> G2{Tag matches artifact version?} + G2 -- no --> X2[Fail: bump CMakeLists VERSION_* first] + G2 -- yes --> G3[Re-verify packages S1-S6] + G3 --> G4[Attach artifacts + sha256 checksums] + G4 --> G5[Push ghcr experimental-binaries image] + G5 --> H([Release live with verified artifacts]) +``` + +## Sequence + +```mermaid +sequenceDiagram + actor M as Maintainer + participant GH as GitHub + participant B as Build workflow
(linux_amd64_build) + participant V as verify-packages job + participant R as Release Actions
(release.yaml) + participant REG as ghcr.io + + M->>GH: merge version-bump PR (CMakeLists VERSION_*) + M->>GH: push tag v + GH->>B: trigger (push: tags v*) + B->>B: install Wire CDT, build + test,
system contracts ON + assert + B->>B: cpack DEB/RPM + package-tgz (ubuntu24) + B->>GH: upload artifact wire-sysio-packages-amd64 + GH->>V: run after build + V->>GH: download artifact + V->>V: S1 tgz - S2 deb - S3 rpm - S5 lint
(S6 systemd service-start inside S2/S3) + V-->>GH: all-passing gate + M->>GH: publish Release for tag + GH->>R: trigger (release: published) + R->>GH: resolve successful tag-build run (gh api) + R->>GH: download wire-sysio-packages-amd64 + R->>R: guard: tag == artifact version + R->>R: re-verify packages (S1-S6) + R->>GH: gh release upload artifacts + checksums + R->>REG: push wire-sysio-experimental-binaries:v +``` From 033367616b17cf1b65db413b2aa16d1cb6854a62 Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 11:56:41 -0400 Subject: [PATCH 5/7] packaging: repack the deb control archive instead of in-place tar edits GNU tar's --delete/--update cannot edit the pax-format control archives CPack emits (tar: Skipping to next header), which broke the Build packages CI step on every leg. Unpack, apply the same Installed-Size/libc6 tweaks, and repack with deterministic GNU-format metadata. Change-Id: I1a10d7a163e583f48062725ebbdff54a852e593b --- tools/packaging/scripts/deb-postprocess.sh | 36 +++++++++++++--------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/tools/packaging/scripts/deb-postprocess.sh b/tools/packaging/scripts/deb-postprocess.sh index e1dd6854c2..05dda50c63 100755 --- a/tools/packaging/scripts/deb-postprocess.sh +++ b/tools/packaging/scripts/deb-postprocess.sh @@ -1,21 +1,24 @@ #!/bin/bash set -euo pipefail -# Tweaks a couple aspects of the built .deb's control file: -# 1. Removes Installed-Size field; this isn't reproducible for some reason, possibly different filesystems -# reporting different sizes for directories? -# 2. Removes all but the first libc Depends rule as the rest are unnecessarily restrictive. The original was being -# generated as, -# libc6 (>= 2.27), libc6 (>> 2.28), libc6 (<< 2.29), libcurl4 (>= 7.16.2), libgcc1 (>= 1:3.3), libgmp10, zlib1g (>= 1:1.2.0) -# and the included sed rule within this script will reduce it to -# libc6 (>= 2.27), libcurl4 (>= 7.16.2), libgcc1 (>= 1:3.3), libgmp10, zlib1g (>= 1:1.2.0) -# This may need to be tweaked in the future further; clearly not ideal. +# Post-processes a built .deb's control archive: +# 1. Removes the Installed-Size field; it is not reproducible across +# filesystems. +# 2. Collapses redundant multi-clause libc6 Depends down to the first clause +# (historically emitted as e.g. +# libc6 (>= 2.27), libc6 (>> 2.28), libc6 (<< 2.29), ... +# which is unnecessarily restrictive). +# +# The control archive is fully unpacked and repacked with deterministic +# metadata instead of being patched in place: GNU tar's --delete/--update +# cannot edit the pax-format archives CPack emits ("Skipping to next +# header"), while a fresh GNU-format repack is portable and reproducible. WORKDIR="$(mktemp -d)" trap 'rm -rf -- "${WORKDIR}"' EXIT if [ $# -lt 1 ]; then - echo "Must specify .deb file to tweak as argument to script" + echo "Must specify .deb file to postprocess as argument to script" exit 1 fi @@ -24,14 +27,17 @@ if [ ! -f "$1" ]; then exit 1 fi -DEB_PATH="$(realpath ${1})" +DEB_PATH="$(realpath "${1}")" cd "${WORKDIR}" ar x "${DEB_PATH}" control.tar.gz gzip -d control.tar.gz -tar xf control.tar ./control -tar --delete -f control.tar ./control -sed -i -E -e '/Installed-Size/d' -e 's/, libc6[^,]+//g' control -tar --update --mtime "@0" --owner=0 --group=0 --numeric-owner -f control.tar ./control +mkdir ctrl +tar xf control.tar -C ctrl +sed -i -E -e '/Installed-Size/d' -e 's/, libc6[^,]+//g' ctrl/control +(cd ctrl && find . -mindepth 1 -maxdepth 1 -type f -printf './%f\n' | LC_ALL=C sort) > members.txt +rm -f control.tar +tar cf control.tar --format=gnu --mtime=@0 --owner=0 --group=0 --numeric-owner \ + --no-recursion -C ctrl -T members.txt gzip -n control.tar ar rD "${DEB_PATH}" control.tar.gz From e05aef2790699d8a064dd5d25917bee0747a76bf Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 18:29:23 -0400 Subject: [PATCH 6/7] feat(opp): publish wire-opp-solana-models crate to the WIRE cargo registry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The opp-bundles publish flow now ships the generated Solana Rust crate to the CodeArtifact cargo registry (wire-pkg / wire-pkg-rust-private, provisioned by wire-infra ArtifactManagementStack) alongside the existing npm publishes, with the same invocation the workflow already uses: `generate-opp-bundles.sh --publish`. - protobuf-bundler: CARGO_PUBLISHABLE_TARGETS (solana) + publishCargoCrate in handlePublish — `cargo publish --registry wire --allow-dirty --no-verify` from the generated crate dir, duplicate-version tolerated so npm/cargo publish skew self-heals on the next synchronized version. - Generated Cargo.toml now carries license (LicenseRef-Wire-Proprietary), repository, and `publish = ["wire"]` so the crate can never land on crates.io by accident. - generate-opp-bundles.sh: when --publish, verifies cargo >= 1.74 and the AWS CLI are available, mints the CodeArtifact token from ambient AWS credentials, and exports CARGO_REGISTRIES_WIRE_{INDEX,TOKEN, CREDENTIAL_PROVIDER} for the bundler. Validate mode stays credential-free. - opp-bundles.yaml: id-token: write + aws-actions/configure-aws-credentials (pinned, v6.2.2) assuming wire-pkg-cargo-publisher, gated to push/workflow_dispatch; the publish step invocation is unchanged. First publish completed: wire-opp-solana-models v1.0.35 is live in wire-pkg-rust-private (synchronized with the npm bundle version). Co-Authored-By: Claude Fable 5 Change-Id: I6919d03b9ce88540934b6cd3b79abf84b4ac39f0 --- .github/workflows/opp-bundles.yaml | 15 +++++ docs/release-layout.md | 22 +++---- .../protobuf-bundler/src/commands/bundle.ts | 65 ++++++++++++++++++- .../tools/protobuf-bundler/src/constants.ts | 16 +++++ .../opp/tools/protobuf-bundler/src/index.ts | 2 +- .../src/steps/generatePackage.ts | 10 ++- .../templates/solana/Cargo.toml.hbs | 3 + .../opp/tools/scripts/generate-opp-bundles.sh | 52 +++++++++++++++ 8 files changed, 171 insertions(+), 14 deletions(-) diff --git a/.github/workflows/opp-bundles.yaml b/.github/workflows/opp-bundles.yaml index bd45c5c0e3..e399079bca 100644 --- a/.github/workflows/opp-bundles.yaml +++ b/.github/workflows/opp-bundles.yaml @@ -19,6 +19,10 @@ on: permissions: contents: read + # Required for the publish step's OIDC role assumption (CodeArtifact cargo + # publish). PR validation never requests a token — the credentials step is + # gated to push/workflow_dispatch below. + id-token: write jobs: opp-bundles: @@ -47,6 +51,17 @@ jobs: cd ./libraries/opp/tools pnpm audit --audit-level=moderate + - name: Configure AWS credentials (CodeArtifact cargo publish) + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d # aws-actions/configure-aws-credentials@v6.2.2 + with: + # wire-infra ArtifactManagementStack — the role trusts ONLY + # repo:Wire-Network/wire-sysio:ref:refs/heads/master via GitHub OIDC. + # generate-opp-bundles.sh --publish mints the CodeArtifact token from + # these credentials and exports CARGO_REGISTRIES_WIRE_INDEX/_TOKEN. + role-to-assume: arn:aws:iam::619322354039:role/wire-pkg-cargo-publisher + aws-region: us-east-1 + - name: Generate & Publish OPP Bundles if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' env: diff --git a/docs/release-layout.md b/docs/release-layout.md index 5698c3e525..43bc4a5d55 100644 --- a/docs/release-layout.md +++ b/docs/release-layout.md @@ -5,18 +5,18 @@ one build tree (see `BUILD.md` → Packaging). Version shown as `` (e.g. `1.0.0-dev`; dpkg/rpm metadata uses the tilde form `1.0.0~dev` so pre-release suffixes sort before the final release). -| Artifact | Name | Install prefix | -|---|---|---| -| Portable tarball | `wire-sysio--.tar.gz` | none — self-contained tree | -| Debian/Ubuntu | `wire-sysio__.deb` + `wire-sysio-dev__.deb` | `/usr` | -| RHEL/Fedora | `wire-sysio--.rpm` + `wire-sysio-dev--.rpm` | `/usr` | +| Artifact | Name | Install prefix | +| ---------------- | ------------------------------------------------------------------- | -------------------------- | +| Portable tarball | `wire-sysio--.tar.gz` | none — self-contained tree | +| Debian/Ubuntu | `wire-sysio__.deb` + `wire-sysio-dev__.deb` | `/usr` | +| RHEL/Fedora | `wire-sysio--.rpm` + `wire-sysio-dev--.rpm` | `/usr` | ## Portable tarball (`.tar.gz`) Runtime payload only (the base component), rooted at a plain `wire-sysio/` directory so that extraction into `/opt` yields `/opt/wire-sysio/bin/nodeop`: -``` +```tree wire-sysio/ ├── bin/ │ ├── clio @@ -66,11 +66,11 @@ restart a running node; removal stops/disables the unit but **never deletes** Runtime directories (created by `systemd-tmpfiles` at install and every boot, matching the unit's command line — nodeop's internal defaults are unchanged): -| Purpose | Path | -|---|---| -| Config (`--config-dir`) | `/etc/wire/sysio` | -| Data (`--data-dir`) | `/var/lib/wire/sysio/data` | -| Logs (unit `append:`) | `/var/log/wire/sysio` (rotated 5 x 1G, copytruncate) | +| Purpose | Path | +| ----------------------- | ---------------------------------------------------- | +| Config (`--config-dir`) | `/etc/wire/sysio` | +| Data (`--data-dir`) | `/var/lib/wire/sysio/data` | +| Logs (unit `append:`) | `/var/log/wire/sysio` (rotated 5 x 1G, copytruncate) | ### `wire-sysio-dev` (headers/libraries/testing; depends on exact base version) diff --git a/libraries/opp/tools/protobuf-bundler/src/commands/bundle.ts b/libraries/opp/tools/protobuf-bundler/src/commands/bundle.ts index e236825611..db1ee94b78 100644 --- a/libraries/opp/tools/protobuf-bundler/src/commands/bundle.ts +++ b/libraries/opp/tools/protobuf-bundler/src/commands/bundle.ts @@ -11,7 +11,12 @@ import { fetchProtos } from "../steps/fetchProtos.js" import { runProtoc } from "../steps/runProtoc.js" import { generatePackage } from "../steps/generatePackage.js" import { generateTypescript } from "../steps/generateTypescript.js" -import { Target, PUBLISHABLE_TARGETS } from "../constants.js" +import { + Target, + PUBLISHABLE_TARGETS, + CARGO_PUBLISHABLE_TARGETS, + CARGO_REGISTRY_NAME +} from "../constants.js" const PROTO_DIR_NAME = "proto" const PROTO_FILE_EXTENSION = ".proto" @@ -385,6 +390,58 @@ function publishPackage(dir: string): void { } } +/** + * Publish the generated Rust crate to the WIRE CodeArtifact cargo registry. + * + * Registry wiring comes from the environment (`CARGO_REGISTRIES_WIRE_INDEX` / + * `_TOKEN`, exported by generate-opp-bundles.sh --publish); no config file is + * written and no token touches disk. A duplicate-version rejection is treated + * as success so a previous run that published the crate but failed the npm + * side (or vice versa) self-heals on the next synchronized version. + */ +function publishCargoCrate(dir: string): void { + const registryEnvPrefix = `CARGO_REGISTRIES_${CARGO_REGISTRY_NAME.toUpperCase()}`, + indexEnvVar = `${registryEnvPrefix}_INDEX`, + tokenEnvVar = `${registryEnvPrefix}_TOKEN` + if (!process.env[indexEnvVar] || !process.env[tokenEnvVar]) { + throw new Error( + `cargo publish requires ${indexEnvVar} and ${tokenEnvVar} in the environment ` + + `(generate-opp-bundles.sh --publish exports them from the CodeArtifact token)` + ) + } + + log.info( + "Publishing cargo crate from %s to registry '%s'…", + dir, + CARGO_REGISTRY_NAME + ) + try { + // --allow-dirty: the output dir lives inside the wire-sysio checkout. + // --no-verify: skip the local crate build; consumers compile it and the + // proto provenance gate has already validated the sources. + const result = execFileSync( + "cargo", + ["publish", "--registry", CARGO_REGISTRY_NAME, "--allow-dirty", "--no-verify"], + { + cwd: dir, + encoding: "utf-8", + stdio: ["pipe", "pipe", "pipe"] + } + ) + log.info("Published cargo crate successfully: %s", result.trim()) + } catch (err: any) { + const stderr: string = err.stderr?.toString() ?? "" + if (/already exist|already uploaded|conflict/i.test(stderr)) { + log.warn( + "Cargo crate version already published — treating as success: %s", + stderr.trim() + ) + return + } + throw new Error(`cargo publish failed: ${stderr || err.message}`) + } +} + async function handlePublish( args: BundleArgs, baseOutputDir: string @@ -394,6 +451,12 @@ async function handlePublish( .forEach(target => { publishPackage(Path.join(baseOutputDir, target)) }) + + args.targets + .filter(t => CARGO_PUBLISHABLE_TARGETS.includes(t)) + .forEach(target => { + publishCargoCrate(Path.join(baseOutputDir, target)) + }) } function copyDirExcluding( diff --git a/libraries/opp/tools/protobuf-bundler/src/constants.ts b/libraries/opp/tools/protobuf-bundler/src/constants.ts index b694659988..ae9014fa7f 100644 --- a/libraries/opp/tools/protobuf-bundler/src/constants.ts +++ b/libraries/opp/tools/protobuf-bundler/src/constants.ts @@ -13,6 +13,22 @@ export const PUBLISHABLE_TARGETS: Target[] = [ Target.Solidity ] +/** Targets that are published to the WIRE CodeArtifact cargo registry (solana). */ +export const CARGO_PUBLISHABLE_TARGETS: Target[] = [Target.Solana] + +/** + * Cargo registry name for the WIRE CodeArtifact repository. The publish + * environment supplies `CARGO_REGISTRIES_WIRE_INDEX` / `_TOKEN` + * (see libraries/opp/tools/scripts/generate-opp-bundles.sh). + */ +export const CARGO_REGISTRY_NAME = "wire" + +/** SPDX license expression stamped into the generated Rust crate. */ +export const CRATE_LICENSE = "LicenseRef-Wire-Proprietary" + +/** Canonical repository URL stamped into the generated Rust crate. */ +export const CRATE_REPOSITORY_URL = "https://github.com/Wire-Network/wire-sysio" + /** * Canonical build order — typescript before solidity (dependency). * Solana is independent so its position doesn't matter. diff --git a/libraries/opp/tools/protobuf-bundler/src/index.ts b/libraries/opp/tools/protobuf-bundler/src/index.ts index e7a4ec4e85..f02cf17bfa 100644 --- a/libraries/opp/tools/protobuf-bundler/src/index.ts +++ b/libraries/opp/tools/protobuf-bundler/src/index.ts @@ -71,7 +71,7 @@ async function main(): Promise { type: "boolean", default: false, describe: - "Publish typescript/solidity packages to npm after generation." + "Publish typescript/solidity packages to npm and the solana crate to the WIRE cargo registry after generation." }) .option("verbose", { type: "boolean", diff --git a/libraries/opp/tools/protobuf-bundler/src/steps/generatePackage.ts b/libraries/opp/tools/protobuf-bundler/src/steps/generatePackage.ts index f3291614ad..292782b334 100644 --- a/libraries/opp/tools/protobuf-bundler/src/steps/generatePackage.ts +++ b/libraries/opp/tools/protobuf-bundler/src/steps/generatePackage.ts @@ -9,7 +9,10 @@ import { Target, TargetPackageName, TemplatePath, - TemplateFile + TemplateFile, + CARGO_REGISTRY_NAME, + CRATE_LICENSE, + CRATE_REPOSITORY_URL } from "../constants.js" /** @@ -91,6 +94,11 @@ async function generateSolanaPackage( packageName, version: packageVersion, repo, + license: CRATE_LICENSE, + repository: CRATE_REPOSITORY_URL, + // Restrict publishing to the WIRE registry — the crate can never be + // pushed to crates.io by accident. + publishRegistries: [CARGO_REGISTRY_NAME], modules: [] as string[], dependencies: {} } diff --git a/libraries/opp/tools/protobuf-bundler/templates/solana/Cargo.toml.hbs b/libraries/opp/tools/protobuf-bundler/templates/solana/Cargo.toml.hbs index 4cbd0d75da..75d10197d4 100644 --- a/libraries/opp/tools/protobuf-bundler/templates/solana/Cargo.toml.hbs +++ b/libraries/opp/tools/protobuf-bundler/templates/solana/Cargo.toml.hbs @@ -12,6 +12,9 @@ repository = "{{repository}}" {{#if authors}} authors = [{{#each authors}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}}] {{/if}} +{{#if publishRegistries}} +publish = [{{#each publishRegistries}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}}] +{{/if}} [features] default = [] diff --git a/libraries/opp/tools/scripts/generate-opp-bundles.sh b/libraries/opp/tools/scripts/generate-opp-bundles.sh index 03570ea890..085fa80ac6 100755 --- a/libraries/opp/tools/scripts/generate-opp-bundles.sh +++ b/libraries/opp/tools/scripts/generate-opp-bundles.sh @@ -30,6 +30,58 @@ done script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" tools_root="$(cd -- "$script_dir/.." && pwd -P)" repo_root="$(cd -- "$tools_root/../../.." && pwd -P)" + +# WIRE CodeArtifact cargo registry (provisioned by wire-infra +# ArtifactManagementStack). The generated wire-opp-solana-models crate is +# published here; the registry name "wire" must match CARGO_REGISTRY_NAME in +# protobuf-bundler/src/constants.ts. +codeartifact_domain="wire-pkg" +codeartifact_domain_owner="619322354039" +codeartifact_region="us-east-1" +cargo_registry_repository="wire-pkg-rust-private" +cargo_registry_index="sparse+https://${codeartifact_domain}-${codeartifact_domain_owner}.d.codeartifact.${codeartifact_region}.amazonaws.com/cargo/${cargo_registry_repository}/" +# Minimum cargo with sparse-registry + registry-token auth support. +cargo_minimum_version="1.74.0" + +# Publishing needs cargo (crate publish), the AWS CLI (CodeArtifact token), +# and AWS credentials (GitHub OIDC role in CI, an SSO profile locally). The +# validate path stays credential- and tool-free beyond node/pnpm. +if [[ "$publish" == true ]]; then + if ! command -v cargo >/dev/null 2>&1; then + echo "Error: cargo is required to publish the wire-opp-solana-models crate but is not in PATH." >&2 + exit 1 + fi + cargo_version="$(cargo --version | awk '{print $2}')" + if [[ "$(printf '%s\n' "$cargo_minimum_version" "$cargo_version" | sort -V | head -1)" != "$cargo_minimum_version" ]]; then + echo "Error: cargo >= $cargo_minimum_version is required for sparse registry auth (found $cargo_version)." >&2 + exit 1 + fi + if ! command -v aws >/dev/null 2>&1; then + echo "Error: the AWS CLI is required to mint the CodeArtifact publish token but is not in PATH." >&2 + exit 1 + fi + + echo "Fetching CodeArtifact authorization token for cargo publish..." + cargo_registry_token="$(aws codeartifact get-authorization-token \ + --domain "$codeartifact_domain" \ + --domain-owner "$codeartifact_domain_owner" \ + --region "$codeartifact_region" \ + --query authorizationToken \ + --output text)" + if [[ -z "$cargo_registry_token" ]]; then + echo "Error: failed to obtain a CodeArtifact authorization token." >&2 + exit 1 + fi + # Keep the token out of GitHub Actions logs; the marker is emitted only in CI. + if [[ "${GITHUB_ACTIONS:-}" == "true" ]]; then + echo "::add-mask::${cargo_registry_token}" + fi + export CARGO_REGISTRIES_WIRE_INDEX="$cargo_registry_index" + export CARGO_REGISTRIES_WIRE_TOKEN="$cargo_registry_token" + # Authenticated alternative registries refuse to operate without an + # explicit credential provider; cargo:token reads the _TOKEN env var above. + export CARGO_REGISTRIES_WIRE_CREDENTIAL_PROVIDER="cargo:token" +fi repo_proto_src_path="$repo_root/libraries/opp/proto" repo_output_path="$repo_root/build/opp" output_paths=("$repo_output_path") From c41ad3069980e6773be170d26ca2c50217859acd Mon Sep 17 00:00:00 2001 From: Jonathan Glanz Date: Mon, 13 Jul 2026 18:45:30 -0400 Subject: [PATCH 7/7] fix(opp): publish wire-opp-solana-models to the PUBLIC cargo repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consumers (wire-solana et al) read the crate anonymously via https://public.crates.pkgs.wire-dev.com — no AWS credentials required. Publishing is unchanged: the GitHub OIDC publisher role authenticates against the native CodeArtifact endpoint. Co-Authored-By: Claude Fable 5 Change-Id: Ibcd739e40800154d7b3a30069aab9880deaaf919 --- libraries/opp/tools/scripts/generate-opp-bundles.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/opp/tools/scripts/generate-opp-bundles.sh b/libraries/opp/tools/scripts/generate-opp-bundles.sh index 085fa80ac6..a3582f584f 100755 --- a/libraries/opp/tools/scripts/generate-opp-bundles.sh +++ b/libraries/opp/tools/scripts/generate-opp-bundles.sh @@ -33,12 +33,15 @@ repo_root="$(cd -- "$tools_root/../../.." && pwd -P)" # WIRE CodeArtifact cargo registry (provisioned by wire-infra # ArtifactManagementStack). The generated wire-opp-solana-models crate is -# published here; the registry name "wire" must match CARGO_REGISTRY_NAME in -# protobuf-bundler/src/constants.ts. +# published to the PUBLIC repository — consumers (wire-solana et al) read it +# anonymously via https://public.crates.pkgs.wire-dev.com with no AWS auth. +# The registry name "wire" must match CARGO_REGISTRY_NAME in +# protobuf-bundler/src/constants.ts. Publishing still authenticates against +# the native CodeArtifact endpoint (GitHub OIDC publisher role). codeartifact_domain="wire-pkg" codeartifact_domain_owner="619322354039" codeartifact_region="us-east-1" -cargo_registry_repository="wire-pkg-rust-private" +cargo_registry_repository="wire-pkg-rust-public" cargo_registry_index="sparse+https://${codeartifact_domain}-${codeartifact_domain_owner}.d.codeartifact.${codeartifact_region}.amazonaws.com/cargo/${cargo_registry_repository}/" # Minimum cargo with sparse-registry + registry-token auth support. cargo_minimum_version="1.74.0"