From d7644312edc2c68b219dfc288fee1ed974b7c385 Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Thu, 18 Jun 2026 10:11:41 -0700 Subject: [PATCH 1/6] fix(rust): bump aws-lc-rs to 1.17.0 and align aws-lc-sys/aws-lc-fips-sys Pin direct aws-lc-sys (0.41) and aws-lc-fips-sys (0.13.1) to match what aws-lc-rs 1.17.0 resolves to, so only a single copy of the aws-lc native crates compiles. --- AwsEncryptionSDK/runtimes/rust/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AwsEncryptionSDK/runtimes/rust/Cargo.toml b/AwsEncryptionSDK/runtimes/rust/Cargo.toml index a3375ff5b..8ea5b4fb5 100644 --- a/AwsEncryptionSDK/runtimes/rust/Cargo.toml +++ b/AwsEncryptionSDK/runtimes/rust/Cargo.toml @@ -16,9 +16,9 @@ readme = "README.md" [dependencies] aws-config = "1.8.12" -aws-lc-rs = {version = "1.15.4"} -aws-lc-sys = { version = "0.39", optional = true } -aws-lc-fips-sys = { version = "0.13", optional = true } +aws-lc-rs = {version = "1.17.0"} +aws-lc-sys = { version = "0.41", optional = true } +aws-lc-fips-sys = { version = "0.13.1", optional = true } aws-sdk-dynamodb = "1.103.0" aws-sdk-kms = "1.98.0" aws-smithy-runtime-api = {version = "1.10.0", features = ["client"] } From 33b98db4d5b9bbfad1a2796e4511ec1e2b802b09 Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Thu, 18 Jun 2026 10:24:29 -0700 Subject: [PATCH 2/6] ci(rust): add duplicate aws-lc-sys/aws-lc-fips-sys check --- .github/workflows/rust_duplicate_deps.yml | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/rust_duplicate_deps.yml diff --git a/.github/workflows/rust_duplicate_deps.yml b/.github/workflows/rust_duplicate_deps.yml new file mode 100644 index 000000000..46984f586 --- /dev/null +++ b/.github/workflows/rust_duplicate_deps.yml @@ -0,0 +1,52 @@ +# Fails CI if more than one version of the aws-lc native crates +# (aws-lc-sys / aws-lc-fips-sys) resolves into the Rust dependency tree. +# aws-lc-rs pulls one of these crates transitively; declaring a divergent +# direct version causes a second copy to compile (~2x native C build time). +name: Rust Duplicate aws-lc Dependency Check + +on: + pull_request: {} + push: + branches: + - mainline + +jobs: + duplicate-aws-lc: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Setup Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + cache: false + + # The Rust sources under runtimes/rust are partially generated + # (gitignored), but `cargo tree` only needs a resolvable manifest. + # Stub any missing targets so dependency resolution succeeds without + # running codegen. + - name: Stub generated targets + shell: bash + working-directory: ./AwsEncryptionSDK/runtimes/rust + run: | + mkdir -p src examples + [ -f src/lib.rs ] || : > src/lib.rs + [ -f examples/main.rs ] || echo 'fn main() {}' > examples/main.rs + + - name: Check for duplicate aws-lc-sys / aws-lc-fips-sys + shell: bash + working-directory: ./AwsEncryptionSDK/runtimes/rust + run: | + set -euo pipefail + fail=0 + for args in "" "--no-default-features --features fips"; do + dupes=$(cargo tree -d $args 2>/dev/null | grep -E '^aws-lc-(sys|fips-sys) v' || true) + if [ -n "$dupes" ]; then + echo "::error::Duplicate aws-lc native crate detected (cargo tree -d $args):" + cargo tree -d $args || true + fail=1 + fi + done + exit $fail From 7d434c383e45a682cc5ad0efefbb44e95862764a Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Thu, 18 Jun 2026 10:31:37 -0700 Subject: [PATCH 3/6] Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/rust_duplicate_deps.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/rust_duplicate_deps.yml b/.github/workflows/rust_duplicate_deps.yml index 46984f586..d553ed37f 100644 --- a/.github/workflows/rust_duplicate_deps.yml +++ b/.github/workflows/rust_duplicate_deps.yml @@ -4,6 +4,9 @@ # direct version causes a second copy to compile (~2x native C build time). name: Rust Duplicate aws-lc Dependency Check +permissions: + contents: read + on: pull_request: {} push: From 73a0ae88e413269ba72fb5e903d9fbcf28cf272e Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Thu, 18 Jun 2026 10:39:14 -0700 Subject: [PATCH 4/6] ci(rust): make duplicate aws-lc check message actionable; document costs --- .github/workflows/rust_duplicate_deps.yml | 68 ++++++++++++++++++----- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/.github/workflows/rust_duplicate_deps.yml b/.github/workflows/rust_duplicate_deps.yml index d553ed37f..8bb90e3c2 100644 --- a/.github/workflows/rust_duplicate_deps.yml +++ b/.github/workflows/rust_duplicate_deps.yml @@ -1,18 +1,30 @@ # Fails CI if more than one version of the aws-lc native crates # (aws-lc-sys / aws-lc-fips-sys) resolves into the Rust dependency tree. -# aws-lc-rs pulls one of these crates transitively; declaring a divergent -# direct version causes a second copy to compile (~2x native C build time). +# +# aws-lc-rs pulls in one of these -sys crates transitively. Declaring a +# DIRECT dependency on a different version forces a second copy of AWS-LC to +# compile, which has real costs: +# * ~2x native C build time, and a larger binary (two libcrypto copies are +# statically linked). +# * The SDK's raw FFI calls (aws_lc_sys_impl::*) run against the version +# declared directly here, while aws-lc-rs's safe APIs run against the +# version aws-lc-rs pulls in. The two paths can therefore use different +# AWS-LC builds, and the raw-FFI path can stay on a stale or vulnerable +# version independently of aws-lc-rs. Only byte buffers cross between the +# two copies, so it is memory-safe -- but wasteful and a security-skew risk. +# +# The fix is always to pin the direct -sys version to match aws-lc-rs. name: Rust Duplicate aws-lc Dependency Check -permissions: - contents: read - on: pull_request: {} push: branches: - mainline +permissions: + contents: read + jobs: duplicate-aws-lc: runs-on: ubuntu-22.04 @@ -43,13 +55,41 @@ jobs: working-directory: ./AwsEncryptionSDK/runtimes/rust run: | set -euo pipefail - fail=0 - for args in "" "--no-default-features --features fips"; do - dupes=$(cargo tree -d $args 2>/dev/null | grep -E '^aws-lc-(sys|fips-sys) v' || true) - if [ -n "$dupes" ]; then - echo "::error::Duplicate aws-lc native crate detected (cargo tree -d $args):" - cargo tree -d $args || true - fail=1 + status=0 + + # Print the duplicate aws-lc blocks for one feature profile, and if + # any exist, explain what to do. `cargo tree -d` lists each duplicated + # package followed by the reverse-dependency tree, so it shows exactly + # which package pulls in each version (e.g. the direct dep vs aws-lc-rs). + check_profile() { + label="$1" + args="$2" + dup=$(cargo tree -d $args 2>/dev/null || true) + awslc=$(printf '%s\n' "$dup" | awk 'BEGIN{RS="";ORS="\n\n"} /^aws-lc-(sys|fips-sys) v/' || true) + if [ -n "$(printf '%s' "$awslc" | tr -d '[:space:]')" ]; then + status=1 + echo "::error::Duplicate aws-lc native crate detected ($label build). See log for how to fix." + echo "------------------------------------------------------------------------" + echo "Duplicate aws-lc native crate(s) in the $label dependency tree." + echo "Each version below compiles a separate copy of AWS-LC. The tree shows" + echo "which package pulls in each version:" + echo "" + printf '%s\n' "$awslc" | sed 's/^/ /' + echo "Declared directly in this crate's Cargo.toml:" + grep -nE '^aws-lc-(sys|fips-sys)[[:space:]]' Cargo.toml | sed 's/^/ /' || true + echo "" + echo "Why this matters: a different DIRECT -sys version forces a second copy" + echo "of AWS-LC to compile (~2x native C build time + larger binary), and the" + echo "SDK's raw FFI (aws_lc_sys_impl::*) then uses the version YOU declared" + echo "while aws-lc-rs uses the one it pulls in -- so the raw path can stay on a" + echo "stale/vulnerable AWS-LC independently of aws-lc-rs." + echo "" + echo "How to fix: set the direct version to the SAME version aws-lc-rs resolves" + echo "to (shown above), then confirm locally with: cargo tree -d" + echo "------------------------------------------------------------------------" fi - done - exit $fail + } + + check_profile "default" "" + check_profile "fips" "--no-default-features --features fips" + exit $status From c86c99076ee1b1dd353743f40ab2e1cab43ca88b Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Thu, 18 Jun 2026 13:37:05 -0700 Subject: [PATCH 5/6] ci(rust): fail loudly if the duplicate check cannot resolve the tree --- .github/workflows/rust_duplicate_deps.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/rust_duplicate_deps.yml b/.github/workflows/rust_duplicate_deps.yml index 8bb90e3c2..fa4abad27 100644 --- a/.github/workflows/rust_duplicate_deps.yml +++ b/.github/workflows/rust_duplicate_deps.yml @@ -64,6 +64,19 @@ jobs: check_profile() { label="$1" args="$2" + + # Liveness guard: a "no duplicates" result is only trustworthy if the + # tree actually resolved. This check intentionally ignores cargo + # errors below, so without this guard a resolution failure (broken + # stub, missing submodule, dropped feature, etc.) would pass silently. + # aws-lc-rs is a non-optional dependency, so it MUST appear; if it + # does not, fail loudly instead of reporting a false "all clear". + if ! cargo tree $args 2>/dev/null | grep -q 'aws-lc-rs v'; then + echo "::error::Duplicate check could not resolve the dependency tree ($label build) -- failing instead of passing silently. Run 'cargo tree $args' locally to debug." + status=1 + return + fi + dup=$(cargo tree -d $args 2>/dev/null || true) awslc=$(printf '%s\n' "$dup" | awk 'BEGIN{RS="";ORS="\n\n"} /^aws-lc-(sys|fips-sys) v/' || true) if [ -n "$(printf '%s' "$awslc" | tr -d '[:space:]')" ]; then From ea0dabc2a348532ce2977256115f3188290a3d78 Mon Sep 17 00:00:00 2001 From: Lucas McDonald Date: Mon, 22 Jun 2026 11:04:38 -0700 Subject: [PATCH 6/6] ci(rust): require the duplicate aws-lc check in pr-ci-all-required Make rust_duplicate_deps a reusable (workflow_call) workflow and invoke it from pull.yml as pr-ci-rust-duplicate-deps, adding it to the pr-ci-all-required needs list so a duplicate-aws-lc failure blocks merge. Addresses review feedback that the check must gate the required CI. --- .github/workflows/pull.yml | 3 +++ .github/workflows/rust_duplicate_deps.yml | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml index 941c5b953..5c3b200ed 100644 --- a/.github/workflows/pull.yml +++ b/.github/workflows/pull.yml @@ -52,6 +52,8 @@ jobs: uses: ./.github/workflows/library_rust_tests.yml with: dafny: ${{needs.getVersion.outputs.version}} + pr-ci-rust-duplicate-deps: + uses: ./.github/workflows/rust_duplicate_deps.yml pr-ci-go: needs: getVersion uses: ./.github/workflows/library_go_tests.yml @@ -84,6 +86,7 @@ jobs: - pr-ci-verification - pr-ci-net - pr-ci-rust + - pr-ci-rust-duplicate-deps - pr-ci-go - pr-test-vectors - pr-dafny-keyring-test-vectors diff --git a/.github/workflows/rust_duplicate_deps.yml b/.github/workflows/rust_duplicate_deps.yml index fa4abad27..cfa659acf 100644 --- a/.github/workflows/rust_duplicate_deps.yml +++ b/.github/workflows/rust_duplicate_deps.yml @@ -17,7 +17,10 @@ name: Rust Duplicate aws-lc Dependency Check on: - pull_request: {} + # Invoked by pull.yml so this check is part of the required + # pr-ci-all-required gate (a failure must block merge). Also runs + # directly on push to the default branch. + workflow_call: {} push: branches: - mainline