nu_plugin_secret 0.7.0

Production-grade secret handling plugin for Nushell with secure CustomValue types that prevent accidental exposure of sensitive data
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# Secret Types Best Practices

This guide provides detailed best practices for each secret type in the `nu_plugin_secret` plugin.

## General Security Principles

### 1. Minimize Unwrapping
**Do:**
```nushell
# Keep secrets wrapped as long as possible
let api_key = "secret123" | secret wrap
let headers = {Authorization: $"Bearer ($api_key)"}  # Still wrapped
http get https://api.example.com --headers $headers
```

**Don't:**
```nushell
# Unnecessary early unwrapping
let api_key = "secret123" | secret wrap | secret unwrap
let headers = {Authorization: $"Bearer ($api_key)"}  # Now exposed
```

### 2. Use Appropriate Granularity
**Do:**
```nushell
# Only wrap sensitive fields
let config = {
    api_key: ("secret123" | secret wrap),
    timeout: 30,              # Not sensitive
    retry_count: 3            # Not sensitive
}
```

**Don't:**
```nushell
# Wrapping entire config when only some fields are sensitive
let config = {
    api_key: "secret123",
    timeout: 30,
    retry_count: 3
} | secret wrap  # Unnecessary protection for timeout/retry_count
```

### 3. Clear Naming Conventions
**Do:**
```nushell
let secret_api_key = "key123" | secret wrap
let secret_db_password = "pass456" | secret wrap
let secret_user_id = 12345 | secret wrap
```

**Don't:**
```nushell
let key = "key123" | secret wrap      # Unclear that it's secret
let data = "pass456" | secret wrap    # Too generic
```

## SecretString Best Practices

### Use Cases and Patterns
```nushell
# API Keys - Most common use case
let github_token = $env.GITHUB_TOKEN | secret wrap
let api_response = http get https://api.github.com/user --headers {
    Authorization: $"token ($github_token)"
}

# Connection Strings
let db_url = "postgresql://user:pass@host:5432/db" | secret wrap
let connection = connect $db_url

# Personal Identifiers
let ssn = "123-45-6789" | secret wrap
let credit_card = "4111-1111-1111-1111" | secret wrap

# File Paths with Sensitive Content
let keyfile_path = "/home/user/.ssh/id_rsa" | secret wrap
```

### String-Specific Security
- Use for any text that shouldn't appear in logs
- Ideal for tokens, passwords, and identifiers
- Consider length - very long strings may impact performance
- Use consistent encoding (UTF-8) for international characters

### Common Mistakes
```nushell
# Don't use SecretString for non-text data
let port = "8080" | secret wrap  # Should be: 8080 | secret wrap
let is_enabled = "true" | secret wrap  # Should be: true | secret wrap
```

## SecretInt Best Practices

### Use Cases and Patterns
```nushell
# Database IDs that shouldn't be exposed
let user_id = 12345 | secret wrap
let account_id = 67890 | secret wrap

# Port Numbers in Security Contexts
let internal_port = 8080 | secret wrap
let db_port = 5432 | secret wrap

# Sensitive Counters
let failed_login_count = 3 | secret wrap
let security_level = 5 | secret wrap

# Version Numbers for Internal APIs
let api_version = 2 | secret wrap
```

### Integer-Specific Considerations
- Use for sensitive numeric identifiers
- Good for port numbers in security contexts
- Consider range - stick to standard Nushell int range
- Use for counts that could reveal system information

### When to Use SecretInt vs SecretString
```nushell
# Use SecretInt for actual numbers
let user_id = 12345 | secret wrap          # ✓ Correct

# Don't stringify numbers unnecessarily
let user_id = "12345" | secret wrap     # ✗ Wrong type choice
```

## SecretBool Best Practices

### Use Cases and Patterns
```nushell
# Permission Flags
let is_admin = true | secret wrap
let has_elevated_access = false | secret wrap

# Security Feature Toggles
let mfa_enabled = true | secret wrap
let audit_logging = true | secret wrap

# Access Control States
let is_authenticated = true | secret wrap
let can_delete_users = false | secret wrap

# Privacy Settings
let profile_is_public = false | secret wrap
```

### Boolean-Specific Security
- Use when the boolean value itself is sensitive
- Good for permission and access control flags
- Useful for feature flags that shouldn't be exposed
- Consider if the boolean reveals sensitive system state

### Usage in Conditionals
```nushell
# Safe conditional usage
let is_admin = true | secret wrap
if ($is_admin | secret unwrap) {
    echo "Admin operations available"
}

# Alternative: utility functions that work with secrets
let is_admin = true | secret wrap
if (secret-is-true $is_admin) {  # Hypothetical utility
    echo "Admin operations available" 
}
```

## SecretRecord Best Practices

### Use Cases and Patterns
```nushell
# Complete Credential Sets
let database_creds = {
    host: "db.internal.company.com",
    username: "app_user",
    password: "complex_password_123", 
    port: 5432,
    database: "production_db"
} | secret wrap

# API Configuration
let api_config = {
    base_url: "https://internal-api.company.com",
    api_key: "sk-1234567890abcdef",
    secret_key: "secret_abcdef1234567890",
    version: "v2"
} | secret wrap

# OAuth Credentials  
let oauth_creds = {
    client_id: "client_123456",
    client_secret: "secret_abcdef", 
    redirect_uri: "https://myapp.com/callback",
    scopes: ["read", "write"]
} | secret wrap
```

### Record-Specific Considerations
- Use when multiple related fields are all sensitive
- Consider partial sensitivity - mix secret and non-secret fields
- Good for structured credentials and configuration
- Enables atomic handling of related sensitive data

### Mixed Sensitivity Records
```nushell
# Better: Mix secret and non-secret fields
let api_config = {
    base_url: "https://api.example.com",        # Public
    timeout: 30,                                # Public
    api_key: ("secret123" | secret wrap), # Secret
    retry_count: 3                              # Public
}

# Instead of wrapping entire record
let api_config = {
    base_url: "https://api.example.com", 
    timeout: 30,
    api_key: "secret123",
    retry_count: 3
} | secret wrap  # All fields become secret unnecessarily
```

## SecretList Best Practices

### Use Cases and Patterns
```nushell
# Backup Codes
let backup_codes = [
    "ABC123DEF", 
    "GHI456JKL", 
    "MNO789PQR"
] | secret wrap

# API Key Collections
let api_keys = [
    "sk-prod-1234567890",
    "sk-staging-abcdef123", 
    "sk-dev-xyz789"
] | secret wrap

# User Token Arrays
let user_tokens = [
    "token_user1_abc123",
    "token_user2_def456", 
    "token_user3_ghi789"
] | secret wrap

# Sensitive Configuration Arrays
let allowed_ips = [
    "192.168.1.100",
    "10.0.0.5", 
    "172.16.0.10"
] | secret wrap
```

### List-Specific Considerations
- Use when each element is sensitive
- Good for collections of similar secret data
- Consider if the list structure itself is sensitive
- Be careful with list operations that might expose elements

### Working with SecretLists
```nushell
# Safe list operations
let secrets = ["a", "b", "c"] | secret wrap
let length = ($secrets | secret unwrap | length)    # Length is safe to expose
let first_secret = ($secrets | secret unwrap | get 0) | secret wrap  # Re-wrap individual elements
```

## SecretFloat Best Practices

### Use Cases and Patterns
```nushell
# Financial Data
let salary = 75000.50 | secret wrap
let bonus_percentage = 0.15 | secret wrap

# Sensitive Measurements
let server_load = 0.85 | secret wrap
let error_rate = 0.02 | secret wrap

# Performance Metrics
let response_time = 245.7 | secret wrap
let cpu_usage = 67.3 | secret wrap

# Scientific Data with Privacy Implications
let patient_measurement = 98.6 | secret wrap
```

### Float-Specific Considerations
- Use for sensitive numeric measurements
- Good for financial amounts and percentages
- Consider precision requirements
- Handle special values (NaN, infinity) appropriately

### Float Precision and Comparison
```nushell
# Be careful with float comparisons
let secret_val = 1.1 | secret wrap
let unwrapped = $secret_val | secret unwrap
# Use appropriate epsilon for comparisons
let is_equal = (($unwrapped - 1.1) | math abs) < 0.0001
```

## SecretBinary Best Practices

### Use Cases and Patterns
```nushell
# Cryptographic Keys
let private_key = (open private.key | into binary) | secret wrap
let public_key = (open public.key | into binary) | secret wrap

# Certificate Data
let ssl_cert = (open certificate.pem | into binary) | secret wrap

# Hash Values
let password_hash = (echo "password123" | hash sha256 | into binary) | secret wrap

# Encrypted Data Blobs
let encrypted_data = (encrypt_data $plaintext | into binary) | secret wrap

# Raw Binary Secrets
let random_seed = (generate_random_bytes 32) | secret wrap
```

### Binary-Specific Considerations
- Use for raw cryptographic material
- Good for certificates, keys, and hashes
- Consider binary data size for performance
- Ensure proper encoding when converting to/from text

### Binary Data Handling
```nushell
# Safe binary operations
let key_data = (open key.bin | into binary) | secret wrap
let key_length = ($key_data | secret unwrap | bytes length)  # Length is safe
let is_empty = ($key_data | secret unwrap | is-empty)        # Emptiness check is safe
```

## SecretDate Best Practices

### Use Cases and Patterns
```nushell
# Account Creation Dates (Privacy)
let account_created = (date now) | secret wrap

# Certificate Expiration
let cert_expires = ("2024-12-31T23:59:59Z" | into datetime) | secret wrap

# Sensitive Event Timestamps
let last_login = (date now) | secret wrap
let password_changed = (date now) | secret wrap

# Audit Timestamps
let security_event_time = (date now) | secret wrap
let access_granted_time = (date now) | secret wrap

# Privacy-Sensitive Dates
let birth_date = ("1990-01-01T00:00:00Z" | into datetime) | secret wrap
```

### Date-Specific Considerations
- Use for timestamps that reveal sensitive information
- Good for privacy-related dates
- Consider timezone handling
- Be careful with date formatting that might expose data

### Safe Date Operations
```nushell
# Safe date operations that don't expose sensitive info
let secret_date = (date now) | secret wrap
let year = ($secret_date | secret unwrap | date to-record | get year)  # Year might be safe
let is_future = ($secret_date | secret unwrap) > (date now)           # Comparison result is safe
```

## Performance Considerations

### Memory Usage
- SecretString: Proportional to string length
- SecretInt/Bool/Float: Fixed small overhead
- SecretRecord/List: Proportional to content size
- SecretBinary: Proportional to binary data size
- SecretDate: Fixed small overhead

### Operation Performance
```nushell
# Efficient: Minimize unwrapping operations
let secrets = generate_secrets | each { |s| $s | secret wrap }

# Less efficient: Frequent unwrapping
let secrets = generate_secrets | each { |s| 
    let wrapped = $s | secret wrap
    let unwrapped = $wrapped | secret unwrap
    validate_secret $unwrapped
    $s | secret wrap
}
```

## Testing Secret Types

### Unit Test Patterns
```nushell
# Test secret creation and unwrapping
def test_secret_string [] {
    let original = "test_value"
    let secret = $original | secret wrap
    let unwrapped = $secret | secret unwrap
    assert ($unwrapped == $original)
}

# Test display protection  
def test_secret_display [] {
    let secret = "sensitive" | secret wrap
    let display = $secret | to text
    assert ($display == "<redacted:string>")
}
```

### Integration Test Patterns
```nushell
# Test secret types in pipelines
def test_secret_pipeline [] {
    let api_key = "key123" | secret wrap
    # Test that secret survives pipeline operations
    let result = [$api_key] | get 0 | secret unwrap
    assert ($result == "key123")
}
```

## Error Handling

### Common Error Scenarios
```nushell
# Handle type mismatches gracefully
def safe_unwrap_string [value] {
    if ($value | secret validate) and ($value | secret type-of) == "string" {
        $value | secret unwrap
    } else {
        error make {msg: "Expected secret string"}
    }
}

# Handle unwrapping failures
def safe_process_secret [secret] {
    try {
        let value = $secret | secret unwrap
        process_value $value
    } catch {
        echo "Failed to process secret safely"
    }
}
```

## Configuration and Templates

### Safe Template Patterns

Use configuration templates that don't expose secret content:

```nushell
# Configure safe redaction templates
secret configure
# Or edit config directly at ~/.local/share/nushell/plugins/secret/config.toml
```

**Recommended templates**:
```toml
# Default - safest option
redaction_template = "<redacted:{{secret_type}}>"

# Show type and length info
redaction_template = "{{secret_type}}({{secret_length}})"

# Visual masking that matches secret length
redaction_template = "{{replicate(s='*', n=secret_length)}}"

# Custom safe format
redaction_template = "[PROTECTED:{{secret_type}}]"
```

### Template Security Guidelines

**✅ Do**:
```toml
# Safe templates that don't expose content
redaction_template = "{{secret_type}}: {{replicate(s='█', n=secret_length)}}"
redaction_template = "<{{secret_type}}-{{secret_length}}>"
redaction_template = "{{replicate(s='*', n=8)}}"  # Fixed safe length
```

**❌ Don't**:
```toml
# Dangerous templates that expose secret data
redaction_template = "{{secret_string()}}"  # Exposes full secret!
redaction_template = "{{take(n=4, s=secret_string())}}"  # Exposes prefix
redaction_template = "{{mask_partial(s=secret_string(), l=3, r=3)}}"  # Partial exposure
```

### Development vs Production Templates

**Development** (with `SHOW_UNREDACTED=1`):
```nushell
# Temporarily show actual values for debugging
export SHOW_UNREDACTED=1
echo "my-secret" | secret wrap  # Shows: my-secret
```

**Production** (secure configuration):
```toml
[redaction]
show_unredacted = false  # Never true in production
redaction_template = "<redacted:{{secret_type}}>"

[security]
level = "paranoid"  # Maximum security
audit_enabled = true
```

### Template Validation

Always validate custom templates:
```nushell
# Check template syntax and security
secret config validate

# Test templates before deployment
secret configure --security-level standard
secret config validate --verbose
```

## Summary

1. **Choose the right type** for your data's actual type and sensitivity
2. **Minimize unwrapping** to maintain security
3. **Use clear naming** to indicate secret status
4. **Handle errors gracefully** when working with secrets
5. **Test thoroughly** including display and serialization protection
6. **Consider performance** implications of different secret types
7. **Follow security principles** consistently across your codebase
8. **Use safe templates** that don't expose secret content
9. **Validate configuration** before deploying to production
10. **Regular security review** of templates and configuration