logbrew-cli 0.1.28

Developer-first observability command-line interface
Documentation
//! Original native debug-artifact contract fixtures.

use std::process::Output;

use crate::support::*;
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, Request, ResponseTemplate};

pub(crate) const ARM64E_UUID: &str = "30313233-3435-3637-3839-3a3b3c3d3e3f";

pub(crate) fn lookup_args<'a>(image_uuid: &'a str, architecture: &'a str) -> Vec<&'a str> {
    vec![
        "debug-artifacts",
        "lookup",
        "--project",
        PROJECT_ID,
        "--release",
        "checkout@1.2.3",
        "--environment",
        "production",
        "--service",
        "checkout-api",
        "--image-uuid",
        image_uuid,
        "--architecture",
        architecture,
        "--json",
    ]
}

pub(crate) async fn malformed_success_server() -> MockServer {
    let server = MockServer::start().await;
    Mock::given(method("GET"))
        .and(path("/api/native-debug-artifacts"))
        .respond_with(ResponseTemplate::new(200).set_body_json(missing_lookup()))
        .mount(&server)
        .await;
    Mock::given(method("POST"))
        .and(path("/api/native-debug-artifacts"))
        .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
            "unexpected": "hostile backend text"
        })))
        .expect(1)
        .mount(&server)
        .await;
    server
}

pub(crate) fn manifest(artifacts: serde_json::Value) -> serde_json::Value {
    serde_json::json!({
        "projectId": PROJECT_ID,
        "release": "checkout@1.2.3",
        "environment": "production",
        "service": "checkout-api",
        "artifactType": "apple_dsym_manifest",
        "validation": {"status": "ready"},
        "artifacts": artifacts
    })
}

pub(crate) fn universal_macho(
    slices: &[(u32, u32, &[u8])],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    let header_size = 8usize.saturating_add(slices.len().saturating_mul(20));
    let mut offsets = Vec::with_capacity(slices.len());
    let mut next_offset = header_size;
    for (_, _, bytes) in slices {
        offsets.push(next_offset);
        next_offset = next_offset.saturating_add(bytes.len());
    }
    let mut universal = Vec::with_capacity(next_offset);
    universal.extend_from_slice(0xcafe_babeu32.to_be_bytes().as_slice());
    universal.extend_from_slice(u32::try_from(slices.len())?.to_be_bytes().as_slice());
    for ((cpu_type, cpu_subtype, bytes), offset) in slices.iter().zip(offsets.iter()) {
        for value in [
            *cpu_type,
            *cpu_subtype,
            u32::try_from(*offset)?,
            u32::try_from(bytes.len())?,
            0,
        ] {
            universal.extend_from_slice(value.to_be_bytes().as_slice());
        }
    }
    for (_, _, bytes) in slices {
        universal.extend_from_slice(bytes);
    }
    Ok(universal)
}

pub(crate) fn assert_invalid_response_is_redacted(
    output: &Output,
    fixture: &Fixture,
    server: &MockServer,
) -> Result<(), Box<dyn std::error::Error>> {
    let (text, body) = json_failure(output)?;
    assert_eq!(body["error"], "native_debug_response_invalid");
    assert_eq!(
        body["next"],
        "retry the native debug-artifact request; if it repeats, report the public response contract"
    );
    assert!(!text.contains("hostile backend text"));
    assert_private_values_absent(text.as_str(), fixture, server.uri().as_str());
    Ok(())
}

pub(crate) fn assert_request_has_no_local_identity(request: &Request, fixture: &Fixture) {
    let body = String::from_utf8_lossy(request.body.as_slice());
    let root = fixture.root.to_string_lossy();
    for private in [
        "Customer Secret",
        "private-arm",
        "private-x86",
        root.as_ref(),
    ] {
        assert!(!body.contains(private));
    }
}