waddling-errors 0.7.3

Structured, secure-by-default diagnostic codes for distributed systems with no_std and role-based documentation
Documentation
//! Authentication & Authorization Component
//!
//! Handles JWT tokens, OAuth2 flows, session management, and permission checks.

use crate::primaries::Primary;
use waddling_errors::ComponentIdDocumented;
use waddling_errors::prelude::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Auth;

impl ComponentId for Auth {
    fn as_str(&self) -> &'static str {
        "Auth"
    }
}

impl ComponentIdDocumented for Auth {
    fn description(&self) -> Option<&'static str> {
        Some(
            "Authentication and authorization system. Handles JWT tokens, OAuth2 flows, \
              session management, and permission checks.",
        )
    }

    fn examples(&self) -> &'static [&'static str] {
        &[
            "E.Auth.Token.001: JWT token missing in Authorization header",
            "E.Auth.Token.003: JWT token signature invalid",
            "E.Auth.Permission.008: User lacks required role for this operation",
        ]
    }

    fn tags(&self) -> &'static [&'static str] {
        &["security", "authentication", "authorization"]
    }
}

// ============================================================================
// Error Code Definitions
// ============================================================================

/// JWT token missing from Authorization header (.001 = MISSING)
pub const ERR_TOKEN_MISSING: Code<Auth, Primary> = Code::error(Auth, Primary::Token, 1);

/// JWT token signature validation failed (.003 = INVALID)
pub const ERR_TOKEN_INVALID: Code<Auth, Primary> = Code::error(Auth, Primary::Token, 3);

/// JWT token expired - refresh required (.017 = TIMEOUT)
pub const ERR_TOKEN_EXPIRED: Code<Auth, Primary> = Code::error(Auth, Primary::Token, 17);

/// JWT token malformed - deprecated, use ERR_TOKEN_INVALID instead
/// @deprecated 2.0.0: Use ERR_TOKEN_INVALID for more precise error reporting
pub const ERR_TOKEN_MALFORMED: Code<Auth, Primary> = Code::error(Auth, Primary::Token, 4);

/// Insufficient permissions for operation (.008 = DENIED)
pub const ERR_PERMISSION_DENIED: Code<Auth, Primary> = Code::error(Auth, Primary::Permission, 8);

/// Limited permissions - some features unavailable (.008 = DENIED)
pub const WARN_PERMISSION_LIMITED: Code<Auth, Primary> =
    Code::warning(Auth, Primary::Permission, 8);

// ============================================================================
// Component Registration
// ============================================================================

#[cfg(feature = "doc-gen")]
pub fn register_component(generator: &mut waddling_errors::doc_generator::DocRegistry) {
    use waddling_errors::Role;

    generator.register_component(
        "Auth",
        Some("Authentication and authorization system. Handles JWT tokens, OAuth2 flows, session management, and permission checks. Implements industry-standard security patterns including token rotation, refresh tokens, and multi-factor authentication."),
        &[
            "JWT token validation and parsing",
            "OAuth2 authorization code flow",
            "Session lifecycle management",
            "Role-based access control (RBAC)",
            "Permission scopes and claims",
            "Token refresh and rotation",
        ],
        &["security", "authentication", "authorization", "jwt", "oauth2", "rbac"]);

    // Register component locations with role-based visibility
    // This demonstrates the security model: control what source locations are visible to which audience

    // PUBLIC: Safe for external users - example usage and integration guides
    generator.register_component_location_with_role(
        "Auth",
        "examples/auth_usage.rs",
        Some(Role::Public),
    );
    generator.register_component_location_with_role(
        "Auth",
        "examples/complete_system/components/auth.rs",
        Some(Role::Public),
    );

    // DEVELOPER: For contributors and third-party developers - debug utilities and test helpers
    generator.register_component_location_with_role(
        "Auth",
        "src/auth/debug_utils.rs",
        Some(Role::Developer),
    );
    generator.register_component_location_with_role(
        "Auth",
        "src/auth/test_helpers.rs",
        Some(Role::Developer),
    );
    generator.register_component_location_with_role(
        "Auth",
        "src/handlers/auth_handler.rs",
        Some(Role::Developer),
    );

    // INTERNAL: For internal team only - sensitive implementation details
    generator.register_component_location_with_role(
        "Auth",
        "src/middleware/auth.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Auth",
        "src/services/token_service.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Auth",
        "src/auth/secret_rotation.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Auth",
        "src/auth/crypto_internals.rs",
        Some(Role::Internal),
    );
}

#[cfg(feature = "doc-gen")]
pub fn register_errors(generator: &mut waddling_errors::doc_generator::DocRegistry) {
    use waddling_errors::Role;

    // Register with Code structs to include hash
    generator
        .register_code_extended(
            &ERR_TOKEN_MISSING,
            "JWT token missing from Authorization header",
            &[
                "Include Authorization header",
                "Check authentication middleware",
            ],
            &["authentication", "security", "http"],
            Some(Role::Internal),
            &["E.Auth.Token.003", "E.Auth.Token.017"], // related_codes
            None,                                      // deprecated
            &[],                                       // see_also
        )
        .expect("Valid error code")
        .add_snippet_for_role(
            "Internal - Usage Example",
            "rust",
            format!(
                "// Internal debugging\nlog::error!(\"[{}] JWT token missing\");",
                ERR_TOKEN_MISSING.code()
            ),
            Role::Internal,
        );

    generator.register_code_extended(
        &ERR_TOKEN_INVALID,
        "JWT token signature validation failed",
        &["Verify JWT_SECRET", "Check token hasn't been modified"],
        &["authentication", "security", "cryptography"],
        Some(Role::Developer),
        &["E.Auth.Token.001", "E.Auth.Token.017"], // related_codes
        None, // deprecated
        &[], // see_also
    )
    .expect("Valid error code")
    .add_snippet_for_role(
        "Developer - Usage Example",
        "rust",
        format!("// Developer API usage\nif let Err(e) = validate_token() {{\n    eprintln!(\"Error: {}\");\n}}", ERR_TOKEN_INVALID.code()),
        Role::Developer
    );

    generator.register_code_extended(
        &ERR_TOKEN_EXPIRED,
        "JWT token expired - refresh required",
        &["Use refresh token endpoint", "Implement auto-refresh"],
        &["authentication", "session"],
        Some(Role::Public),
        &["E.Auth.Token.001", "E.Auth.Token.003"], // related_codes
        None, // deprecated
        &[], // see_also
    )
    .expect("Valid error code")
    .add_snippet_for_role(
        "Public - Usage Example",
        "rust",
        "// Public error handling\nmatch result {\n    Err(_) => println!(\"Token expired, please refresh\"),\n    Ok(_) => println!(\"Success\"),\n}".to_string(),
        Role::Public
    );

    generator.register_code_extended(
        &ERR_PERMISSION_DENIED,
        "Insufficient permissions for operation",
        &["Check user roles", "Request elevated permissions"],
        &["authorization", "rbac"],
        Some(Role::Public),
        &[], // related_codes
        None, // deprecated
        &[], // see_also
    )
    .expect("Valid error code")
    .add_snippet_for_role(
        "Public - Usage Example",
        "rust",
        "// Public error handling\nmatch result {\n    Err(_) => println!(\"Permission denied\"),\n    Ok(_) => println!(\"Success\"),\n}".to_string(),
        Role::Public
    );

    generator.register_code_extended(
        &WARN_PERMISSION_LIMITED,
        "Limited permissions - some features unavailable",
        &["Upgrade account tier", "Contact support for access"],
        &["authorization", "account"],
        Some(Role::Public),
        &["E.Auth.Permission.008"], // related_codes
        None, // deprecated
        &[], // see_also
    )
    .expect("Valid error code")
    .add_snippet_for_role(
        "Public - Usage Example",
        "rust",
        "// Public warning handling\nif limited_permissions {\n    println!(\"Some features unavailable\");\n}".to_string(),
        Role::Public
    );

    // Register deprecated error with migration path
    // Now uses structured deprecated field!
    let _ = generator.register_code_extended(
        &ERR_TOKEN_MALFORMED,
        "JWT token malformed",
        &[
            "Migrate to E.Auth.Token.003 for new code",
            "This error is deprecated since v2.0.0",
        ],
        &["authentication", "deprecated"],
        Some(Role::Internal),
        &["E.Auth.Token.003"],     // related_codes: migration target
        Some("2.0.0".to_string()), // deprecated since version 2.0.0
        &["E.Auth.Token.003"],     // see_also: migration target
    );
}

// ============================================================================
// Demo Functions
// ============================================================================

pub fn demo() {
    println!("🔐 AUTH Component Errors:\n");
    println!("  {} - JWT token missing", ERR_TOKEN_MISSING.code());
    println!("  {} - JWT token invalid", ERR_TOKEN_INVALID.code());
    println!("  {} - JWT token expired", ERR_TOKEN_EXPIRED.code());
    println!("  {} - Permission denied", ERR_PERMISSION_DENIED.code());
    println!("  {} - Limited permissions", WARN_PERMISSION_LIMITED.code());
}