v0.5.1: Security patch, SEO improvements, and gRPC build tooling#82
Merged
Conversation
Fixes RUSTSEC-2026-0098 / GHSA-965h-392x-2mh5: rustls-webpki incorrectly accepted URI name constraints during X.509 path validation, potentially letting a CA bypass its own URI NameConstraints for certificates it should have been restricted from issuing. a2a-protocol-client pulls rustls-webpki transitively via rustls -> hyper-rustls / tokio-rustls when the tls-rustls feature is enabled. Practical exploitability requires a trust chain whose CA uses URI name constraints (uncommon in the public Web PKI via webpki-roots, but possible for private/enterprise CA bundles). Release as a dedicated patch so downstreams can pick up the fix without waiting for unrelated in-flight work on 0.5.0: - cargo update -p rustls-webpki --precise 0.103.12 - bump all four publishable crates 0.5.0 -> 0.5.1 (a2a-protocol-types, a2a-protocol-client, a2a-protocol-server, a2a-protocol-sdk) and their cross-references - CHANGELOG.md: new [0.5.1] - 2026-04-15 Security entry mirroring the earlier RUSTSEC-2026-0049 note, above the still-staged [0.5.0] - book/src/reference/changelog.md: matching v0.5.1 section - CITATION.cff: version 0.5.1, date-released 2026-04-15
Applies cargo update to pull every semver-compatible patch/minor bump: axum 0.8.8 -> 0.8.9 bitflags 2.11.0 -> 2.11.1 cc 1.2.57 -> 1.2.60 fastrand 2.3.0 -> 2.4.1 hashbrown 0.16.1 -> 0.17.0 hyper 1.8.1 -> 1.9.0 hyper-rustls 0.27.7 -> 0.27.9 icu_* 2.1.x -> 2.2.0 indexmap 2.13.0 -> 2.14.0 iri-string 0.7.10 -> 0.7.12 itoa 1.0.17 -> 1.0.18 js-sys 0.3.91 -> 0.3.95 libc 0.2.183 -> 0.2.185 libredox 0.1.14 -> 0.1.16 litemap 0.8.1 -> 0.8.2 mio 1.1.1 -> 1.2.0 num-conv 0.2.0 -> 0.2.1 pkg-config 0.3.32 -> 0.3.33 potential_utf 0.1.4 -> 0.1.5 proptest 1.10.0 -> 1.11.0 rand 0.9.2 -> 0.9.4 rayon 1.11.0 -> 1.12.0 redox_syscall 0.7.3 -> 0.7.4 rustc-hash 2.1.1 -> 2.1.2 rustls 0.23.37 -> 0.23.38 semver 1.0.27 -> 1.0.28 tinystr 0.8.2 -> 0.8.3 tokio 1.50.0 -> 1.52.0 tokio-macros 2.6.1 -> 2.7.0 unicode-segmentation 1.12.0 -> 1.13.2 uuid 1.22.0 -> 1.23.0 wasm-bindgen 0.2.114 -> 0.2.118 (and friends) web-sys 0.3.91 -> 0.3.95 zerocopy 0.8.42 -> 0.8.48 zerofrom 0.1.6 -> 0.1.7 zerotrie 0.2.3 -> 0.2.4 zerovec 0.11.5 -> 0.11.6 writeable 0.6.2 -> 0.6.3 yoke 0.8.1 -> 0.8.2 (+ assorted Windows target-metadata crates) Verification: - cargo check --workspace --all-targets: clean - cargo check --workspace --all-features --all-targets: clean (requires protobuf-compiler on PATH for grpc feature) - cargo test --workspace: all 64 suites pass, zero failures Out-of-semver bumps (criterion, tonic/tonic-build/prost, opentelemetry stack, tokio-tungstenite, rcgen, genai, socket2) are evaluated in follow-up commits so each breaking-change group is reviewable in isolation.
…enite, criterion, rcgen, genai, socket2
Brings every remaining dependency to its latest upstream version, with
source migrations where the new version introduced breaking changes.
Each group was verified with the relevant feature flags enabled and the
full workspace test suite (64 suites, ~1.4k assertions) passing.
tonic / prost / tonic-build 0.12 -> 0.14 (grpc feature)
- tonic-build 0.14 split off the prost integration into a separate
`tonic-prost-build` crate (for build scripts) and `tonic-prost`
crate (for the runtime codec). Updated both build.rs files to
`tonic_prost_build::configure()` and added `tonic-prost` as a
runtime dep alongside `tonic`. Application code in
`transport/grpc.rs` and `dispatch/grpc.rs` needed no changes — the
public tonic::* surface is stable across 0.12 -> 0.14 for our
usage (Channel, Status, Code, Request, Streaming, metadata).
opentelemetry stack 0.28 -> 0.31 (otel feature)
- No changes needed in `src/otel/mod.rs` or `src/otel/pipeline.rs`
production code — MetricExporter, PeriodicReader, SdkMeterProvider
and Resource builders are unchanged.
- `data::ResourceMetrics` and friends in 0.31 switched from public
fields to iterator accessors (`.scope_metrics()`, `.metrics()`,
`.name()`, `.data()`, `.data_points()`, `.value()`, `.count()`,
and a concrete `AggregatedMetrics` enum instead of
`dyn Any + downcast_ref::<Sum<T>>()`). Rewrote the observable-effect
tests to the iterator API, which is also more type-safe.
- The `ManualReader` + `MetricReader` trait used by the tests was
moved behind the `experimental_metrics_custom_reader` feature, so
that feature is now enabled on the `opentelemetry_sdk` dep (with
a comment explaining it is only needed for tests and adds no
runtime cost). The `MetricReader::shutdown` method was replaced
with `shutdown_with_timeout` — test impl updated accordingly.
tokio-tungstenite 0.24 -> 0.29 (websocket feature)
- `WsMessage::Text(String)` became `WsMessage::Text(Utf8Bytes)`.
Added `.into()` at every send site in websocket transport and
dispatcher (production + tests). Receive-side code paths already
work via `Deref<Target = str>` on `Utf8Bytes`.
- `WsMessage::Ping(Vec<u8>)` became `WsMessage::Ping(bytes::Bytes)`.
Added `.into()` at both ping test sites.
- `Message::into_text()` now returns `Utf8Bytes` instead of `String`;
updated the `read_text` test helper to `.as_str().to_owned()`.
criterion 0.5 -> 0.8 (benchmarks, dev-dep)
- No API breakage in the benchmark harness itself.
- `criterion::black_box` is deprecated in favour of
`std::hint::black_box`. Migrated all 87 call sites across 12
benchmark files (import change plus fully-qualified-path
substitution). Zero deprecation warnings remaining.
rcgen 0.13 -> 0.14 (TLS integration tests, dev-dep)
- `CertificateParams::signed_by()` now takes `&Issuer<'_, _>` instead
of separate `(&Certificate, &KeyPair)`. Construct `Issuer::new(
params, key)` once and reuse it across child-cert signings in the
TLS and mTLS test helpers. All 7 TLS integration tests still pass.
genai 0.1 -> 0.5 (genai-agent example)
- `ChatResponse::content_text_as_str` deprecated in favour of
`first_text`. Updated the one call site.
socket2 0.5 -> 0.6 (benchmarks, transitive)
- No source changes needed; patch-only bump for the benchmark
server's SO_REUSEADDR path.
Verification matrix (all passing, 0 failures across the board):
cargo test --workspace 64 suites
cargo test --workspace --features websocket 64 suites
cargo test --workspace --features grpc 64 suites
cargo test -p a2a-protocol-server --features otel 33 suites
cargo test -p a2a-protocol-server --features sqlite 33 suites
cargo test -p a2a-protocol-server --features postgres 28 suites
cargo test -p a2a-protocol-client --features tls-rustls --test tls_integration_tests 7/7
cargo check --workspace --benches clean, zero warnings
cargo bench -p a2a-protocol-types --bench json_serde -- --test ok
The benchmark dashboard at /reference/benchmark-dashboard.html used to load Chart.js 4 from cdn.jsdelivr.net and Space Grotesk + JetBrains Mono from fonts.googleapis.com. Both domains are routinely blocked by corporate egress proxies and Pi-hole-style DNS filters, and the dashboard would render with an invisible font-fallback chain and a missing Chart constructor — the symptom that triggered the "site blocked on corp networks" bug report. Vendoring the assets sidesteps the entire class of problem: every request now goes to the same origin as the HTML. Phase 3a — corp-network blocker fix ----------------------------------- - Vendor Chart.js 4.5.1 UMD build at `book/static/vendor/chart.umd.min.js` (209 KB, MIT-licensed, one pinned version), with a `vendor/README.md` that documents the upstream, license, and the one-liner to re-vendor a new upstream release. - Drop the Google Fonts `<link>` and `preconnect` entirely from `benchmark-dashboard.html`. Replace the Space Grotesk / JetBrains Mono families with system-ui / ui-monospace stacks (Apple, Segoe UI, Roboto, SF Mono, Menlo, Consolas, Liberation Mono). System fonts render on every OS without a network round-trip. An inline comment explains the rationale so a future contributor does not "fix" it by re-adding the CDN reference. - Point the `<script>` tag at `../vendor/chart.umd.min.js`, a relative same-origin path that works whether the site is served at https://a2a-rust.com/, at a preview URL, or opened from disk. - `.github/workflows/docs.yml` now copies the entire `book/static/` tree into the built site (not just robots.txt + sitemap.xml), so `vendor/` ships automatically. The CI step asserts that the critical files land where they are expected — catching a broken deploy at build time rather than in production. - New `book/static/vendor/README.md` documents the vendoring policy. Phase 3b — SEO polish --------------------- - Add `site-url = "https://a2a-rust.com/"` to `book.toml` so mdbook emits canonical URLs and absolute asset paths consistently across pages. The value must stay in sync with `theme/head.hbs` og:url, the sitemap <loc> entries, and the robots.txt `Sitemap:` directive — the comment in `book.toml` spells this out. - Strengthen `theme/head.hbs`: - `robots` meta now includes `max-snippet:-1,max-image-preview:large, max-video-preview:-1` so Google/Bing can show full descriptions and large preview cards in SERPs. - Twitter card upgraded from `summary` to `summary_large_image` (renders with a full-width preview on X, LinkedIn, Slack, Discord). - Open Graph now emits `og:image` (1200x630) with width/height/alt attributes, `og:locale`, and structured alternate `hreflang` links (en + x-default) so the canonical URL is unambiguous. - JSON-LD structured data expanded: adds `@type SoftwareSourceCode` author block, `ComputerLanguage` reference for Rust, explicit `applicationCategory DeveloperApplication`, `operatingSystem` list, and a curated `keywords` array. This is what drives developer-tool carousels on Google search. - Regenerate `sitemap.xml` with 42 URLs (was 41 — adds `/reference/dashboard.html` and `/reference/benchmark-dashboard.html` which were missing), bumped lastmod to 2026-04-15, and adds `changefreq` hints (weekly for frequently-updated pages like the benchmarks and dashboard, monthly for stable reference material). - Expand `robots.txt` with a documented policy (indexing open, 1s crawl-delay for courtesy, AI training crawlers allowed per Apache-2.0 license, explicit sitemap discovery line). Verification ------------ - `mdbook build book` → clean, no warnings. - Simulated the CI `cp -r book/static/. book/book/` step locally: `book/book/vendor/chart.umd.min.js`, `robots.txt`, and `sitemap.xml` all land at the expected output paths. - `grep -E '(href|src)=".*(fonts.googleapis|jsdelivr)'` against both source and built HTML returns nothing — zero external network requests remain on the benchmark dashboard page. - Built pages now contain `og:image`, `summary_large_image`, JSON-LD `SoftwareSourceCode`, canonical + alternate hreflang links. Scope notes ----------- - The young `.com` domain age (registered ~2026-03-30, ~2 weeks old at the time of this commit) is a secondary cause of corp-network friction and is not fixable from inside the repo. It resolves naturally as domain reputation builds. - No GSC / Bing verification files are committed — those are account-scoped secrets the repo owner should drop into `book/static/` separately (they ship as-is via the new blanket static-copy step).
…re trait, context_id placement, Part::url
Systematic audit of every high-risk book page against the 0.5.1 source.
Most pages were accurate; this commit fixes the specific drift found.
api-reference.md
- `serve(addr, dispatcher)` and `serve_with_addr(addr, dispatcher)`
were labelled "blocking" — they are `async fn`s. Replace the one-
line description with the full return type and an explicit `async`
marker so readers understand they must be `.await`ed.
- Streaming types table didn't distinguish `EventQueueWriter` /
`EventQueueReader` (traits) from `EventQueueManager`, `EventEmitter`,
`InMemoryQueueWriter`, `InMemoryQueueReader` (structs). Added a
`Kind` column and rewrote the descriptions.
- Built-in implementations table was missing the three built-in
`TenantResolver` impls (`HeaderTenantResolver`,
`BearerTokenTenantResolver`, `PathSegmentTenantResolver`) and the
built-in `HttpPushSender`. Added all four with accurate feature-gate
annotations.
handler.md
- `HandlerLimits` table was missing `max_context_locks` (default
10,000). The field is real — `crates/a2a-server/src/handler/limits.rs:51`
— but undocumented. Added the row.
- The "Custom Task Stores" example described the trait methods as
`get, put, list, delete`. The actual `TaskStore` trait uses
`save, get, list, insert_if_absent, delete`. Fixed the comment.
(`put` has never existed; `save` has always been the method, and
`insert_if_absent` is required for single-flight task creation.)
configuration.md
- Same `max_context_locks` omission as `handler.md`. Added the row.
first-agent.md
- Removed a non-existent `context_id: None` field from a
`MessageSendParams` struct literal. `MessageSendParams` has only
`{tenant, message, configuration, metadata}`; the `context_id`
lives on the inner `Message` struct. The bad snippet would have
compiled only with a `..Default::default()` escape hatch, which
was not present.
sending-messages.md
- Four occurrences of the same `context_id` placement bug as
above. The continuation-of-conversation example was particularly
misleading — it declared `context_id` at both the `Message`
level *and* the `MessageSendParams` level. Now it lives on the
`Message` only, as the wire format requires.
- Replaced `Part::file_uri("https://...")` (a 0.3.x back-compat alias
kept only so old code still compiles) with the idiomatic v1.0
`Part::url("https://...").with_media_type("image/png")`. Both
produce the same wire JSON, but the book should show the
forward-compatible API.
crates/a2a-server/src/builder.rs
- `RequestHandlerBuilder::with_event_queue_capacity` rustdoc said
"Defaults to 64 items". The actual default is
`DEFAULT_QUEUE_CAPACITY = 256` — the per-event cost inflection
bump described in the 0.5.0 performance work. The value in code
is correct and the book already says 256; only the rustdoc on the
builder method was stale. Fix it and link to the canonical
constant so the next bump stays in sync.
Pages audited and verified drift-free (read in full, every type /
method / field cross-checked against 0.5.1 source — no changes):
building-agents/executor.md
building-agents/stores.md (&Task breaking change already reflected)
building-agents/dispatchers.md
building-agents/interceptors.md
building-agents/push-notifications.md
concepts/protocol-overview.md
concepts/transport-layers.md
concepts/tasks-and-messages.md
concepts/agent-cards.md
concepts/streaming.md
getting-started/installation.md (MSRV 1.93 matches Cargo.toml:22)
getting-started/quick-start.md
getting-started/project-structure.md
client/builder.md
client/streaming.md
client/task-management.md
client/error-handling.md
Verification
cargo check --workspace: clean, zero warnings
cargo check -p a2a-protocol-server (builder.rs rustdoc link resolved)
No .md file is pulled into a doctest via include_str!, so the book
changes cannot break compilation — only the builder.rs rustdoc
touched by this commit affected the build.
…r, protoc auto-vendor
Fixes every real CI failure surfaced on the
`claude/update-rustls-webpki-CUIUy` branch's first push, and removes
the "needs system protoc" foot-gun that was gating every contributor's
`cargo build --features grpc`. All 8 CI clippy combinations and all 9
CI test combinations now pass locally, matching the full
`.github/workflows/ci.yml` matrix.
1. Format (black_box import order)
----------------------------------
The dep-bump commit migrated 87 `criterion::black_box` call sites to
`std::hint::black_box` across 12 bench files. The sed that added the
`use std::hint::black_box;` import put it before `use criterion::...`,
which violates rustfmt's `Imports granularity = Module` ordering. Six
files were affected. Auto-fixed with `cargo fmt --all` and verified
clean with `cargo fmt --all --check`.
2. rustls CryptoProvider ambiguity under `--all-features` (the real
1.93-matrix failure)
---------------------------------------------------------------------
Root cause: the `genai 0.1 -> 0.5` bump pulls in a new `reqwest` which
drags `rustls-platform-verifier` with the `aws-lc-rs` crypto provider.
With `cargo test --workspace --all-features`, feature unification
links *both* `ring` (from `a2a-protocol-client`'s explicit dep) and
`aws-lc-rs` into every test binary. rustls 0.23.38 then refuses to
pick one and panics at construction time:
Could not automatically determine the process-level CryptoProvider
from Rustls crate features.
Every test in `builder::*`, `client::*`, `discovery::*`,
`transport::*`, `tls::*` that constructs a `ClientConfig` through the
default builder hits this — 57 tests on the first pass, plus the 7
TLS integration tests on the second.
This is also exactly why the "Test (1.93, ubuntu-latest)" CI job
exited 101 (Rust's panic exit code). It is not a rust 1.93 MSRV issue
— it is a feature-unification issue that the branch would have hit
on any rust version.
Fix (source-level, no CI-only workaround):
- `crates/a2a-client/src/tls.rs`: switch `default_tls_config` and
`tls_config_with_extra_roots` from `ClientConfig::builder()` to
`ClientConfig::builder_with_provider(ring_provider())` where
`ring_provider()` returns
`Arc::new(rustls::crypto::ring::default_provider())`. This makes
every production TLS handshake deterministic regardless of what
other providers exist in the dep graph. Added `# Panics` docs
explaining that the `.expect("...")` is unreachable for every
`ring` version this crate pins against.
- `crates/a2a-client/tests/tls_integration_tests.rs`: apply the same
pattern to every `ServerConfig::builder()`, `ClientConfig::builder()`
and `WebPkiClientVerifier::builder()` call via `..._with_provider`,
using a new `test_ring_provider()` helper. Comment explains the
feature-unification interaction for future maintainers.
Result: `cargo test --workspace --all-features` → 64 suites, 0
failures (was 64 failures on this step before).
3. Clippy redundant-closure warnings from the 0.31 opentelemetry
test rewrite
----------------------------------------------------------------
`redundant_closure_for_method_calls` flags
`.map(|dp| dp.value())` → `.map(SumDataPoint::value)`. Clippy only
fires this at the `--all-features` edge because that is the only combo
that compiles the `otel` observable-effect tests. Replaced three
closures with method-path references in `crates/a2a-server/src/otel/mod.rs`
and pulled `SumDataPoint`, `HistogramDataPoint`, `GaugeDataPoint` into
scope via the existing `opentelemetry_sdk::metrics::data` import.
4. Missing `# Panics` doc sections (all-features clippy)
--------------------------------------------------------
`clippy::missing_panics_doc` — added `# Panics` sections to
`default_tls_config` and `tls_config_with_extra_roots` documenting
that the `.expect("ring provider supports default protocol versions")`
is unreachable in practice.
5. protoc auto-install via `protoc-bin-vendored`
------------------------------------------------
The grpc feature used to require contributors to `apt-get install
protobuf-compiler` / `brew install protobuf` / choco before
`cargo build --features grpc` would work, and CI installed it via the
`arduino/setup-protoc` action (+ a GitHub token). Running
`cargo check --features grpc` on a clean machine would panic in
build.rs with a `Could not find 'protoc'` error and no actionable
recovery path for the user.
Fix:
- Added `protoc-bin-vendored = { version = "3" }` to `[workspace.dependencies]`.
This crate ships pre-built `protoc` binaries for Linux
x86_64/aarch64/ppcle/s390, macOS x86_64/aarch64, and Windows x86_64
— covering every platform in the CI matrix and every architecture
a normal Rust contributor runs.
- Both `crates/a2a-client/build.rs` and `crates/a2a-server/build.rs`
now set `PROTOC` to the vendored binary path at build-script start,
*only if the user has not already set `PROTOC` themselves*, so CI
jobs that want to pin a system protoc can still do so:
if std::env::var_os("PROTOC").is_none() {
if let Ok(path) = protoc_bin_vendored::protoc_bin_path() {
std::env::set_var("PROTOC", path);
}
}
- Wired `protoc-bin-vendored` into each crate's `[build-dependencies]`
as an `optional = true` dep gated on the `grpc` feature, so the
vendored binary is only pulled in when grpc is enabled (no cost for
default-feature builds).
- Removed every `arduino/setup-protoc` step from `ci.yml`, `coverage.yml`,
`mutants.yml`, and `release.yml` (four occurrences in release.yml
alone). Replaced each with a one-line comment pointing at the
vendored-crate fallback so future readers do not re-add it reflexively.
Verification
$ which protoc && mv /usr/bin/protoc /tmp/protoc.bak
$ cargo clean -p a2a-protocol-server -p a2a-protocol-client
$ cargo check -p a2a-protocol-server -p a2a-protocol-client --features grpc
[...]
Checking tonic v0.14.5
Checking tonic-prost v0.14.5
Finished `dev` profile [unoptimized + debuginfo] target(s) in 24.96s
With `protoc` completely absent from `PATH` the grpc feature builds
cleanly via the vendored binary, proving the fallback works.
Final verification matrix (all passing)
---------------------------------------
cargo fmt --all --check ok
cargo clippy --workspace --all-targets -- -D warnings ok
cargo clippy --workspace --all-targets --features signing -- -D warnings ok
cargo clippy --workspace --all-targets --features tracing -- -D warnings ok
cargo clippy -p a2a-protocol-client --all-targets --features tls-rustls -- -D warnings ok
cargo clippy -p a2a-protocol-server --all-targets --features sqlite -- -D warnings ok
cargo clippy -p a2a-protocol-server --all-targets --features postgres -- -D warnings ok
cargo clippy -p a2a-protocol-server --all-targets --features axum -- -D warnings ok
cargo clippy --workspace --all-targets --all-features -- -D warnings ok
cargo test --workspace 64 suites / 0 failures
cargo test --workspace --features signing 64 suites / 0 failures
cargo test --workspace --features tracing 64 suites / 0 failures
cargo test -p a2a-protocol-client --features tls-rustls 11 suites / 0 failures
cargo test -p a2a-protocol-server --features sqlite 33 suites / 0 failures
cargo test -p a2a-protocol-server --features postgres 33 suites / 0 failures
cargo test -p a2a-protocol-server --features axum 33 suites / 0 failures
cargo test --workspace --all-features 64 suites / 0 failures
cargo test --workspace --no-default-features 64 suites / 0 failures
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps ok
Scope notes
-----------
- The `Node.js 20 is deprecated` warnings on every CI step are a
GitHub Actions ecosystem deprecation unrelated to this branch. They
affect every workflow using `actions/checkout@v4.3.1`. Ignored here;
fix separately at the org/repo level.
- Did NOT push to main, publish to crates.io, or create a PR — the
user is handling the PR in a fresh session after this lands.
Addresses two Google Search Console findings surfaced after the first dep-bump push: 1. "Duplicate without user-selected canonical" on https://a2a-rust.com/introduction.html (GSC, first seen 2026-03-17, 1 affected page) --------------------------------------------------------------------- Root cause I introduced in the previous head.hbs rewrite: the `<link rel="canonical">`, `<meta property="og:url">`, and `<meta name="twitter:url">` tags were all hardcoded to `https://a2a-rust.com/`. Every single page in the book was claiming to be the canonical of the site root, so Google saw `/introduction.html` and `/` as duplicates with no usable canonical signal and flagged the page. A clean server-side fix would compute the canonical from `{{path}}` via Handlebars, but mdbook's Handlebars pipeline does not register any string-manipulation helpers (only `toc` and `fa`) and the path variable comes in as e.g. `introduction.md` — there is no built-in way to rewrite `.md` → `.html` from a user `head.hbs` override. Fix: keep the hardcoded tags as seed values pointing at the root, give them stable `id` attributes, and rewrite them at page load time from `location.pathname` via a tiny synchronous inline script: var canonicalUrl = "https://a2a-rust.com" + location.pathname; var canonicalEl = document.getElementById("a2a-canonical"); if (canonicalEl) canonicalEl.href = canonicalUrl; // ...same for og:url and twitter:url Both Googlebot and Bingbot run Chromium and pick up JS-written canonicals in their rendering pass, so this works for the search engines that matter. Long-tail non-JS crawlers fall back to the site-root canonical — strictly better than the pre-fix state where every page had a *wrong* per-page canonical. The JSON-LD `SoftwareSourceCode.url` legitimately describes the project as a whole and is left pointing at the root — it is not a per-page canonical. 2. "Excluded by 'noindex' tag" on https://a2a-rust.com/print.html (GSC, first seen 2026-03-21, 1 affected page) ----------------------------------------------------------------- This was working as intended: mdbook emits `print.html` as a "print this book" aggregate view and marks it `<meta name="robots" content="noindex">` because it would dilute per-page SEO. GSC surfaces this as informational. Polish: add `Disallow: /print.html` to `book/static/robots.txt` so crawlers do not waste budget fetching the page in the first place, and the "Excluded by noindex" warning will clear from GSC on the next crawl pass. Comment in robots.txt explains why and notes that the page is still reachable by humans who click "Print this book" in the sidebar (that link does a `window.print()` not a crawl). On the third GSC finding ("Page with redirect") ----------------------------------------------- Three URLs (`http://a2a-rust.com/`, `http://www.a2a-rust.com/`, `https://www.a2a-rust.com/`) are flagged as "Page with redirect". This is informational — it means Google hit them, they redirected correctly to `https://a2a-rust.com/` (the canonical), and Google indexed the canonical. This is the *correct* behaviour for HTTP→HTTPS and www→apex redirects. No fix is needed; clicking "Validate Fix" in GSC after the next crawl will re-verify and clear the status. Verification ------------ - `mdbook build book`: clean, no warnings. - Built `book/book/introduction.html` contains the JS rewrite block (3 element IDs resolved), plus `<link rel="canonical">` seed. - `grep "Disallow: /print.html" book/static/robots.txt` → present. - All per-feature clippy/test matrices from the sibling CI-fix commit still pass (no production source touched).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This release addresses a critical TLS security vulnerability, significantly improves documentation SEO and discoverability, and eliminates the need for manual
protocinstallation by vendoring the protobuf compiler.Key Changes
Security
a2a-protocol-clienttransitively via rustls.Documentation & SEO
SUMMARY.md. Expanded from 43 to 71 lines with detailed guidance.summary_large_imagefor better preview renderingprint.htmlcdn.jsdelivr.net); addedbook/static/vendor/README.mdwith upstream trackingserve()andserve_with_addr()as async functions with return types; added three newTenantResolverimplementations to the built-in types tableBuild Tooling
arduino/setup-protocGitHub Action withprotoc-bin-vendoredcrate:a2a-clientanda2a-serverto use vendored binary whenPROTOCenv var is unsetcargo build --features grpcon a clean machine without manual protobuf-compiler installationtonic-prostandtonic-prost-buildcratesCode Quality
rustls::crypto::ring::default_provider()viabuilder_with_provider()to handle multi-provider scenarios (fixes panic when bothringandaws-lc-rsare in the dependency graph)metric.data.as_any().downcast_ref::<Sum<u64>>()to pattern-match onAggregatedMetrics::U64(MetricData::Sum(...))scope_metrics(),metrics(),metric.name(),metric.data(),sum.data_points(),SumDataPoint::value()shutdown()toshutdown_with_timeout().into()for type coercion (e.g.,WsMessage::Text(json.into()))https://claude.ai/code/session_01GnfmC2YVHMP1SJVwzjAccC