Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions .github/workflows/conan_create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,38 @@ jobs:
CC: ${{ matrix.compiler[0] }}
CXX: ${{ matrix.compiler[1] }}
run: |
conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True
conan create . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True
- name: Generate CycloneDX SBOM from canonical Conan lockfile
if: matrix.compiler[0] == 'gcc'
run: |
rm -rf sbom
conan install . \
--lockfile=conan/safe-defaults.lock \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need to use the lockfile for the conan create command. To ensure that both commands use the same deps (and do not build libs twice).

I also think we should use the lock file in the rest of the conan builds. This ensures that the CI builds are reproducible, including upstream dependencies.

--deployer=cyclone_1.6 \
--deployer-folder=sbom \
-b missing \
-pr:b default \
-pr:h default \
-s:h build_type=${{ matrix.type }} \
-o celix/*:build_all=True \
-o celix/*:celix_cxx17=True \
-o mosquitto/*:broker=True \
-o *:shared=True
- name: Upload canonical Conan lockfile and CycloneDX SBOM
if: matrix.compiler[0] == 'gcc'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2

@PengZheng PengZheng Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my understanding, SBOM should be used with the final binary, thus uploading SBOM alone makes no sense.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the SBOM to scan the resolved dependencies for vulnerabilities, as described in a separate follow-up ticket: [#825](#825).

Then we at least know which vulnerabilities exist in the dependencies selected by the current default resolution. However, I am not sure how useful this is without a conan.lock file. With a lockfile, the Celix sources would include a reproducible, resolved dependency list.

Maybe we could generate the lockfile for a GCC Linux build on Ubuntu with build_all=True and use it as our canonical dependency reference. It could then serve as the basis for future vulnerability scans and help ensure more reproducible builds. (and we should document the intended use for a the lockfile and explain that celix is useable without a lockfile).

@PengZheng, maybe we should introduce such a lockfile. WDYT?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the SBOM to scan the resolved dependencies for vulnerabilities, as described in a separate follow-up ticket: [#825](#825).

This can be done with Conan Audit. We can use it to generate vulnerabilities reports so that we can update Celix dependencies promptly to provide our users with safe defaults.

maybe we should introduce such a lockfile. WDYT?

Both SBOM and lockfile are associated with a specific set of dependencies/options, and our users have freedom to change them at their will. IMHO, providing them a safe defaults should be enough for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both SBOM and lockfile are associated with a specific set of dependencies/options, and our users have freedom to change them at their will. IMHO, providing them a safe defaults should be enough for now.

To ensure we are the same page, do you mean that

a) we should not configure a lock file in our source control

or

b) we can provide a lock file and sbom, but we should communicate that this is a safe defaults, and users have to freedom to change the dependency versions when needed.

I think I prefer option b, but then also document this more clearly (lock file exists for safe defaults, and help in reproducible builds during development)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer option b, but then also document this more clearly (lock file exists for safe defaults, and help in reproducible builds during development)

I agree.

with:
name: celix-conan-safe-defaults
path: |
conan/safe-defaults.lock
sbom/sbom-cyclonedx-1.6.json
if-no-files-found: error
- name: Dependency Deduction Test
env:
CC: ${{ matrix.compiler[0] }}
CXX: ${{ matrix.compiler[1] }}
run: |
conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done
conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done
- name: Remove Celix
run: |
conan remove -c celix/*
Expand Down Expand Up @@ -116,10 +141,10 @@ jobs:
${{ runner.os }}-ccache-Release-
- name: Create Celix
run: |
conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o celix/*:enable_address_sanitizer=True -o mosquitto/*:broker=True -o *:shared=True
conan create . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o celix/*:enable_address_sanitizer=True -o mosquitto/*:broker=True -o *:shared=True
- name: Dependency Deduction Test
run: |
conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ && !/build_rsa_remote_service_admin_shm_v2/ && !/build_rsa_discovery_zeroconf/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done
conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ && !/build_rsa_remote_service_admin_shm_v2/ && !/build_rsa_discovery_zeroconf/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done
- name: Remove Celix
run: |
conan remove -c celix/*
2 changes: 1 addition & 1 deletion .github/workflows/containers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
-v ~/.ccache-container:/bome/celixdev/.ccache \
-v $(pwd):/home/celixdev/workspace apache/celix-conan-build:latest /bin/bash -c \
"cd /home/celixdev/workspace && \
conan build . -pr:b release -pr:h debug --build=missing \
conan build . --lockfile=conan/safe-defaults.lock -pr:b release -pr:h debug --build=missing \
--options celix/*:build_all=True --options celix/*:enable_address_sanitizer=True \
--options celix/*:enable_testing=True --options celix/*:enable_ccache=True \
-o mosquitto/*:broker=True -o *:shared=True \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
-o mosquitto/*:broker=True
-o *:shared=True
run: |
conan build . -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
conan build . --lockfile=conan/safe-defaults.lock -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
- name: Test with coverage
run: |
cd build/Debug
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/fuzzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
-o celix/*:enable_undefined_sanitizer=True
-o celix/*:celix_err_buffer_size=5120
-o *:shared=True
run: conan build -c tools.cmake.cmaketoolchain:generator=Ninja ${CONAN_BUILD_OPTIONS} -b missing
run: conan build --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja ${CONAN_BUILD_OPTIONS} -b missing
- name: Set fuzzer run time
id: set-runtime
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
-o mosquitto/*:broker=True
-o *:shared=True
run: |
conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release ${CONAN_BUILD_OPTIONS} -b missing
conan build . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release ${CONAN_BUILD_OPTIONS} -b missing
- name: Test
run: ctest --preset conan-release --output-on-failure -j1

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
-o mosquitto/*:broker=True
-o *:shared=True
run: |
conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
conan build . --lockfile=conan/safe-defaults.lock -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
- name: Test
env:
CONAN_PRESET: ${{ matrix.type == 'Debug' && 'conan-debug' || 'conan-relwithdebinfo' }}
Expand Down
64 changes: 64 additions & 0 deletions conan/safe-defaults.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"version": "0.5",
"requires": [
"zstd/1.5.7#b68ca8e3de04ba5957761751d1d661f4%1760955092.069",
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1765284699.337",
"xz_utils/5.8.3#a8432fead347c69d8b2737c35f936132%1775752656.4",
"util-linux-libuuid/2.41.2#3ba347c98172dadfe417700cf399adac%1781172622.732",
"rapidjson/1.1.0#9f5e39d1f4a6b67d48c6a343c4592f32%1705070241.006",
"openssl/3.6.3#a81313131c78c6414f25b5fe0a83204b%1783446193.901",
"mosquitto/2.0.22#2800cdcc6c3ad3fcfe274c905a73a853%1765786795.688",
"mdnsresponder/1310.140.1#5116b98dc767ebb2ea48a2a584a365b4%1686542086.05",
"libzip/1.11.4#cf55b90c94be0184eae424ce54e71247%1778489193.132",
"libxml2/2.15.3#3406c6d8d327e9b84c0c894feb859514%1777886326.291",
"libuv/1.51.0#ea781dcacf58c65462ab0d3d75e9b002%1764745176.352",
"libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1774021608.288",
"libgettext/0.22#b09eea019e19b9b9c46d8f1da7d75444%1765809130.834",
"libffi/3.4.8#a045c00fb26779635e3bed40e80c5254%1753360042.396",
"libcurl/8.21.0#dd94e078c967e162aae33d353142fa31%1786959569.239",
"jansson/2.14#7710071716bc129093fec1cc4d19f424%1760696859.73",
"gtest/1.17.0#43201cc96e5d35332662ce8890cceb27%1786446850.202",
"gettext/0.21#b0c966878ab30fc52d80173175a0423c%1765299123.464",
"civetweb/1.16#f4a42c8aa0bc0fe4bbe2a2270af0cea2%1750148475.207",
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1762886692.465",
"benchmark/1.9.5#b885dc73ad67b40a55d45684d1c88ad1%1774363287.434"
],
"build_requires": [
"zstd/1.5.5#a4398ab5244b10fb081eeac217b5ef9f%1760955096.505",
"pkgconf/2.5.1#93c2051284cba1279494a43a4fcfeae2%1757684701.089",
"ninja/1.13.2#c8c5dc2a52ed6e4e42a66d75b4717ceb%1764096931.974",
"meson/1.10.2#9d2d10681fe7fe61c788c58626c89b25%1775558003.754",
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
"libtool/2.4.7#14e7739cc128bc1623d2ed318008e47e%1755679003.847",
"hiredis/1.1.0#8b3ef72a6cee0e83ddbe0b52da5ceb54%1744279491.095",
"gnu-config/cci.20210814#466e9d4d7779e1c142443f7ea44b4284%1762363589.329",
"cmake/3.26.4#0b40747e190e755932767f2ec4768ff5%1685461463.385",
"ccache/4.7.4#83eaaa1059cdc33a90eb35249e1df6fb%1689758368.487",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86"
],
"python_requires": [],
"overrides": {
"openssl/[>=3.2.0 <4]": [
"openssl/3.6.3"
],
"zlib/[>=1.2.11 <2]": [
"zlib/1.3.1"
],
"openssl/[>=1.1 <4]": [
"openssl/3.6.3#a81313131c78c6414f25b5fe0a83204b",
"openssl/[>=3.2.0 <4]"
],
"openssl/[>=3 <4]": [
"openssl/3.6.3",
"openssl/[>=3.2.0 <4]"
],
"zlib/[>=1.3.1 <2]": [
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20"
],
"openssl/[>=1 <4]": [
"openssl/3.6.3#a81313131c78c6414f25b5fe0a83204b"
]
},
"config_requires": []
}
1 change: 1 addition & 0 deletions documents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ bundles contains binaries depending on the stdlibc++ library.

* Building
* [Building and Installing Apache Celix](building/README.md)
* [Software Bill of Materials](building/sbom.md)
* C Patterns
* [Apache Celix C Patterns](c_patterns.md)
* Utils
Expand Down
117 changes: 117 additions & 0 deletions documents/building/sbom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
title: Software Bill of Materials
---

<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Software Bill of Materials

Apache Celix provides a committed `conan/safe-defaults.lock` that pins the
recipe revisions used across the Conan CI builds. CI also publishes a
CycloneDX 1.6 SBOM for one documented Linux / GCC / Release configuration.
Together they provide a reproducible **safe-default dependency baseline** for
development and vulnerability review.

The lockfile is intentionally not named `conan.lock` at the repository root.
Conan automatically discovers a root `conan.lock` for ordinary commands, which
would make the baseline an implicit constraint on unrelated builds. Keeping the
safe-default lockfile at an explicit path means users opt in to it with
`--lockfile=conan/safe-defaults.lock`.

The lockfile is not a repository-wide dependency mandate. Celix users remain
free to build without the lockfile, override dependency versions, or maintain a
lockfile for their own application configuration. When those inputs change,
the resulting dependency graph and SBOM can change as well.

## Canonical safe-default configuration

The canonical SBOM baseline is the Linux / GCC / Release Conan graph with:

* `celix/*:build_all=True`
* `celix/*:celix_cxx17=True`
* `mosquitto/*:broker=True`
* `*:shared=True`

The lockfile also contains recipe revisions required by the other supported
Conan CI graphs, including platform-specific macOS dependencies. Those extra
entries make the CI dependency resolution reproducible without changing the
contents of the Linux / GCC / Release SBOM; Conan uses only the entries needed
by the selected graph.

The CI-only `enable_ccache` option is intentionally not part of this baseline;
ccache accelerates compilation but should not define the dependency policy
presented to downstream Celix users.

This baseline does not claim to describe every possible Celix build. Different
platforms, build types, option sets, or user-selected dependency overrides can
produce different graphs.

## CI generation

The Conan CI builds explicitly use `conan/safe-defaults.lock` so their
upstream recipe revisions remain reproducible. For the Linux GCC Release
configuration, CI additionally generates the CycloneDX SBOM with Conan's
built-in deployer using the same lockfile:

```bash
conan install . \
--lockfile=conan/safe-defaults.lock \
--deployer=cyclone_1.6 \
--deployer-folder=sbom \
-b missing \
-pr:b default \
-pr:h default \
-s:h build_type=Release \
-o celix/*:build_all=True \
-o celix/*:celix_cxx17=True \
-o mosquitto/*:broker=True \
-o *:shared=True
```

Using the lockfile means the SBOM is generated from the exact recipe revisions
selected by the committed baseline rather than whatever dependency revisions
happen to be newest when CI runs. If the lockfile no longer satisfies the Celix
recipe, the CI step fails instead of silently generating evidence for a
different graph.

CI publishes `conan/safe-defaults.lock` and
`sbom/sbom-cyclonedx-1.6.json` together as the
`celix-conan-safe-defaults` workflow artifact.

## Using the baseline locally

After creating a Conan profile compatible with the configuration above, opt in
to the committed lockfile to reproduce the safe-default graph:

```bash
conan install . \
--lockfile=conan/safe-defaults.lock \
-b missing \
-pr:b default \
-pr:h default \
-s:h build_type=Release \
-o celix/*:build_all=True \
-o celix/*:celix_cxx17=True \
-o mosquitto/*:broker=True \
-o *:shared=True
```

Applications may intentionally choose newer or different dependencies instead.
In that case, generate and retain a lockfile and SBOM for that application
configuration rather than treating the Celix safe-default files as evidence for
a graph they do not describe.