use prikk_error::Result;
use prikk_object::{
BlobKind, BlobPayload, CanonicalEncode, CreateFile, NodeId, ObjectEnvelope, ObjectId,
ObjectType, Operation, OperationKind, PatchPayload, PatchPurpose,
};
use crate::author_signing::author_signature;
use crate::maintainer_signing::{
Ed25519MaintainerSigner, MaintainerSigner as _, maintainer_signature,
};
use crate::rfc111_seal_simulation::simulate_one_seal;
use crate::sync_negotiation::sync_test_support::fresh_repo;
use crate::wal::Wal;
use crate::{
Ed25519AuthorSigner, FileObjectStore, ObjectWriter, RepositoryLayout, add_trusted_maintainer,
};
pub(super) use crate::sync_negotiation::sync_test_support::cleanup;
pub(super) fn repo(name: &str) -> Result<RepositoryLayout> {
fresh_repo(name)
}
pub(super) fn maintainer_signer(seed: u8) -> Result<Ed25519MaintainerSigner> {
Ed25519MaintainerSigner::from_seed(format!("sender-maintainer-{seed}"), &[seed; 32])
}
pub(super) fn author_signer(seed: u8) -> Result<Ed25519AuthorSigner> {
Ed25519AuthorSigner::from_seed(format!("sender-author-{seed}"), &[seed; 32])
}
pub(super) fn adopt(layout: &RepositoryLayout, signer: &Ed25519MaintainerSigner) -> Result<()> {
let public_key_hex: String = signer
.public_key_bytes()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect();
add_trusted_maintainer(layout, signer.key_id(), &public_key_hex)?;
Ok(())
}
pub(super) fn write_blob(objects: &mut FileObjectStore, content: &[u8]) -> Result<ObjectId> {
let signer = maintainer_signer(0xFF)?;
let payload = BlobPayload::new(BlobKind::Text, content.to_vec());
let mut envelope = ObjectEnvelope::unsigned(ObjectType::Blob, 1, payload.to_canonical_bytes()?);
let id = envelope.object_id();
envelope.add_signature(maintainer_signature(&signer, ObjectType::Blob, id)?)?;
objects.write_object(&envelope)
}
pub(super) fn create_file_patch(
signer: &Ed25519AuthorSigner,
path: &str,
node_seed: u8,
blob_id: ObjectId,
) -> Result<ObjectEnvelope> {
let payload = PatchPayload {
operations: vec![Operation {
op_seq: 1,
op_id: None,
preconditions: Vec::new(),
kind: OperationKind::CreateFile(CreateFile {
path: path.to_string(),
node_id: NodeId::from_bytes([node_seed; 32]),
blob_id,
mode: 0o100_644,
}),
}],
intent: None,
preconditions: Vec::new(),
purpose: PatchPurpose::Normal,
};
let mut envelope =
ObjectEnvelope::unsigned(ObjectType::Patch, 1, payload.to_canonical_bytes()?);
let id = envelope.object_id();
envelope.add_signature(author_signature(signer, id)?)?;
Ok(envelope)
}
pub(super) fn seal_patches_onto(
layout: &RepositoryLayout,
ref_name: &str,
patches: &[ObjectEnvelope],
signer: &Ed25519MaintainerSigner,
) -> Result<ObjectId> {
crate::active::write_active_ref_metadata(layout, ref_name)?;
let wal = Wal::for_layout(layout);
for patch in patches {
wal.append_patch(patch)?;
}
simulate_one_seal(layout, ref_name, signer)?;
let ref_store = crate::RefStore::new(layout.clone());
let objects = FileObjectStore::new(layout.clone());
let ref_state_id = ref_store
.read_current_ref_state_id(ref_name)?
.ok_or_else(|| {
prikk_error::PrikkError::Integrity("ref state missing after seal".to_string())
})?;
let envelope = crate::object_store::ObjectReader::read_typed(
&objects,
ref_state_id,
ObjectType::RefState,
)?
.ok_or_else(|| prikk_error::PrikkError::Integrity("ref state envelope missing".to_string()))?;
let payload = prikk_object::RefStatePayload::decode_canonical(
&envelope.canonical_payload,
envelope.schema_version,
)?;
Ok(payload.target_object_id)
}