Digest rendered OpenAPI contract

This commit is contained in:
2026-09-18 18:37:55 +09:00
parent 103fee0ba4
commit bbd949e57f
2 changed files with 14 additions and 16 deletions
+13 -15
View File
@@ -172,32 +172,30 @@ pub trait ServerApi {
) -> Result<CreateWorkspaceRepositoryResponse, RepositoryApiError>; ) -> Result<CreateWorkspaceRepositoryResponse, RepositoryApiError>;
} }
/// Digest of every authoritative input used to derive the canonical OpenAPI artifact. /// Digest of the fully rendered canonical contract with its digest slot normalized.
pub fn canonical_openapi_source_digest() -> String { pub fn canonical_openapi_source_digest() -> Result<String, api_macros::openapi::OpenApiError> {
let mut hasher = Sha256::new(); const NORMALIZED_DIGEST: &str =
for source in [ "sha256:0000000000000000000000000000000000000000000000000000000000000000";
include_bytes!("lib.rs").as_slice(), let normalized = server_api_openapi(api_macros::openapi::OpenApiInfo {
include_bytes!("../../api-macros-impl/src/lib.rs").as_slice(), title: "Yoi Server API",
include_bytes!("../../api-macros/src/lib.rs").as_slice(), version: env!("CARGO_PKG_VERSION"),
include_bytes!("../../api-macros/src/openapi.rs").as_slice(), source_digest: NORMALIZED_DIGEST,
] { })?
hasher.update((source.len() as u64).to_le_bytes()); .to_json()?;
hasher.update(source); let digest = Sha256::digest(normalized.as_bytes());
}
let digest = hasher.finalize();
let mut encoded = String::with_capacity("sha256:".len() + digest.len() * 2); let mut encoded = String::with_capacity("sha256:".len() + digest.len() * 2);
encoded.push_str("sha256:"); encoded.push_str("sha256:");
for byte in digest { for byte in digest {
use std::fmt::Write as _; use std::fmt::Write as _;
write!(&mut encoded, "{byte:02x}").expect("writing to String cannot fail"); write!(&mut encoded, "{byte:02x}").expect("writing to String cannot fail");
} }
encoded Ok(encoded)
} }
/// Build the deployment-independent canonical ServerApi OpenAPI document. /// Build the deployment-independent canonical ServerApi OpenAPI document.
pub fn canonical_openapi_document() pub fn canonical_openapi_document()
-> Result<api_macros::openapi::OpenApiDocument, api_macros::openapi::OpenApiError> { -> Result<api_macros::openapi::OpenApiDocument, api_macros::openapi::OpenApiError> {
let source_digest = canonical_openapi_source_digest(); let source_digest = canonical_openapi_source_digest()?;
server_api_openapi(api_macros::openapi::OpenApiInfo { server_api_openapi(api_macros::openapi::OpenApiInfo {
title: "Yoi Server API", title: "Yoi Server API",
version: env!("CARGO_PKG_VERSION"), version: env!("CARGO_PKG_VERSION"),
+1 -1
View File
@@ -353,7 +353,7 @@
"info": { "info": {
"title": "Yoi Server API", "title": "Yoi Server API",
"version": "0.1.0", "version": "0.1.0",
"x-yoi-source-digest": "sha256:9ba281f960b7a6bf8f1e8e29c1a5821ab5d8808f53a7b0f98abe76832e658189" "x-yoi-source-digest": "sha256:37e4ff70a1e2a6fb75a514b03a6d14306ca7fc96ef53a3271186f29acc558e00"
}, },
"openapi": "3.1.0", "openapi": "3.1.0",
"paths": { "paths": {