From 27c569ef71a2f338f362eff28a36193812422a82 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 09:28:48 +0000 Subject: [PATCH 1/7] ci: guard committed capnp code against schema drift Add a check_capnp_generated job that regenerates the committed capnp code and fails if it drifted from the schema (the build no longer regenerates it). The capnpc-rust plugin is pinned to the exact version (=0.23.2, matching the capnp runtime) because the generated bytes depend on the plugin version and a floating range would yield spurious diffs. Regenerate hypersync_net_types_capnp.rs with capnpc 0.23.2 so the committed code matches the pinned plugin; the previous file predated the 0.23 codegen (panic! helper calls). Document the required toolchain in the Makefile. Co-authored-by: claude --- .github/workflows/ci.yaml | 27 ++++++ hypersync-net-types/Makefile | 6 ++ .../hypersync_net_types_capnp.rs | 82 +++++++++---------- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 53aa314..e3693c0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -70,6 +70,33 @@ jobs: cargo package -p hypersync-net-types cargo package -p hypersync-client + # The capnp-generated code is committed rather than built from build.rs, so it + # can drift from the schema if someone edits the .capnp file without + # regenerating. Regenerate here and fail if the committed code is stale. The + # plugin version is pinned exactly: the generated code's bytes depend on the + # capnpc-rust version, so a floating "^0.23" would produce spurious diffs. + check_capnp_generated: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v2 + - name: Install capnp schema compiler + run: | + export DEBIAN_FRONTEND=noninteractive + sudo apt-get install -y capnproto libcapnp-dev + - name: Install capnpc-rust plugin + run: cargo install capnpc --version "=0.23.2" + - name: Regenerate capnp code + run: make -C hypersync-net-types generate_capnp_types + - name: Verify committed capnp code is up to date + run: | + git diff --exit-code -- hypersync-net-types/src/__generated__ \ + || (echo "::error::Committed capnp code is out of date. Run 'make -C hypersync-net-types generate_capnp_types' (with capnpc 0.23.2) and commit the result." && exit 1) + lint: runs-on: ubuntu-latest steps: diff --git a/hypersync-net-types/Makefile b/hypersync-net-types/Makefile index c9e7ef3..05046f2 100644 --- a/hypersync-net-types/Makefile +++ b/hypersync-net-types/Makefile @@ -1,3 +1,9 @@ +# Regenerating the committed Cap'n Proto code requires two tools: +# 1. The capnp schema compiler: apt-get install -y capnproto libcapnp-dev +# 2. The capnpc-rust plugin, pinned to the EXACT version CI uses (the +# generated bytes depend on the plugin version), matching the `capnp` +# runtime dependency in Cargo.toml: +# cargo install capnpc --version "=0.23.2" .PHONY: generate_capnp_types clean_generated_capnp_types generate_capnp_types: diff --git a/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs b/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs index 7cfc853..f8746d1 100644 --- a/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs +++ b/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs @@ -412,14 +412,14 @@ pub mod query_response_data { 1 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), 2 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), 3 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -840,14 +840,14 @@ pub mod rollback_guard { 2 => ::introspect(), 3 => ::introspect(), 4 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -1306,14 +1306,14 @@ pub mod query_response { 2 => ::introspect(), 3 => ::introspect(), 4 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -1589,14 +1589,14 @@ pub mod cached_query_response { pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { match index { 0 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -1947,14 +1947,14 @@ pub mod cached_query_response { match index { 0 => ::introspect(), 1 => <() as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -2417,7 +2417,7 @@ pub mod selection { match index { 0 => ::introspect(), 1 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( @@ -2427,7 +2427,7 @@ pub mod selection { where T: ::capnp::traits::Owned, { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -2781,14 +2781,14 @@ pub mod block_filter { match index { 0 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), 1 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -3206,14 +3206,14 @@ pub mod log_filter { 0 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), 1 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), 2 => <::capnp::list_list::Owned<::capnp::data_list::Owned> as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -3575,14 +3575,14 @@ pub mod authorization_selection { match index { 0 => <::capnp::primitive_list::Owned as ::capnp::introspect::Introspect>::introspect(), 1 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -4463,14 +4463,14 @@ pub mod transaction_filter { 8 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), 9 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), 10 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -5267,14 +5267,14 @@ pub mod trace_filter { 7 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), 8 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), 9 => <::capnp::data_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -5809,14 +5809,14 @@ pub mod field_selection { 1 => <::capnp::enum_list::Owned as ::capnp::introspect::Introspect>::introspect(), 2 => <::capnp::enum_list::Owned as ::capnp::introspect::Introspect>::introspect(), 3 => <::capnp::enum_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -5920,7 +5920,7 @@ mod join_mode { ::capnp::word(105, 110, 103, 0, 0, 0, 0, 0), ]; pub fn get_annotation_types(child_index: Option, index: u32) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } } @@ -6183,7 +6183,7 @@ mod block_field { ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ]; pub fn get_annotation_types(child_index: Option, index: u32) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } } @@ -6570,7 +6570,7 @@ mod transaction_field { ::capnp::word(115, 104, 0, 0, 0, 0, 0, 0), ]; pub fn get_annotation_types(child_index: Option, index: u32) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } } @@ -6721,7 +6721,7 @@ mod log_field { ::capnp::word(116, 111, 112, 105, 99, 51, 0, 0), ]; pub fn get_annotation_types(child_index: Option, index: u32) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } } @@ -6955,7 +6955,7 @@ mod trace_field { ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), ]; pub fn get_annotation_types(child_index: Option, index: u32) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } } @@ -7988,14 +7988,14 @@ pub mod query_body { 8 => ::introspect(), 9 => ::introspect(), 10 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -8325,14 +8325,14 @@ pub mod block_range { match index { 0 => ::introspect(), 1 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -8691,14 +8691,14 @@ pub mod request { 0 => ::introspect(), 1 => ::introspect(), 2 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -9073,14 +9073,14 @@ pub mod request { match index { 0 => ::introspect(), 1 => <::capnp::data::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -9361,14 +9361,14 @@ pub mod opt_u_int64 { pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { match index { 0 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { @@ -9636,14 +9636,14 @@ pub mod opt_u_int8 { pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { match index { 0 => ::introspect(), - _ => panic!("invalid field index {}", index), + _ => ::capnp::introspect::panic_invalid_field_index(index), } } pub fn get_annotation_types( child_index: Option, index: u32, ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) } pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = ::capnp::introspect::RawStructSchema { From b502e294d1565356dfb73fb5973120b884f1d445 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 09:41:26 +0000 Subject: [PATCH 2/7] ci: drop internal-implementation comments from capnp job Co-authored-by: claude --- .github/workflows/ci.yaml | 5 ----- hypersync-net-types/Makefile | 6 ------ 2 files changed, 11 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e3693c0..8fc246b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -70,11 +70,6 @@ jobs: cargo package -p hypersync-net-types cargo package -p hypersync-client - # The capnp-generated code is committed rather than built from build.rs, so it - # can drift from the schema if someone edits the .capnp file without - # regenerating. Regenerate here and fail if the committed code is stale. The - # plugin version is pinned exactly: the generated code's bytes depend on the - # capnpc-rust version, so a floating "^0.23" would produce spurious diffs. check_capnp_generated: runs-on: ubuntu-latest steps: diff --git a/hypersync-net-types/Makefile b/hypersync-net-types/Makefile index 05046f2..c9e7ef3 100644 --- a/hypersync-net-types/Makefile +++ b/hypersync-net-types/Makefile @@ -1,9 +1,3 @@ -# Regenerating the committed Cap'n Proto code requires two tools: -# 1. The capnp schema compiler: apt-get install -y capnproto libcapnp-dev -# 2. The capnpc-rust plugin, pinned to the EXACT version CI uses (the -# generated bytes depend on the plugin version), matching the `capnp` -# runtime dependency in Cargo.toml: -# cargo install capnpc --version "=0.23.2" .PHONY: generate_capnp_types clean_generated_capnp_types generate_capnp_types: From fe599f709baf0fbf664d04ebea380f0b03c7406f Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 11:11:38 +0000 Subject: [PATCH 3/7] ci: generate capnp code in a pinned Docker image for determinism Run codegen inside a pinned toolchain image (rust + capnproto + capnpc-rust) via the Makefile and the check_capnp_generated job, instead of relying on the host's locally installed capnp/rustfmt. This makes the committed generated code byte-for-byte reproducible across developer machines and CI, avoiding spurious diffs from platform/version mismatches. Co-authored-by: claude --- .github/workflows/ci.yaml | 13 +------------ hypersync-net-types/Makefile | 8 ++++++-- hypersync-net-types/capnp-codegen.Dockerfile | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 hypersync-net-types/capnp-codegen.Dockerfile diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8fc246b..be792c2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -74,23 +74,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - - name: Install capnp schema compiler - run: | - export DEBIAN_FRONTEND=noninteractive - sudo apt-get install -y capnproto libcapnp-dev - - name: Install capnpc-rust plugin - run: cargo install capnpc --version "=0.23.2" - name: Regenerate capnp code run: make -C hypersync-net-types generate_capnp_types - name: Verify committed capnp code is up to date run: | git diff --exit-code -- hypersync-net-types/src/__generated__ \ - || (echo "::error::Committed capnp code is out of date. Run 'make -C hypersync-net-types generate_capnp_types' (with capnpc 0.23.2) and commit the result." && exit 1) + || (echo "::error::Committed capnp code is out of date. Run 'make -C hypersync-net-types generate_capnp_types' and commit the result." && exit 1) lint: runs-on: ubuntu-latest diff --git a/hypersync-net-types/Makefile b/hypersync-net-types/Makefile index c9e7ef3..c83f919 100644 --- a/hypersync-net-types/Makefile +++ b/hypersync-net-types/Makefile @@ -1,8 +1,12 @@ .PHONY: generate_capnp_types clean_generated_capnp_types +CAPNP_CODEGEN_IMAGE ?= hypersync-capnp-codegen + generate_capnp_types: - capnp compile hypersync_net_types.capnp -o rust:./src/__generated__ - rustfmt src/__generated__/hypersync_net_types_capnp.rs + docker build -f capnp-codegen.Dockerfile -t $(CAPNP_CODEGEN_IMAGE) . + docker run --rm -u $$(id -u):$$(id -g) -v "$$(pwd)":/work $(CAPNP_CODEGEN_IMAGE) \ + sh -c "capnp compile hypersync_net_types.capnp -o rust:./src/__generated__ \ + && rustfmt src/__generated__/hypersync_net_types_capnp.rs" clean_generated_capnp_types: rm -f src/__generated__/hypersync_net_types_capnp.rs diff --git a/hypersync-net-types/capnp-codegen.Dockerfile b/hypersync-net-types/capnp-codegen.Dockerfile new file mode 100644 index 0000000..d9024ee --- /dev/null +++ b/hypersync-net-types/capnp-codegen.Dockerfile @@ -0,0 +1,15 @@ +# Pinned toolchain for deterministic Cap'n Proto code generation. Running codegen +# inside this image keeps the committed output byte-for-byte reproducible across +# developer machines and CI, regardless of the host's capnp/rustfmt versions. +FROM rust:1.94-slim-bookworm + +# Must stay compatible with the `capnp` runtime dependency in Cargo.toml. +ARG CAPNPC_VERSION=0.23.2 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends capnproto \ + && rm -rf /var/lib/apt/lists/* +RUN rustup component add rustfmt +RUN cargo install capnpc --version "=${CAPNPC_VERSION}" --locked + +WORKDIR /work From 617a1e5301036634773daf2b12f3851809cc9242 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 11:18:12 +0000 Subject: [PATCH 4/7] ci: pin capnp codegen base image by digest Pin the Docker base image to an immutable digest so the codegen toolchain (notably rustfmt) can't drift when the rust:1.94-slim-bookworm tag moves, keeping the generated output fully reproducible. Co-authored-by: claude --- hypersync-net-types/capnp-codegen.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hypersync-net-types/capnp-codegen.Dockerfile b/hypersync-net-types/capnp-codegen.Dockerfile index d9024ee..94fe5f9 100644 --- a/hypersync-net-types/capnp-codegen.Dockerfile +++ b/hypersync-net-types/capnp-codegen.Dockerfile @@ -1,7 +1,7 @@ # Pinned toolchain for deterministic Cap'n Proto code generation. Running codegen # inside this image keeps the committed output byte-for-byte reproducible across # developer machines and CI, regardless of the host's capnp/rustfmt versions. -FROM rust:1.94-slim-bookworm +FROM rust:1.94-slim-bookworm@sha256:cf9dd0ec73e75f827fe59123fff9dc65af1a1c8363c3c31ee8d7f8ad0b6a5fb2 # Must stay compatible with the `capnp` runtime dependency in Cargo.toml. ARG CAPNPC_VERSION=0.23.2 From 936ed85474ec4e245ab7deee9432e8846d1a9245 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 11:50:04 +0000 Subject: [PATCH 5/7] ci: generate capnp code in one docker build, on capnp 1.1.0 Collapse the Makefile target into a single `docker build --output` that runs codegen inside the image and exports the generated file directly, dropping the separate `docker run`, the volume mount and UID/GID mapping. A .dockerignore keeps the build context to just the schema. Move the codegen base to Debian trixie so the capnp compiler is 1.1.0 (>=1.0) instead of bookworm's 0.9.2, and pin both the base image digest and the capnproto apt version since the compiler version affects the generated schema blobs. Regenerate the committed code accordingly. Co-authored-by: claude --- hypersync-net-types/.dockerignore | 2 + hypersync-net-types/Makefile | 8 +- hypersync-net-types/capnp-codegen.Dockerfile | 16 ++- .../hypersync_net_types_capnp.rs | 115 +++++++++++------- 4 files changed, 86 insertions(+), 55 deletions(-) create mode 100644 hypersync-net-types/.dockerignore diff --git a/hypersync-net-types/.dockerignore b/hypersync-net-types/.dockerignore new file mode 100644 index 0000000..5f68d49 --- /dev/null +++ b/hypersync-net-types/.dockerignore @@ -0,0 +1,2 @@ +* +!hypersync_net_types.capnp diff --git a/hypersync-net-types/Makefile b/hypersync-net-types/Makefile index c83f919..5d8d62e 100644 --- a/hypersync-net-types/Makefile +++ b/hypersync-net-types/Makefile @@ -1,12 +1,8 @@ .PHONY: generate_capnp_types clean_generated_capnp_types -CAPNP_CODEGEN_IMAGE ?= hypersync-capnp-codegen - generate_capnp_types: - docker build -f capnp-codegen.Dockerfile -t $(CAPNP_CODEGEN_IMAGE) . - docker run --rm -u $$(id -u):$$(id -g) -v "$$(pwd)":/work $(CAPNP_CODEGEN_IMAGE) \ - sh -c "capnp compile hypersync_net_types.capnp -o rust:./src/__generated__ \ - && rustfmt src/__generated__/hypersync_net_types_capnp.rs" + DOCKER_BUILDKIT=1 docker build -f capnp-codegen.Dockerfile --target export \ + --output type=local,dest=src/__generated__ . clean_generated_capnp_types: rm -f src/__generated__/hypersync_net_types_capnp.rs diff --git a/hypersync-net-types/capnp-codegen.Dockerfile b/hypersync-net-types/capnp-codegen.Dockerfile index 94fe5f9..93addc0 100644 --- a/hypersync-net-types/capnp-codegen.Dockerfile +++ b/hypersync-net-types/capnp-codegen.Dockerfile @@ -1,15 +1,25 @@ -# Pinned toolchain for deterministic Cap'n Proto code generation. Running codegen +# Pinned toolchain for deterministic Cap'n Proto code generation. Generating # inside this image keeps the committed output byte-for-byte reproducible across # developer machines and CI, regardless of the host's capnp/rustfmt versions. -FROM rust:1.94-slim-bookworm@sha256:cf9dd0ec73e75f827fe59123fff9dc65af1a1c8363c3c31ee8d7f8ad0b6a5fb2 +FROM rust:1.94-slim-trixie@sha256:cf09adf8c3ebaba10779e5c23ff7fe4df4cccdab8a91f199b0c142c53fef3e1a AS codegen # Must stay compatible with the `capnp` runtime dependency in Cargo.toml. ARG CAPNPC_VERSION=0.23.2 +# The capnp compiler version affects the generated schema blobs, so pin it too. +ARG CAPNPROTO_VERSION=1.1.0-2 RUN apt-get update \ - && apt-get install -y --no-install-recommends capnproto \ + && apt-get install -y --no-install-recommends "capnproto=${CAPNPROTO_VERSION}" \ && rm -rf /var/lib/apt/lists/* RUN rustup component add rustfmt RUN cargo install capnpc --version "=${CAPNPC_VERSION}" --locked WORKDIR /work +COPY hypersync_net_types.capnp . +RUN mkdir -p out \ + && capnp compile hypersync_net_types.capnp -o rust:out \ + && rustfmt out/hypersync_net_types_capnp.rs + +# Minimal stage so `docker build --output` exports only the generated file. +FROM scratch AS export +COPY --from=codegen /work/out/hypersync_net_types_capnp.rs / diff --git a/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs b/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs index f8746d1..bccf1fd 100644 --- a/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs +++ b/hypersync-net-types/src/__generated__/hypersync_net_types_capnp.rs @@ -323,13 +323,14 @@ pub mod query_response_data { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 81] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 82] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(49, 157, 62, 151, 169, 39, 204, 137), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(4, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(22, 0, 0, 0, 138, 0, 0, 0), ::capnp::word(21, 0, 0, 0, 98, 1, 0, 0), ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -732,13 +733,14 @@ pub mod rollback_guard { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 99] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 100] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(75, 175, 253, 87, 239, 86, 125, 149), ::capnp::word(26, 0, 0, 0, 1, 0, 3, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(140, 0, 0, 0, 43, 1, 0, 0), ::capnp::word(21, 0, 0, 0, 66, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -1198,13 +1200,14 @@ pub mod query_response { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 99] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 100] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(226, 9, 54, 243, 16, 76, 106, 205), ::capnp::word(26, 0, 0, 0, 1, 0, 3, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 1, 0, 0, 228, 1, 0, 0), ::capnp::word(21, 0, 0, 0, 66, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -1556,13 +1559,14 @@ pub mod cached_query_response { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 28] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 29] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(13, 163, 224, 48, 162, 54, 215, 144), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(230, 1, 0, 0, 99, 2, 0, 0), ::capnp::word(21, 0, 0, 0, 114, 1, 0, 0), ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -1889,13 +1893,14 @@ pub mod cached_query_response { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 52] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 53] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(88, 76, 83, 210, 227, 145, 72, 201), ::capnp::word(46, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(13, 163, 224, 48, 162, 54, 215, 144), ::capnp::word(1, 0, 7, 0, 1, 0, 2, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(21, 0, 0, 0, 170, 1, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -2356,13 +2361,14 @@ pub mod selection { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 52] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 53] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(123, 136, 14, 45, 199, 154, 37, 201), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(101, 2, 0, 0, 162, 2, 0, 0), ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -2718,13 +2724,14 @@ pub mod block_filter { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 57] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 58] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(198, 210, 137, 50, 10, 244, 5, 189), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(165, 2, 0, 0, 238, 2, 0, 0), ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -3122,13 +3129,14 @@ pub mod log_filter { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 77] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 78] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(179, 254, 244, 73, 117, 248, 19, 160), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(3, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(241, 2, 0, 0, 94, 3, 0, 0), ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -3510,13 +3518,14 @@ pub mod authorization_selection { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 59] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 60] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(141, 105, 202, 172, 115, 150, 48, 135), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(96, 3, 0, 0, 187, 3, 0, 0), ::capnp::word(21, 0, 0, 0, 138, 1, 0, 0), ::capnp::word(45, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -4228,13 +4237,14 @@ pub mod transaction_filter { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 220] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 221] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(56, 147, 107, 206, 187, 26, 251, 190), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(11, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(189, 3, 0, 0, 34, 5, 0, 0), ::capnp::word(21, 0, 0, 0, 98, 1, 0, 0), ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -5051,13 +5061,14 @@ pub mod trace_filter { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 202] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 203] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(197, 194, 61, 54, 113, 80, 134, 163), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(10, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(36, 5, 0, 0, 67, 6, 0, 0), ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -5704,13 +5715,14 @@ pub mod field_selection { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 97] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 98] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(110, 171, 199, 124, 78, 87, 136, 142), ::capnp::word(26, 0, 0, 0, 1, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(4, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(69, 6, 0, 0, 230, 6, 0, 0), ::capnp::word(21, 0, 0, 0, 74, 1, 0, 0), ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -5885,13 +5897,14 @@ impl ::capnp::traits::HasTypeId for JoinMode { const TYPE_ID: u64 = 0x814f_2ba3_6715_2ce1u64; } mod join_mode { - pub static ENCODED_NODE: [::capnp::Word; 32] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 33] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(225, 44, 21, 103, 163, 43, 79, 129), ::capnp::word(26, 0, 0, 0, 2, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(232, 6, 0, 0, 45, 7, 0, 0), ::capnp::word(21, 0, 0, 0, 26, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -6027,13 +6040,14 @@ impl ::capnp::traits::HasTypeId for BlockField { const TYPE_ID: u64 = 0xafe0_b452_5564_492cu64; } mod block_field { - pub static ENCODED_NODE: [::capnp::Word; 153] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 154] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(44, 73, 100, 85, 82, 180, 224, 175), ::capnp::word(26, 0, 0, 0, 2, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(47, 7, 0, 0, 99, 9, 0, 0), ::capnp::word(21, 0, 0, 0, 42, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -6327,13 +6341,14 @@ impl ::capnp::traits::HasTypeId for TransactionField { const TYPE_ID: u64 = 0xc1e6_cb8a_6cfa_21d7u64; } mod transaction_field { - pub static ENCODED_NODE: [::capnp::Word; 240] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 241] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(215, 33, 250, 108, 138, 203, 230, 193), ::capnp::word(26, 0, 0, 0, 2, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 9, 0, 0, 254, 12, 0, 0), ::capnp::word(21, 0, 0, 0, 90, 1, 0, 0), ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -6645,13 +6660,14 @@ impl ::capnp::traits::HasTypeId for LogField { const TYPE_ID: u64 = 0x90a5_87ce_c0d2_ca79u64; } mod log_field { - pub static ENCODED_NODE: [::capnp::Word; 73] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 74] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(121, 202, 210, 192, 206, 135, 165, 144), ::capnp::word(26, 0, 0, 0, 2, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 13, 0, 0, 228, 13, 0, 0), ::capnp::word(21, 0, 0, 0, 26, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -6822,13 +6838,14 @@ impl ::capnp::traits::HasTypeId for TraceField { const TYPE_ID: u64 = 0xdce3_386f_0944_4dd1u64; } mod trace_field { - pub static ENCODED_NODE: [::capnp::Word; 130] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 131] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(209, 77, 68, 9, 111, 56, 227, 220), ::capnp::word(26, 0, 0, 0, 2, 0, 0, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(230, 13, 0, 0, 172, 15, 0, 0), ::capnp::word(21, 0, 0, 0, 42, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -7715,13 +7732,14 @@ pub mod query_body { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 258] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 259] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(237, 135, 130, 51, 42, 10, 136, 130), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(9, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(174, 15, 0, 0, 100, 17, 0, 0), ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -8269,13 +8287,14 @@ pub mod block_range { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 50] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 51] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(186, 223, 151, 95, 15, 240, 183, 229), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(102, 17, 0, 0, 176, 17, 0, 0), ::capnp::word(21, 0, 0, 0, 42, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -8625,13 +8644,14 @@ pub mod request { } } mod _private { - pub static ENCODED_NODE: [::capnp::Word; 59] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 60] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(84, 0, 180, 54, 227, 78, 133, 190), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(213, 18, 0, 0, 134, 19, 0, 0), ::capnp::word(21, 0, 0, 0, 18, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -9019,13 +9039,14 @@ pub mod request { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 48] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 49] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(11, 115, 36, 192, 91, 123, 70, 177), ::capnp::word(34, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(84, 0, 180, 54, 227, 78, 133, 190), ::capnp::word(2, 0, 7, 0, 1, 0, 2, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(21, 0, 0, 0, 58, 1, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -9322,13 +9343,14 @@ pub mod opt_u_int64 { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 34] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 35] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(145, 156, 229, 39, 5, 172, 222, 134), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(136, 19, 0, 0, 178, 19, 0, 0), ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), @@ -9597,13 +9619,14 @@ pub mod opt_u_int8 { } impl Pipeline {} mod _private { - pub static ENCODED_NODE: [::capnp::Word; 34] = [ - ::capnp::word(0, 0, 0, 0, 5, 0, 6, 0), + pub static ENCODED_NODE: [::capnp::Word; 35] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), ::capnp::word(50, 179, 230, 200, 42, 167, 255, 167), ::capnp::word(26, 0, 0, 0, 1, 0, 1, 0), ::capnp::word(197, 128, 248, 24, 106, 165, 137, 146), ::capnp::word(0, 0, 7, 0, 0, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(180, 19, 0, 0, 220, 19, 0, 0), ::capnp::word(21, 0, 0, 0, 26, 1, 0, 0), ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), From d253ec66512e1f1460dbe6699efdc28a99be22f1 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 12:52:12 +0000 Subject: [PATCH 6/7] ci: least-privilege token and document .dockerignore Add a top-level `permissions: contents: read` block since every CI job is read-only, and document the .dockerignore schema-only build context. Co-authored-by: claude --- .github/workflows/ci.yaml | 4 ++++ hypersync-net-types/.dockerignore | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index be792c2..f21f6bf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,6 +8,10 @@ on: branches: - main +# All jobs only read the repo (build/test/lint/package/codegen-check/fuzz). +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/hypersync-net-types/.dockerignore b/hypersync-net-types/.dockerignore index 5f68d49..4c87a4c 100644 --- a/hypersync-net-types/.dockerignore +++ b/hypersync-net-types/.dockerignore @@ -1,2 +1,4 @@ +# Keep the build context minimal: only the schema is needed for codegen. +# If the schema ever `import`s another .capnp file, un-ignore it here too. * !hypersync_net_types.capnp From 8b57cf9c7bb47b27864d0372e8e81aa410d90a7f Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 9 Jun 2026 13:12:56 +0000 Subject: [PATCH 7/7] ci: verify pinned capnpc matches the capnp dependency Add a step to check_capnp_generated that fails if the capnpc version pinned in capnp-codegen.Dockerfile drifts from any `capnp` dependency in the workspace Cargo.toml files. The codegen plugin and the runtime are released in lockstep, so they must stay aligned. Co-authored-by: claude --- .github/workflows/ci.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f21f6bf..dd48405 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -78,6 +78,21 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + # The capnpc plugin and the `capnp` runtime are released in lockstep, so + # the Dockerfile's pinned capnpc must match every `capnp` Cargo dependency. + - name: Check capnpc version matches the capnp dependency + run: | + expected=$(sed -nE 's/^ARG CAPNPC_VERSION=([0-9]+\.[0-9]+).*/\1/p' hypersync-net-types/capnp-codegen.Dockerfile) + status=0 + for f in $(grep -rl -E '^capnp = "' --include=Cargo.toml .); do + ver=$(sed -nE 's/^capnp = "([0-9]+\.[0-9]+).*/\1/p' "$f") + if [ "$ver" != "$expected" ]; then + echo "::error file=$f::capnp = \"$ver\" does not match the pinned capnpc $expected in capnp-codegen.Dockerfile" + status=1 + fi + done + [ "$status" -eq 0 ] && echo "capnp/capnpc versions aligned ($expected)" + exit $status - name: Regenerate capnp code run: make -C hypersync-net-types generate_capnp_types - name: Verify committed capnp code is up to date