@@ -447,6 +447,8 @@ pub enum InterchangeProjectValidationError {
447447 SemVerConstraintParse ( String , semver:: Error ) ,
448448 #[ error( "failed to parse `{0}` as RFC3339 datetime: {1}" ) ]
449449 DatetimeParse ( Box < str > , chrono:: ParseError ) ,
450+ #[ error( "file `{0}` is present in symbol index, but absent in file checksums" ) ]
451+ MissingFileInChecksum ( Box < str > ) ,
450452 #[ error(
451453 "invalid file checksum algorithm `{0}`, expected one of:\n \
452454 SHA1, SHA224, SHA256, SHA-384, SHA3-256, SHA3-384, SHA3-512\n \
@@ -482,6 +484,16 @@ impl InterchangeProjectMetadataRaw {
482484 & self ,
483485 ) -> Result < InterchangeProjectMetadata , InterchangeProjectValidationError > {
484486 let checksum = if let Some ( checksum) = & self . checksum {
487+ // Checksum must include all the files mentioned in index,
488+ // but index may mention less files than checksum.
489+ for path in self . index . values ( ) {
490+ if !checksum. contains_key ( path) {
491+ return Err ( InterchangeProjectValidationError :: MissingFileInChecksum (
492+ path. as_str ( ) . into ( ) ,
493+ ) ) ;
494+ }
495+ }
496+
485497 let mut res = IndexMap :: with_capacity ( checksum. len ( ) ) ;
486498 for ( k, v) in checksum {
487499 let k = Utf8UnixPath :: new ( k) . to_path_buf ( ) ;
@@ -508,16 +520,19 @@ impl InterchangeProjectMetadataRaw {
508520 } ;
509521 res. insert ( k, InterchangeProjectChecksum { value, algorithm } ) ;
510522 }
523+
511524 Some ( res)
512525 } else {
513526 None
514527 } ;
528+
515529 Ok ( InterchangeProjectMetadata {
516530 index : self
517531 . index
518532 . iter ( )
519533 . map ( |( k, v) | ( k. to_owned ( ) , Utf8UnixPath :: new ( v) . to_path_buf ( ) ) )
520534 . collect ( ) ,
535+ // TODO: this is not strictly correct, as RFC3339 only partially overlaps with ISO8601
521536 created : chrono:: DateTime :: parse_from_rfc3339 ( & self . created )
522537 . map_err ( |e| {
523538 InterchangeProjectValidationError :: DatetimeParse (
0 commit comments