waddling-errors-macros 0.7.3

Procedural macros for structured error codes with compile-time validation and taxonomy enforcement
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
# Component Location Roles - Security Feature

## Overview

Component locations (file paths where component code lives) now support **role-based visibility** for security. This prevents leaking sensitive internal file paths in public documentation while still providing full transparency to internal teams.

## Why This Matters 🔒

**Security Concern**: Exposing internal file paths in public documentation can:
- Reveal internal application structure
- Help attackers understand code organization
- Leak implementation details that should remain private
- Show sensitive file names (e.g., `secret_rotation.rs`, `admin_backdoor.rs`)

**Solution**: Role-based filtering ensures only appropriate audiences see specific file paths.

---

## Role System

The feature uses the existing three-role hierarchy:

| Role | Privilege Level | Can See |
|------|----------------|---------|
| **Public** | 0 (most restrictive) | Only Public content |
| **Developer** | 1 | Public + Developer content |
| **Internal** | 2 (least restrictive) | Everything (Public + Developer + Internal) |

---

## API Reference

### Default Behavior (Secure by Default)

```rust
use waddling_errors::doc_generator::DocRegistry;

let mut registry = DocRegistry::new("MyApp", "1.0.0");

// Defaults to Internal role - only visible in internal docs
registry.register_component_location(
    "AUTH",
    "src/auth/jwt_signer.rs"
);
```

**Security Best Practice**: This is the default behavior to prevent accidental exposure of internal paths.

---

### Explicit Role Control

```rust
use waddling_errors::doc_generator::DocRegistry;
use waddling_errors::Role;

let mut registry = DocRegistry::new("MyApp", "1.0.0");

// Public: Safe to show everyone (documentation examples)
registry.register_component_location_with_role(
    "AUTH",
    "examples/auth_usage.rs",
    Some(Role::Public)
);

// Developer: For contributors and team (debugging utilities)
registry.register_component_location_with_role(
    "AUTH",
    "src/auth/debug_utils.rs",
    Some(Role::Developer)
);

// Internal: Team only (implementation details)
registry.register_component_location_with_role(
    "AUTH",
    "src/auth/secret_rotation.rs",
    Some(Role::Internal)
);

// Visible to all (NOT RECOMMENDED for security)
registry.register_component_location_with_role(
    "AUTH",
    "src/auth/public_api.rs",
    None
);
```

---

## Real-World Example

### Component Registration with Security

```rust
#[cfg(feature = "doc-gen")]
pub fn register_component(generator: &mut DocRegistry) {
    use waddling_errors::Role;
    
    generator.register_component(
        "AUTH",
        Some("Authentication and authorization system..."),
        &[...],
        &[...]
    );

    // ✅ PUBLIC: Documentation examples - safe for everyone
    generator.register_component_location_with_role(
        "AUTH",
        "examples/complete_system/components/auth.rs",
        Some(Role::Public)
    );
    
    // ❌ INTERNAL: Implementation details - team only (SECURE BY DEFAULT)
    generator.register_component_location("AUTH", "src/middleware/auth.rs");
    generator.register_component_location("AUTH", "src/handlers/auth_handler.rs");
    generator.register_component_location("AUTH", "src/services/token_service.rs");
    generator.register_component_location("AUTH", "src/auth/secret_rotation.rs");
}
```

---

## Generated Documentation Comparison

### Public Documentation (`myapp-pub.json`)

```json
{
  "components": {
    "AUTH": {
      "name": "AUTH",
      "description": "Authentication and authorization system...",
      "locations": [
        {
          "path": "examples/complete_system/components/auth.rs",
          "role": "Public"
        }
      ]
    }
  }
}
```

**✅ Secure**: Only shows the public example file. Internal implementation paths are hidden.

---

### Developer Documentation (`myapp-dev.json`)

```json
{
  "components": {
    "AUTH": {
      "name": "AUTH",
      "description": "Authentication and authorization system...",
      "locations": [
        {
          "path": "examples/complete_system/components/auth.rs",
          "role": "Public"
        },
        {
          "path": "src/auth/debug_utils.rs",
          "role": "Developer"
        }
      ]
    }
  }
}
```

**✅ Team Context**: Shows public examples + developer utilities. Still protects internal secrets.

---

### Internal Documentation (`myapp-int.json`)

```json
{
  "components": {
    "AUTH": {
      "name": "AUTH",
      "description": "Authentication and authorization system...",
      "locations": [
        {
          "path": "examples/complete_system/components/auth.rs",
          "role": "Public"
        },
        {
          "path": "src/auth/debug_utils.rs",
          "role": "Developer"
        },
        {
          "path": "src/middleware/auth.rs",
          "role": "Internal"
        },
        {
          "path": "src/handlers/auth_handler.rs",
          "role": "Internal"
        },
        {
          "path": "src/services/token_service.rs",
          "role": "Internal"
        },
        {
          "path": "src/auth/secret_rotation.rs",
          "role": "Internal"
        }
      ]
    }
  }
}
```

**✅ Full Transparency**: Internal team sees everything for maintenance and debugging.

---

## Security Benefits

### 1. **Information Security**
- Public documentation doesn't leak internal file structure
- Attackers can't map your codebase from docs
- Sensitive file names remain private

### 2. **Professional Documentation**
- Public docs show only relevant examples
- Internal docs provide complete context for team
- Different audiences get appropriate information

### 3. **Compliance**
- Helps meet security audit requirements
- Demonstrates security-conscious design
- Prevents accidental information disclosure

### 4. **Secure by Default**
- No action needed for security - it's the default
- Must explicitly opt-in to public visibility
- Reduces risk of configuration errors

---

## Best Practices

### ✅ DO

```rust
// ✅ Mark documentation examples as Public
generator.register_component_location_with_role(
    "Auth",
    "examples/auth_example.rs",
    Some(Role::Public)
);

// ✅ Use default (Internal) for implementation files
generator.register_component_location("Auth", "src/auth/jwt.rs");

// ✅ Mark debugging utilities as Developer
generator.register_component_location_with_role(
    "Auth",
    "src/auth/debug_logger.rs",
    Some(Role::Developer)
);
```

### ❌ DON'T

```rust
// ❌ DON'T mark internal implementations as Public
generator.register_component_location_with_role(
    "Auth",
    "src/auth/secret_rotation.rs",  // SENSITIVE!
    Some(Role::Public)  // ❌ SECURITY RISK!
);

// ❌ DON'T use None for sensitive paths
generator.register_component_location_with_role(
    "Auth",
    "src/auth/admin_backdoor.rs",  // VERY SENSITIVE!
    None  // ❌ Visible to everyone!
);
```

---

## Migration Guide

### Updating Existing Code

**Before (v0.4.x - No role support):**
```rust
generator.register_component_location("AUTH", "src/auth/jwt.rs");
```

**After (v0.5.x - Secure by default):**
```rust
// Same call, but now defaults to Internal (secure!)
generator.register_component_location("AUTH", "src/auth/jwt.rs");

// For public examples, explicitly mark them:
generator.register_component_location_with_role(
    "AUTH",
    "examples/auth_example.rs",
    Some(Role::Public)
);
```

**No Breaking Changes**: Existing code works as-is, but now has secure defaults! 🎉

---

## Data Structures

### ComponentLocation

```rust
pub struct ComponentLocation {
    /// File path (e.g., "src/auth/jwt_signer.rs")
    pub path: String,
    
    /// Role visibility (Public, Developer, Internal)
    /// None = visible to all roles (not recommended for security)
    pub role: Option<String>,
}
```

### Convenience Constructors

```rust
impl ComponentLocation {
    /// Create with any role
    pub fn new(path: impl Into<String>, role: Option<String>) -> Self;
    
    /// Create public location
    pub fn public(path: impl Into<String>) -> Self;
    
    /// Create developer location
    pub fn developer(path: impl Into<String>) -> Self;
    
    /// Create internal location (default/secure)
    pub fn internal(path: impl Into<String>) -> Self;
}
```

---

## Technical Details

### Filtering Implementation

Component locations are filtered during documentation rendering in `render_all_roles()`:

```rust
// Filter component locations by role
let filtered_components: HashMap<String, ComponentMeta> = self
    .components
    .iter()
    .map(|(name, comp)| {
        let filtered_locations: Vec<ComponentLocation> = comp
            .locations
            .iter()
            .filter(|loc| html::is_visible_at_role(loc.role.as_deref(), role))
            .cloned()
            .collect();
        
        let mut filtered_comp = comp.clone();
        filtered_comp.locations = filtered_locations;
        (name.clone(), filtered_comp)
    })
    .collect();
```

### Visibility Rules

```rust
fn is_visible_at_role(content_role: Option<&str>, viewer_role: Role) -> bool {
    match content_role {
        None => true,  // Unspecified = visible to all
        Some("Public") => true,  // Everyone can see Public
        Some("Developer") => viewer_role != Role::Public,  // Dev + Internal
        Some("Internal") => viewer_role == Role::Internal,  // Internal only
        _ => false,
    }
}
```

---

## Future Enhancements

Potential future additions (not yet implemented):

1. **Custom Roles**: Define your own role hierarchies
2. **Compartmentalization**: Numeric role system (0-9999) for complex orgs
3. **Macro Support**: `#[in_component(Auth, role = Internal)]` attribute
4. **Auto-Discovery**: Scan codebase for component usage patterns
5. **LSP Integration**: IDE navigation using component metadata

---

## FAQ

### Q: Why default to Internal instead of Public?

**A**: **Security by default**. It's safer to accidentally hide a path than to accidentally expose it. Public documentation should be curated and intentional.

### Q: Can I make all locations public?

**A**: Yes, but not recommended. Use `Role::Public` explicitly for documentation examples only. Keep implementation details internal.

### Q: What if I forget to set roles?

**A**: You're safe! The default is `Internal`, so paths are hidden from public docs unless you explicitly mark them as `Public`.

### Q: Does this affect runtime behavior?

**A**: No. Roles only affect documentation generation. Runtime error handling is unchanged.

### Q: Can I have the same file in multiple components?

**A**: Yes. A file like `src/utils/crypto.rs` could be marked as part of both `Auth` and `Storage` components with different roles.

---

## Summary

🔒 **Secure by Default**: Component locations default to `Internal` for security  
📘 **Role-Based Filtering**: Public, Developer, and Internal visibility levels  
🎯 **Explicit Control**: Use `register_component_location_with_role()` for fine-grained control  
✅ **Zero Breaking Changes**: Existing code works with added security  
🛡️ **Professional**: Prevents information leakage in public documentation  

**This feature demonstrates that error handling can be security-conscious from the start!** 🦆