a3s-use-core 0.2.2

Shared typed contracts for A3S Use domains
Documentation
use a3s_use_core::{
    PlanActor, PlanAuthority, PlanEnforcementProfile, PlanPackageChangeKind, PlanPackageRole,
    PlanPolicyDecision, PlanQualifiedSurfaceRef, PlanScope, PlanScopeKind, PlannedOperationImpact,
    PlannedPackageState, PlannedPackageTransition, PlannedPluginRelease, PlannedProviderEvidence,
    PlannedSecretChange, PlannedSecretChangeKind, PlannedStateEvidence, PlannedSurfaceChange,
    PlannedWorkspaceImpact, PluginCatalogRecord, PluginOperationAction,
    PluginOperationConfirmation, PluginOperationPlan, PluginOperationPlanEnvelope,
    PluginPlanSource, PluginSurfaceKind, PluginSurfaceRef, SurfaceChangeKind,
    VerifiedCatalogProvenance, PLUGIN_OPERATION_CONFIRMATION_SCHEMA, PLUGIN_OPERATION_PLAN_SCHEMA,
};

const CATALOG_RECORD: &[u8] = include_bytes!("../fixtures/plugins/catalog-record-v1.json");
const INSTALL_PLAN: &[u8] = include_bytes!("../fixtures/plugins/operation-plan-install-v1.json");
const INSTALL_PLAN_DIGEST: &str =
    include_str!("../fixtures/plugins/operation-plan-install-v1.sha256").trim_ascii_end();
const OPERATION_CONFIRMATION: &[u8] =
    include_bytes!("../fixtures/plugins/operation-confirmation-v1.json");
const OPERATION_CONFIRMATION_DIGEST: &str =
    include_str!("../fixtures/plugins/operation-confirmation-v1.sha256").trim_ascii_end();
const DIGEST_A: &str = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const DIGEST_C: &str = "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
const DIGEST_D: &str = "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
const DIGEST_E: &str = "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const DIGEST_F: &str = "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";

fn qualified(kind: PluginSurfaceKind, id: &str) -> PlanQualifiedSurfaceRef {
    PlanQualifiedSurfaceRef {
        package_id: "acme/research".to_owned(),
        surface: PluginSurfaceRef {
            kind,
            id: id.to_owned(),
        },
    }
}

fn canonical_fixture(bytes: &[u8]) -> &[u8] {
    bytes.strip_suffix(b"\n").unwrap_or(bytes)
}

fn provider(
    kind: PluginSurfaceKind,
    id: &str,
    provider_id: &str,
    enforcement: PlanEnforcementProfile,
) -> PlannedProviderEvidence {
    PlannedProviderEvidence {
        surface: qualified(kind, id),
        provider_id: provider_id.to_owned(),
        provider_build_id: "runtime:0.3.0:linux-x86_64".to_owned(),
        capability_digest: DIGEST_D.to_owned(),
        semantics_profile_digest: DIGEST_E.to_owned(),
        enforcement,
    }
}

fn install_plan() -> PluginOperationPlan {
    let catalog = PluginCatalogRecord::from_json(CATALOG_RECORD).unwrap();
    let surfaces = catalog
        .surfaces
        .iter()
        .map(|surface| PlannedSurfaceChange {
            surface: PluginSurfaceRef {
                kind: surface.kind,
                id: surface.id.clone(),
            },
            change: SurfaceChangeKind::Add,
            before_digest: None,
            after_digest: Some(surface.descriptor_digest().unwrap()),
        })
        .collect();
    let after = PlannedPackageState {
        release: PlannedPluginRelease {
            package_id: catalog.package_id.clone(),
            version: catalog.version.clone(),
            channel: catalog.channel,
            target: catalog.target.clone(),
            package_sha256: catalog.package.sha256.clone().unwrap(),
            manifest_sha256: DIGEST_C.to_owned(),
            permission_ceiling_digest: catalog.permission_ceiling_digest.clone(),
            surfaces: catalog.surfaces.clone(),
        },
        permissions: catalog.permission_ceiling.clone(),
    };

    PluginOperationPlan {
        schema: PLUGIN_OPERATION_PLAN_SCHEMA.to_owned(),
        operation_id: "install:acme-research:0001".to_owned(),
        created_at_ms: 1_785_360_000_000,
        expires_at_ms: 1_785_360_600_000,
        action: PluginOperationAction::Install,
        package_id: catalog.package_id.clone(),
        component_id: "runtime:local".to_owned(),
        scope: PlanScope {
            kind: PlanScopeKind::Workspace,
            id: "workspace:research".to_owned(),
        },
        package_lock_digest: None,
        prior_package_lock_digest: None,
        packages: vec![PlannedPackageTransition {
            package_id: catalog.package_id,
            role: PlanPackageRole::Root,
            change: PlanPackageChangeKind::Add,
            before: None,
            after: Some(after),
            source: Some(PluginPlanSource::Registry {
                provenance: VerifiedCatalogProvenance {
                    registry_name: "official".to_owned(),
                    registry_url: "https://plugins.a3s.dev/catalog".to_owned(),
                    root_sha256: DIGEST_F.to_owned(),
                    root_version: 7,
                    timestamp_version: 42,
                    snapshot_version: 41,
                    targets_version: 39,
                    catalog_record_digest: DIGEST_E.to_owned(),
                },
                archive: catalog.archive,
            }),
            surfaces,
        }],
        secret_changes: vec![PlannedSecretChange {
            surface: qualified(PluginSurfaceKind::Tool, "convert"),
            secret_name: "research-api".to_owned(),
            change: PlannedSecretChangeKind::Grant,
        }],
        providers: vec![
            provider(
                PluginSurfaceKind::Mcp,
                "library",
                "runtime:mcp-http",
                PlanEnforcementProfile::Container,
            ),
            provider(
                PluginSurfaceKind::Tool,
                "convert",
                "runtime:tool-task",
                PlanEnforcementProfile::Sandbox,
            ),
            provider(
                PluginSurfaceKind::Tool,
                "index",
                "runtime:tool-service",
                PlanEnforcementProfile::Container,
            ),
        ],
        workspace_impacts: vec![PlannedWorkspaceImpact {
            scope_id: "workspace:research".to_owned(),
            grant_before_digest: None,
            grant_after_digest: Some(DIGEST_F.to_owned()),
            enabled_before: false,
            enabled_after: true,
        }],
        impact: PlannedOperationImpact {
            download_bytes: 1_048_576,
            installed_bytes_after: 4_194_304,
            reclaimed_bytes: 0,
            drain_required: false,
            retained_data: false,
            okf_changes: Vec::new(),
        },
        authority: PlanAuthority {
            actor: PlanActor::User,
            decision: PlanPolicyDecision::Ask,
            policy_digest: DIGEST_A.to_owned(),
            confirmation_required: true,
        },
        state: PlannedStateEvidence {
            state_revision: 3,
            capability_generation: 12,
            receipt_digest: None,
        },
    }
}

#[test]
fn canonical_install_plan_fixture_binds_the_complete_resolved_delta() {
    let plan = install_plan();
    plan.validate().unwrap();
    let decoded = PluginOperationPlan::from_json(INSTALL_PLAN).unwrap();
    assert_eq!(decoded, plan);
    assert_eq!(
        decoded.canonical_bytes().unwrap(),
        canonical_fixture(INSTALL_PLAN)
    );
    assert_eq!(decoded.descriptor_digest().unwrap(), INSTALL_PLAN_DIGEST);
}

#[test]
fn an_empty_host_can_plan_from_capability_generation_zero() {
    let mut plan = install_plan();
    plan.state.capability_generation = 0;
    plan.validate().unwrap();
}

#[test]
fn apply_requires_the_reviewed_digest_and_valid_time_window() {
    let envelope = PluginOperationPlanEnvelope::new(install_plan()).unwrap();
    envelope
        .verify_apply(
            "install:acme-research:0001",
            &envelope.plan_digest,
            1_785_360_300_000,
        )
        .unwrap();

    let mismatch = envelope
        .verify_apply("install:acme-research:0001", DIGEST_F, 1_785_360_300_000)
        .unwrap_err();
    assert_eq!(mismatch.code, "use.plugin.plan_mismatch");
    let early = envelope
        .verify_apply(
            "install:acme-research:0001",
            &envelope.plan_digest,
            1_785_359_999_999,
        )
        .unwrap_err();
    assert_eq!(early.code, "use.plugin.plan_expired");
    let expired = envelope
        .verify_apply(
            "install:acme-research:0001",
            &envelope.plan_digest,
            1_785_360_600_000,
        )
        .unwrap_err();
    assert_eq!(expired.code, "use.plugin.plan_expired");
}

#[test]
fn ask_apply_requires_user_confirmation_of_the_exact_operation_plan() {
    let envelope = PluginOperationPlanEnvelope::new(install_plan()).unwrap();
    assert_eq!(
        envelope
            .verify_confirmed_apply(
                "install:acme-research:0001",
                &envelope.plan_digest,
                None,
                1_785_360_300_000,
            )
            .unwrap_err()
            .code,
        "use.plugin.plan_confirmation_required"
    );
    let confirmation = PluginOperationConfirmation {
        schema: PLUGIN_OPERATION_CONFIRMATION_SCHEMA.to_string(),
        operation_id: envelope.plan.operation_id.clone(),
        plan_digest: envelope.plan_digest.clone(),
        confirmed_by: PlanActor::User,
        confirmed_at_ms: 1_785_360_200_000,
    };
    assert_eq!(
        confirmation.canonical_bytes().unwrap(),
        canonical_fixture(OPERATION_CONFIRMATION)
    );
    assert_eq!(
        PluginOperationConfirmation::from_json(OPERATION_CONFIRMATION).unwrap(),
        confirmation
    );
    assert_eq!(
        confirmation.descriptor_digest().unwrap(),
        OPERATION_CONFIRMATION_DIGEST
    );
    envelope
        .verify_confirmed_apply(
            "install:acme-research:0001",
            &envelope.plan_digest,
            Some(&confirmation),
            1_785_360_300_000,
        )
        .unwrap();

    let mut substituted = confirmation;
    substituted.plan_digest = DIGEST_F.to_string();
    assert_eq!(
        envelope
            .verify_confirmed_apply(
                "install:acme-research:0001",
                &envelope.plan_digest,
                Some(&substituted),
                1_785_360_300_000,
            )
            .unwrap_err()
            .code,
        "use.plugin.plan_confirmation_mismatch"
    );

    let mut future = PluginOperationConfirmation::from_json(OPERATION_CONFIRMATION).unwrap();
    future.confirmed_at_ms = 1_785_360_300_001;
    assert_eq!(
        envelope
            .verify_confirmed_apply(
                "install:acme-research:0001",
                &envelope.plan_digest,
                Some(&future),
                1_785_360_300_000,
            )
            .unwrap_err()
            .code,
        "use.plugin.plan_confirmation_mismatch"
    );

    let mut unknown: serde_json::Value = serde_json::from_slice(OPERATION_CONFIRMATION).unwrap();
    unknown["userToken"] = serde_json::json!("do-not-echo");
    let error =
        PluginOperationConfirmation::from_json(&serde_json::to_vec(&unknown).unwrap()).unwrap_err();
    assert_eq!(error.code, "use.plugin.plan_confirmation_invalid");
    assert!(!error.message.contains("do-not-echo"));
}

#[test]
fn plan_rejects_permission_provider_and_source_drift() {
    let mut secret_drift = install_plan();
    secret_drift.secret_changes.clear();
    assert!(secret_drift.validate().is_err());

    let mut provider_drift = install_plan();
    provider_drift.providers[1].enforcement = PlanEnforcementProfile::Container;
    assert!(provider_drift.validate().is_err());

    let mut source_drift = install_plan();
    source_drift.packages[0].source = Some(PluginPlanSource::ReleaseBundle {
        bundle_digest: DIGEST_D.to_owned(),
        package_digest: DIGEST_C.to_owned(),
    });
    assert!(source_drift.validate().is_err());
}

#[test]
fn unattended_agent_cannot_accept_unconfined_or_unsigned_execution() {
    let mut unconfined = install_plan();
    unconfined.authority = PlanAuthority {
        actor: PlanActor::Agent,
        decision: PlanPolicyDecision::Allow,
        policy_digest: DIGEST_A.to_owned(),
        confirmation_required: false,
    };
    unconfined.providers[1].enforcement = PlanEnforcementProfile::NativeUnconfined;
    assert!(unconfined.validate().is_err());

    let mut local = install_plan();
    local.authority = PlanAuthority {
        actor: PlanActor::Agent,
        decision: PlanPolicyDecision::Allow,
        policy_digest: DIGEST_A.to_owned(),
        confirmation_required: false,
    };
    local.packages[0].source = Some(PluginPlanSource::LocalReviewed {
        source_digest: DIGEST_D.to_owned(),
        package_digest: DIGEST_A.to_owned(),
        unsigned: true,
    });
    let Some(after) = local.packages[0].after.as_mut() else {
        panic!("fixture has an after state");
    };
    after.release.package_sha256 = DIGEST_A.to_owned();
    assert!(local.validate().is_err());
}

#[test]
fn unknown_plan_fields_fail_closed_without_echoing_values() {
    let mut value: serde_json::Value = serde_json::from_slice(INSTALL_PLAN).unwrap();
    value["authority"]["secretValue"] = serde_json::json!("do-not-echo");
    let error = PluginOperationPlan::from_json(&serde_json::to_vec(&value).unwrap()).unwrap_err();
    assert_eq!(error.code, "use.plugin.plan_invalid");
    assert!(!error.message.contains("do-not-echo"));
}