Skip to content

pull in async trait from & account for repo reorg in dice-util - #11674

Open
flihp wants to merge 6 commits into
mainfrom
flihp/dice-util-update
Open

flihp wants to merge 6 commits into
mainfrom
flihp/dice-util-update

Conversation

@flihp

@flihp flihp commented Nov 3, 2026

Copy link
Copy Markdown

This work is intended to simplify the machinery behind the existing sled-agent RoT interface & to bring sled-agent up to date w/ some reorganization & renaming done in the dice-util repo. The hard work was already done in oxidecomputer/dice-util#360. This PR just brings sled-agent up to date allowing it to benefit from the newly async trait & impls.

flihp added 3 commits November 2, 2026 10:03
These two tests are:
- `rot_attestor_verify_attestation`: get the required artifacts through the
  `RotAttestationHandle`, and then verify the attestation returned using
  the `dice-verifier`
- `rot_attestor_busy`: ensure that the `RotAttestationTask` will reject
  requests with `RotError::Busy` / `http::StatusCode::SERVICE_UNAVAILABLE`
  when `QUEUE_SIZE` requests are outstanding

This requires a few utility functions to:
- generate mock keys and certs using the sprockets test utils
- generate a mock measurement log using `attest-mock` and some KDL
This commit updates `AttestIpcc` to use this new async version of the
trait. `AttestIpcc` now handles blocking I/O internally. This eliminates
a lot of machinery and simplifies the request queuing logic.

The `RotAttestationTask` & `RotAttestationHandle` are now combined in a
single `RotAttestor` type. We now use a `Mutex` to serialize requests
while preserving the existing limit on outstanding requests with a
`Semaphore`.
@flihp
flihp requested review from andrewjstone and luqmana November 3, 2026 16:55
@flihp flihp linked an issue Nov 3, 2026 that may be closed by this pull request
@flihp
flihp requested review from jmpesp and papertigers and removed request for andrewjstone November 3, 2026 17:28

@jmpesp jmpesp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To check my assumptions: RotAttestor now takes care of spawning the necessary background task(s)? Does that mean RotError::Shutdown can still come from the functions called on guard.attest?

Comment thread sled-agent/src/rot.rs Resolved
Comment thread sled-agent/src/rot.rs Outdated
let attestor = RotAttestationTask::launch(&logctx.log, &cfg).unwrap();
let log = attestor.get_measurement_log().await.unwrap();
let chain = attestor.get_certificate_chain().await.unwrap();
let nonce: Nonce = SaRotTypes::Nonce::N32([7u8; 32]).into();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Any reason not to generate a random nonce here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I went back and forth on this. TL;DR simplicity won out and as written, this tests all of he parts that we care about here.

Some of the logic behind the choice:
There's nothing bad about creating the qualifying data from a random nonce here, but for the purposes of this test we don't really care about freshness or even appraising the attestation. All we care about is that the machinery in sled-agent behaves the way we expect. Verifying the attestation here serves as a means to check the integrity of the data we get back from the plumbing, but that's it. There are tests in the dice-util repo where we try to mimic the "real world" as much as possible and we use a random nonce there. I didn't think there was much use recreating those tests here.

All that said the cost associated with dipping into the RNG is pretty low so I'm not really attached to either approach. LMK if you have a preference?

Comment thread sled-agent/src/rot.rs Resolved
Comment thread sled-agent/src/rot.rs
pub struct QualifyingData(oxide_rot::QualifyingData);

impl From<SaRotTypes::Nonce> for Nonce {
impl From<SaRotTypes::Nonce> for QualifyingData {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we plan to also change the API-visible names as well?

@flihp flihp Nov 5, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

At this point I avoided doing so because the change is just cosmetic. I've got a few topic branches where I'm working out how to add support for the HeliosRot and that will require API changes. It seemed logical to do that in a single PR ... or maybe just leave this part of the API alone? I'm not fully convinced this is the right approach so suggestions / opinions are welcome.

@flihp

flihp commented Nov 3, 2026 •

Copy link
Copy Markdown
Author

in reply to @jmpesp from #11674 (review)

To check my assumptions: RotAttestor now takes care of spawning the necessary background task(s)?

Yes: https://github.com/oxidecomputer/dice-util/blob/main/oxide-rot/src/ipcc.rs#L39

Does that mean RotError::Shutdown can still come from the functions called on guard.attest?

As written now I believe the answer is 'no'. AFAIK: RotError::Shutdown was produced in response to errors from the oneshot receive channel used by the http endpoint to get responses from the long running background task / RotAttestationTask :

pub async fn get_measurement_log(
&self,
) -> Result<MeasurementLog, RotError> {
let (tx, rx) = oneshot::channel();
self.tx.try_send(AttestationMessage::GetMeasurementLog(tx))?;
Ok(rx.await.map_err(|_| RotError::Shutdown)??)
}

and

pub fn launch(
log: &Logger,
attest_config: &AttestConfig,
) -> Result<RotAttestationHandle, RotError> {
let (task, handle) = Self::new(log, attest_config)?;
tokio::task::spawn_blocking(move || task.run());
Ok(handle)
}

This doesn't give us much info about what happened to the task, but it means that the task that should respond is not going to and Shutdown seems reasonable there. The use of spawn_blocking has been moved into a much shorter lived task (one request) here:

https://github.com/oxidecomputer/dice-util/blob/994c3fcdb7e3897283f5082a892b67db397c0738/oxide-rot/src/ipcc.rs#L39-L47

This code now immediately calls await on the JoinHandle returned by spawn_blocking and that's the only place where an error may occur that is at least similar to the RotError::Shutdown. In this code however we do JoinHandle.await.expect(..) and that will cause that code to panic on a JoinError. AFAIK this only happens if the task spawned panics and that's ... impossible?

All that said, instead of expecting, we could turn the JoinError into something akin to RotError::Shutdown (that should probably be mapped to an HTTP internal error?) if we think that's the right thing to do. But as currently written, the Shutdown variant of RotError is no longer useful.

Comment thread sled-agent/src/rot.rs Resolved
Comment thread sled-agent/src/rot.rs Resolved
Comment thread sled-agent/src/rot.rs Resolved

This branch has not been deployed

No deployments
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.

update dice-util deps

3 participants