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
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
# Migration Guide: From Plain Types to Secret Types

This guide helps you migrate from using plain Nushell types to secure `nu_plugin_secret` types for handling sensitive data.

## ๐Ÿ” Why Migrate?

Plain Nushell types can accidentally expose sensitive data through:
- Debug output and logging
- Serialization to JSON/YAML/etc.
- Copy/paste operations
- Memory dumps

Secret types prevent these exposures while maintaining full functionality.

## ๐Ÿ“‹ Migration Checklist

### Before You Start
- [ ] Install `nu_plugin_secret`: `cargo install nu_plugin_secret`
- [ ] Register the plugin: `plugin add ~/.cargo/bin/nu_plugin_secret`
- [ ] Activate the plugin: `plugin use secret`
- [ ] Verify installation: `secret info`

## ๐Ÿ”„ Type-by-Type Migration

### 1. Strings โ†’ SecretString

**Before:**
```nushell
let api_key = "sk-1234567890abcdef"
echo $api_key  # โŒ Exposes secret
```

**After:**
```nushell
let api_key = "sk-1234567890abcdef" | secret wrap
echo $api_key  # โœ… Shows <redacted:string>
```

**Common Use Cases:**
- API keys and tokens
- Passwords and passphrases
- Connection strings
- Private keys

### 2. Integers โ†’ SecretInt

**Before:**
```nushell
let user_id = 12345
echo $user_id  # โŒ May expose sensitive ID
```

**After:**
```nushell
let user_id = 12345 | secret wrap
echo $user_id  # โœ… Shows <redacted:int>
```

**Common Use Cases:**
- User IDs and account numbers
- Port numbers for internal services
- Sensitive numeric codes
- Database IDs

### 3. Booleans โ†’ SecretBool

**Before:**
```nushell
let is_admin = true
echo $is_admin  # โŒ May expose privilege level
```

**After:**
```nushell
let is_admin = true | secret wrap
echo $is_admin  # โœ… Shows <redacted:bool>
```

**Common Use Cases:**
- Permission flags
- Feature toggles
- Security settings
- Access control flags

### 4. Floats โ†’ SecretFloat

**Before:**
```nushell
let latitude = 37.7749
echo $latitude  # โŒ Exposes location data
```

**After:**
```nushell
let latitude = 37.7749 | secret wrap
echo $latitude  # โœ… Shows <redacted:float>
```

**Common Use Cases:**
- GPS coordinates
- Financial amounts
- Sensitive measurements
- Performance metrics

### 5. Records โ†’ SecretRecord

**Before:**
```nushell
let credentials = {
  username: "admin",
  password: "secret123",
  server: "prod.example.com"
}
echo $credentials  # โŒ Exposes all sensitive data
```

**After:**
```nushell
let credentials = {
  username: "admin",
  password: "secret123",
  server: "prod.example.com"
} | secret wrap
echo $credentials  # โœ… Shows <redacted:record>
```

**Common Use Cases:**
- Configuration objects
- User profiles
- Connection details
- Authentication data

### 6. Lists โ†’ SecretList

**Before:**
```nushell
let api_keys = ["key1", "key2", "key3"]
echo $api_keys  # โŒ Exposes all keys
```

**After:**
```nushell
let api_keys = ["key1", "key2", "key3"] | secret wrap
echo $api_keys  # โœ… Shows <redacted:list>
```

**Common Use Cases:**
- Multiple API keys
- User lists
- Permission arrays
- Sensitive collections

### 7. Binary Data โ†’ SecretBinary

**Before:**
```nushell
let key_data = 0x[deadbeef1234567890abcdef]
echo $key_data  # โŒ Exposes binary key
```

**After:**
```nushell
let key_data = 0x[deadbeef1234567890abcdef] | secret wrap
echo $key_data  # โœ… Shows <redacted:binary>
```

**Common Use Cases:**
- Cryptographic keys
- Binary tokens
- Encrypted data
- Certificate data

### 8. Dates โ†’ SecretDate

**Before:**
```nushell
let birth_date = "2000-01-01" | into datetime
echo $birth_date  # โŒ Exposes personal information
```

**After:**
```nushell
let birth_date = "2000-01-01" | into datetime | secret wrap
echo $birth_date  # โœ… Shows <redacted:date>
```

**Common Use Cases:**
- Birth dates
- Event timestamps
- Expiration dates
- Personal milestones

## ๐Ÿ”ง Working with Secret Types

### Extracting Values (Use Sparingly)

```nushell
# Only when absolutely necessary
let plain_value = $secret_value | secret unwrap
# โš ๏ธ  Logs security warning
```

### Type Checking

```nushell
# Check if value is a secret type
$value | secret validate

# Get the underlying type
$secret_value | secret type-of
```

### Pipeline Integration

```nushell
# Secret types work in pipelines
"sensitive-data" 
| secret wrap 
| secret type-of  # Returns "string"
```

## ๐Ÿ—๏ธ Migration Patterns

### Pattern 1: Configuration Files

**Before:**
```nushell
let config = {
  database_url: "postgres://user:pass@localhost/db",
  api_key: "sk-1234567890",
  debug: true
}
```

**After:**
```nushell
let config = {
  database_url: "postgres://user:pass@localhost/db" | secret wrap,
  api_key: "sk-1234567890" | secret wrap,
  debug: true | secret wrap
} | secret wrap
```

### Pattern 2: Environment Variables

**Before:**
```nushell
let env_vars = {
  API_KEY: ($env.API_KEY),
  DB_PASSWORD: ($env.DB_PASSWORD)
}
```

**After:**
```nushell
let env_vars = {
  API_KEY: ($env.API_KEY | secret wrap),
  DB_PASSWORD: ($env.DB_PASSWORD | secret wrap)
} | secret wrap
```

### Pattern 3: User Input

**Before:**
```nushell
let password = (input "Enter password: ")
echo $"Password entered: {$password}"  # โŒ Exposes password
```

**After:**
```nushell
let password = (input "Enter password: ") | secret wrap
echo $"Password entered: {$password}"  # โœ… Shows <redacted:string>
```

### Pattern 4: Mixed Sensitivity Data

**Before:**
```nushell
let server_config = {
  hostname: "api.example.com",     # Public
  port: 443,                       # Public  
  api_key: "sk-secret123",         # Secret
  timeout: 30,                     # Public
  admin_password: "admin123"       # Secret
}
```

**After:**
```nushell
let server_config = {
  hostname: "api.example.com",                        # Keep public
  port: 443,                                          # Keep public
  api_key: ("sk-secret123" | secret wrap),    # Wrap secret
  timeout: 30,                                        # Keep public
  admin_password: ("admin123" | secret wrap)  # Wrap secret
}
# Don't wrap entire record - only sensitive fields
```

### Pattern 5: Database Credentials

**Before:**
```nushell
let db_creds = {
  host: "db.internal.com",
  port: 5432,
  username: "app_user", 
  password: "db_password_123",
  database: "production",
  ssl: true
}

# Connect using plain credentials (exposed in memory/logs)
let connection = db connect $db_creds
```

**After:**
```nushell
let db_creds = {
  host: "db.internal.com",                               # Public
  port: (5432 | secret wrap),                        # May be sensitive
  username: ("app_user" | secret wrap),           # Sensitive
  password: ("db_password_123" | secret wrap),    # Secret
  database: "production",                                 # Public
  ssl: true                                              # Public
}

# Connection function handles secret unwrapping internally
let connection = db connect_secure $db_creds
```

### Pattern 6: API Client Migration

**Before:**
```nushell
def call_api [endpoint: string, api_key: string] {
  http get $endpoint --headers {
    Authorization: $"Bearer ($api_key)"
  }
}

let key = "sk-1234567890"
call_api "https://api.example.com/data" $key  # Key exposed in call
```

**After:**
```nushell
def call_api [endpoint: string, api_key: any] {
  # Function expects secret type
  let key = if ($api_key | secret validate) {
    $api_key | secret unwrap
  } else {
    error make {msg: "API key must be a secret type"}
  }
  
  http get $endpoint --headers {
    Authorization: $"Bearer ($key)"
  }
}

let key = "sk-1234567890" | secret wrap
call_api "https://api.example.com/data" $key  # Key remains protected
```

### Pattern 7: Bulk Data Processing

**Before:**
```nushell
# Processing list of sensitive user data
let users = [
  {id: 123, name: "Alice", ssn: "123-45-6789"},
  {id: 456, name: "Bob", ssn: "987-65-4321"}
]

$users | each { |user|
  echo $"Processing user: ($user.name), SSN: ($user.ssn)"  # โŒ Exposes SSN
}
```

**After:**
```nushell
# Wrap sensitive fields during processing
let users = [
  {id: 123, name: "Alice", ssn: ("123-45-6789" | secret wrap)},
  {id: 456, name: "Bob", ssn: ("987-65-4321" | secret wrap)}
]

$users | each { |user|
  echo $"Processing user: ($user.name), SSN: ($user.ssn)"  # โœ… Shows <redacted:string>
  # Only unwrap when absolutely necessary for external systems
  process_user_external ($user.ssn | secret unwrap)
}
```

### Pattern 8: File I/O with Secrets

**Before:**
```nushell
# Reading sensitive config from file
let config = open config.json | from json
echo $"API key: ($config.api_key)"  # โŒ May expose in logs

# Writing sensitive data
{api_key: "secret123"} | to json | save output.json  # โŒ Exposes in file
```

**After:**
```nushell
# Reading and immediately protecting
let config = open config.json | from json
let secure_config = {
  api_key: ($config.api_key | secret wrap),
  other_field: $config.other_field
}
echo $"API key: ($secure_config.api_key)"  # โœ… Shows <redacted:string>

# Only save non-sensitive representations
let safe_config = {api_key: "<redacted>", other_field: $config.other_field}
$safe_config | to json | save output.json  # โœ… No secrets in file
```

### Pattern 9: Function Parameter Migration

**Before:**
```nushell
def deploy_app [
  app_name: string,
  api_key: string,        # Plain string parameter
  database_url: string,   # Plain string parameter
  port: int              # Plain int parameter
] {
  echo $"Deploying ($app_name) with key: ($api_key)"  # โŒ Exposes key
  # ... deployment logic
}

deploy_app "myapp" "sk-secret123" "postgres://user:pass@host/db" 8080
```

**After:**
```nushell
def deploy_app [
  app_name: string,
  api_key: any,          # Accept secret type
  database_url: any,     # Accept secret type  
  port: any             # Accept secret type
] {
  # Validate secret types
  if not ($api_key | secret validate) {
    error make {msg: "api_key must be a secret type"}
  }
  if not ($database_url | secret validate) {
    error make {msg: "database_url must be a secret type"}
  }
  if not ($port | secret validate) {
    error make {msg: "port must be a secret type"}
  }
  
  echo $"Deploying ($app_name) with key: ($api_key)"  # โœ… Shows <redacted:string>
  
  # Only unwrap for actual use
  let key = $api_key | secret unwrap
  let db = $database_url | secret unwrap
  let p = $port | secret unwrap
  
  # ... deployment logic with unwrapped values
}

# Call with secret types
deploy_app "myapp" 
  ("sk-secret123" | secret wrap)
  ("postgres://user:pass@host/db" | secret wrap)
  (8080 | secret wrap)
```

### Pattern 10: Gradual Migration Strategy

**Phase 1: Identify sensitive data**
```nushell
# Audit existing scripts for sensitive data
def audit_script [file: path] {
  open $file 
  | lines 
  | enumerate 
  | where item =~ "password|api_key|secret|token|credential"
  | each { |line| 
      echo $"Line ($line.index + 1): ($line.item)" 
    }
}
```

**Phase 2: Add secret wrapping at input boundaries**
```nushell
# Wrap secrets as soon as they enter your script
let api_key = ($env.API_KEY | default "" | secret wrap)
let db_pass = ($env.DB_PASSWORD | default "" | secret wrap)
```

**Phase 3: Update functions to accept secret types**
```nushell
# Modify functions to handle both plain and secret types during transition
def flexible_auth [token: any] {
  let auth_token = if ($token | secret validate) {
    $token
  } else {
    $token | secret wrap  # Auto-wrap plain types
  }
  
  # Work with secret type from here on
  use_auth_token $auth_token
}
```

**Phase 4: Remove compatibility and enforce secret types**
```nushell
# Final version - only accept secret types
def secure_auth [token: any] {
  if not ($token | secret validate) {
    error make {
      msg: "Authentication token must be a secret type",
      help: "Use: $token | secret wrap"
    }
  }
  
  use_auth_token $token
}
```

## ๐Ÿšจ Security Best Practices

### 1. **Default to Secret Types**
Always use secret types for any data that could be sensitive.

### 2. **Minimize Unwrapping**
Only use `secret unwrap` when absolutely necessary for external APIs.

### 3. **Validate Types**
Use `secret validate` to ensure you're working with secret types.

### 4. **Pipeline Safety**
Secret types remain protected throughout pipeline operations.

### 5. **Memory Safety**
Secret types automatically clean memory when dropped.

## โš ๏ธ Common Pitfalls

### 1. **Forgetting to Wrap**
```nushell
# โŒ Still exposed
let api_key = "secret123"
let wrapped = $api_key | secret wrap  # Too late!

# โœ… Immediate protection
let api_key = "secret123" | secret wrap
```

### 2. **Unnecessary Unwrapping**
```nushell
# โŒ Defeats the purpose
let secret = "data" | secret wrap | secret unwrap

# โœ… Keep it wrapped
let secret = "data" | secret wrap
```

### 3. **Type Confusion**
```nushell
# โœ… Use type checking
if ($value | secret validate) {
  let type = $value | secret type-of
  echo $"Working with secret {$type}"
}
```

## ๐Ÿงช Testing Your Migration

### 1. **Verify Protection**
```nushell
let secret = "sensitive" | secret wrap
echo $secret  # Should show <redacted:string>
```

### 2. **Test Functionality**
```nushell
let secret = 42 | secret wrap
($secret | secret type-of) == "int"  # Should be true
```

### 3. **Pipeline Compatibility**
```nushell
"test" | secret wrap | secret validate  # Should be true
```

## ๐Ÿ“š Additional Resources

- **Plugin Documentation**: `secret info`
- **Security Guide**: [docs/SECURITY.md]SECURITY.md
- **API Reference**: [docs/API.md]API.md
- **Examples**: [examples/]../examples/

## ๐Ÿ†˜ Getting Help

If you encounter issues during migration:

1. **Check Plugin Status**: `plugin list | where name == secret`
2. **Validate Installation**: `secret info`
3. **Test Basic Functionality**: `"test" | secret wrap`
4. **Review Logs**: Check for any error messages
5. **File Issues**: [GitHub Issues]https://github.com/nushell-works/nu_plugin_secret/issues

---

**Remember**: Migration to secret types is a security enhancement. Take time to identify all sensitive data in your scripts and wrap them appropriately. The initial effort pays off in long-term security and peace of mind.