Security & Supply Chain
This page documents the security model and supply chain integrity measures for the duckdb-behavioral extension.
Versioning
This project follows Semantic Versioning (SemVer).
Version format: MAJOR.MINOR.PATCH (e.g., 0.1.0, 1.0.0, 1.2.3)
| Component | Bumped when |
|---|---|
| MAJOR | Breaking changes to SQL function signatures, return types, or behavior |
| MINOR | New functions, new modes, new pattern syntax operators |
| PATCH | Bug fixes, performance improvements, documentation updates |
Pre-1.0 policy: While the version is 0.x.y, MINOR bumps may include
breaking changes per SemVer section 4.
Version sources: The version is maintained in three files that must stay in sync:
Cargo.toml(version = "X.Y.Z")description.yml(version: X.Y.Z)- Git tag (
vX.Y.Z)
The release workflow validates that all three match before building.
Dependency Audit
Runtime Dependencies
The extension has exactly two runtime dependencies:
| Crate | Version | Purpose |
|---|---|---|
quack-rs | =0.18.0 | Rust SDK for DuckDB loadable extensions — entry point macro, aggregate builders, safe state management, vector I/O |
libduckdb-sys | =1.10506.0 | DuckDB C API bindings (re-exported by quack-rs; pinned explicitly because the FFI callbacks use its raw types) |
Both versions are pinned exactly to prevent silent dependency updates.
quack-rs provides entry_point_v2!, Connection/Registrar trait,
AggregateFunctionSetBuilder, FfiState<T>, VectorReader/VectorWriter,
the aggregate_{update,combine,finalize}_callback! macros (panic guard that
reports a panic as a SQL error), and AggregateTestHarness.
libduckdb-sys with the loadable-extension feature provides runtime
function pointer stubs via global atomic statics.
Dev-Only Dependencies
These are used only by tests and benchmarks and are NOT linked into the release extension binary:
| Crate | Purpose |
|---|---|
duckdb | Declared without the bundled feature so test builds link a prebuilt libduckdb (DUCKDB_DOWNLOAD_LIB=1 or DUCKDB_LIB_DIR); not referenced by any code in src/, tests/, or benches/ |
quack-rs (bundled-test-prebuilt) | InMemoryDb for the in-process extension-load integration test |
criterion | Benchmarking framework |
proptest | Property-based testing |
License Compliance
All dependencies are audited via cargo-deny in CI. The allow list in
deny.toml:
Allowed licenses: MIT, Apache-2.0, BSD-3-Clause, CDLA-Permissive-2.0,
ISC, Unicode-3.0, Zlib
One crate-scoped exception allows CC0-1.0 for tiny-keccak, a lockfile-only
transitive entry that is not part of any buildable dependency graph.
Build Integrity
Reproducible Builds
Release builds use the following Cargo profile for deterministic output:
[profile.release]
opt-level = 3
lto = true # Full link-time optimization
codegen-units = 1 # Single codegen unit
panic = "unwind" # Required: quack-rs turns callback panics into SQL errors
strip = true # Strip debug symbols
Using codegen-units = 1 and lto = true reduces non-determinism from
parallel compilation. The Cargo.lock file is committed to the repository
to pin all transitive dependency versions.
Build Provenance
Release artifacts include:
- SHA256 checksums (
SHA256SUMS.txt) for every release artifact - GitHub artifact attestations via
actions/attest-build-provenancev4.1.0 (SHA-pinned), which provides a cryptographic link between the artifact and the GitHub Actions build that produced it - Immutable build logs in GitHub Actions with full command output
Verification
# Verify downloaded artifact checksum
sha256sum -c SHA256SUMS.txt
# Verify GitHub attestation (requires gh CLI)
gh attestation verify behavioral-v0.10.0-linux_amd64.tar.gz \
--repo tomtom215/duckdb-behavioral
Code Safety
Unsafe Code Confinement
All hand-written unsafe code is confined to the 9 files in src/ffi/ (the
quack_rs::entry_point_v2! macro in src/lib.rs generates the
extern "C" entry point). Business logic in
src/sessionize.rs, src/retention.rs, src/window_funnel.rs,
src/sequence.rs, src/sequence_next_node.rs, and src/pattern/ is
100% safe Rust.
Every callback's unsafe block has a // SAFETY: comment explaining why the
invariants are upheld. The aggregate update, combine, and finalize callbacks
are generated by quack-rs macros that catch panics and report them as SQL
errors; this relies on panic = "unwind" in the release profile.
No Network Access
The extension makes zero network calls at runtime. It operates purely on data provided by DuckDB through the C API.
No File System Access
The extension does not read from or write to the file system. All state is managed in-memory through DuckDB's aggregate function lifecycle.
Extension Loading Security
DuckDB requires the -unsigned flag (or allow_unsigned_extensions) to load
locally-built extensions, and only loads files ending in .duckdb_extension
that carry the metadata footer (make configure release produces
build/release/behavioral.duckdb_extension).
The community extension distribution path uses DuckDB's built-in extension
signing and verification system, which the build system handles automatically.
Reporting Vulnerabilities
Report security issues via GitHub Issues at github.com/tomtom215/duckdb-behavioral/issues.