otel-arrow-dfe-engine 0.61.0

Async pipeline engine
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

//! Component inventory: link-time metadata for security-relevant components.
//!
//! This module implements the runtime surface of [RFC 0001: Component
//! Inventory][rfc]. Components annotated with the
//! [`#[component_inventory]`][macro] attribute macro (in
//! `otel-arrow-dfe-engine-macros`) emit one [`ComponentMeta`] entry into the
//! [`COMPONENT_INVENTORY`] distributed slice at link time. Offline tooling
//! (`cargo xtask component-inventory`, added in a later phase) reads the slice
//! to detect new/removed components for threat-model drift detection,
//! documentation coverage, and security review.
//!
//! This mirrors the existing `#[capability]` -> `KNOWN_CAPABILITIES` mechanism
//! (`crate::capability`). The data is read only by offline tooling and never at
//! runtime, so the mechanism is zero-cost.
//!
//! [rfc]: https://github.com/open-telemetry/otel-arrow/blob/main/rust/otap-dataflow/rfcs/0001-component-inventory.md
//! [macro]: otel_arrow_dfe_engine_macros::component_inventory

/// Component category (RFC 0001).
///
/// Re-exported from the leaf `otel-arrow-dfe-component-inventory-syntax` crate, which is
/// the single source of truth shared by the runtime type (here), the
/// `#[component_inventory]` proc macro, and the `cargo xtask component-inventory`
/// scanner. Defining it once there (rather than duplicating a string table in
/// each consumer) means adding a variant updates every consumer through the
/// type system and the three cannot drift.
///
/// The `#[component_inventory]` macro accepts a bare identifier (e.g.
/// `Receiver`) and rejects unknown variants at compile time, preventing
/// misspellings like `Reciever` from silently corrupting the inventory. For
/// factory components the macro also validates the category against the URN's
/// middle segment (e.g. `urn:otel:`**`receiver`**`:otlp`).
///
/// See [`Category`] for the full list of variants and their intended meanings.
pub use otel_arrow_dfe_component_inventory_syntax::Category;

/// Well-known attribute keys (RFC 0001, "Option A": free-form map + key
/// constants). Contributors are encouraged to use these constants for the
/// security-relevant attributes so keys stay consistent across components.
///
/// The `attributes` map is intentionally free-form (`&[(&str, &str)]`) so any
/// component can express any property; these constants only standardize the
/// common keys. Value validation for security-relevant keys (RFC "Option C")
/// is intentionally not implemented in Phase 1.
//
// TODO(stability): a component "stability" attribute was considered but
// intentionally omitted. Stability is not modeled per-signal: many components
// have no signal type, or handle multiple signal types, so a single per-signal
// stability field does not fit. Revisit with the SIG if a component-level
// stability key is wanted later.
pub mod attrs {
    /// Network port the component listens on for inbound connections (e.g. a
    /// receiver or admin server accepting traffic on `"4317"`). Use
    /// [`REMOTE_PORT`] for the destination port of an outbound connection.
    pub const LISTEN_PORT: &str = "listen_port";
    /// Destination port the component connects out to (e.g. an exporter dialing
    /// a downstream collector on `"4317"`). Use [`LISTEN_PORT`] for an inbound
    /// listening port.
    pub const REMOTE_PORT: &str = "remote_port";
    /// Wire protocol (e.g. `"gRPC (HTTP/2)"`, `"HTTP"`).
    pub const PROTOCOL: &str = "protocol";
    /// Authentication mechanism (e.g. `"mTLS (opt-in)"`, `"NONE"`).
    pub const AUTH: &str = "auth";
    /// Whether/how the component accesses the local filesystem.
    pub const FILESYSTEM_ACCESS: &str = "filesystem_access";
    /// Cloud API the component talks to, if any.
    pub const CLOUD_API: &str = "cloud_api";
    /// Cargo feature flag gating the component, if any.
    pub const FEATURE_FLAG: &str = "feature_flag";
}

/// Inventory metadata for one security-relevant component.
///
/// Collected at link time via the [`COMPONENT_INVENTORY`] distributed slice;
/// extracted by `cargo xtask component-inventory`. Identity and category are
/// the fixed fields; all domain-specific properties live in the free-form
/// [`attributes`](ComponentMeta::attributes) slice so the struct is not biased
/// toward any one access pattern (network, filesystem, cloud, ...).
///
/// Note: this struct is deliberately **not** `#[non_exhaustive]` -- the
/// `#[component_inventory]` macro constructs it directly with a struct literal
/// from other crates, which `#[non_exhaustive]` would forbid. New fields must
/// therefore be added in lockstep with the macro's emission.
#[derive(Debug, Clone, Copy)]
pub struct ComponentMeta {
    /// Unique identifier. For factory components this is the factory's URN
    /// (its `name` field). For non-factory components it is an explicit,
    /// URN-shaped id supplied on the annotation.
    pub id: &'static str,

    /// Component category (validated against the URN segment when a URN exists).
    pub category: Category,

    /// Short human-readable description.
    pub description: Option<&'static str>,

    /// Source file, auto-populated via [`file!`] by the macro.
    pub file: &'static str,

    /// Source line, auto-populated via [`line!`] by the macro.
    pub line: u32,

    /// Free-form key/value attributes. Well-known keys are provided as
    /// constants in [`attrs`].
    pub attributes: &'static [(&'static str, &'static str)],
}

impl ComponentMeta {
    /// Look up an attribute value by key, if present.
    #[must_use]
    pub fn attribute(&self, key: &str) -> Option<&'static str> {
        self.attributes
            .iter()
            .find(|(k, _)| *k == key)
            .map(|(_, v)| *v)
    }
}

/// Link-time registry of all components annotated with `#[component_inventory]`
/// compiled into the binary.
///
/// Populated by the `#[component_inventory]` proc macro. Read only by offline
/// tooling (`cargo xtask component-inventory`); never at runtime.
//
// `linkme::distributed_slice` requires a `pub static`; `#[doc(hidden)]`
// excludes it from generated rustdoc so external crates don't see it in the
// public API surface. `#[allow(unsafe_code)]` is required because
// `linkme::distributed_slice` emits a static with `#[link_section = "..."]`,
// which the engine crate's `-D unsafe-code` lint would otherwise reject.
#[doc(hidden)]
#[allow(unsafe_code)]
#[linkme::distributed_slice]
pub static COMPONENT_INVENTORY: [ComponentMeta] = [..];

/// Iterate over every component registered in the [`COMPONENT_INVENTORY`]
/// distributed slice.
///
/// Mirrors the iteration pattern used for `KNOWN_CAPABILITIES`.
#[must_use]
pub fn components() -> &'static [ComponentMeta] {
    &COMPONENT_INVENTORY
}