@celilo/cli 0.1.0

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.
Files changed (267) hide show
  1. package/README.md +1566 -0
  2. package/bin/celilo +16 -0
  3. package/drizzle/0000_complex_puma.sql +179 -0
  4. package/drizzle/0001_dizzy_wolfpack.sql +2 -0
  5. package/drizzle/0002_web_routes.sql +16 -0
  6. package/drizzle/0003_backup_storage.sql +32 -0
  7. package/drizzle/meta/0000_snapshot.json +1151 -0
  8. package/drizzle/meta/0001_snapshot.json +1167 -0
  9. package/drizzle/meta/0002_snapshot.json +1257 -0
  10. package/drizzle/meta/_journal.json +27 -0
  11. package/package.json +64 -0
  12. package/schemas/system_config.json +106 -0
  13. package/src/__integration__/container-services-cli.integration.test.ts +246 -0
  14. package/src/ansible/dependencies.test.ts +309 -0
  15. package/src/ansible/dependencies.ts +896 -0
  16. package/src/ansible/inventory.test.ts +463 -0
  17. package/src/ansible/inventory.ts +445 -0
  18. package/src/ansible/secrets.ts +222 -0
  19. package/src/ansible/validation.test.ts +92 -0
  20. package/src/ansible/validation.ts +272 -0
  21. package/src/api-clients/digitalocean.ts +94 -0
  22. package/src/api-clients/proxmox.ts +655 -0
  23. package/src/capabilities/logging-wrapper.test.ts +217 -0
  24. package/src/capabilities/lookup.test.ts +149 -0
  25. package/src/capabilities/lookup.ts +89 -0
  26. package/src/capabilities/public-web-helpers.test.ts +198 -0
  27. package/src/capabilities/public-web-publish.test.ts +458 -0
  28. package/src/capabilities/registration.test.ts +395 -0
  29. package/src/capabilities/registration.ts +200 -0
  30. package/src/capabilities/route-validation.test.ts +121 -0
  31. package/src/capabilities/route-validation.ts +96 -0
  32. package/src/capabilities/secret-ref.test.ts +313 -0
  33. package/src/capabilities/secret-validation.ts +157 -0
  34. package/src/capabilities/secrets.test.ts +750 -0
  35. package/src/capabilities/secrets.ts +244 -0
  36. package/src/capabilities/validation.test.ts +613 -0
  37. package/src/capabilities/validation.ts +160 -0
  38. package/src/capabilities/well-known.test.ts +238 -0
  39. package/src/capabilities/well-known.ts +222 -0
  40. package/src/cli/cli.test.ts +654 -0
  41. package/src/cli/command-registry.ts +742 -0
  42. package/src/cli/command-tree-parser.test.ts +180 -0
  43. package/src/cli/command-tree-parser.ts +193 -0
  44. package/src/cli/commands/backup-create.ts +137 -0
  45. package/src/cli/commands/backup-delete.ts +74 -0
  46. package/src/cli/commands/backup-import.ts +97 -0
  47. package/src/cli/commands/backup-list.ts +132 -0
  48. package/src/cli/commands/backup-name.ts +73 -0
  49. package/src/cli/commands/backup-prune.ts +98 -0
  50. package/src/cli/commands/backup-restore.ts +122 -0
  51. package/src/cli/commands/capability-info.ts +121 -0
  52. package/src/cli/commands/capability-list.ts +47 -0
  53. package/src/cli/commands/completion.ts +87 -0
  54. package/src/cli/commands/hook-run.ts +176 -0
  55. package/src/cli/commands/ipam.ts +607 -0
  56. package/src/cli/commands/machine-add.ts +235 -0
  57. package/src/cli/commands/machine-earmark.ts +82 -0
  58. package/src/cli/commands/machine-list.ts +77 -0
  59. package/src/cli/commands/machine-remove.ts +90 -0
  60. package/src/cli/commands/machine-status.ts +131 -0
  61. package/src/cli/commands/module-audit.ts +51 -0
  62. package/src/cli/commands/module-build.ts +60 -0
  63. package/src/cli/commands/module-config.ts +170 -0
  64. package/src/cli/commands/module-deploy.ts +71 -0
  65. package/src/cli/commands/module-generate.ts +236 -0
  66. package/src/cli/commands/module-health.ts +108 -0
  67. package/src/cli/commands/module-import.ts +80 -0
  68. package/src/cli/commands/module-list.ts +43 -0
  69. package/src/cli/commands/module-logs.ts +73 -0
  70. package/src/cli/commands/module-remove.ts +162 -0
  71. package/src/cli/commands/module-show.ts +208 -0
  72. package/src/cli/commands/module-status.ts +131 -0
  73. package/src/cli/commands/module-types.ts +189 -0
  74. package/src/cli/commands/module-upgrade.ts +192 -0
  75. package/src/cli/commands/package.ts +68 -0
  76. package/src/cli/commands/secret-list.ts +99 -0
  77. package/src/cli/commands/secret-set.ts +134 -0
  78. package/src/cli/commands/service-add-digitalocean.ts +133 -0
  79. package/src/cli/commands/service-add-proxmox.ts +342 -0
  80. package/src/cli/commands/service-config-get.ts +83 -0
  81. package/src/cli/commands/service-config-set.ts +145 -0
  82. package/src/cli/commands/service-list.ts +74 -0
  83. package/src/cli/commands/service-reconfigure.ts +230 -0
  84. package/src/cli/commands/service-remove.ts +103 -0
  85. package/src/cli/commands/service-verify.ts +240 -0
  86. package/src/cli/commands/status.ts +216 -0
  87. package/src/cli/commands/storage-add-local.ts +106 -0
  88. package/src/cli/commands/storage-add-s3.ts +114 -0
  89. package/src/cli/commands/storage-list.ts +72 -0
  90. package/src/cli/commands/storage-remove.ts +54 -0
  91. package/src/cli/commands/storage-set-default.ts +44 -0
  92. package/src/cli/commands/storage-verify.ts +54 -0
  93. package/src/cli/commands/system-config.ts +168 -0
  94. package/src/cli/commands/system-init.ts +314 -0
  95. package/src/cli/commands/system-secret-get.ts +98 -0
  96. package/src/cli/commands/system-secret-set.ts +76 -0
  97. package/src/cli/commands/system-vault-password.ts +34 -0
  98. package/src/cli/completion.test.ts +37 -0
  99. package/src/cli/completion.ts +482 -0
  100. package/src/cli/fuel-gauge.test.ts +208 -0
  101. package/src/cli/fuel-gauge.ts +405 -0
  102. package/src/cli/generate-zsh-completion.test.ts +95 -0
  103. package/src/cli/generate-zsh-completion.ts +497 -0
  104. package/src/cli/index.ts +1583 -0
  105. package/src/cli/interactive-config.test.ts +201 -0
  106. package/src/cli/interactive-config.ts +62 -0
  107. package/src/cli/parser.test.ts +227 -0
  108. package/src/cli/parser.ts +244 -0
  109. package/src/cli/prompts.test.ts +33 -0
  110. package/src/cli/prompts.ts +121 -0
  111. package/src/cli/types.ts +38 -0
  112. package/src/cli/validators.test.ts +235 -0
  113. package/src/cli/validators.ts +188 -0
  114. package/src/config/env.ts +41 -0
  115. package/src/config/paths.test.ts +172 -0
  116. package/src/config/paths.ts +108 -0
  117. package/src/db/client.ts +190 -0
  118. package/src/db/migrate.ts +30 -0
  119. package/src/db/schema.test.ts +221 -0
  120. package/src/db/schema.ts +434 -0
  121. package/src/hooks/capability-loader-firewall.test.ts +246 -0
  122. package/src/hooks/capability-loader.test.ts +100 -0
  123. package/src/hooks/capability-loader.ts +520 -0
  124. package/src/hooks/define-hook.test.ts +488 -0
  125. package/src/hooks/executor.test.ts +462 -0
  126. package/src/hooks/executor.ts +469 -0
  127. package/src/hooks/logger.test.ts +54 -0
  128. package/src/hooks/logger.ts +95 -0
  129. package/src/hooks/test-fixtures/failing-hook.ts +13 -0
  130. package/src/hooks/test-fixtures/no-default-hook.ts +6 -0
  131. package/src/hooks/test-fixtures/success-hook.ts +20 -0
  132. package/src/hooks/test-fixtures/unbranded-hook.ts +11 -0
  133. package/src/hooks/test-fixtures/void-hook.ts +13 -0
  134. package/src/hooks/types.ts +89 -0
  135. package/src/infrastructure/property-extractor.test.ts +194 -0
  136. package/src/infrastructure/property-extractor.ts +151 -0
  137. package/src/ipam/allocator.test.ts +442 -0
  138. package/src/ipam/allocator.ts +369 -0
  139. package/src/ipam/auto-allocator.test.ts +247 -0
  140. package/src/ipam/auto-allocator.ts +270 -0
  141. package/src/ipam/subnet-parser.test.ts +107 -0
  142. package/src/ipam/subnet-parser.ts +136 -0
  143. package/src/manifest/contracts/index.ts +61 -0
  144. package/src/manifest/contracts/v1.ts +118 -0
  145. package/src/manifest/json-schema-roundtrip.test.ts +99 -0
  146. package/src/manifest/schema.ts +367 -0
  147. package/src/manifest/template-validator.test.ts +231 -0
  148. package/src/manifest/template-validator.ts +322 -0
  149. package/src/manifest/validate.test.ts +1180 -0
  150. package/src/manifest/validate.ts +415 -0
  151. package/src/module/import.test.ts +355 -0
  152. package/src/module/import.ts +676 -0
  153. package/src/module/packaging/audit.ts +169 -0
  154. package/src/module/packaging/build.ts +228 -0
  155. package/src/module/packaging/checksum.ts +41 -0
  156. package/src/module/packaging/extract.ts +234 -0
  157. package/src/module/packaging/signature.ts +47 -0
  158. package/src/secrets/encryption.test.ts +284 -0
  159. package/src/secrets/encryption.ts +162 -0
  160. package/src/secrets/generators.test.ts +112 -0
  161. package/src/secrets/generators.ts +127 -0
  162. package/src/secrets/master-key.test.ts +159 -0
  163. package/src/secrets/master-key.ts +114 -0
  164. package/src/secrets/storage.test.ts +115 -0
  165. package/src/secrets/storage.ts +106 -0
  166. package/src/secrets/vault.test.ts +35 -0
  167. package/src/secrets/vault.ts +42 -0
  168. package/src/services/backup-create.ts +532 -0
  169. package/src/services/backup-metadata.ts +198 -0
  170. package/src/services/backup-restore.ts +229 -0
  171. package/src/services/backup-retention.ts +84 -0
  172. package/src/services/backup-storage.ts +281 -0
  173. package/src/services/build-stream.test.ts +122 -0
  174. package/src/services/build-stream.ts +201 -0
  175. package/src/services/config-interview.ts +694 -0
  176. package/src/services/container-service.test.ts +298 -0
  177. package/src/services/container-service.ts +401 -0
  178. package/src/services/cross-module-data-manager.test.ts +405 -0
  179. package/src/services/cross-module-data-manager.ts +412 -0
  180. package/src/services/deploy-ansible.ts +88 -0
  181. package/src/services/deploy-planner.ts +153 -0
  182. package/src/services/deploy-preflight.ts +274 -0
  183. package/src/services/deploy-ssh.ts +131 -0
  184. package/src/services/deploy-terraform.test.ts +55 -0
  185. package/src/services/deploy-terraform.ts +445 -0
  186. package/src/services/deploy-validation.ts +311 -0
  187. package/src/services/dns-auto-register.ts +211 -0
  188. package/src/services/health-runner.ts +184 -0
  189. package/src/services/infrastructure-selector.test.ts +485 -0
  190. package/src/services/infrastructure-selector.ts +245 -0
  191. package/src/services/infrastructure-variable-resolver.test.ts +751 -0
  192. package/src/services/infrastructure-variable-resolver.ts +234 -0
  193. package/src/services/machine-detector.ts +328 -0
  194. package/src/services/machine-pool.test.ts +405 -0
  195. package/src/services/machine-pool.ts +316 -0
  196. package/src/services/manifest-validation.ts +120 -0
  197. package/src/services/module-build.test.ts +290 -0
  198. package/src/services/module-build.ts +431 -0
  199. package/src/services/module-config.test.ts +237 -0
  200. package/src/services/module-config.ts +298 -0
  201. package/src/services/module-deploy.ts +862 -0
  202. package/src/services/module-types-drift.test.ts +73 -0
  203. package/src/services/module-types-generator.test.ts +288 -0
  204. package/src/services/module-types-generator.ts +189 -0
  205. package/src/services/proxmox-state-recovery.ts +140 -0
  206. package/src/services/schema-validation.ts +155 -0
  207. package/src/services/secret-schema-loader.test.ts +311 -0
  208. package/src/services/secret-schema-loader.ts +239 -0
  209. package/src/services/ssh-key-manager.test.ts +283 -0
  210. package/src/services/ssh-key-manager.ts +193 -0
  211. package/src/services/storage-providers/local.ts +105 -0
  212. package/src/services/storage-providers/s3.ts +182 -0
  213. package/src/services/storage-providers/types.ts +24 -0
  214. package/src/services/system-config-schema-types.ts +25 -0
  215. package/src/services/system-config-validator.test.ts +160 -0
  216. package/src/services/system-config-validator.ts +74 -0
  217. package/src/services/system-init.test.ts +153 -0
  218. package/src/services/system-init.ts +253 -0
  219. package/src/services/terraform-safety.ts +174 -0
  220. package/src/services/zone-detector.test.ts +110 -0
  221. package/src/services/zone-detector.ts +102 -0
  222. package/src/services/zone-policy.test.ts +97 -0
  223. package/src/services/zone-policy.ts +126 -0
  224. package/src/templates/generator.test.ts +645 -0
  225. package/src/templates/generator.ts +1119 -0
  226. package/src/templates/types.ts +62 -0
  227. package/src/test-utils/INTERACTIVE_PROMPTS.md +167 -0
  228. package/src/test-utils/cli-context-interactive.test.ts +152 -0
  229. package/src/test-utils/cli-context-server.test.ts +66 -0
  230. package/src/test-utils/cli-context.test.ts +273 -0
  231. package/src/test-utils/cli-context.ts +677 -0
  232. package/src/test-utils/cli-result.test.ts +282 -0
  233. package/src/test-utils/cli-result.ts +241 -0
  234. package/src/test-utils/cli.ts +55 -0
  235. package/src/test-utils/completion-harness.test.ts +126 -0
  236. package/src/test-utils/completion-harness.ts +82 -0
  237. package/src/test-utils/database.test.ts +182 -0
  238. package/src/test-utils/database.ts +126 -0
  239. package/src/test-utils/filesystem.test.ts +208 -0
  240. package/src/test-utils/filesystem.ts +142 -0
  241. package/src/test-utils/fixtures.test.ts +123 -0
  242. package/src/test-utils/fixtures.ts +160 -0
  243. package/src/test-utils/golden-diff.ts +197 -0
  244. package/src/test-utils/index.ts +77 -0
  245. package/src/test-utils/integration.ts +81 -0
  246. package/src/test-utils/module-fixtures.ts +468 -0
  247. package/src/test-utils/modules.test.ts +144 -0
  248. package/src/test-utils/modules.ts +183 -0
  249. package/src/test-utils/setup-test-db.ts +90 -0
  250. package/src/test-utils/value-extractor.test.ts +231 -0
  251. package/src/test-utils/value-extractor.ts +228 -0
  252. package/src/types/infrastructure.ts +157 -0
  253. package/src/utils/shell.test.ts +365 -0
  254. package/src/utils/shell.ts +159 -0
  255. package/src/validation/schemas.ts +166 -0
  256. package/src/variables/ansible-resolver.test.ts +142 -0
  257. package/src/variables/ansible-resolver.ts +69 -0
  258. package/src/variables/capability-self-ref.test.ts +220 -0
  259. package/src/variables/context.test.ts +1265 -0
  260. package/src/variables/context.ts +624 -0
  261. package/src/variables/declarative-derivation.test.ts +743 -0
  262. package/src/variables/declarative-derivation.ts +200 -0
  263. package/src/variables/parser.test.ts +231 -0
  264. package/src/variables/parser.ts +76 -0
  265. package/src/variables/resolver.test.ts +458 -0
  266. package/src/variables/resolver.ts +282 -0
  267. package/src/variables/types.ts +59 -0
@@ -0,0 +1,405 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
2
+ import { existsSync } from 'node:fs';
3
+ import { unlink } from 'node:fs/promises';
4
+ import { type DbClient, createDbClient } from '../db/client';
5
+ import { capabilities, moduleConfigs, modules, secrets, systemConfig } from '../db/schema';
6
+ import type { NewModule } from '../db/schema';
7
+ import { CrossModuleDataManager } from './cross-module-data-manager';
8
+
9
+ describe('CrossModuleDataManager', () => {
10
+ let db: DbClient;
11
+ let manager: CrossModuleDataManager;
12
+ let testDbPath: string;
13
+
14
+ beforeEach(async () => {
15
+ testDbPath = `./test-cross-module-${Date.now()}-${Math.random()}.db`;
16
+ db = createDbClient({ path: testDbPath });
17
+
18
+ // Tables are automatically created by auto-migration in createDbClient()
19
+
20
+ // Insert test module
21
+ const testModule: NewModule = {
22
+ id: 'test-module',
23
+ name: 'Test Module',
24
+ version: '1.0.0',
25
+ sourcePath: '/test',
26
+ manifestData: {},
27
+ };
28
+ db.insert(modules).values(testModule).run();
29
+
30
+ // Insert system config
31
+ db.insert(systemConfig)
32
+ .values({
33
+ key: 'dns.primary',
34
+ value: '1.1.1.1',
35
+ })
36
+ .run();
37
+
38
+ // Create and initialize manager
39
+ manager = new CrossModuleDataManager(db);
40
+ await manager.initialize();
41
+ });
42
+
43
+ afterEach(async () => {
44
+ db.$client.close();
45
+ if (existsSync(testDbPath)) {
46
+ await unlink(testDbPath);
47
+ }
48
+ const walPath = `${testDbPath}-wal`;
49
+ const shmPath = `${testDbPath}-shm`;
50
+ if (existsSync(walPath)) {
51
+ await unlink(walPath);
52
+ }
53
+ if (existsSync(shmPath)) {
54
+ await unlink(shmPath);
55
+ }
56
+ });
57
+
58
+ describe('Configuration Storage', () => {
59
+ test('should store and retrieve string config', async () => {
60
+ await manager.storeConfigData('test-module', 'hostname', 'example.com', false);
61
+
62
+ const value = manager.getConfigData('test-module', 'hostname');
63
+ expect(value).toBe('example.com');
64
+ });
65
+
66
+ test('should store and retrieve number config', async () => {
67
+ await manager.storeConfigData('test-module', 'port', 8080, false);
68
+
69
+ const value = manager.getConfigData('test-module', 'port');
70
+ expect(value).toBe(8080);
71
+ });
72
+
73
+ test('should store and retrieve boolean config', async () => {
74
+ await manager.storeConfigData('test-module', 'enabled', true, false);
75
+
76
+ const value = manager.getConfigData('test-module', 'enabled');
77
+ expect(value).toBe(true);
78
+ });
79
+
80
+ test('should store and retrieve array config', async () => {
81
+ const arrayValue = ['item1', 'item2', 'item3'];
82
+ await manager.storeConfigData('test-module', 'items', arrayValue, false);
83
+
84
+ const value = manager.getConfigData('test-module', 'items');
85
+ expect(value).toEqual(arrayValue);
86
+ });
87
+
88
+ test('should store and retrieve object config', async () => {
89
+ const objectValue = { host: 'localhost', port: 5432, database: 'test' };
90
+ await manager.storeConfigData('test-module', 'db_config', objectValue, false);
91
+
92
+ const value = manager.getConfigData('test-module', 'db_config');
93
+ expect(value).toEqual(objectValue);
94
+ });
95
+
96
+ test('should update existing config', async () => {
97
+ await manager.storeConfigData('test-module', 'hostname', 'old.example.com', false);
98
+ await manager.storeConfigData('test-module', 'hostname', 'new.example.com', false);
99
+
100
+ const value = manager.getConfigData('test-module', 'hostname');
101
+ expect(value).toBe('new.example.com');
102
+
103
+ // Should only have one record
104
+ const allConfigs = db.select().from(moduleConfigs).all();
105
+ expect(allConfigs).toHaveLength(1);
106
+ });
107
+
108
+ test('should return null for non-existent config', () => {
109
+ const value = manager.getConfigData('test-module', 'nonexistent');
110
+ expect(value).toBeNull();
111
+ });
112
+ });
113
+
114
+ describe('Secret Storage', () => {
115
+ test('should store and retrieve secret', async () => {
116
+ const secretValue = 'super-secret-password';
117
+ await manager.storeSecret('test-module', 'db_password', secretValue);
118
+
119
+ const retrieved = manager.getSecret('test-module', 'db_password');
120
+ expect(retrieved).toBe(secretValue);
121
+ });
122
+
123
+ test('should encrypt secrets in database', async () => {
124
+ const secretValue = 'my-secret';
125
+ await manager.storeSecret('test-module', 'api_key', secretValue);
126
+
127
+ // Read directly from database
128
+ const secret = db.select().from(secrets).get();
129
+ expect(secret).toBeDefined();
130
+
131
+ // Encrypted value should not equal plaintext
132
+ expect(secret?.encryptedValue).not.toBe(secretValue);
133
+
134
+ // Should have IV and auth tag
135
+ expect(secret?.iv).toBeDefined();
136
+ expect(secret?.authTag).toBeDefined();
137
+ });
138
+
139
+ test('should update existing secret', async () => {
140
+ await manager.storeSecret('test-module', 'password', 'old-password');
141
+ await manager.storeSecret('test-module', 'password', 'new-password');
142
+
143
+ const retrieved = manager.getSecret('test-module', 'password');
144
+ expect(retrieved).toBe('new-password');
145
+
146
+ // Should only have one record
147
+ const allSecrets = db.select().from(secrets).all();
148
+ expect(allSecrets).toHaveLength(1);
149
+ });
150
+
151
+ test('should return null for non-existent secret', () => {
152
+ const value = manager.getSecret('test-module', 'nonexistent');
153
+ expect(value).toBeNull();
154
+ });
155
+
156
+ test('should get all secrets for a module', async () => {
157
+ await manager.storeSecret('test-module', 'password', 'pass123');
158
+ await manager.storeSecret('test-module', 'api_key', 'key456');
159
+ await manager.storeSecret('test-module', 'token', 'token789');
160
+
161
+ const allSecrets = manager.getAllSecrets('test-module');
162
+
163
+ expect(allSecrets).toEqual({
164
+ password: 'pass123',
165
+ api_key: 'key456',
166
+ token: 'token789',
167
+ });
168
+ });
169
+
170
+ test('should store secret via storeConfigData with isSecret=true', async () => {
171
+ await manager.storeConfigData('test-module', 'secret_key', 'my-secret', true);
172
+
173
+ const retrieved = manager.getSecret('test-module', 'secret_key');
174
+ expect(retrieved).toBe('my-secret');
175
+ });
176
+ });
177
+
178
+ describe('Capability Lookup', () => {
179
+ test('should find capability provider', () => {
180
+ // Insert dns-external module
181
+ db.insert(modules)
182
+ .values({
183
+ id: 'dns-external',
184
+ name: 'DNS External',
185
+ version: '1.0.0',
186
+ sourcePath: '/test/dns-external',
187
+ manifestData: {},
188
+ })
189
+ .run();
190
+
191
+ // Insert capability
192
+ db.insert(capabilities)
193
+ .values({
194
+ moduleId: 'dns-external',
195
+ capabilityName: 'dns_external',
196
+ version: '1.0.0',
197
+ data: {
198
+ server: {
199
+ ip: { primary: '10.0.10.10' },
200
+ port: 53,
201
+ },
202
+ },
203
+ })
204
+ .run();
205
+
206
+ const capability = manager.findCapabilityProvider('dns_external');
207
+
208
+ expect(capability).toBeDefined();
209
+ expect(capability?.moduleId).toBe('dns-external');
210
+ expect(capability?.capabilityName).toBe('dns_external');
211
+ expect(capability?.version).toBe('1.0.0');
212
+ expect(capability?.data).toEqual({
213
+ server: {
214
+ ip: { primary: '10.0.10.10' },
215
+ port: 53,
216
+ },
217
+ });
218
+ });
219
+
220
+ test('should return null for non-existent capability', () => {
221
+ const capability = manager.findCapabilityProvider('nonexistent');
222
+ expect(capability).toBeNull();
223
+ });
224
+ });
225
+
226
+ describe('Parameter Resolution', () => {
227
+ beforeEach(() => {
228
+ // Add dns-external module for capability tests
229
+ db.insert(modules)
230
+ .values({
231
+ id: 'dns-external',
232
+ name: 'DNS External',
233
+ version: '1.0.0',
234
+ sourcePath: '/test/dns-external',
235
+ manifestData: {},
236
+ })
237
+ .run();
238
+
239
+ // Add module config for $self: resolution
240
+ db.insert(moduleConfigs)
241
+ .values([
242
+ { moduleId: 'test-module', key: 'domain', value: 'example.com', valueJson: null },
243
+ { moduleId: 'test-module', key: 'port', value: '8080', valueJson: null },
244
+ ])
245
+ .run();
246
+
247
+ // Add capability for $capability: resolution
248
+ db.insert(capabilities)
249
+ .values({
250
+ moduleId: 'dns-external',
251
+ capabilityName: 'dns_external',
252
+ version: '1.0.0',
253
+ data: {
254
+ server: {
255
+ ip: { primary: '10.0.10.10' },
256
+ },
257
+ },
258
+ })
259
+ .run();
260
+ });
261
+
262
+ test('should resolve $self: variables', async () => {
263
+ const params = {
264
+ url: 'https://$self:domain',
265
+ };
266
+
267
+ const resolved = await manager.resolveParameters('test-module', params);
268
+
269
+ expect(resolved).toEqual({
270
+ url: 'https://example.com',
271
+ });
272
+ });
273
+
274
+ test('should resolve $system: variables', async () => {
275
+ const params = {
276
+ dns: '$system:dns.primary',
277
+ };
278
+
279
+ const resolved = await manager.resolveParameters('test-module', params);
280
+
281
+ expect(resolved).toEqual({
282
+ dns: '1.1.1.1',
283
+ });
284
+ });
285
+
286
+ test('should resolve $capability: variables', async () => {
287
+ const params = {
288
+ dns_server: '$capability:dns_external.server.ip.primary',
289
+ };
290
+
291
+ const resolved = await manager.resolveParameters('test-module', params);
292
+
293
+ expect(resolved).toEqual({
294
+ dns_server: '10.0.10.10',
295
+ });
296
+ });
297
+
298
+ test('should resolve variables in arrays', async () => {
299
+ const params = {
300
+ urls: ['https://$self:domain', 'http://$self:domain:$self:port'],
301
+ };
302
+
303
+ const resolved = await manager.resolveParameters('test-module', params);
304
+
305
+ expect(resolved).toEqual({
306
+ urls: ['https://example.com', 'http://example.com:8080'],
307
+ });
308
+ });
309
+
310
+ test('should resolve nested objects', async () => {
311
+ const params = {
312
+ server: {
313
+ host: '$self:domain',
314
+ port: 443,
315
+ },
316
+ };
317
+
318
+ const resolved = await manager.resolveParameters('test-module', params);
319
+
320
+ expect(resolved).toEqual({
321
+ server: {
322
+ host: 'example.com',
323
+ port: 443,
324
+ },
325
+ });
326
+ });
327
+
328
+ test('should throw error for unresolvable variables', async () => {
329
+ const params = {
330
+ invalid: '$self:nonexistent',
331
+ };
332
+
333
+ await expect(manager.resolveParameters('test-module', params)).rejects.toThrow(
334
+ 'Failed to resolve parameter',
335
+ );
336
+ });
337
+ });
338
+
339
+ describe('Secret Generation', () => {
340
+ test('should generate TSIG key', () => {
341
+ const key = manager.generateTSIGKey();
342
+
343
+ expect(typeof key).toBe('string');
344
+ expect(key.length).toBeGreaterThan(0);
345
+
346
+ // Should be valid base64
347
+ expect(() => atob(key)).not.toThrow();
348
+ });
349
+
350
+ test('should generate different TSIG keys', () => {
351
+ const key1 = manager.generateTSIGKey();
352
+ const key2 = manager.generateTSIGKey();
353
+
354
+ expect(key1).not.toBe(key2);
355
+ });
356
+
357
+ test('should generate hex secret', () => {
358
+ const secret = manager.generateSecret(32, 'hex');
359
+
360
+ expect(typeof secret).toBe('string');
361
+ expect(secret.length).toBe(64); // 32 bytes = 64 hex chars
362
+ expect(/^[0-9a-f]+$/.test(secret)).toBe(true);
363
+ });
364
+
365
+ test('should generate base64 secret', () => {
366
+ const secret = manager.generateSecret(32, 'base64');
367
+
368
+ expect(typeof secret).toBe('string');
369
+ expect(secret.length).toBeGreaterThan(0);
370
+
371
+ // Should be valid base64
372
+ expect(() => atob(secret)).not.toThrow();
373
+ });
374
+
375
+ test('should generate different secrets', () => {
376
+ const secret1 = manager.generateSecret();
377
+ const secret2 = manager.generateSecret();
378
+
379
+ expect(secret1).not.toBe(secret2);
380
+ });
381
+ });
382
+
383
+ describe('Initialization', () => {
384
+ test('should require initialization before use', async () => {
385
+ const uninitializedManager = new CrossModuleDataManager(db);
386
+
387
+ // Should throw when trying to use secrets without initialization
388
+ await expect(uninitializedManager.storeSecret('test-module', 'key', 'value')).rejects.toThrow(
389
+ 'not initialized',
390
+ );
391
+ });
392
+
393
+ test('should work after initialization', async () => {
394
+ const newManager = new CrossModuleDataManager(db);
395
+ await newManager.initialize();
396
+
397
+ // Should work now
398
+ await newManager.storeSecret('test-module', 'key', 'value');
399
+
400
+ // Verify secret was stored
401
+ const retrieved = newManager.getSecret('test-module', 'key');
402
+ expect(retrieved).toBe('value');
403
+ });
404
+ });
405
+ });