commit f0462b2728c017b44136caacf62916fe30732592
parent a20e552683916395fa5f3014320374f57fa31bdd
Author: triesap <tyson@radroots.org>
Date: Fri, 2 Oct 2026 11:58:46 +0000
availability: define public listing and publisher identities
- Add shared-backed publisher and exact event-version references
- Bound canonical listing coordinates while preserving opaque identifiers
- Keep the domain dependency and source-lock digest guards atomic
- Verify fourteen frozen cases and affected native source consumers
Diffstat:
7 files changed, 560 insertions(+), 3 deletions(-)
diff --git a/core/Cargo.lock b/core/Cargo.lock
@@ -991,6 +991,7 @@ name = "harvestcircle_domain"
version = "0.1.0-alpha"
dependencies = [
"bech32",
+ "radroots_event",
"radroots_identity",
"secrecy",
"zeroize",
diff --git a/core/crates/harvestcircle_domain/Cargo.toml b/core/crates/harvestcircle_domain/Cargo.toml
@@ -13,6 +13,7 @@ include = ["src/**", "Cargo.toml"]
[dependencies]
bech32 = "=0.11.1"
+radroots_event.workspace = true
radroots_identity.workspace = true
secrecy = "=0.10.3"
zeroize = "=1.9.0"
diff --git a/core/crates/harvestcircle_domain/src/availability/identity.rs b/core/crates/harvestcircle_domain/src/availability/identity.rs
@@ -0,0 +1,548 @@
+//! Bounded public references for availability publishers, versions and listings.
+//!
+//! These references identify public data. Their construction proves no event
+//! signature, installed account, signing custody, ownership or physical stock.
+
+use radroots_event::envelope::kind::KIND_CLASSIFIED_LISTING;
+use radroots_event::id::{Nip01Coordinate, RADROOTS_NIP01_COORDINATE_MAX_BYTES};
+
+use crate::{PublicKey, SafeError, SafeErrorCode, SafeMessage};
+
+const EVENT_ID_HEX_BYTES: usize = 64;
+const LISTING_COORDINATE_PREFIX: &str = "30402:";
+
+/// A validated public publisher identity, independent of installed accounts.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct PublicPublisher(PublicKey);
+
+impl PublicPublisher {
+ #[must_use]
+ pub const fn from_public_key(value: PublicKey) -> Self {
+ Self(value)
+ }
+
+ /// Parses a canonical lowercase hexadecimal public author.
+ ///
+ /// # Errors
+ ///
+ /// Returns a safe invalid-public-key error for malformed or invalid keys.
+ pub fn from_hex(value: &str) -> Result<Self, SafeError> {
+ PublicKey::from_hex(value).map(Self)
+ }
+
+ /// Validates an x-only secp256k1 public author using shared identity policy.
+ ///
+ /// # Errors
+ ///
+ /// Returns a safe invalid-public-key error for an invalid curve point.
+ pub fn from_bytes(value: [u8; 32]) -> Result<Self, SafeError> {
+ PublicKey::from_bytes(value).map(Self)
+ }
+
+ #[must_use]
+ pub const fn public_key(self) -> PublicKey {
+ self.0
+ }
+}
+
+/// An exact event-ID reference, separate from a logical listing coordinate.
+///
+/// Possessing an ID does not establish the referenced event's signature or its
+/// relationship to any listing. Those facts require shared verified evidence.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct AvailabilityEventVersion(radroots_event::EventId);
+
+impl AvailabilityEventVersion {
+ #[must_use]
+ pub const fn from_canonical(value: radroots_event::EventId) -> Self {
+ Self(value)
+ }
+
+ /// Parses exactly 64 canonical lowercase hexadecimal event-ID bytes.
+ ///
+ /// # Errors
+ ///
+ /// Returns a safe public-reference error for malformed or ambiguous input.
+ pub fn from_hex(value: &str) -> Result<Self, SafeError> {
+ if value.len() != EVENT_ID_HEX_BYTES
+ || !value
+ .bytes()
+ .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
+ {
+ return Err(invalid_reference());
+ }
+ radroots_event::EventId::parse(value)
+ .map(Self)
+ .map_err(|_| invalid_reference())
+ }
+
+ #[must_use]
+ pub const fn event_id(self) -> radroots_event::EventId {
+ self.0
+ }
+}
+
+/// A nonempty kind-30402 logical listing reference with shared coordinate bounds.
+///
+/// The identifier remains opaque, including colons, whitespace, controls and
+/// Unicode. This reference does not apply strict authored FoodIdentifier policy
+/// and must not replace broader raw inbound or event-head admission. Empty or
+/// longer raw head identifiers remain evidence at their shared owner boundary.
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct AvailabilityListingCoordinate(Nip01Coordinate);
+
+impl AvailabilityListingCoordinate {
+ /// Parses a canonical listing reference without normalizing its identifier.
+ ///
+ /// App bounds, framing and author validation precede shared owned copies.
+ /// Shared parsing owns coordinate interpretation and canonical construction.
+ ///
+ /// # Errors
+ ///
+ /// Returns a safe public-reference error for invalid, noncanonical, empty or
+ /// oversized listing references.
+ pub fn parse(value: &str) -> Result<Self, SafeError> {
+ if value.len() > RADROOTS_NIP01_COORDINATE_MAX_BYTES {
+ return Err(invalid_reference());
+ }
+ let remainder = value
+ .strip_prefix(LISTING_COORDINATE_PREFIX)
+ .ok_or_else(invalid_reference)?;
+ let (author, identifier) = remainder.split_once(':').ok_or_else(invalid_reference)?;
+ if identifier.is_empty() {
+ return Err(invalid_reference());
+ }
+ PublicKey::from_hex(author).map_err(|_| invalid_reference())?;
+ let coordinate = Nip01Coordinate::parse(value).map_err(|_| invalid_reference())?;
+ Self::from_canonical(coordinate)
+ }
+
+ /// Moves a shared coordinate after checking the app's listing invariants.
+ ///
+ /// # Errors
+ ///
+ /// Returns a safe public-reference error for another kind, an empty
+ /// identifier or a coordinate exceeding the selected shared byte bound.
+ pub fn from_canonical(value: Nip01Coordinate) -> Result<Self, SafeError> {
+ if value.kind() != KIND_CLASSIFIED_LISTING
+ || value.identifier().is_empty()
+ || value.as_str().len() > RADROOTS_NIP01_COORDINATE_MAX_BYTES
+ {
+ return Err(invalid_reference());
+ }
+ Ok(Self(value))
+ }
+
+ #[must_use]
+ pub const fn canonical(&self) -> &Nip01Coordinate {
+ &self.0
+ }
+
+ #[must_use]
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
+
+ #[must_use]
+ pub fn publisher(&self) -> PublicPublisher {
+ PublicPublisher::from_public_key(PublicKey::from_canonical(*self.0.pubkey()))
+ }
+
+ #[must_use]
+ pub const fn kind(&self) -> u32 {
+ self.0.kind()
+ }
+
+ #[must_use]
+ pub fn identifier(&self) -> &str {
+ self.0.identifier()
+ }
+}
+
+const fn invalid_reference() -> SafeError {
+ SafeError::new(
+ SafeErrorCode::InvalidProfileMetadata,
+ SafeMessage::new("The public availability reference is invalid."),
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use std::collections::HashSet;
+ use std::error::Error;
+
+ use radroots_event::food::availability::FoodIdentifier;
+ use radroots_event::id::{Nip01Coordinate, RADROOTS_NIP01_COORDINATE_MAX_BYTES};
+
+ use super::{AvailabilityEventVersion, AvailabilityListingCoordinate, PublicPublisher};
+ use crate::{PublicKey, SafeError, SafeErrorCode};
+
+ const AUTHOR_HEX: &str = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
+
+ fn author() -> PublicKey {
+ PublicKey::from_hex(AUTHOR_HEX).expect("valid public author")
+ }
+
+ fn coordinate_text(identifier: &str) -> String {
+ format!("30402:{AUTHOR_HEX}:{identifier}")
+ }
+
+ fn coordinate(identifier: &str) -> AvailabilityListingCoordinate {
+ AvailabilityListingCoordinate::parse(&coordinate_text(identifier))
+ .expect("valid listing reference")
+ }
+
+ fn identifier_at_byte_limit(unit: &str, maximum: usize) -> String {
+ unit.repeat(maximum / unit.len()) + &"x".repeat(maximum % unit.len())
+ }
+
+ fn assert_invalid_reference(error: SafeError) {
+ assert_eq!(error.code(), SafeErrorCode::InvalidProfileMetadata);
+ }
+
+ #[test]
+ fn public_publisher_uses_shared_identity_without_installed_account() {
+ let shared =
+ radroots_identity::PublicKey::from_hex(AUTHOR_HEX).expect("valid shared public author");
+ let publisher = PublicPublisher::from_public_key(PublicKey::from_canonical(shared));
+
+ assert_eq!(publisher.public_key().canonical(), shared);
+ assert_eq!(
+ PublicPublisher::from_hex(AUTHOR_HEX).expect("public author"),
+ publisher
+ );
+ assert_eq!(
+ PublicPublisher::from_bytes(*shared.as_bytes()).expect("public author bytes"),
+ publisher
+ );
+ assert_eq!(HashSet::from([publisher, publisher]).len(), 1);
+ }
+
+ #[test]
+ fn public_publisher_rejects_invalid_curve_and_noncanonical_author() {
+ let invalid_curve = "ff".repeat(32);
+ let uppercase = AUTHOR_HEX.to_ascii_uppercase();
+ let short = &AUTHOR_HEX[..63];
+ let padded = format!(" {AUTHOR_HEX}");
+ let invalid_character = "g".repeat(64);
+
+ for invalid in [
+ "",
+ invalid_curve.as_str(),
+ uppercase.as_str(),
+ short,
+ padded.as_str(),
+ invalid_character.as_str(),
+ "npub1invalid",
+ ] {
+ assert_eq!(
+ PublicPublisher::from_hex(invalid)
+ .expect_err("invalid public author")
+ .code(),
+ SafeErrorCode::InvalidPublicKey
+ );
+ }
+ assert_eq!(
+ PublicPublisher::from_bytes([u8::MAX; 32])
+ .expect_err("invalid x-only curve point")
+ .code(),
+ SafeErrorCode::InvalidPublicKey
+ );
+ }
+
+ #[test]
+ fn event_version_retains_exact_shared_event_id() {
+ let shared = radroots_event::EventId::from_bytes([0xab; 32]);
+ let version = AvailabilityEventVersion::from_canonical(shared);
+
+ assert_eq!(version.event_id(), shared);
+ assert_eq!(version.event_id().as_bytes(), &[0xab; 32]);
+ assert_eq!(
+ AvailabilityEventVersion::from_hex(&"ab".repeat(32)).expect("exact event ID"),
+ version
+ );
+ assert_eq!(HashSet::from([version, version]).len(), 1);
+ assert_ne!(
+ version,
+ AvailabilityEventVersion::from_canonical(radroots_event::EventId::from_bytes(
+ [0xcd; 32]
+ ))
+ );
+ }
+
+ #[test]
+ fn event_version_rejects_malformed_and_ambiguous_hex() {
+ let uppercase = "AB".repeat(32);
+ let short = "a".repeat(63);
+ let long = "a".repeat(65);
+ let invalid_character = "g".repeat(64);
+ let leading_space = format!(" {}", "ab".repeat(32));
+ let prefixed = format!("0x{}", "ab".repeat(32));
+ let multibyte = "é".repeat(32);
+
+ for invalid in [
+ "",
+ uppercase.as_str(),
+ short.as_str(),
+ long.as_str(),
+ invalid_character.as_str(),
+ leading_space.as_str(),
+ prefixed.as_str(),
+ multibyte.as_str(),
+ ] {
+ assert_invalid_reference(
+ AvailabilityEventVersion::from_hex(invalid).expect_err("invalid exact event ID"),
+ );
+ }
+ }
+
+ #[test]
+ fn listing_coordinate_delegates_to_shared_canonical_coordinate() {
+ let text = coordinate_text("farm:lot-1");
+ let shared = Nip01Coordinate::parse(&text).expect("shared coordinate");
+ let reference = AvailabilityListingCoordinate::parse(&text).expect("listing coordinate");
+
+ assert_eq!(reference.canonical(), &shared);
+ assert_eq!(reference.as_str(), shared.as_str());
+ assert_eq!(reference.kind(), 30_402);
+ assert_eq!(reference.publisher().public_key(), author());
+ assert_eq!(reference.identifier(), "farm:lot-1");
+ assert_eq!(
+ AvailabilityListingCoordinate::from_canonical(shared).expect("typed coordinate"),
+ reference
+ );
+ }
+
+ #[test]
+ fn listing_coordinate_rejects_wrong_kind_and_empty_identifier() {
+ for kind in [0, 3, 5, 10_000, 30_000, 30_401, 30_403, 39_999, 40_000] {
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&format!("{kind}:{AUTHOR_HEX}:lot"))
+ .expect_err("wrong listing kind"),
+ );
+ }
+ for invalid in [
+ String::new(),
+ coordinate_text(""),
+ format!("30402:{AUTHOR_HEX}"),
+ "30402:bad:lot".to_owned(),
+ format!("30402:{}:lot", "ff".repeat(32)),
+ ] {
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&invalid)
+ .expect_err("invalid listing coordinate"),
+ );
+ }
+ assert!(
+ Nip01Coordinate::parse(coordinate_text("")).is_ok(),
+ "raw shared coordinate admission remains broader than this listing reference"
+ );
+ }
+
+ #[test]
+ fn listing_coordinate_rejects_noncanonical_kind_and_author_aliases() {
+ for kind in ["+30402", "030402", "+030402", " 30402", "30402 "] {
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&format!("{kind}:{AUTHOR_HEX}:lot"))
+ .expect_err("noncanonical kind encoding"),
+ );
+ }
+ for invalid in [
+ format!("30402:{}:lot", AUTHOR_HEX.to_ascii_uppercase()),
+ format!("30402: {AUTHOR_HEX}:lot"),
+ format!("30402:{AUTHOR_HEX} :lot"),
+ format!("\u{2003}30402:{AUTHOR_HEX}:lot"),
+ ] {
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&invalid)
+ .expect_err("noncanonical author or coordinate framing"),
+ );
+ }
+ }
+
+ #[test]
+ fn listing_coordinate_preserves_opaque_identifier_after_second_colon() {
+ for identifier in [
+ ":",
+ "::",
+ "farm:lot:2026",
+ " victoria:\0seed:\u{2603}\n",
+ "a\u{200d}b",
+ "e\u{301}",
+ "a\r\tb",
+ " trailing ",
+ ] {
+ let reference = coordinate(identifier);
+ let shared = Nip01Coordinate::parse(coordinate_text(identifier))
+ .expect("shared opaque coordinate");
+
+ assert_eq!(reference.identifier().as_bytes(), identifier.as_bytes());
+ assert_eq!(
+ reference.as_str().as_bytes(),
+ coordinate_text(identifier).as_bytes()
+ );
+ assert_eq!(reference.canonical(), &shared);
+ }
+ }
+
+ #[test]
+ fn listing_reference_identifier_policy_is_distinct_from_authored_food_identifier() {
+ let oversized_authored = "x".repeat(513);
+ for identifier in [oversized_authored.as_str(), " farm ", "a\0b", "a\u{200d}b"] {
+ assert_eq!(coordinate(identifier).identifier(), identifier);
+ assert!(
+ FoodIdentifier::parse(identifier).is_err(),
+ "opaque public references cannot inherit strict authored identifier policy"
+ );
+ }
+ let strict = FoodIdentifier::parse("farm:lot-1").expect("strict colon identifier");
+ assert_eq!(coordinate(strict.as_str()).identifier(), strict.as_str());
+ }
+
+ #[test]
+ fn listing_coordinate_accepts_exact_ascii_byte_limit_and_rejects_overflow() {
+ assert_eq!(RADROOTS_NIP01_COORDINATE_MAX_BYTES, 4_096);
+ let prefix = coordinate_text("");
+ assert_eq!(prefix.len(), 71);
+ let identifier = "x".repeat(RADROOTS_NIP01_COORDINATE_MAX_BYTES - prefix.len());
+ let exact = coordinate_text(&identifier);
+
+ assert_eq!(identifier.len(), 4_025);
+ assert_eq!(exact.len(), RADROOTS_NIP01_COORDINATE_MAX_BYTES);
+ assert_eq!(
+ AvailabilityListingCoordinate::parse(&exact)
+ .expect("exact full coordinate limit")
+ .identifier(),
+ identifier
+ );
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&(exact + "x"))
+ .expect_err("one byte above full coordinate limit"),
+ );
+ }
+
+ #[test]
+ fn listing_coordinate_enforces_multibyte_and_combining_byte_limits() {
+ let maximum = RADROOTS_NIP01_COORDINATE_MAX_BYTES - coordinate_text("").len();
+ for unit in ["é", "🥕", "e\u{301}"] {
+ let identifier = identifier_at_byte_limit(unit, maximum);
+ let exact = coordinate_text(&identifier);
+
+ assert_eq!(identifier.len(), maximum);
+ assert_eq!(exact.len(), RADROOTS_NIP01_COORDINATE_MAX_BYTES);
+ assert_eq!(
+ AvailabilityListingCoordinate::parse(&exact)
+ .expect("exact UTF-8 coordinate limit")
+ .identifier()
+ .as_bytes(),
+ identifier.as_bytes()
+ );
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::parse(&(exact + "x"))
+ .expect_err("one UTF-8 byte above coordinate limit"),
+ );
+ }
+ assert_ne!(coordinate("é"), coordinate("e\u{301}"));
+ }
+
+ #[test]
+ fn typed_coordinate_constructor_cannot_bypass_listing_invariants() {
+ for text in [
+ format!("30000:{AUTHOR_HEX}:lot"),
+ format!("0:{AUTHOR_HEX}:"),
+ coordinate_text(""),
+ ] {
+ let shared = Nip01Coordinate::parse(text).expect("valid broader shared coordinate");
+ assert_invalid_reference(
+ AvailabilityListingCoordinate::from_canonical(shared)
+ .expect_err("shared coordinate is not a nonempty listing reference"),
+ );
+ }
+ let canonicalized = Nip01Coordinate::parse(format!(
+ "030402:{}:farm:lot",
+ AUTHOR_HEX.to_ascii_uppercase()
+ ))
+ .expect("shared canonicalization");
+ let reference = AvailabilityListingCoordinate::from_canonical(canonicalized)
+ .expect("already canonical shared listing reference");
+ assert_eq!(reference.as_str(), coordinate_text("farm:lot"));
+ }
+
+ #[test]
+ fn event_versions_and_listing_coordinates_preserve_distinct_identity() {
+ let first_id = radroots_event::EventId::from_bytes([0xab; 32]);
+ let first = AvailabilityEventVersion::from_canonical(first_id);
+ let repeated = AvailabilityEventVersion::from_hex(&first_id.to_hex())
+ .expect("repeated exact event version");
+ let revision = AvailabilityEventVersion::from_canonical(
+ radroots_event::EventId::from_bytes([0xcd; 32]),
+ );
+ let listing = coordinate("lot-1");
+ let same_listing = AvailabilityListingCoordinate::from_canonical(
+ Nip01Coordinate::parse(coordinate_text("lot-1")).expect("same shared coordinate"),
+ )
+ .expect("same listing coordinate");
+ let different_identifier = coordinate("lot-2");
+ let other_author = PublicKey::from_bytes([7; 32]).expect("another public author");
+ let different_publisher =
+ AvailabilityListingCoordinate::parse(&format!("30402:{}:lot-1", other_author.to_hex()))
+ .expect("distinct publisher coordinate");
+
+ assert_eq!(first, repeated);
+ assert_ne!(first, revision);
+ assert_eq!(listing, same_listing);
+ assert_ne!(listing, different_identifier);
+ assert_ne!(listing, different_publisher);
+ assert_eq!(HashSet::from([first, repeated, revision]).len(), 2);
+ assert_eq!(
+ HashSet::from([
+ listing,
+ same_listing,
+ different_identifier,
+ different_publisher
+ ])
+ .len(),
+ 3
+ );
+ }
+
+ #[test]
+ fn availability_reference_errors_contain_only_static_safe_messages() {
+ const INPUT_MARKER: &str = "raw_availability_input_diagnostic_marker";
+ let publisher_error =
+ PublicPublisher::from_hex(INPUT_MARKER).expect_err("malformed public author");
+ let version_error =
+ AvailabilityEventVersion::from_hex(INPUT_MARKER).expect_err("malformed exact event ID");
+ let coordinate_error =
+ AvailabilityListingCoordinate::parse(&format!("30403:{AUTHOR_HEX}:{INPUT_MARKER}"))
+ .expect_err("wrong kind with opaque input marker");
+
+ assert_eq!(publisher_error.code(), SafeErrorCode::InvalidPublicKey);
+ assert_invalid_reference(version_error);
+ assert_invalid_reference(coordinate_error);
+ assert_eq!(
+ publisher_error.message(),
+ PublicPublisher::from_hex("")
+ .expect_err("empty public author")
+ .message()
+ );
+ assert_eq!(
+ version_error.message(),
+ AvailabilityEventVersion::from_hex("")
+ .expect_err("empty event ID")
+ .message()
+ );
+ assert_eq!(
+ coordinate_error.message(),
+ AvailabilityListingCoordinate::parse("")
+ .expect_err("empty coordinate")
+ .message()
+ );
+ for error in [publisher_error, version_error, coordinate_error] {
+ assert!(!error.message().as_str().contains(INPUT_MARKER));
+ assert!(!error.to_string().contains(INPUT_MARKER));
+ assert!(!format!("{error:?}").contains(INPUT_MARKER));
+ assert!(error.source().is_none());
+ }
+ }
+}
diff --git a/core/crates/harvestcircle_domain/src/availability/mod.rs b/core/crates/harvestcircle_domain/src/availability/mod.rs
@@ -0,0 +1,5 @@
+//! Public availability references kept separate from local account authority.
+
+pub mod identity;
+
+pub use identity::{AvailabilityEventVersion, AvailabilityListingCoordinate, PublicPublisher};
diff --git a/core/crates/harvestcircle_domain/src/lib.rs b/core/crates/harvestcircle_domain/src/lib.rs
@@ -1,11 +1,13 @@
#![doc = "HarvestCircle Nostr identity domain types."]
+pub mod availability;
pub mod error;
pub mod identity;
pub mod key;
pub mod profile;
pub mod time;
+pub use availability::{AvailabilityEventVersion, AvailabilityListingCoordinate, PublicPublisher};
pub use error::{SafeError, SafeErrorCode, SafeMessage};
pub use identity::{
IdentityCreatedAt, IdentityLabel, LocalKeyringBinding, NostrIdentity, NostrIdentityReference,
diff --git a/radroots.lib.source-lock.v1.toml b/radroots.lib.source-lock.v1.toml
@@ -6,4 +6,4 @@ workspace_catalog_sha256 = "ee295f2352e2577a4052d980624415aec9871197d4fc9910a4c2
version = "0.1.0-alpha"
source_archive_sha256 = "c648a3ab993d10253b9073e7e86db7b8970863bdf1d394d9fc30d66825695240"
lockfile = "core/Cargo.lock"
-lockfile_sha256 = "648040384ae6978d255be3794f3a69bb37287fd929bb4b9bb8c1cb15e8f34976"
+lockfile_sha256 = "1cf1c2d3f60883fbfe8a336fd0e20cb755b79f29a241324d1832d1e819b2cebd"
diff --git a/tools/xtask/src/lib.rs b/tools/xtask/src/lib.rs
@@ -1159,7 +1159,7 @@ fn provenance_check(root: &Path, inventory: &Inventory, findings: &mut Vec<Strin
"version = \"0.1.0-alpha\"\n",
"source_archive_sha256 = \"c648a3ab993d10253b9073e7e86db7b8970863bdf1d394d9fc30d66825695240\"\n",
"lockfile = \"core/Cargo.lock\"\n",
- "lockfile_sha256 = \"648040384ae6978d255be3794f3a69bb37287fd929bb4b9bb8c1cb15e8f34976\"\n",
+ "lockfile_sha256 = \"1cf1c2d3f60883fbfe8a336fd0e20cb755b79f29a241324d1832d1e819b2cebd\"\n",
);
let source_lock_bytes =
match bounded_no_follow_bytes(root, Path::new(SOURCE_LOCK_PATH), MAX_SOURCE_LOCK_BYTES) {
@@ -2434,7 +2434,7 @@ mod tests {
"version = \"0.1.0-alpha\"\n",
"source_archive_sha256 = \"c648a3ab993d10253b9073e7e86db7b8970863bdf1d394d9fc30d66825695240\"\n",
"lockfile = \"core/Cargo.lock\"\n",
- "lockfile_sha256 = \"648040384ae6978d255be3794f3a69bb37287fd929bb4b9bb8c1cb15e8f34976\"\n",
+ "lockfile_sha256 = \"1cf1c2d3f60883fbfe8a336fd0e20cb755b79f29a241324d1832d1e819b2cebd\"\n",
),
);
write(&root, "core/Cargo.toml", "");