test fixes and new product advisories work

This commit is contained in:
master
2026-01-28 02:30:48 +02:00
parent 82caceba56
commit 644887997c
288 changed files with 69101 additions and 375 deletions

View File

@@ -0,0 +1,211 @@
# eBPF Reachability Test Fixtures
This directory contains frozen test fixtures for determinism validation of the eBPF evidence collection system.
## Directory Structure
```
fixtures/ebpf/
├── README.md # This file
├── proc/ # Mock /proc filesystem data
│ ├── {pid}-maps.txt # Memory map files
│ └── {pid}-cgroup.txt # Cgroup membership
├── elf/ # Mock ELF symbol data
│ └── *-symbols.json # Symbol tables in JSON format
├── events/ # Simulated eBPF events
│ └── *-events.json # Event sequences by type
└── golden/ # Expected NDJSON output
└── *-golden.ndjson # Canonical output for comparison
```
## Fixture Types
### /proc Filesystem Fixtures (`proc/`)
Mock `/proc/{pid}/maps` and `/proc/{pid}/cgroup` files for testing symbol resolution and container identification.
**Format for maps:**
```
start-end permissions offset device inode pathname
7f0000000000-7f0000001000 r--p 00000000 fd:01 12345678 /lib/libc.so.6
```
**Format for cgroup:**
```
0::/system.slice/containerd.service/container-id
```
### ELF Symbol Fixtures (`elf/`)
JSON representation of ELF symbol tables for testing address resolution.
**Schema:**
```json
{
"path": "/path/to/binary",
"format": "ELF64",
"symbols": [
{ "name": "symbol_name", "address": "0x1000", "size": 256, "type": "FUNC" }
],
"buildId": "hexstring"
}
```
### Event Fixtures (`events/`)
JSON arrays of simulated eBPF events with binary-compatible structures.
**Event Types:**
- `1` - File access (sys_enter_openat)
- `2` - Process exec (sched_process_exec)
- `3` - TCP state (inet_sock_set_state)
- `4` - Network op (uprobe connect/accept)
- `5` - SSL op (uprobe SSL_read/SSL_write)
- `6` - Symbol call (uprobe function)
### Golden Output Fixtures (`golden/`)
Canonical NDJSON files representing expected output when processing event fixtures with enrichment.
**Requirements:**
- Sorted JSON keys (alphabetical)
- No trailing whitespace
- Single newline per record
- No pretty-printing
## Determinism Testing
### Running Tests
```bash
# Run determinism tests
dotnet test --filter "Category=Determinism"
# Verify against golden files
dotnet test --filter "FullyQualifiedName~GoldenFileTests"
```
### Updating Golden Files
**IMPORTANT:** Only update golden files when schema changes are intentional.
1. Set environment variable to enable updates:
```bash
export STELLAOPS_UPDATE_FIXTURES=true
```
2. Run the test that generates output:
```bash
dotnet test --filter "FullyQualifiedName~GenerateGoldenOutput"
```
3. Review changes carefully:
```bash
git diff tests/reachability/fixtures/ebpf/golden/
```
4. Commit with explanation:
```bash
git add tests/reachability/fixtures/ebpf/golden/
git commit -m "Update golden files: <reason for change>"
```
### CI Integration
The CI workflow runs determinism tests automatically:
```yaml
# .gitea/workflows/test.yaml
- name: Determinism Tests
run: dotnet test --filter "Category=Determinism"
env:
STELLAOPS_UPDATE_FIXTURES: "false" # Never auto-update in CI
```
If tests fail:
1. Check if schema changes were intentional
2. If intentional, update golden files locally and commit
3. If unintentional, fix the determinism bug
## Adding New Fixtures
### Adding a New Event Type
1. Create input fixture in `events/`:
```json
// events/new-type-events.json
[
{
"event_type": 7,
"timestamp_ns": 1000000000000,
...
}
]
```
2. Generate golden output:
```bash
STELLAOPS_UPDATE_FIXTURES=true dotnet test --filter "GenerateNewTypeGolden"
```
3. Verify output is deterministic:
```bash
# Run multiple times, output should be identical
for i in {1..3}; do
dotnet test --filter "NewTypeGolden" 2>/dev/null
sha256sum golden/new-type-golden.ndjson
done
```
### Adding a New Process Fixture
1. Create mock `/proc` files:
```bash
# proc/{pid}-maps.txt
# proc/{pid}-cgroup.txt
```
2. Create corresponding ELF symbols if needed:
```bash
# elf/{binary}-symbols.json
```
3. Update container mapping in test setup
## Validation
Golden files must satisfy these constraints:
1. **Byte-identical output**: Same input always produces same output
2. **Sorted keys**: JSON keys in alphabetical order
3. **No floating point**: Use integers for all numeric values
4. **UTF-8 NFC**: All strings in NFC normalization form
5. **No null values**: Omit fields with null values
6. **Consistent timestamps**: Use nanoseconds since boot
Run validation:
```bash
# Validate golden file format
stella evidence validate tests/reachability/fixtures/ebpf/golden/*.ndjson
```
## Troubleshooting
### Test Fails: "Output differs from golden file"
1. Check for unintended schema changes
2. Verify timestamp handling is deterministic
3. Check for locale-dependent formatting
4. Ensure random values aren't leaking into output
### Test Fails: "Cannot load fixture"
1. Verify fixture file exists and is valid JSON
2. Check file permissions
3. Ensure no BOM in JSON files
### Test Fails: "Symbol resolution failed"
1. Verify mock maps file has correct format
2. Check address ranges don't overlap
3. Ensure symbol addresses are within mapped regions

View File

@@ -0,0 +1,16 @@
{
"path": "/usr/lib/x86_64-linux-gnu/libc.so.6",
"format": "ELF64",
"symbols": [
{ "name": "connect", "address": "0x120000", "size": 128, "type": "FUNC" },
{ "name": "accept", "address": "0x120080", "size": 96, "type": "FUNC" },
{ "name": "accept4", "address": "0x1200e0", "size": 112, "type": "FUNC" },
{ "name": "read", "address": "0x121000", "size": 64, "type": "FUNC" },
{ "name": "write", "address": "0x121040", "size": 64, "type": "FUNC" },
{ "name": "open", "address": "0x122000", "size": 96, "type": "FUNC" },
{ "name": "openat", "address": "0x122060", "size": 112, "type": "FUNC" },
{ "name": "close", "address": "0x1220d0", "size": 48, "type": "FUNC" }
],
"version": "2.35",
"buildId": "fedcba9876543210fedcba9876543210fedcba98"
}

View File

@@ -0,0 +1,14 @@
{
"path": "/usr/lib/x86_64-linux-gnu/libssl.so.3",
"format": "ELF64",
"symbols": [
{ "name": "SSL_read", "address": "0x15000", "size": 256, "type": "FUNC" },
{ "name": "SSL_write", "address": "0x15100", "size": 256, "type": "FUNC" },
{ "name": "SSL_connect", "address": "0x15200", "size": 384, "type": "FUNC" },
{ "name": "SSL_accept", "address": "0x15380", "size": 320, "type": "FUNC" },
{ "name": "SSL_get_fd", "address": "0x154c0", "size": 64, "type": "FUNC" },
{ "name": "SSL_get_peer_certificate", "address": "0x15500", "size": 128, "type": "FUNC" }
],
"version": "3.0.0",
"buildId": "112233445566778899aabbccddeeff0011223344"
}

View File

@@ -0,0 +1,19 @@
{
"path": "/app/bin/myapp",
"format": "ELF64",
"symbols": [
{ "name": "main", "address": "0x1000", "size": 256, "type": "FUNC" },
{ "name": "parse_json", "address": "0x1100", "size": 512, "type": "FUNC" },
{ "name": "vulnerable_parse_json", "address": "0x1300", "size": 384, "type": "FUNC" },
{ "name": "handle_request", "address": "0x1480", "size": 640, "type": "FUNC" },
{ "name": "process_config", "address": "0x1700", "size": 192, "type": "FUNC" },
{ "name": "connect_database", "address": "0x17c0", "size": 448, "type": "FUNC" },
{ "name": "send_response", "address": "0x1980", "size": 320, "type": "FUNC" }
],
"sections": {
".text": { "address": "0x1000", "size": "0x2000", "offset": "0x1000" },
".rodata": { "address": "0x3000", "size": "0x800", "offset": "0x3000" },
".data": { "address": "0x4000", "size": "0x200", "offset": "0x4000" }
},
"buildId": "abc123def456789012345678901234567890"
}

View File

@@ -0,0 +1,44 @@
[
{
"event_type": 1,
"timestamp_ns": 1000000000000,
"pid": 1234,
"tid": 1234,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"dfd": -100,
"flags": 0,
"mode": 0,
"filename": "/etc/myapp/config.yaml"
}
},
{
"event_type": 1,
"timestamp_ns": 1000100000000,
"pid": 1234,
"tid": 1235,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"dfd": -100,
"flags": 1,
"mode": 420,
"filename": "/var/log/myapp/access.log"
}
},
{
"event_type": 1,
"timestamp_ns": 1000200000000,
"pid": 5678,
"tid": 5678,
"cgroup_id": 9876543210,
"comm": "nginx",
"payload": {
"dfd": -100,
"flags": 0,
"mode": 0,
"filename": "/etc/nginx/nginx.conf"
}
}
]

View File

@@ -0,0 +1,26 @@
[
{
"event_type": 2,
"timestamp_ns": 900000000000,
"pid": 1234,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"ppid": 1,
"filename": "/app/bin/myapp",
"argv": ["myapp", "--config", "/etc/myapp/config.yaml"]
}
},
{
"event_type": 2,
"timestamp_ns": 850000000000,
"pid": 5678,
"cgroup_id": 9876543210,
"comm": "nginx",
"payload": {
"ppid": 1,
"filename": "/usr/bin/nginx",
"argv": ["nginx", "-g", "daemon off;"]
}
}
]

View File

@@ -0,0 +1,28 @@
[
{
"event_type": 5,
"timestamp_ns": 1000500000000,
"pid": 1234,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"operation": 1,
"requested_bytes": 1024,
"actual_bytes": 1024,
"ssl_ptr": 140234567890
}
},
{
"event_type": 5,
"timestamp_ns": 1000600000000,
"pid": 1234,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"operation": 0,
"requested_bytes": 4096,
"actual_bytes": 2048,
"ssl_ptr": 140234567890
}
}
]

View File

@@ -0,0 +1,34 @@
[
{
"event_type": 3,
"timestamp_ns": 1000300000000,
"pid": 1234,
"cgroup_id": 1234567890,
"comm": "myapp",
"payload": {
"family": 2,
"old_state": 2,
"new_state": 1,
"sport": 45678,
"dport": 5432,
"saddr_v4": "10.0.0.5",
"daddr_v4": "10.0.1.100"
}
},
{
"event_type": 3,
"timestamp_ns": 1000400000000,
"pid": 5678,
"cgroup_id": 9876543210,
"comm": "nginx",
"payload": {
"family": 2,
"old_state": 0,
"new_state": 1,
"sport": 80,
"dport": 54321,
"saddr_v4": "0.0.0.0",
"daddr_v4": "192.168.1.50"
}
}
]

View File

@@ -0,0 +1,3 @@
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"access":"read","flags":0,"mode":0,"path":"/etc/myapp/config.yaml","type":"file_access"},"pid":1234,"src":"tracepoint:syscalls:sys_enter_openat","tid":1234,"ts_ns":1000000000000}
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"access":"write","flags":1,"mode":420,"path":"/var/log/myapp/access.log","type":"file_access"},"pid":1234,"src":"tracepoint:syscalls:sys_enter_openat","tid":1235,"ts_ns":1000100000000}
{"cgroup_id":9876543210,"comm":"nginx","container_id":"fedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432","event":{"access":"read","flags":0,"mode":0,"path":"/etc/nginx/nginx.conf","type":"file_access"},"pid":5678,"src":"tracepoint:syscalls:sys_enter_openat","tid":5678,"ts_ns":1000200000000}

View File

@@ -0,0 +1,2 @@
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"argv":["myapp","--config","/etc/myapp/config.yaml"],"filename":"/app/bin/myapp","ppid":1,"type":"process_exec"},"pid":1234,"src":"tracepoint:sched:sched_process_exec","ts_ns":900000000000}
{"cgroup_id":9876543210,"comm":"nginx","container_id":"fedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432","event":{"argv":["nginx","-g","daemon off;"],"filename":"/usr/bin/nginx","ppid":1,"type":"process_exec"},"pid":5678,"src":"tracepoint:sched:sched_process_exec","ts_ns":850000000000}

View File

@@ -0,0 +1,2 @@
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"actual_bytes":1024,"operation":"write","requested_bytes":1024,"ssl_ptr":140234567890,"type":"ssl_op"},"pid":1234,"src":"uprobe:libssl.so.3:SSL_write","ts_ns":1000500000000}
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"actual_bytes":2048,"operation":"read","requested_bytes":4096,"ssl_ptr":140234567890,"type":"ssl_op"},"pid":1234,"src":"uprobe:libssl.so.3:SSL_read","ts_ns":1000600000000}

View File

@@ -0,0 +1,2 @@
{"cgroup_id":1234567890,"comm":"myapp","container_id":"abc123def456789012345678901234567890123456789012345678901234","event":{"dst_addr":"10.0.1.100","dst_port":5432,"family":"ipv4","new_state":"ESTABLISHED","old_state":"SYN_SENT","src_addr":"10.0.0.5","src_port":45678,"type":"tcp_state"},"pid":1234,"src":"tracepoint:sock:inet_sock_set_state","ts_ns":1000300000000}
{"cgroup_id":9876543210,"comm":"nginx","container_id":"fedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432","event":{"dst_addr":"192.168.1.50","dst_port":54321,"family":"ipv4","new_state":"ESTABLISHED","old_state":"CLOSED","src_addr":"0.0.0.0","src_port":80,"type":"tcp_state"},"pid":5678,"src":"tracepoint:sock:inet_sock_set_state","ts_ns":1000400000000}

View File

@@ -0,0 +1 @@
0::/system.slice/containerd.service/kubepods-besteffort-pod12345678.slice:cri-containerd:abc123def456789012345678901234567890123456789012345678901234

View File

@@ -0,0 +1,14 @@
7f0000000000-7f0000001000 r--p 00000000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f0000001000-7f0000180000 r-xp 00001000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f0000180000-7f00001d8000 r--p 00180000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f00001d8000-7f00001dc000 r--p 001d7000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f00001dc000-7f00001de000 rw-p 001db000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f0000200000-7f0000210000 r--p 00000000 fd:01 87654321 /usr/lib/x86_64-linux-gnu/libssl.so.3
7f0000210000-7f0000280000 r-xp 00010000 fd:01 87654321 /usr/lib/x86_64-linux-gnu/libssl.so.3
7f0000280000-7f00002a0000 r--p 00080000 fd:01 87654321 /usr/lib/x86_64-linux-gnu/libssl.so.3
7f0000400000-7f0000450000 r-xp 00000000 fd:01 11223344 /app/bin/myapp
7f0000450000-7f0000460000 r--p 00050000 fd:01 11223344 /app/bin/myapp
7f0000460000-7f0000461000 rw-p 00060000 fd:01 11223344 /app/bin/myapp
7ffff7ff0000-7ffff7ff4000 r--p 00000000 00:00 0 [vvar]
7ffff7ff4000-7ffff7ff6000 r-xp 00000000 00:00 0 [vdso]
7ffff7ff6000-7ffff7ff8000 rw-p 00000000 00:00 0 [stack]

View File

@@ -0,0 +1 @@
0::/docker/fedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432

View File

@@ -0,0 +1,4 @@
7f1000000000-7f1000001000 r--p 00000000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f1000001000-7f1000180000 r-xp 00001000 fd:01 12345678 /usr/lib/x86_64-linux-gnu/libc.so.6
7f1000200000-7f1000300000 r-xp 00000000 fd:01 99887766 /usr/bin/nginx
7f1000300000-7f1000310000 r--p 00100000 fd:01 99887766 /usr/bin/nginx