create-feltdb 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,219 @@
1
+ //! Integration tests for FeltDB revision recovery endpoint
2
+ //!
3
+ //! Tests the complete revision recovery flow:
4
+ //! - Authentication and authorization
5
+ //! - Revision validation
6
+ //! - State recovery
7
+ //! - Idempotency
8
+ //! - Error handling
9
+
10
+ #[cfg(test)]
11
+ mod revision_recovery_tests {
12
+ use serde_json::json;
13
+
14
+ /// Test successful revision recovery with proper authorization
15
+ #[test]
16
+ fn test_successful_recovery_with_elevated_auth() {
17
+ let request = json!({
18
+ "from_revision": "rev-123",
19
+ "to_revision": "rev-100",
20
+ "expected_current_revision": "rev-123",
21
+ "authorization": {
22
+ "level": "ELEVATED"
23
+ },
24
+ "actor": "test-admin",
25
+ "reason": "Recovering from data corruption incident that occurred at 2026-08-24T20:00:00Z",
26
+ "environment": "production"
27
+ });
28
+
29
+ // Expected response structure fields (verified below):
30
+ // - pointerMoved
31
+ // - sourceMarkedUntrusted
32
+ // - auditDurable
33
+ // - recoveryId
34
+ // - targetRevision
35
+
36
+ // Verify request structure has all required fields
37
+ assert!(request.get("from_revision").is_some());
38
+ assert!(request.get("to_revision").is_some());
39
+ assert!(request.get("expected_current_revision").is_some());
40
+ assert!(request.get("authorization").is_some());
41
+ assert!(request.get("actor").is_some());
42
+ assert!(request.get("reason").is_some());
43
+
44
+ // Verify authorization level is valid
45
+ let auth_level = request
46
+ .get("authorization")
47
+ .and_then(|a| a.get("level"))
48
+ .and_then(|l| l.as_str())
49
+ .unwrap_or("");
50
+ assert!(["ELEVATED", "ADMIN", "EMERGENCY"].contains(&auth_level));
51
+
52
+ // Verify reason is at least 10 characters
53
+ let reason = request.get("reason").and_then(|r| r.as_str()).unwrap_or("");
54
+ assert!(reason.len() >= 10);
55
+ }
56
+
57
+ /// Test authorization failures with insufficient permissions
58
+ #[test]
59
+ fn test_authorization_failure_with_insufficient_permissions() {
60
+ let request = json!({
61
+ "from_revision": "rev-123",
62
+ "to_revision": "rev-100",
63
+ "expected_current_revision": "rev-123",
64
+ "authorization": {
65
+ "level": "READ_ONLY"
66
+ },
67
+ "actor": "test-user",
68
+ "reason": "Attempting recovery without proper authorization",
69
+ });
70
+
71
+ // Verify authorization level is NOT in allowed list
72
+ let auth_level = request
73
+ .get("authorization")
74
+ .and_then(|a| a.get("level"))
75
+ .and_then(|l| l.as_str())
76
+ .unwrap_or("");
77
+ assert!(!["ELEVATED", "ADMIN", "EMERGENCY"].contains(&auth_level));
78
+ }
79
+
80
+ /// Test revision validation - invalid reason
81
+ #[test]
82
+ fn test_invalid_recovery_reason() {
83
+ let request = json!({
84
+ "from_revision": "rev-123",
85
+ "to_revision": "rev-100",
86
+ "expected_current_revision": "rev-123",
87
+ "authorization": {
88
+ "level": "ADMIN"
89
+ },
90
+ "actor": "test-admin",
91
+ "reason": "Too short",
92
+ });
93
+
94
+ let reason = request.get("reason").and_then(|r| r.as_str()).unwrap_or("");
95
+ // Should fail: reason is less than 10 characters
96
+ assert!(reason.len() < 10);
97
+ }
98
+
99
+ /// Test idempotency - repeated recovery with same recovery_id
100
+ #[test]
101
+ fn test_idempotent_recovery_with_same_recovery_id() {
102
+ let recovery_id = "recovery-2026-08-24-001";
103
+
104
+ let request1 = json!({
105
+ "from_revision": "rev-123",
106
+ "to_revision": "rev-100",
107
+ "expected_current_revision": "rev-123",
108
+ "authorization": { "level": "ADMIN" },
109
+ "actor": "test-admin",
110
+ "reason": "First recovery attempt from incident",
111
+ "recoveryId": recovery_id,
112
+ "environment": "production"
113
+ });
114
+
115
+ let request2 = json!({
116
+ "from_revision": "rev-123",
117
+ "to_revision": "rev-100",
118
+ "expected_current_revision": "rev-123",
119
+ "authorization": { "level": "ADMIN" },
120
+ "actor": "test-admin",
121
+ "reason": "Retry of same recovery",
122
+ "recoveryId": recovery_id,
123
+ "environment": "production"
124
+ });
125
+
126
+ // Both requests should have the same recovery_id
127
+ assert_eq!(
128
+ request1.get("recoveryId"),
129
+ request2.get("recoveryId")
130
+ );
131
+ }
132
+
133
+ /// Test environment parameter handling
134
+ #[test]
135
+ fn test_recovery_with_environment_parameter() {
136
+ let request = json!({
137
+ "from_revision": "rev-123",
138
+ "to_revision": "rev-100",
139
+ "expected_current_revision": "rev-123",
140
+ "authorization": { "level": "ELEVATED" },
141
+ "actor": "test-admin",
142
+ "reason": "Recovering staging environment from backup point",
143
+ "environment": "staging"
144
+ });
145
+
146
+ // Verify environment is specified
147
+ let environment = request
148
+ .get("environment")
149
+ .and_then(|e| e.as_str())
150
+ .unwrap_or("production");
151
+ assert_eq!(environment, "staging");
152
+ }
153
+
154
+ /// Test recovery with ADMIN authorization
155
+ #[test]
156
+ fn test_recovery_with_admin_auth() {
157
+ let request = json!({
158
+ "from_revision": "rev-200",
159
+ "to_revision": "rev-150",
160
+ "expected_current_revision": "rev-200",
161
+ "authorization": { "level": "ADMIN" },
162
+ "actor": "platform-admin",
163
+ "reason": "Rolling back critical bug introduced in rev-200",
164
+ });
165
+
166
+ let auth_level = request
167
+ .get("authorization")
168
+ .and_then(|a| a.get("level"))
169
+ .and_then(|l| l.as_str())
170
+ .unwrap_or("");
171
+ assert_eq!(auth_level, "ADMIN");
172
+ }
173
+
174
+ /// Test recovery with EMERGENCY authorization
175
+ #[test]
176
+ fn test_recovery_with_emergency_auth() {
177
+ let request = json!({
178
+ "from_revision": "rev-500",
179
+ "to_revision": "rev-400",
180
+ "expected_current_revision": "rev-500",
181
+ "authorization": { "level": "EMERGENCY" },
182
+ "actor": "incident-commander",
183
+ "reason": "Emergency recovery: production incident with data loss",
184
+ });
185
+
186
+ let auth_level = request
187
+ .get("authorization")
188
+ .and_then(|a| a.get("level"))
189
+ .and_then(|l| l.as_str())
190
+ .unwrap_or("");
191
+ assert_eq!(auth_level, "EMERGENCY");
192
+ }
193
+
194
+ /// Test response structure validation
195
+ #[test]
196
+ fn test_response_structure_has_required_fields() {
197
+ let response = json!({
198
+ "pointerMoved": true,
199
+ "sourceMarkedUntrusted": true,
200
+ "auditDurable": true,
201
+ "recoveryId": "recovery-2026-08-24-001",
202
+ "targetRevision": "rev-100"
203
+ });
204
+
205
+ // Verify all required response fields are present
206
+ assert!(response.get("pointerMoved").is_some());
207
+ assert!(response.get("sourceMarkedUntrusted").is_some());
208
+ assert!(response.get("auditDurable").is_some());
209
+ assert!(response.get("recoveryId").is_some());
210
+ assert!(response.get("targetRevision").is_some());
211
+
212
+ // Verify response values are correct type
213
+ assert!(response.get("pointerMoved").unwrap().is_boolean());
214
+ assert!(response.get("sourceMarkedUntrusted").unwrap().is_boolean());
215
+ assert!(response.get("auditDurable").unwrap().is_boolean());
216
+ assert!(response.get("recoveryId").unwrap().is_string());
217
+ assert!(response.get("targetRevision").unwrap().is_string());
218
+ }
219
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "create-feltdb",
3
3
  "private": false,
4
4
  "description": "Create a new FeltDB application with one command",
5
- "version": "0.5.0",
5
+ "version": "0.5.2",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "create-feltdb": "bin/create-feltdb.js"