Assessment Date: February 7, 2026 Scope: Rust CLI workspace (tf-config, tf-logging, tf-security) for QA process automation Risk Level: LOW (baseline implementation complete; anonymization & retention policies pending)
The test-framework CLI tool implements strong baseline security controls for a local automation tool. Sensitive field redaction is comprehensive and well-tested. OS keyring integration prevents plaintext secret storage. No hardcoded secrets found.
Critical gaps are architectural rather than implementation gaps:
- Anonymization pipeline for cloud operations (story 0.7 pending)
- Audit log retention & purge policies (no story assigned)
- Dependency vulnerability scanning in CI/CD (cargo-audit missing)
Compliance status:
- GDPR: Partial (redaction done; anonymization & purge policies pending)
- Audit logging: Baseline (logs without PII done; retention policy pending)
- Secret management: Compliant
- Code safety: Compliant (#![forbid(unsafe_code)])
Status: IMPLEMENTED & TESTED Coverage: 12 base field names + 26 compound suffixes + URL params + span fields Test count: 25+ redaction-specific unit tests + 46 total tf-logging tests
Evidence:
SENSITIVE_FIELDS: token, api_key, apikey, key, secret, password, passwd, pwd, auth, authorization, credential, credentialsSENSITIVE_SUFFIXES: 26 patterns (access_token, auth_token, session_key, api_secret, user_password, db_credential, etc.)RedactingVisitorimplementstracing::field::Visitwithis_sensitive()checks on all types- URL redaction via
redact_url_sensitive_params()handles 27+ param names with encoding variants - Parent span fields processed through same redaction pipeline
- All workspace tests pass: 263 tf-config, 61 tf-logging, 30 tf-security
Design:
- Redaction happens at log emission time (via custom FormatEvent formatter)
- Safe for all log levels (INFO, DEBUG, WARN, ERROR)
- Free-text message content NOT scanned (documented limitation; users must use named fields)
Status: VERIFIED Evidence:
- Codebase scan: zero hardcoded credentials in non-test code
- Test fixtures use generic placeholders (test-token, secret_value_123, etc.)
- Config references secrets via
${SECRET:key_name}pattern (documented, not yet runtime-resolved)
Status: IMPLEMENTED (tf-security story 0-3, complete) Platform support:
- Linux: gnome-keyring, kwallet (Secret Service D-Bus)
- macOS: Keychain Access
- Windows: Credential Manager
Design:
SecretStorewrapskeyringcrate v3.6- Thread-safe (Send + Sync)
- Error handling returns hints, never exposes secret values
- Debug impl safe (service_name only)
Operations requirement: Ensure OS keyring service is running in deployment/CI.
Status: IMPLEMENTED Coverage: 6 structs with custom Debug impls hiding secrets
| Struct | Redaction |
|---|---|
| JiraConfig | endpoint URLs + token [REDACTED] |
| SquashConfig | endpoint URLs + password [REDACTED] |
| LlmConfig | endpoint URLs + api_key [REDACTED] |
| SecretStore | service_name only (no secrets) |
| LogGuard | RAII, no sensitive fields |
| LoadedTemplate | custom impl for template content |
Status: ENFORCED
- tf-config:
# - tf-logging:
#![deny(unsafe_code)] - Zero unsafe blocks in security-critical paths
- Platform/crypto operations delegated to audited crates
Status: GAP Current: No cargo-audit in CI/CD Direct deps: serde, tracing, keyring, thiserror (all recent, stable versions) Risk: Unknown vulnerabilities in transitive dependencies
Action:
- Immediate:
cargo install cargo-audit && cargo audit - CI/CD: Add
cargo auditstep to GitHub Actions - Policy: Document version pinning + monthly audit schedule
Status: NOT YET IMPLEMENTED (story 0.7 planned) Requirement (PRD/Architecture): "Anonymisation obligatoire avant tout envoi cloud" Current: Redaction in logs only (insufficient for GDPR compliance) Gap:
- No anonymization rules defined (PII patterns, Jira keys, etc.)
- No anonymization functions in tf-security yet
- No cloud LLM integration (tf-llm crate does not exist)
- No pre-send validation gate for PII detection
Action: Implement story 0.7 (anonymization pipeline) before cloud LLM integration.
Status: NOT YET IMPLEMENTED (no story assigned) Requirement (Architecture): "Rétention 90 jours, purge données locales < 24h" Current:
- Daily log rotation (tracing-appender)
- No retention policy tracking
- No automated purge
Gaps:
- No
audit_retention_daysconfig field - No background purge job
- No local data lifecycle management
- No GDPR right-to-be-forgotten mechanism
Action: Implement as story 0.6 or 0.8 before production if GDPR applies.
| Crate | Test Count | Key Coverage |
|---|---|---|
| tf-config | 263 | URL redaction, config validation, redact trait impls |
| tf-logging | 61 | Sensitive field redaction (25+ tests), span fields, RFC 3339 formatting |
| tf-security | 30 | SecretStore API, error handling, Debug impl |
| Total | 354 | 0 failures, 16 ignored (require OS keyring) |
| Threat | Status | Evidence |
|---|---|---|
| Hardcoded secrets | ✓ PASS | Zero found in production code |
| Plaintext credentials | ✓ PASS | OS keyring storage only |
| Secret leakage in logs | ✓ PASS | 25+ redaction tests, custom Debug impls |
| URL param leakage | ✓ PASS | 27+ sensitive param names redacted |
| Error message leaks | ✓ PASS | Error variants tested, never include secret values |
| Unsafe code | ✓ PASS | forbid/deny attributes enforced |
| Threat | Status | Reason |
|---|---|---|
| SQL injection | N/A | No database queries |
| XSS | N/A | No web UI |
| CSRF | N/A | No web endpoints |
| YAML injection | N/A | Trusted local config files (serde_yaml 0.9 in use, no known CVEs) |
| Requirement | Status | Evidence |
|---|---|---|
| Data minimization | PARTIAL | Logs redact PII; anonymization pipeline pending |
| Right to erasure | NOT IMPLEMENTED | No purge on demand; awaits story implementation |
| Data retention limit | PARTIAL | 90-day policy documented, not enforced |
| Audit trail | BASELINE | JSON logs without PII; no audit-specific trail |
| Data protection | PARTIAL | Keyring storage OK; local purge < 24h not implemented |
Status: NOT READY for GDPR compliance until stories 0.6 (purge) & 0.7 (anonymization) complete.
| Requirement | Status | Evidence |
|---|---|---|
| Minimal logs | ✓ PASS | Structured JSON: timestamp, level, message, target, spans |
| No sensitive data | ✓ PASS | 25+ redaction tests verify masking |
| Timestamp precision | ✓ PASS | RFC 3339 UTC (manual algorithm, no chrono dependency) |
| Structured format | ✓ PASS | JSON with typed fields (not opaque strings) |
| Retention policy | ⚠ PENDING | No story assigned; architecture mandates 90 days |
| Purge automation | ⚠ PENDING | No story assigned; architecture mandates < 24h local |
| Priority | Action | Owner | Timeline |
|---|---|---|---|
| IMMEDIATE | Install cargo-audit; run cargo audit |
DevOps | Before release |
| IMMEDIATE | Add cargo-audit to GitHub Actions CI | DevOps | Before release |
| HIGH | Implement anonymization pipeline (story 0.7) | Engineering | Before cloud LLM integration |
| HIGH | Implement retention & purge (story 0.6 or 0.8) | Engineering | Before go-live if GDPR applies |
| MEDIUM | Code review checklist: verify Debug impls for sensitive configs | Engineering | Ongoing (PR reviews) |
| MEDIUM | Document secret management policy in CONTRIBUTING.md | Docs | Before first external contribution |
| LOW | Add pre-commit hook (git-secrets) | DevOps | Nice-to-have |
- Deploy with local logging baseline (story 0-5 complete)
- Use local LLM only (Ollama) — NO cloud LLM integration
- Requires: cargo-audit in CI/CD
- Add anonymization pipeline
- Implement retention & purge policies
- Then enable cloud LLM mode
- Requires: GDPR legal review before processing personal data
- Add right-to-be-forgotten endpoint (API or CLI command)
- Generate SBOM for compliance reports
- Centralized audit log ingestion (if organizational policy requires)
| File | Change Summary |
|---|---|
/home/edouard/test-framework/SECURITY_ASSESSMENT.json |
This assessment (structured JSON) |
crates/tf-config/src/config.rs |
Custom Debug impls (JiraConfig, SquashConfig, LlmConfig); URL redaction function (+216 tests) |
crates/tf-config/src/lib.rs |
Public re-export of redact_url_sensitive_params |
crates/tf-logging/src/lib.rs |
Public API: init_logging, LogGuard, LoggingConfig, LoggingError |
crates/tf-logging/src/init.rs |
init_logging function with non-blocking I/O, LogGuard lifecycle |
crates/tf-logging/src/redact.rs |
RedactingJsonFormatter, SENSITIVE_FIELDS (12), SENSITIVE_SUFFIXES (26), span redaction, 46 tests |
crates/tf-logging/src/config.rs |
LoggingConfig struct, derivation from ProjectConfig |
crates/tf-logging/src/error.rs |
LoggingError enum with actionable hints |
crates/tf-security/src/lib.rs |
SecretStore public API documentation |
crates/tf-security/src/keyring.rs |
SecretStore implementation (thread-safe, 30 tests) |
crates/tf-security/src/error.rs |
SecretError variants, platform-specific hints (287 lines, 16+ error tests) |
The test-framework CLI demonstrates strong baseline security for local automation. Sensitive data redaction, secret storage, and code safety are mature and well-tested.
The tool is NOT YET ready for GDPR compliance or cloud data processing until anonymization and retention policies are implemented.
Immediate action: Add cargo-audit to CI/CD to close the dependency vulnerability scanning gap.
Next steps: Complete stories 0.6 (retention/purge) and 0.7 (anonymization) before production release with cloud features enabled.
Assessment Completed: 2026-02-07 Assessor: Claude Code (Haiku 4.5) - Security NFR Domain Assessment Type: Structured security domain review (PRD/Architecture compliance, evidence-based)