Skip to content

Commit 918cfa3

Browse files
chore: user-testing validation synthesis for nip46-fix-and-polish milestone
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 1f91f50 commit 918cfa3

3 files changed

Lines changed: 239 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
{
2+
"groupId": "nip46-interop",
3+
"testedAt": "2026-05-28T12:30:00.000Z",
4+
"isolation": {
5+
"workingDirectory": "/Users/plebdev/Desktop/Work/code/frostr/igloo/igloo-server",
6+
"testRunner": "bun",
7+
"testFile": "tests/routes/nip46.spec.ts",
8+
"testNamePattern": "nip44",
9+
"serverRequired": false
10+
},
11+
"toolsUsed": ["bun test"],
12+
"assertions": [
13+
{
14+
"id": "VAL-NIP46-001",
15+
"title": "nip44_encrypt produces ciphertext decryptable by a standards-compliant external peer",
16+
"status": "pass",
17+
"steps": [
18+
{
19+
"action": "Run bun test tests/routes/nip46.spec.ts --test-name-pattern 'nip44'",
20+
"expected": "Test 'nip44_encrypt produces ciphertext decryptable by a standards-compliant external peer' passes",
21+
"observed": "Test passed in 48.10ms"
22+
},
23+
{
24+
"action": "Verify ciphertext produced by Nip46Service.handleNip44Encrypt can be decrypted by nostr-tools nip44.decrypt using standards-compliant conversation key",
25+
"expected": "Decrypted plaintext matches 'hello from igloo nip46'",
26+
"observed": "Decrypted plaintext matches exactly"
27+
}
28+
],
29+
"evidence": {
30+
"testOutput": "(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_encrypt produces ciphertext decryptable by a standards-compliant external peer [48.10ms]"
31+
},
32+
"issues": null
33+
},
34+
{
35+
"id": "VAL-NIP46-002",
36+
"title": "nip44_decrypt accepts externally generated standards-compliant ciphertext",
37+
"status": "pass",
38+
"steps": [
39+
{
40+
"action": "Run bun test tests/routes/nip46.spec.ts --test-name-pattern 'nip44'",
41+
"expected": "Test 'nip44_decrypt accepts externally generated standards-compliant ciphertext' passes",
42+
"observed": "Test passed in 44.82ms"
43+
},
44+
{
45+
"action": "Encrypt plaintext using nostr-tools nip44.encrypt with standards-compliant conversation key, then decrypt via Nip46Service.handleNip44Decrypt",
46+
"expected": "Decrypted plaintext matches 'hello from external nip44 peer'",
47+
"observed": "Decrypted plaintext matches exactly"
48+
}
49+
],
50+
"evidence": {
51+
"testOutput": "(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_decrypt accepts externally generated standards-compliant ciphertext [44.82ms]"
52+
},
53+
"issues": null
54+
},
55+
{
56+
"id": "VAL-NIP46-003",
57+
"title": "nip44_decrypt rejects legacy raw-shared-secret / malformed / non-v2 ciphertext",
58+
"status": "pass",
59+
"steps": [
60+
{
61+
"action": "Run bun test tests/routes/nip46.spec.ts --test-name-pattern 'nip44'",
62+
"expected": "Three negative tests pass: legacy raw-shared-secret, malformed, and non-v2 ciphertext",
63+
"observed": "All three negative tests passed"
64+
},
65+
{
66+
"action": "Test 1: Pass legacy ciphertext encrypted with raw shared X (pre-fix non-standard behavior) to handleNip44Decrypt",
67+
"expected": "Returns null result and throws error (no fallback)",
68+
"observed": "result is null, error is a string describing the failure"
69+
},
70+
{
71+
"action": "Test 2: Pass malformed non-base64 ciphertext '!!!not-base64!!!' to handleNip44Decrypt",
72+
"expected": "Returns null result and throws error",
73+
"observed": "result is null, error is a string describing the failure"
74+
},
75+
{
76+
"action": "Test 3: Tamper valid ciphertext version byte from 2 to 1 and pass to handleNip44Decrypt",
77+
"expected": "Returns null result and throws error containing 'encryption version'",
78+
"observed": "result is null, error contains 'encryption version'"
79+
}
80+
],
81+
"evidence": {
82+
"testOutputs": [
83+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_decrypt rejects legacy raw-shared-secret ciphertext (no fallback) on an allowed session [43.63ms]",
84+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_decrypt rejects malformed ciphertext on an allowed session [40.98ms]",
85+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_decrypt rejects non-v2 payload on an allowed session [43.48ms]"
86+
]
87+
},
88+
"issues": null
89+
},
90+
{
91+
"id": "VAL-NIP46-004",
92+
"title": "nip44_encrypt and nip44_decrypt accept x-only and compressed 02/03 peer pubkeys, error on missing/empty params, and preserve request id",
93+
"status": "pass",
94+
"steps": [
95+
{
96+
"action": "Run bun test tests/routes/nip46.spec.ts --test-name-pattern 'nip44'",
97+
"expected": "Three sub-tests pass: pubkey formats, param validation, and request id preservation",
98+
"observed": "All three sub-tests passed"
99+
},
100+
{
101+
"action": "Test pubkey formats: Use x-only pubkey, compressed 02 prefix, and compressed 03 prefix for both encrypt and decrypt",
102+
"expected": "All three formats produce valid ciphertext and decrypt to expected plaintext",
103+
"observed": "All three formats work correctly; plaintexts match 'shape-' + prefix"
104+
},
105+
{
106+
"action": "Test param validation: Call encrypt/decrypt with no params, empty peer, and empty payload/ciphertext",
107+
"expected": "All six cases throw descriptive error messages",
108+
"observed": "All six cases threw errors with non-null messages"
109+
},
110+
{
111+
"action": "Test request id preservation: Execute nip44_encrypt (success) and nip44_decrypt with bad ciphertext (error) via handleSocketRequest",
112+
"expected": "Success response contains original request id 'happy-id-42' with result; error response contains original request id 'sad-id-99' with error",
113+
"observed": "Both response ids preserved correctly; happy has result, sad has error"
114+
}
115+
],
116+
"evidence": {
117+
"testOutputs": [
118+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_encrypt and nip44_decrypt accept x-only and compressed 02/03 peer pubkeys [44.01ms]",
119+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44_encrypt and nip44_decrypt error on missing/empty params with descriptive messages [42.11ms]",
120+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44 RPC responses preserve the original request id on success and on error [600.11ms]"
121+
]
122+
},
123+
"issues": null
124+
}
125+
],
126+
"frictions": [],
127+
"blockers": [],
128+
"summary": "Tested 4 assigned assertions covering 8 test cases (plus 4 additional related tests): all 12 tests passed, 0 failed. VAL-NIP46-001 and VAL-NIP46-002 confirm standards-compliant NIP-44 v2 interop in both directions. VAL-NIP46-003 confirms three rejection modes for invalid ciphertext. VAL-NIP46-004 confirms pubkey format flexibility, parameter validation, and RPC id preservation."
129+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"groupId": "nip46-policy-cross",
3+
"testedAt": "2026-05-28T12:25:00Z",
4+
"isolation": {
5+
"workingDirectory": "/Users/plebdev/Desktop/Work/code/frostr/igloo/igloo-server",
6+
"testRunner": "bun",
7+
"mode": "in-process integration tests (no server startup)"
8+
},
9+
"toolsUsed": ["bun test"],
10+
"assertions": [
11+
{
12+
"id": "VAL-NIP46-005",
13+
"title": "NIP-46 nip44 method-specific policy controls auto-approval vs pending",
14+
"status": "pass",
15+
"steps": [
16+
{
17+
"action": "Run bun test tests/routes/nip46.spec.ts --test-name-pattern 'method-specific policy'",
18+
"expected": "All 3 policy tests pass",
19+
"observed": "3 pass, 0 fail, 15 expect() calls"
20+
},
21+
{
22+
"action": "Verify sub-test: only nip44_encrypt granted auto-approves while nip44_decrypt stays pending",
23+
"expected": "encryptStatus='completed', encryptHasResult=true, decryptStatus='pending', sendsCount=1",
24+
"observed": "Test passed (621.40ms)"
25+
},
26+
{
27+
"action": "Verify sub-test: only nip44_decrypt granted auto-approves while nip44_encrypt stays pending",
28+
"expected": "decryptStatus='completed', decryptResult='peer-encrypted', encryptStatus='pending', sendsCount=1",
29+
"observed": "Test passed (608.53ms)"
30+
},
31+
{
32+
"action": "Verify sub-test: both granted means both auto-approve",
33+
"expected": "encryptStatus='completed', decryptStatus='completed', sendsCount=2, original request IDs preserved",
34+
"observed": "Test passed (602.42ms)"
35+
}
36+
],
37+
"evidence": {
38+
"testOutput": [
39+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44 method-specific policy: only nip44_encrypt granted auto-approves while nip44_decrypt stays pending [621.40ms]",
40+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44 method-specific policy: only nip44_decrypt granted auto-approves while nip44_encrypt stays pending [608.53ms]",
41+
"(pass) NIP-46 nip44 RPC standards-compliant interop > nip44 method-specific policy: both granted means both auto-approve [602.42ms]",
42+
"3 pass / 15 filtered out / 0 fail / 15 expect() calls"
43+
]
44+
},
45+
"issues": null
46+
},
47+
{
48+
"id": "VAL-CROSS-001",
49+
"title": "Cross-surface NIP-44 interop between HTTP /api/nip44/* and NIP-46 nip44_* methods",
50+
"status": "pass",
51+
"steps": [
52+
{
53+
"action": "Run bun test tests/routes/protected.api.spec.ts --test-name-pattern 'cross-surface nip44 interop'",
54+
"expected": "All 3 cross-surface interop tests pass",
55+
"observed": "3 pass, 0 fail, 10 expect() calls"
56+
},
57+
{
58+
"action": "Verify HTTP→NIP-46: HTTP /api/nip44/encrypt ciphertext decrypts via NIP-46 nip44_decrypt (x-only peer)",
59+
"expected": "HTTP encrypt produces valid ciphertext, NIP-46 decrypt returns original plaintext",
60+
"observed": "Test passed (67.31ms)"
61+
},
62+
{
63+
"action": "Verify NIP-46→HTTP: NIP-46 nip44_encrypt ciphertext decrypts via HTTP /api/nip44/decrypt (compressed peer)",
64+
"expected": "NIP-46 encrypt produces valid ciphertext, HTTP decrypt returns original plaintext",
65+
"observed": "Test passed (45.67ms)"
66+
},
67+
{
68+
"action": "Verify external peer: standards-compliant external peer ciphertext decrypts on both HTTP and NIP-46",
69+
"expected": "External ciphertext decrypts to 'external peer message' on both surfaces",
70+
"observed": "Test passed (45.80ms)"
71+
}
72+
],
73+
"evidence": {
74+
"testOutput": [
75+
"(pass) API key-protected route handlers > cross-surface nip44 interop: HTTP /api/nip44/encrypt ciphertext decrypts via NIP-46 nip44_decrypt (x-only peer) [67.31ms]",
76+
"(pass) API key-protected route handlers > cross-surface nip44 interop: NIP-46 nip44_encrypt ciphertext decrypts via HTTP /api/nip44/decrypt (compressed peer) [45.67ms]",
77+
"(pass) API key-protected route handlers > cross-surface nip44 interop: standards-compliant external peer ciphertext decrypts on both HTTP and NIP-46 [45.80ms]",
78+
"3 pass / 8 filtered out / 0 fail / 10 expect() calls"
79+
]
80+
},
81+
"issues": null
82+
}
83+
],
84+
"frictions": [],
85+
"blockers": [],
86+
"summary": "Tested 2 assertions (VAL-NIP46-005, VAL-CROSS-001): both passed. VAL-NIP46-005: 3/3 method-specific policy sub-tests passed (encrypt-only, decrypt-only, both). VAL-CROSS-001: 3/3 cross-surface NIP-44 interop sub-tests passed (HTTP→NIP-46 x-only, NIP-46→HTTP compressed, external peer on both)."
87+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"milestone": "nip46-fix-and-polish",
3+
"round": 1,
4+
"status": "pass",
5+
"assertionsSummary": {
6+
"total": 6,
7+
"passed": 6,
8+
"failed": 0,
9+
"blocked": 0
10+
},
11+
"passedAssertions": [
12+
"VAL-NIP46-001",
13+
"VAL-NIP46-002",
14+
"VAL-NIP46-003",
15+
"VAL-NIP46-004",
16+
"VAL-NIP46-005",
17+
"VAL-CROSS-001"
18+
],
19+
"failedAssertions": [],
20+
"blockedAssertions": [],
21+
"appliedUpdates": [],
22+
"previousRound": null
23+
}

0 commit comments

Comments
 (0)