|
| 1 | +# Fuzz Testing |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Console employs two complementary fuzzing strategies: |
| 6 | + |
| 7 | +1. **Internal function fuzzing** — Go's built-in `go test -fuzz` framework targets parsing, transformation, validation, and cryptographic functions at the unit level. |
| 8 | +2. **API fuzzing** — *(planned)* HTTP-level fuzzing of Console's REST API endpoints. |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Internal Function Fuzzing |
| 13 | + |
| 14 | +Uses Go's native fuzzing to test internal functions for crash resistance, determinism, and input-safety. There are **17 fuzz targets** across **11 test files** covering four categories: JSON/DTO validation, use-case DTO↔entity transforms, cryptographic parsing, and string parsing. |
| 15 | + |
| 16 | +### Coverage Summary |
| 17 | + |
| 18 | +#### 1. JSON Deserialization & DTO Validation (7 targets) |
| 19 | + |
| 20 | +All targets live in a single file and share a generic helper `fuzzJSONAndValidate[T]` that verifies `json.Unmarshal` determinism, `reflect.DeepEqual` consistency, and struct-level validator stability. |
| 21 | + |
| 22 | +| Target | DTO Type | Validators Exercised | File | |
| 23 | +|--------|----------|----------------------|------| |
| 24 | +| `FuzzDeviceJSONProcessing` | `Device` | default | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 25 | +| `FuzzProfileJSONProcessing` | `Profile` | `ValidateAMTPassOrGenRan`, `ValidateCIRAOrTLS`, `ValidateWiFiDHCP` | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 26 | +| `FuzzDomainJSONProcessing` | `Domain` | `ValidateAlphaNumHyphenUnderscore` | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 27 | +| `FuzzCIRAConfigJSONProcessing` | `CIRAConfig` | default | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 28 | +| `FuzzWirelessConfigJSONProcessing` | `WirelessConfig` | `ValidateAuthandIEEE` | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 29 | +| `FuzzIEEE8021xJSONProcessing` | `IEEE8021xConfig` | `AuthProtocolValidator` | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 30 | +| `FuzzProfileWiFiJSONProcessing` | `ProfileWiFiConfigs` | default | `internal/entity/dto/v1/json_fuzz_test.go` | |
| 31 | + |
| 32 | +**What is tested:** arbitrary JSON payloads (valid, malformed, deeply nested, oversized, unicode/null-byte) are deserialized twice and validated twice. Failures in determinism, panics, or mismatched validation results are caught. |
| 33 | + |
| 34 | +#### 2. Use-Case DTO↔Entity Transform Round-Trips (7 targets) |
| 35 | + |
| 36 | +Each target fuzzes both `dtoToEntity` and `entityToDTO` in its respective use-case package. Cryptographic dependencies are satisfied with mock implementations. All targets assert determinism via dual invocation and `reflect.DeepEqual`. |
| 37 | + |
| 38 | +| Target | Package | Functions Under Test | File | |
| 39 | +|--------|---------|----------------------|------| |
| 40 | +| `FuzzCIRAConfigTransforms` | `ciraconfigs` | `dtoToEntity`, `entityToDTO` | `internal/usecase/ciraconfigs/transform_fuzz_test.go` | |
| 41 | +| `FuzzDeviceTransforms` | `devices` | `dtoToEntity`, `entityToDTO` + GUID lowercasing, cert-hash nil check | `internal/usecase/devices/transform_fuzz_test.go` | |
| 42 | +| `FuzzDomainTransforms` | `domains` | `dtoToEntity`, `entityToDTO` + RFC3339 expiration parsing, password encryption | `internal/usecase/domains/transform_fuzz_test.go` | |
| 43 | +| `FuzzIEEE8021xConfigTransforms` | `ieee8021xconfigs` | `dtoToEntity`, `entityToDTO` | `internal/usecase/ieee8021xconfigs/transform_fuzz_test.go` | |
| 44 | +| `FuzzProfileTransforms` | `profiles` | `dtoToEntity`, `entityToDTO` + tag join consistency | `internal/usecase/profiles/transform_fuzz_test.go` | |
| 45 | +| `FuzzProfileWiFiConfigTransforms` | `profilewificonfigs` | `dtoToEntity`, `entityToDTO` | `internal/usecase/profilewificonfigs/transform_fuzz_test.go` | |
| 46 | +| `FuzzWirelessConfigTransforms` | `wificonfigs` | `dtoToEntity`, `entityToDTO` + link-policy nil handling | `internal/usecase/wificonfigs/transform_fuzz_test.go` | |
| 47 | + |
| 48 | +**What is tested:** fuzzed field values (strings, ints, bools, timestamps, oversized/unicode/null-byte data) are passed through transform functions. Panics, non-deterministic results, and invariant violations (e.g. GUID not lowercased, nil pointer where expected) are caught. |
| 49 | + |
| 50 | +#### 3. Cryptographic Parsing (2 targets) |
| 51 | + |
| 52 | +| Target | Package | Function Under Test | File | |
| 53 | +|--------|---------|---------------------|------| |
| 54 | +| `FuzzParseCertificateFromPEM` | `certificates` | `ParseCertificateFromPEM` | `internal/certificates/generate_fuzz_test.go` | |
| 55 | +| `FuzzDecryptAndCheckCertExpiration` | `domains` | `DecryptAndCheckCertExpiration` | `internal/usecase/domains/usecase_fuzz_test.go` | |
| 56 | + |
| 57 | +**What is tested:** |
| 58 | +- `FuzzParseCertificateFromPEM`: valid, truncated, corrupted, swapped, and random PEM cert+key pairs. Asserts determinism, no data-alongside-error, no nil-without-error, and serial/key consistency. |
| 59 | +- `FuzzDecryptAndCheckCertExpiration`: valid, expired, corrupted, and random base64-encoded PKCS12 blobs with varied passwords. Asserts determinism, no expired-cert-without-error, and byte-level certificate consistency. |
| 60 | + |
| 61 | +#### 4. String Parsing (1 target) |
| 62 | + |
| 63 | +| Target | Package | Function Under Test | File | |
| 64 | +|--------|---------|---------------------|------| |
| 65 | +| `FuzzParseInterval` | `devices` | `ParseInterval` (ISO 8601 duration → minutes) | `internal/usecase/devices/alarms_fuzz_test.go` | |
| 66 | + |
| 67 | +**What is tested:** arbitrary strings (empty, malformed, oversized, unicode/control-character, and valid ISO 8601 durations) are parsed twice. Asserts determinism, no panics, and consistent error/result pairs across invocations. |
| 68 | + |
| 69 | +--- |
| 70 | + |
| 71 | +### Seed Corpus Strategy |
| 72 | + |
| 73 | +All targets use explicit `f.Add()` seeds covering: |
| 74 | +- **Happy path:** well-formed, realistic inputs. |
| 75 | +- **Empty/zero:** empty strings, zero ints, nil-equivalent bools. |
| 76 | +- **Unicode & control characters:** CJK, emoji, null bytes (`\x00`), newlines. |
| 77 | +- **Oversized inputs:** strings up to 4 KB, arrays with 4096 elements. |
| 78 | +- **Type confusion:** wrong JSON types (number where string expected, etc.). |
| 79 | +- **Boundary values:** `int` min/max, year-zero and year-9999 timestamps, port 65535. |
| 80 | +- **Crypto edge cases:** truncated PEM, corrupted base64, swapped cert/key, wrong passwords, expired certificates. |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +### Running Internal Fuzz Tests |
| 85 | + |
| 86 | +#### Prerequisites |
| 87 | + |
| 88 | +```sh |
| 89 | +cp .env.example .env # Makefile includes .env |
| 90 | +``` |
| 91 | + |
| 92 | +#### Make Targets |
| 93 | + |
| 94 | +```sh |
| 95 | +# List all 17 fuzz targets |
| 96 | +make fuzz-list |
| 97 | + |
| 98 | +# Run a single target (recommended for local dev) |
| 99 | +make fuzz-one PKG=./internal/usecase/devices TARGET=FuzzParseInterval FUZZTIME=30s |
| 100 | + |
| 101 | +# Quick smoke: run every target once (seed corpus only) |
| 102 | +make fuzz-smoke |
| 103 | + |
| 104 | +# Full run: every target sequentially with time budget |
| 105 | +make fuzz-all FUZZTIME=2m |
| 106 | +``` |
| 107 | + |
| 108 | +#### Direct go test (single target) |
| 109 | + |
| 110 | +```sh |
| 111 | +go test ./internal/usecase/devices -run='^$' -fuzz='^FuzzParseInterval$' -fuzztime=30s |
| 112 | +``` |
| 113 | + |
| 114 | +> **Note:** Go requires `-fuzz` to match exactly one fuzz function per package. Packages with multiple targets (e.g. `internal/entity/dto/v1` has 7) must be run one target at a time. The `make fuzz-all` target handles this automatically. |
| 115 | +
|
| 116 | +#### CI Usage |
| 117 | + |
| 118 | +| Trigger | Command | Purpose | |
| 119 | +|---------|---------|---------| |
| 120 | +| Pull request | `make fuzz-smoke` | Replay seed corpus, catch regressions | |
| 121 | +| Nightly/weekly schedule | `make fuzz-all FUZZTIME=2m` | Discover new crashes with mutation | |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +### File Index |
| 126 | + |
| 127 | +| File | Targets | Package | |
| 128 | +|------|---------|---------| |
| 129 | +| `internal/certificates/generate_fuzz_test.go` | 1 | `certificates` | |
| 130 | +| `internal/entity/dto/v1/json_fuzz_test.go` | 7 | `dto` | |
| 131 | +| `internal/usecase/ciraconfigs/transform_fuzz_test.go` | 1 | `ciraconfigs` | |
| 132 | +| `internal/usecase/devices/alarms_fuzz_test.go` | 1 | `devices` | |
| 133 | +| `internal/usecase/devices/transform_fuzz_test.go` | 1 | `devices` | |
| 134 | +| `internal/usecase/domains/transform_fuzz_test.go` | 1 | `domains` | |
| 135 | +| `internal/usecase/domains/usecase_fuzz_test.go` | 1 | `domains` | |
| 136 | +| `internal/usecase/ieee8021xconfigs/transform_fuzz_test.go` | 1 | `ieee8021xconfigs` | |
| 137 | +| `internal/usecase/profiles/transform_fuzz_test.go` | 1 | `profiles` | |
| 138 | +| `internal/usecase/profilewificonfigs/transform_fuzz_test.go` | 1 | `profilewificonfigs` | |
| 139 | +| `internal/usecase/wificonfigs/transform_fuzz_test.go` | 1 | `wificonfigs` | |
| 140 | +| **Total** | **17** | **10 packages** | |
| 141 | + |
| 142 | +--- |
| 143 | + |
| 144 | +## API Fuzzing |
| 145 | + |
| 146 | +*Planned — this section will document HTTP-level fuzz testing of Console's REST API endpoints.* |
0 commit comments