Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for public extensions in Reports. #754

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jhoyla
Copy link
Contributor

@jhoyla jhoyla commented Dec 31, 2024

Draft 13 adds mandatory support for public extensions in the ReportMetadata, but doesn't define any (Taskprov is (for now) a private extension). This PR adds support for rejecting unknown extensions, which is all of them.

Copy link
Contributor

@cjpatton cjpatton left a comment

Choose a reason for hiding this comment

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

I believe we're missing one feature: we need to resolve repeated extensions across the public and private extension fields.

crates/daphne/src/error/aborts.rs Outdated Show resolved Hide resolved
crates/daphne/src/error/aborts.rs Outdated Show resolved Hide resolved
crates/daphne/src/messages/mod.rs Outdated Show resolved Hide resolved
crates/daphne/src/protocol/report_init.rs Outdated Show resolved Hide resolved
crates/daphne/src/protocol/report_init.rs Outdated Show resolved Hide resolved
@jhoyla
Copy link
Contributor Author

jhoyla commented Jan 2, 2025

I believe we're missing one feature: we need to resolve repeated extensions across the public and private extension fields.

So the spec says:

type. (For the purposes of this check, a private report extension can conflict
with a public report extension.) If so, the Aggregator MUST mark the input share
as invalid with error invalid_message.

Which I take to mean a conflict between the public and private extensions is allowed.
If I add support for taskprov as a public extension do I reject it if it appears in both places?

Copy link
Collaborator

@mendess mendess left a comment

Choose a reason for hiding this comment

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

not even a nit, just a comment. I don't have a preference but instead of Vec::new() you can write vec![]

@cjpatton
Copy link
Contributor

cjpatton commented Jan 2, 2025

I believe we're missing one feature: we need to resolve repeated extensions across the public and private extension fields.

So the spec says:

type. (For the purposes of this check, a private report extension can conflict
with a public report extension.) If so, the Aggregator MUST mark the input share
as invalid with error invalid_message.

Which I take to mean a conflict between the public and private extensions is allowed. If I add support for taskprov as a public extension do I reject it if it appears in both places?

The intent of the text is: "if the same extension appears twice, then the report MUST be rejected - regardless of what fields the extensions appear in." In particular, if the taskprov extension appears in the public and private fields, then reject.

@jhoyla jhoyla force-pushed the jhoyla/public-extensions branch 3 times, most recently from 692eb78 to eda9b3c Compare January 8, 2025 11:37
@jhoyla jhoyla force-pushed the jhoyla/public-extensions branch from eda9b3c to 5078b99 Compare January 8, 2025 12:41
@jhoyla jhoyla requested review from mendess and cjpatton January 8, 2025 12:49
Copy link
Contributor

@cjpatton cjpatton left a comment

Choose a reason for hiding this comment

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

The code looks largely correct, though I have some suggestions for behavior changes. I think the tests need a bit of work. Also, I have some suggestions for making the code a little cleaner/easier to read.

@@ -533,6 +537,150 @@ async fn leader_upload_taskprov_wrong_version(version: DapVersion) {

async_test_versions!(leader_upload_taskprov_wrong_version);

#[tokio::test]
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the test coverage in the daphne::roles module is high enough that we could just as easily move theses tests there. You can call leader::handle_upload_req() on the mock aggregator, just as you already do in a new test in that module.

Any code path that can be tested without the e2e setup ought to be moved to a unit test, since unit tests are easier to run.

task_id: &TaskId,
unknown_extensions: &[u16],
) -> Result<Self, DapError> {
let detail = serde_json::to_string(&unknown_extensions);
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary reference

Suggested change
let detail = serde_json::to_string(&unknown_extensions);
let detail = serde_json::to_string(unknown_extensions);

detail: s,
task_id: *task_id,
}),
Err(x) => Err(fatal_error!(err = %x,)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Err(x) => Err(fatal_error!(err = %x,)),
Err(x) => Err(fatal_error!(err = %x)),

task_id: &TaskId,
unknown_extensions: &[u16],
) -> Result<Self, DapError> {
let detail = serde_json::to_string(&unknown_extensions);
Copy link
Contributor

Choose a reason for hiding this comment

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

More Rusty

Suggested change
let detail = serde_json::to_string(&unknown_extensions);
let detail = serde_json::to_string(&unknown_extensions).map_err(|e| fatal_error!(err = e))?;

Comment on lines +79 to +82
public_extensions: match version {
DapVersion::Draft09 => None,
DapVersion::Latest => Some(Vec::new()),
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the extensions are replicated between the Leader and Helper, perhaps it makes more sense to include them in the public extensions field rather than in the private extension fields.

If you take this suggestion, let's also rename extensions to public_extensions.

}
);
}
test_versions! {handle_unknown_public_extensions_in_report}
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: This creates the test for all versions of DAP, including draft 09.

) {
(Some(extensions), DapVersion::Latest) => {
let mut unknown_extensions = Vec::<u16>::new();
if crate::protocol::no_duplicates(extensions.iter()).is_err() {
Copy link
Contributor

Choose a reason for hiding this comment

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

And use crate::protocol;. Also, we should rename no_duplicates to something more distinctive.

Suggested change
if crate::protocol::no_duplicates(extensions.iter()).is_err() {
if protocol::no_duplicates(extensions.iter()).is_err() {

@@ -223,6 +223,47 @@ pub async fn handle_upload_req<A: DapLeader>(
.into());
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Add a comment here telling the reader what's going on.

Comment on lines +253 to +264
(Some(_), DapVersion::Draft09) => {
return Err(DapError::Abort(DapAbort::version_mismatch(
DapVersion::Draft09,
DapVersion::Latest,
)))
}
(None, DapVersion::Latest) => {
return Err(DapError::Abort(DapAbort::version_mismatch(
DapVersion::Latest,
DapVersion::Draft09,
)))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure either of these arms could ever be reached, assuming the code that sets public_extensions is correct. If I were you, I would use the public_extension.is_some() to deduce which version was negotiated. Tnen we could replace this big ugly match with:

if let Some(public_extensions) = &report.report_metadata.public_extensions {
    ...  // check for duplicates, unorecgonized values, and so on
}

@@ -1348,6 +1496,116 @@ async fn leader_selected() {
.unwrap();
}

#[tokio::test]
async fn leader_collect_taskprov_repeated_abort() {
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this new test do?

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.

3 participants