Skip to content

chore(attestation): gate azure generation on the target, not the feature alone - #94

Merged
ameba23 merged 2 commits into
flashbots:mainfrom
SeismicSystems:upstream/azure-attester-target-gate
Sep 9, 2026
Merged

ameba23 merged 2 commits into
flashbots:mainfrom
SeismicSystems:upstream/azure-attester-target-gate

Conversation

@samlaf

@samlaf samlaf commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

This is just a nice to have, but it's been annoying me. I open a bunch of related repos in vscode, and turn on all-features on rust-analyzer because that's the only easy way that vscode workspaces can configure features (they don't read repo-specific settings.json file when inside a workspace).

But even without the vscode workspace issue, I think generally this is a nice to have cleanup as it makes it more obvious by the build.rs injected feature name that its x86 linux only.

LLM Summary

cargo check --all-features, and anything else that turned on azure-attester, failed to build on any host that is not x86_64 linux. Two dependencies of the generation path do not compile elsewhere: tss-esapi-sys ships pregenerated bindings for a fixed list of target tuples that omits aarch64-darwin and panics on anything outside it, and az-tdx-vtpm takes az-cvm-vtpm with default features, whose verifier turns on sev/openssl and so rdrand 0.8, which has no non-x86 support (virtee/sev#369). That put a whole-crate build failure in front of anyone on an Apple Silicon or aarch64 machine running a feature-complete check, rust-analyzer and cargo doc included.

Gating on the feature alone was the mistake: a feature records what the caller asked for, not what the target can provide. So declare az-tdx-vtpm and tss-esapi in a
cfg(all(target_os = "linux", target_arch = "x86_64")) dependency table, and have build.rs derive an azure_attester_x86_64_linux cfg from the feature and those same two target values. The generation code moves from cfg(feature = "azure-attester") onto that cfg. Both halves are load bearing: the feature keeps the native tpm2-tss stack opt-in so verification never links it, which a build script cannot do since it can neither add nor remove a dependency, while the cfg is what asserts the code compiles here. The cfg carries the platform in its name so the gate sites need not each repeat the condition, and so that reading one makes clear it is not the feature.

Enabling azure-attester off x86_64 linux is now a no-op rather than an error. Cargo still reports the feature as enabled; its two dependencies are simply absent from the graph and build.rs withholds the cfg, leaving the compiled surface equal to azure-verifier on its own: detect() never reports AzureTdx, and generation returns AttestationTypeNotSupported. Verification is untouched and still needs no TPM stack anywhere.

Narrowing to x86_64 is not a workaround waiting on those upstream fixes. TDX is an Intel technology and the vTPM is read through a linux device, so an Azure TDX CVM is x86_64 linux by construction and the gate is permanent; the sev issue is linked as evidence for anyone who later tries to widen it. The upstream fix that would let us delete code is kinvolk/azure-cvm-tooling#95, so tpm_quote's retirement note now names it.

The macOS CI job gains a cargo check -p attestation --all-features step, which is what would have caught this. The crate readme claimed it was impossible to compile with azure-attester on macOS, and now describes the no-op instead.

One hazard when editing either file: the platform condition lives in both Cargo.toml's target table and build.rs, and nothing enforces that the two agree. A build.rs broader than the table fails the build outright; a narrower one silently drops the generation code. Comments in both places say so.

…ure alone

`cargo check --all-features`, and anything else that turned on
`azure-attester`, failed to build on any host that is not x86_64 linux.
Two dependencies of the generation path do not compile elsewhere:
tss-esapi-sys ships pregenerated bindings for a fixed list of target
tuples that omits aarch64-darwin and panics on anything outside it, and
az-tdx-vtpm takes az-cvm-vtpm with default features, whose `verifier`
turns on `sev/openssl` and so rdrand 0.8, which has no non-x86 support
(virtee/sev#369). That put a whole-crate build failure in front of
anyone on an Apple Silicon or aarch64 machine running a feature-complete
check, rust-analyzer and cargo doc included.

Gating on the feature alone was the mistake: a feature records what the
caller asked for, not what the target can provide. So declare
az-tdx-vtpm and tss-esapi in a
cfg(all(target_os = "linux", target_arch = "x86_64")) dependency table,
and have build.rs derive an `azure_attester_x86_64_linux` cfg from the
feature and those same two target values. The generation code moves from
`cfg(feature = "azure-attester")` onto that cfg. Both halves are load
bearing: the feature keeps the native tpm2-tss stack opt-in so
verification never links it, which a build script cannot do since it can
neither add nor remove a dependency, while the cfg is what asserts the
code compiles here. The cfg carries the platform in its name so the gate
sites need not each repeat the condition, and so that reading one makes
clear it is not the feature.

Enabling `azure-attester` off x86_64 linux is now a no-op rather than an
error. Cargo still reports the feature as enabled; its two dependencies
are simply absent from the graph and build.rs withholds the cfg, leaving
the compiled surface equal to `azure-verifier` on its own: detect() never
reports AzureTdx, and generation returns AttestationTypeNotSupported.
Verification is untouched and still needs no TPM stack anywhere.

Narrowing to x86_64 is not a workaround waiting on those upstream fixes.
TDX is an Intel technology and the vTPM is read through a linux device, so
an Azure TDX CVM is x86_64 linux by construction and the gate is
permanent; the sev issue is linked as evidence for anyone who later tries
to widen it. The upstream fix that would let us delete code is
kinvolk/azure-cvm-tooling#95, so tpm_quote's retirement note now names it.

The macOS CI job gains a `cargo check -p attestation --all-features` step,
which is what would have caught this. The crate readme claimed it was
impossible to compile with `azure-attester` on macOS, and now describes
the no-op instead.

One hazard when editing either file: the platform condition lives in both
Cargo.toml's target table and build.rs, and nothing enforces that the two
agree. A build.rs broader than the table fails the build outright; a
narrower one silently drops the generation code. Comments in both places
say so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@ameba23 ameba23 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I hesitated a bit to approve this, as it might give developers a false sense of security that the azure feature will compile correctly when it will not in production.

But since this would anyway be picked up by CI checks, and this PR reduces friction for developers not on linux, let do it.

Could you log compile-time warning from build.rs when compiled with azure-attester enabled but no x86 linux target. Then happy to merge.

Enabling `azure-attester` off x86_64 linux builds cleanly and does
nothing, which is the point of the target gate but is silent about it.
Someone who asks for generation on an Apple Silicon machine gets a crate
that compiles, reports the feature as on, and then fails at runtime with
AttestationTypeNotSupported, with nothing along the way to say why.

So build.rs now emits a `cargo::warning` on the path where the feature is
enabled but the target is not x86_64 linux. It names the target it saw
and both consequences a caller will actually hit — detect() never
returning AzureTdx, generate_attestation for AzureTdx failing with
AttestationTypeNotSupported — and says verification is unaffected. A
warning rather than a hard error, because `--all-features` has to stay
buildable everywhere; that is the property the target table exists to
protect and erroring here would give it away.

The Cargo.toml comment dropped its link to virtee/sev#369. That issue was
one of two reasons those deps did not build off x86_64, and it no longer
applies: sev 6.3.1 handles non-x86 rather than failing to compile
(identify_host_generation returns an error there). tss-esapi-sys is the
reason that remains, since it has no bindings for most target tuples, so
the comment now cites that alone. The gate stays exactly as wide as it
was; only the justification was stale.

Both the comment and the readme also implied you must build on x86_64
linux. You must build *for* it. The condition reads CARGO_CFG_TARGET_*,
so any host with a cross toolchain and tpm2-tss and openssl for the
target gets the generation code via --target x86_64-unknown-linux-gnu.
The readme says so and the warning points at the flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@samlaf
samlaf force-pushed the upstream/azure-attester-target-gate branch from bdec5fe to 28a0f5e Compare September 8, 2026 15:00
@samlaf

samlaf commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@ameba23 done

@ameba23
ameba23 merged commit 33539a3 into flashbots:main Sep 9, 2026
2 checks passed
@samlaf
samlaf deleted the upstream/azure-attester-target-gate branch September 9, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants