diff --git a/info.yml b/info.yml index 43b62da..d8c69ce 100644 --- a/info.yml +++ b/info.yml @@ -1,7 +1,7 @@ name: crun description: A fast and lightweight fully featured OCI runtime and C library for running containers -version: "1.28" -revision: 2 +version: 1.29.1 +revision: 1 url: https://github.com/containers/crun license: GPL2-or-later,LGPL2.1-or-later maintainers: @@ -14,6 +14,7 @@ depends: - libseccomp - libudev make_depends: + - criu - go-md2man - libtool - python3=3.14.* @@ -24,4 +25,4 @@ downloads: - url: https://github.com/containers/crun/releases/download/${BPM_PKG_VERSION}/crun-${BPM_PKG_VERSION}.tar.gz extract_to: ${BPM_SOURCE} extract_strip_components: 1 - checksum: eb8fe73ffe44d868b14bb94fa6c295bd57e8bf023de43b61579da826c07cc406 + checksum: b6be9fd9613efe5df414c568ddfaf09857c72ec17a00999f15c132a3d9e120fd diff --git a/recipe.sh b/recipe.sh index 0fe7733..021ef8f 100644 --- a/recipe.sh +++ b/recipe.sh @@ -7,6 +7,7 @@ prepare() { cd "$BPM_SOURCE" patch -Np1 -i "$BPM_WORKDIR"/0001-fix-missing-json-c-symbols-in-build.patch + patch -Np1 -i "$BPM_WORKDIR"/2188.patch ./autogen.sh } diff --git a/source-files/2188.patch b/source-files/2188.patch new file mode 100644 index 0000000..e8263b7 --- /dev/null +++ b/source-files/2188.patch @@ -0,0 +1,511 @@ +From b5d243463c24309b155f9b6e98544ab8e8046fba Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:11:13 +0000 +Subject: [PATCH 1/9] libcrun: export parse_json_file for the language bindings + +The Python and Lua bindings parse a process JSON blob (in their +update/exec helpers) with parse_json_file() before calling +libcrun_container_exec(). libcrun is built with -fvisibility=hidden and +a version script (libcrun.lds) that only exports symbols matching a few +name patterns, so parse_json_file was not exported and loading either +module failed with: + + undefined symbol: parse_json_file + +Mark it LIBCRUN_PUBLIC (so it reaches the dynamic symbol table) and add +it to the version script global list (both are required to export it). + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + libcrun.lds | 2 ++ + src/libcrun/utils.h | 4 +++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libcrun.lds b/libcrun.lds +index 8e141724d2..c9cdce5466 100644 +--- a/libcrun.lds ++++ b/libcrun.lds +@@ -2,6 +2,8 @@ + global: + /* Not all the libcrun_ functions are exported, only those marked LIBCRUN_PUBLIC. */ + libcrun_*; ++ /* Utility used by the language bindings (python/, lua/). */ ++ parse_json_file; + /* libocispec functions */ + runtime_spec_*; + free_runtime_spec_*; +diff --git a/src/libcrun/utils.h b/src/libcrun/utils.h +index 4e8d100790..2304196f9b 100644 +--- a/src/libcrun/utils.h ++++ b/src/libcrun/utils.h +@@ -352,7 +352,9 @@ void get_current_timestamp (char *out, size_t len); + + int set_blocking_fd (int fd, bool blocking, libcrun_error_t *err); + +-int parse_json_file (json_object **out, const char *jsondata, struct parser_context *ctx, libcrun_error_t *err); ++/* Exported for the language bindings (python/, lua/), which parse a ++ process JSON blob before calling libcrun_container_exec. */ ++LIBCRUN_PUBLIC int parse_json_file (json_object **out, const char *jsondata, struct parser_context *ctx, libcrun_error_t *err); + + /* Check that the string STR has the prefix PREFIX. */ + static inline int + +From ef6b9343fcee52b7442b11c1457a0d60f0678437 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:11:13 +0000 +Subject: [PATCH 2/9] libcrun: guard _GNU_SOURCE redefinition in string_map.h + +Python.h defines _GNU_SOURCE to 1, so a translation unit that includes +it before string_map.h (as the Python binding does, transitively via +container.h) hits a "_GNU_SOURCE redefined" warning, which is fatal +under -Werror. Only define it when it is not already defined. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + src/libcrun/string_map.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/libcrun/string_map.h b/src/libcrun/string_map.h +index 9819df1b87..f647769190 100644 +--- a/src/libcrun/string_map.h ++++ b/src/libcrun/string_map.h +@@ -19,7 +19,9 @@ + #ifndef STRING_MAP_H + #define STRING_MAP_H + +-#define _GNU_SOURCE ++#ifndef _GNU_SOURCE ++# define _GNU_SOURCE ++#endif + + #include + + +From 004cf513da2924a25a891082671b332f08c2d8f5 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:13:14 +0000 +Subject: [PATCH 3/9] python: include libcrun/spec.h for libcrun_container_spec + +libcrun_container_spec() moved from container.h to spec.h, but the +Python bindings were never updated and still only included container.h. +Building the bindings failed with an implicit-declaration error. Add +the missing include. + +Closes: https://github.com/containers/crun/issues/2187 +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + python/crun_python.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/python/crun_python.c b/python/crun_python.c +index 47bd7b1608..8846f32d07 100644 +--- a/python/crun_python.c ++++ b/python/crun_python.c +@@ -36,6 +36,7 @@ python_crun.run(ctx, ctr) + #include + #include + #include ++#include + #include + #include + + +From f757ac4fcf84d5e5f6c1867cc69669f9c3c26ee6 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:13:23 +0000 +Subject: [PATCH 4/9] python: register the missing start method + +container_start() was defined but never added to the method table, so +python_crun had no "start" entry and the function triggered a +-Werror=unused-function build failure. Register it. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + python/crun_python.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/python/crun_python.c b/python/crun_python.c +index 8846f32d07..34fd2297d3 100644 +--- a/python/crun_python.c ++++ b/python/crun_python.c +@@ -468,6 +468,7 @@ static PyMethodDef CrunMethods[] = { + {"create", container_create, METH_VARARGS, "Create a container."}, + {"delete", container_delete, METH_VARARGS, "Delete a container."}, + {"kill", container_kill, METH_VARARGS, "Kill a container."}, ++ {"start", container_start, METH_VARARGS, "Start a container."}, + {"list", containers_list, METH_VARARGS, "List the containers."}, + {"status", container_status, METH_VARARGS, + "Get the status of a container."}, + +From 0c1b48c848b21624ae72fde01b551e114f658629 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:13:31 +0000 +Subject: [PATCH 5/9] python: drop the duplicate spec method entry + +The method table registered "spec" twice with the same handler. The +duplicate is harmless at runtime but confusing; remove it. "spec" +remains available via the earlier entry. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + python/crun_python.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/python/crun_python.c b/python/crun_python.c +index 34fd2297d3..0958c3f3e5 100644 +--- a/python/crun_python.c ++++ b/python/crun_python.c +@@ -480,8 +480,6 @@ static PyMethodDef CrunMethods[] = { + "Create a context object."}, + {"set_verbosity", set_verbosity, METH_VARARGS, "Set the logging verbosity."}, + {"get_verbosity", get_verbosity, METH_NOARGS, "Get the logging verbosity."}, +- {"spec", container_spec, METH_VARARGS, +- "Generate a new configuration file."}, + {NULL, NULL, 0, NULL} + }; + + +From 3a605804159b7d3ec8ca1a4086517f8c089901f5 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:14:08 +0000 +Subject: [PATCH 6/9] python: fix context capsule destructor and drop dead code + +make_context() created its capsule with a NULL destructor, so the +libcrun_context_t and its strdup'd fields leaked whenever a context was +garbage collected. It also leaked the freshly allocated context if +argument parsing failed. + +Wire up free_context() as the capsule destructor and free the context +on the parse-error path. free_context() now retrieves the pointer with +PyCapsule_GetPointer() (the previous cast of the raw PyObject* was +wrong for a capsule destructor) and also frees the previously-forgotten +bundle field. + +While here, remove unused local variables from container_status, +container_spec and set_verbosity that tripped -Werror. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + python/crun_python.c | 35 ++++++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/python/crun_python.c b/python/crun_python.c +index 0958c3f3e5..b14994f757 100644 +--- a/python/crun_python.c ++++ b/python/crun_python.c +@@ -106,13 +106,23 @@ container_load_from_memory (PyObject *self arg_unused, PyObject *args) + } + + static void +-free_context (void *ptr) ++free_context (PyObject *ptr) + { +- libcrun_context_t *ctx = ptr; +- char *id = (char *) ctx->id; +- free (ctx->state_root); +- free (ctx->notify_socket); ++ libcrun_context_t *ctx = PyCapsule_GetPointer (ptr, CONTEXT_OBJ_TAG); ++ void *id, *bundle, *state_root, *notify_socket; ++ ++ if (ctx == NULL) ++ return; ++ ++ id = (void *) ctx->id; ++ bundle = (void *) ctx->bundle; ++ state_root = (void *) ctx->state_root; ++ notify_socket = (void *) ctx->notify_socket; ++ + free (id); ++ free (bundle); ++ free (state_root); ++ free (notify_socket); + free (ctx); + } + +@@ -135,13 +145,16 @@ make_context (PyObject *self arg_unused, PyObject *args, PyObject *kwargs) + if (!PyArg_ParseTupleAndKeywords + (args, kwargs, "s|ssbsbbbb", kwlist, &id, &bundle, &state_root, + &ctx->systemd_cgroup, ¬ify_socket, &ctx->detach, &ctx->no_new_keyring, &ctx->force_no_cgroup, &ctx->no_pivot)) +- return NULL; ++ { ++ free (ctx); ++ return NULL; ++ } + + ctx->id = xstrdup (id); + ctx->bundle = xstrdup (bundle ? bundle : "."); + ctx->state_root = xstrdup (state_root); + ctx->notify_socket = xstrdup (notify_socket); +- return PyCapsule_New (ctx, CONTEXT_OBJ_TAG, NULL); ++ return PyCapsule_New (ctx, CONTEXT_OBJ_TAG, free_context); + } + + static PyObject * +@@ -329,7 +342,6 @@ container_status (PyObject *self arg_unused, PyObject *args) + PyObject *ctx_obj = NULL; + libcrun_context_t *ctx; + char *id = NULL; +- libcrun_container_status_t status; + cleanup_free char *buffer = NULL; + FILE *memfile; + int ret; +@@ -414,10 +426,6 @@ static PyObject * + container_spec (PyObject *self arg_unused, PyObject *args arg_unused) + { + libcrun_error_t err = NULL; +- PyObject *ctx_obj = NULL; +- libcrun_context_t *ctx; +- char *id = NULL; +- libcrun_container_status_t status; + cleanup_free char *buffer = NULL; + FILE *memfile; + int ret; +@@ -447,9 +455,6 @@ get_verbosity (PyObject *self arg_unused, PyObject *args) + static PyObject * + set_verbosity (PyObject *self arg_unused, PyObject *args) + { +- libcrun_error_t err; +- PyObject *ctx_obj = NULL; +- libcrun_context_t *ctx; + int verbosity; + + if (!PyArg_ParseTuple (args, "i", &verbosity)) + +From 7369dcf9ecf4aef7caa924188c49332db64b3418 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:14:25 +0000 +Subject: [PATCH 7/9] lua: include libcrun/spec.h for libcrun_container_spec + +libcrun_container_spec() moved from container.h to spec.h, but the Lua +bindings still only included container.h. Building the bindings failed +with an implicit-declaration error. Add the missing include. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + lua/lua_crun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lua/lua_crun.c b/lua/lua_crun.c +index cdd22b8907..fc0fecb97f 100644 +--- a/lua/lua_crun.c ++++ b/lua/lua_crun.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + + +From a1bc828ecd2cdd2e697a5b12d81d12411ff730cb Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:14:33 +0000 +Subject: [PATCH 8/9] lua: return luaL_error from luacrun_ctx_run + +luaL_error() is not declared as noreturn, so falling off the end of the +function after calling it triggered a -Werror=return-type build failure. +Return its result (it never actually returns) to satisfy the compiler. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + lua/lua_crun.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lua/lua_crun.c b/lua/lua_crun.c +index fc0fecb97f..84ca34ebc3 100644 +--- a/lua/lua_crun.c ++++ b/lua/lua_crun.c +@@ -369,7 +369,7 @@ luacrun_ctx_run (lua_State *S) + lua_pushnil (S); + return luacrun_error (S, &crun_err) + 1; + } else { +- luaL_error(S, "failed to run container"); ++ return luaL_error (S, "failed to run container"); + } + } + else + +From 9d97f481028f912e06ff3679a51a083af63d00ac Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Thu, 13 Aug 2026 15:14:45 +0000 +Subject: [PATCH 9/9] ci: build and smoke-test the Python and Lua bindings + +The language bindings link against internal libcrun symbols but were +never built in CI, so API drift (libcrun_container_spec moving to +spec.h) and missing symbol exports (parse_json_file) went unnoticed +until a build broke. + +Add a "bindings" test job that configures with --with-python-bindings +and --with-lua-bindings under -Werror, builds the modules, and loads +each freshly built module to run a smoke test. The smoke tests check +that spec generation still works, that every documented entry point is +registered, that the verbosity constants exist, and that loading a +container resolves all the needed symbols. + +Ship the new test scripts in the tarball via EXTRA_DIST. + +Co-Authored-By: Claude Opus 4.8 +Signed-off-by: Giuseppe Scrivano +--- + Makefile.am | 3 +- + lua/test_lua_bindings.lua | 56 +++++++++++++++++++++++++++++ + python/test_python_bindings.py | 64 ++++++++++++++++++++++++++++++++++ + 4 files changed, 136 insertions(+), 2 deletions(-) + create mode 100644 lua/test_lua_bindings.lua + create mode 100644 python/test_python_bindings.py + +diff --git a/Makefile.am b/Makefile.am +index 6905f5fa2e..4266b134a9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -186,7 +186,8 @@ EXTRA_DIST = COPYING COPYING.libcrun README.md NEWS SECURITY.md rpm/crun.spec au + src/libcrun/syscalls.h \ + crun.1.md crun.1 libcrun.lds \ + krun.1.md krun.1 \ +- lua/luacrun.rockspec ++ lua/luacrun.rockspec lua/test_lua_bindings.lua \ ++ python/test_python_bindings.py + + if !HAVE_EMBEDDED_BLAKE3 + EXTRA_DIST += src/libcrun/blake3/blake3.c \ +diff --git a/lua/test_lua_bindings.lua b/lua/test_lua_bindings.lua +new file mode 100644 +index 0000000000..468f296204 +--- /dev/null ++++ b/lua/test_lua_bindings.lua +@@ -0,0 +1,56 @@ ++-- crun - OCI runtime written in C ++-- ++-- Copyright (C) 2026 crun Authors ++-- crun is free software; you can redistribute it and/or modify ++-- it under the terms of the GNU Lesser General Public License as published by ++-- the Free Software Foundation; either version 2.1 of the License, or ++-- (at your option) any later version. ++-- ++-- crun is distributed in the hope that it will be useful, ++-- but WITHOUT ANY WARRANTY; without even the implied warranty of ++-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++-- GNU Lesser General Public License for more details. ++-- ++-- You should have received a copy of the GNU Lesser General Public License ++-- along with crun. If not, see . ++-- ++-- Smoke test for the Lua bindings. It does not run a container (that ++-- requires a privileged environment); it only exercises the parts of the ++-- module that must keep working so a build/link regression is caught early. ++-- Set package.cpath (or LUA_CPATH) so that require("luacrun") resolves to ++-- the freshly built luacrun.so before running. ++ ++local crun = require("luacrun") ++ ++-- Spec generation must keep working (feature exercised by callers). ++local spec = crun.container_spec(true) ++assert(type(spec) == "string" and #spec > 0, "generated spec is empty") ++assert(spec:find("ociVersion"), "generated spec has no ociVersion") ++ ++-- Every documented entry point must be present. This also catches a missing ++-- registration in luacrun_library_reg. ++local expected = { ++ "new_ctx", "container_spec", "new_container_from_string", ++ "new_container_from_file", "get_verbosity", "set_verbosity", "run", ++ "create_container", "delete_container", "kill_container", ++ "start_container", "status_container", "iter_container_names", ++ "update_container", ++} ++for _, name in ipairs(expected) do ++ assert(crun[name] ~= nil, "missing function " .. name) ++end ++ ++-- Verbosity constants. ++for _, name in ipairs({ "VERBOSITY_ERROR", "VERBOSITY_WARNING", "VERBOSITY_DEBUG" }) do ++ assert(crun[name] ~= nil, "missing constant " .. name) ++end ++ ++crun.set_verbosity(crun.VERBOSITY_ERROR) ++assert(crun.get_verbosity() == crun.VERBOSITY_ERROR, "verbosity round-trip failed") ++ ++-- Loading a container from the generated spec must resolve every symbol the ++-- module needs (this is what caught the missing parse_json_file / ++-- libcrun_container_spec exports). ++assert(crun.new_container_from_string(spec) ~= nil, "new_container_from_string failed") ++ ++print("lua bindings smoke test: OK") +diff --git a/python/test_python_bindings.py b/python/test_python_bindings.py +new file mode 100644 +index 0000000000..3acd76ef1a +--- /dev/null ++++ b/python/test_python_bindings.py +@@ -0,0 +1,64 @@ ++#!/usr/bin/env python3 ++# crun - OCI runtime written in C ++# ++# Copyright (C) 2026 crun Authors ++# crun is free software; you can redistribute it and/or modify ++# it under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++# ++# crun is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public License ++# along with crun. If not, see . ++# ++# Smoke test for the Python bindings. It does not run a container (that ++# requires a privileged environment); it only exercises the parts of the ++# module that must keep working so a build/link regression is caught early. ++# Point PYTHONPATH at the directory holding python_crun.so before running. ++ ++import gc ++import json ++import sys ++ ++import python_crun ++ ++ ++def main(): ++ # Spec generation must keep working (feature exercised by callers). ++ spec = json.loads(python_crun.spec()) ++ assert spec.get("ociVersion"), "generated spec has no ociVersion" ++ assert spec["process"]["args"], "generated spec has no process args" ++ ++ # Every documented entry point must be present. ++ expected = [ ++ "load_from_file", "load_from_memory", "run", "create", "delete", ++ "kill", "start", "list", "status", "update", "spec", "make_context", ++ "set_verbosity", "get_verbosity", ++ ] ++ missing = [name for name in expected if not hasattr(python_crun, name)] ++ assert not missing, "missing methods: %s" % missing ++ ++ # Verbosity constants. ++ for const in ("VERBOSITY_ERROR", "VERBOSITY_WARNING", "VERBOSITY_DEBUG"): ++ assert hasattr(python_crun, const), "missing constant %s" % const ++ ++ # Loading a container from the generated spec must resolve every symbol ++ # the module needs (this is what caught the missing parse_json_file / ++ # libcrun_container_spec exports). ++ python_crun.load_from_memory(json.dumps(spec)) ++ ++ # Creating and dropping a context must run the capsule destructor without ++ # crashing. ++ ctx = python_crun.make_context("crun-python-smoke-test") ++ del ctx ++ gc.collect() ++ ++ print("python bindings smoke test: OK") ++ ++ ++if __name__ == "__main__": ++ sys.exit(main())