Skip to content

feat: [#243] introduce SecretString-based secret types for sensitive data#245

Merged
josecelano merged 5 commits intomainfrom
243-introduce-secret-type-for-sensitive-data
Dec 18, 2025
Merged

feat: [#243] introduce SecretString-based secret types for sensitive data#245
josecelano merged 5 commits intomainfrom
243-introduce-secret-type-for-sensitive-data

Conversation

@josecelano
Copy link
Copy Markdown
Member

@josecelano josecelano commented Dec 18, 2025

Summary

This PR implements issue #243, introducing type-safe wrappers for sensitive data (API tokens, passwords) using the secrecy crate. This prevents accidental exposure of secrets in logs, debug output, and error messages while maintaining code clarity with explicit expose_secret() calls.

Changes

Core Implementation

  • Added secrecy crate dependency (v0.10.3)
  • Created src/shared/secrets/ module with:
    • ApiToken - wrapper for API tokens
    • Password - wrapper for passwords
    • PlainApiToken and PlainPassword type aliases for DTO boundaries

Security Features

  • Memory Protection: Automatic memory zeroing when secrets are dropped
  • Debug Redaction: Secrets display as "[REDACTED SecretString]" in logs/debug
  • Development Tracing: Debug builds log secret access with caller location (TRACE level)
  • Zero Production Cost: Tracing completely removed in release builds via #[cfg(debug_assertions)]

Integration Points

  • Provider Config: Updated Hetzner provider to use ApiToken
  • Database Config: Updated MySQL config to use Password
  • JSON Schema: Verified schema generation works correctly (18 tests passing)

Documentation

  • Created comprehensive guide in docs/contributing/secret-handling.md
  • Updated AGENTS.md with Rule 18 for future development
  • Added ADR documenting the decision and rationale

Testing

  • All 1538 unit tests passing
  • Added 18+ new tests for secret type behavior
  • E2E tests verified (infrastructure lifecycle + deployment workflow)
  • JSON schema generation confirmed working

Breaking Changes

⚠️ API Changes:

  • HetznerConfig::api_token() now returns &ApiToken instead of &String
  • DatabaseConfig::password() now returns &Password instead of &String
  • Callers must use .expose_secret() to access the actual string values

Migration Guide

Replace direct string access with expose_secret():

// Before
let token = config.api_token();

// After
let token = config.api_token().expose_secret();

Related

Checklist

  • All tests pass
  • Documentation updated
  • Pre-commit checks pass
  • ADR created
  • Breaking changes documented

@josecelano josecelano self-assigned this Dec 18, 2025
@josecelano josecelano requested a review from da2ce7 December 18, 2025 10:55
@josecelano josecelano marked this pull request as draft December 18, 2025 11:01
@josecelano josecelano marked this pull request as ready for review December 18, 2025 11:27
@josecelano
Copy link
Copy Markdown
Member Author

ACK fa24387

@josecelano josecelano merged commit e114867 into main Dec 18, 2025
42 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce Secret Type for Sensitive Data

1 participant