@getaegis/cli 0.8.0 → 0.9.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 (242) hide show
  1. package/README.md +43 -14
  2. package/dist/agent/agent.d.ts +98 -0
  3. package/dist/agent/agent.d.ts.map +1 -0
  4. package/dist/agent/agent.js +212 -0
  5. package/dist/agent/agent.js.map +1 -0
  6. package/dist/agent/index.d.ts +3 -0
  7. package/dist/agent/index.d.ts.map +1 -0
  8. package/dist/agent/index.js +2 -0
  9. package/dist/agent/index.js.map +1 -0
  10. package/dist/cli/auth.d.ts +19 -0
  11. package/dist/cli/auth.d.ts.map +1 -0
  12. package/dist/cli/auth.js +44 -0
  13. package/dist/cli/auth.js.map +1 -0
  14. package/dist/cli/commands/agent.d.ts +6 -0
  15. package/dist/cli/commands/agent.d.ts.map +1 -0
  16. package/dist/cli/commands/agent.js +241 -0
  17. package/dist/cli/commands/agent.js.map +1 -0
  18. package/dist/cli/commands/config.d.ts +6 -0
  19. package/dist/cli/commands/config.d.ts.map +1 -0
  20. package/dist/cli/commands/config.js +125 -0
  21. package/dist/cli/commands/config.js.map +1 -0
  22. package/dist/cli/commands/dashboard.d.ts +6 -0
  23. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  24. package/dist/cli/commands/dashboard.js +195 -0
  25. package/dist/cli/commands/dashboard.js.map +1 -0
  26. package/dist/cli/commands/db.d.ts +6 -0
  27. package/dist/cli/commands/db.d.ts.map +1 -0
  28. package/dist/cli/commands/db.js +139 -0
  29. package/dist/cli/commands/db.js.map +1 -0
  30. package/dist/cli/commands/doctor.d.ts +6 -0
  31. package/dist/cli/commands/doctor.d.ts.map +1 -0
  32. package/dist/cli/commands/doctor.js +39 -0
  33. package/dist/cli/commands/doctor.js.map +1 -0
  34. package/dist/cli/commands/gate.d.ts +6 -0
  35. package/dist/cli/commands/gate.d.ts.map +1 -0
  36. package/dist/cli/commands/gate.js +202 -0
  37. package/dist/cli/commands/gate.js.map +1 -0
  38. package/dist/cli/commands/init.d.ts +6 -0
  39. package/dist/cli/commands/init.d.ts.map +1 -0
  40. package/dist/cli/commands/init.js +175 -0
  41. package/dist/cli/commands/init.js.map +1 -0
  42. package/dist/cli/commands/key.d.ts +6 -0
  43. package/dist/cli/commands/key.d.ts.map +1 -0
  44. package/dist/cli/commands/key.js +49 -0
  45. package/dist/cli/commands/key.js.map +1 -0
  46. package/dist/cli/commands/ledger.d.ts +6 -0
  47. package/dist/cli/commands/ledger.d.ts.map +1 -0
  48. package/dist/cli/commands/ledger.js +140 -0
  49. package/dist/cli/commands/ledger.js.map +1 -0
  50. package/dist/cli/commands/mcp.d.ts +6 -0
  51. package/dist/cli/commands/mcp.d.ts.map +1 -0
  52. package/dist/cli/commands/mcp.js +224 -0
  53. package/dist/cli/commands/mcp.js.map +1 -0
  54. package/dist/cli/commands/policy.d.ts +6 -0
  55. package/dist/cli/commands/policy.d.ts.map +1 -0
  56. package/dist/cli/commands/policy.js +126 -0
  57. package/dist/cli/commands/policy.js.map +1 -0
  58. package/dist/cli/commands/user.d.ts +6 -0
  59. package/dist/cli/commands/user.d.ts.map +1 -0
  60. package/dist/cli/commands/user.js +150 -0
  61. package/dist/cli/commands/user.js.map +1 -0
  62. package/dist/cli/commands/vault-manager.d.ts +6 -0
  63. package/dist/cli/commands/vault-manager.d.ts.map +1 -0
  64. package/dist/cli/commands/vault-manager.js +240 -0
  65. package/dist/cli/commands/vault-manager.js.map +1 -0
  66. package/dist/cli/commands/vault.d.ts +6 -0
  67. package/dist/cli/commands/vault.d.ts.map +1 -0
  68. package/dist/cli/commands/vault.js +265 -0
  69. package/dist/cli/commands/vault.js.map +1 -0
  70. package/dist/cli/commands/webhook.d.ts +6 -0
  71. package/dist/cli/commands/webhook.d.ts.map +1 -0
  72. package/dist/cli/commands/webhook.js +151 -0
  73. package/dist/cli/commands/webhook.js.map +1 -0
  74. package/dist/cli/helpers.d.ts +12 -0
  75. package/dist/cli/helpers.d.ts.map +1 -0
  76. package/dist/cli/helpers.js +61 -0
  77. package/dist/cli/helpers.js.map +1 -0
  78. package/dist/cli/index.d.ts +19 -0
  79. package/dist/cli/index.d.ts.map +1 -0
  80. package/dist/cli/index.js +19 -0
  81. package/dist/cli/index.js.map +1 -0
  82. package/dist/cli/validation.d.ts +37 -0
  83. package/dist/cli/validation.d.ts.map +1 -0
  84. package/dist/cli/validation.js +104 -0
  85. package/dist/cli/validation.js.map +1 -0
  86. package/dist/cli.d.ts +3 -0
  87. package/dist/cli.d.ts.map +1 -0
  88. package/dist/cli.js +37 -0
  89. package/dist/cli.js.map +1 -0
  90. package/dist/config.d.ts +120 -0
  91. package/dist/config.d.ts.map +1 -0
  92. package/dist/config.js +401 -0
  93. package/dist/config.js.map +1 -0
  94. package/dist/dashboard/dashboard-server.d.ts +95 -0
  95. package/dist/dashboard/dashboard-server.d.ts.map +1 -0
  96. package/dist/dashboard/dashboard-server.js +329 -0
  97. package/dist/dashboard/dashboard-server.js.map +1 -0
  98. package/dist/dashboard/index.d.ts +3 -0
  99. package/dist/dashboard/index.d.ts.map +1 -0
  100. package/dist/dashboard/index.js +2 -0
  101. package/dist/dashboard/index.js.map +1 -0
  102. package/dist/dashboard/public/assets/index-Cah0_BKk.js +148 -0
  103. package/dist/dashboard/public/assets/index-CpMruPNh.css +1 -0
  104. package/dist/dashboard/public/favicon.svg +6 -0
  105. package/dist/dashboard/public/index.html +14 -0
  106. package/dist/db.d.ts +27 -0
  107. package/dist/db.d.ts.map +1 -0
  108. package/dist/db.js +209 -0
  109. package/dist/db.js.map +1 -0
  110. package/dist/doctor.d.ts +37 -0
  111. package/dist/doctor.d.ts.map +1 -0
  112. package/dist/doctor.js +216 -0
  113. package/dist/doctor.js.map +1 -0
  114. package/dist/gate/body-inspector.d.ts +31 -0
  115. package/dist/gate/body-inspector.d.ts.map +1 -0
  116. package/dist/gate/body-inspector.js +193 -0
  117. package/dist/gate/body-inspector.js.map +1 -0
  118. package/dist/gate/gate.d.ts +190 -0
  119. package/dist/gate/gate.d.ts.map +1 -0
  120. package/dist/gate/gate.js +1243 -0
  121. package/dist/gate/gate.js.map +1 -0
  122. package/dist/gate/index.d.ts +7 -0
  123. package/dist/gate/index.d.ts.map +1 -0
  124. package/dist/gate/index.js +4 -0
  125. package/dist/gate/index.js.map +1 -0
  126. package/dist/gate/rate-limiter.d.ts +59 -0
  127. package/dist/gate/rate-limiter.d.ts.map +1 -0
  128. package/dist/gate/rate-limiter.js +120 -0
  129. package/dist/gate/rate-limiter.js.map +1 -0
  130. package/dist/index.d.ts +28 -0
  131. package/dist/index.d.ts.map +1 -0
  132. package/dist/index.js +17 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/key-storage/credential-manager-windows.d.ts +19 -0
  135. package/dist/key-storage/credential-manager-windows.d.ts.map +1 -0
  136. package/dist/key-storage/credential-manager-windows.js +87 -0
  137. package/dist/key-storage/credential-manager-windows.js.map +1 -0
  138. package/dist/key-storage/file-fallback.d.ts +21 -0
  139. package/dist/key-storage/file-fallback.d.ts.map +1 -0
  140. package/dist/key-storage/file-fallback.js +62 -0
  141. package/dist/key-storage/file-fallback.js.map +1 -0
  142. package/dist/key-storage/index.d.ts +6 -0
  143. package/dist/key-storage/index.d.ts.map +1 -0
  144. package/dist/key-storage/index.js +6 -0
  145. package/dist/key-storage/index.js.map +1 -0
  146. package/dist/key-storage/key-storage.d.ts +41 -0
  147. package/dist/key-storage/key-storage.d.ts.map +1 -0
  148. package/dist/key-storage/key-storage.js +70 -0
  149. package/dist/key-storage/key-storage.js.map +1 -0
  150. package/dist/key-storage/keychain-macos.d.ts +19 -0
  151. package/dist/key-storage/keychain-macos.d.ts.map +1 -0
  152. package/dist/key-storage/keychain-macos.js +51 -0
  153. package/dist/key-storage/keychain-macos.js.map +1 -0
  154. package/dist/key-storage/secret-service-linux.d.ts +19 -0
  155. package/dist/key-storage/secret-service-linux.d.ts.map +1 -0
  156. package/dist/key-storage/secret-service-linux.js +55 -0
  157. package/dist/key-storage/secret-service-linux.js.map +1 -0
  158. package/dist/ledger/index.d.ts +3 -0
  159. package/dist/ledger/index.d.ts.map +1 -0
  160. package/dist/ledger/index.js +2 -0
  161. package/dist/ledger/index.js.map +1 -0
  162. package/dist/ledger/ledger.d.ts +98 -0
  163. package/dist/ledger/ledger.d.ts.map +1 -0
  164. package/dist/ledger/ledger.js +145 -0
  165. package/dist/ledger/ledger.js.map +1 -0
  166. package/dist/logger/index.d.ts +3 -0
  167. package/dist/logger/index.d.ts.map +1 -0
  168. package/dist/logger/index.js +2 -0
  169. package/dist/logger/index.js.map +1 -0
  170. package/dist/logger/logger.d.ts +58 -0
  171. package/dist/logger/logger.d.ts.map +1 -0
  172. package/dist/logger/logger.js +201 -0
  173. package/dist/logger/logger.js.map +1 -0
  174. package/dist/mcp/index.d.ts +3 -0
  175. package/dist/mcp/index.d.ts.map +1 -0
  176. package/dist/mcp/index.js +2 -0
  177. package/dist/mcp/index.js.map +1 -0
  178. package/dist/mcp/mcp-server.d.ts +130 -0
  179. package/dist/mcp/mcp-server.d.ts.map +1 -0
  180. package/dist/mcp/mcp-server.js +775 -0
  181. package/dist/mcp/mcp-server.js.map +1 -0
  182. package/dist/metrics/index.d.ts +3 -0
  183. package/dist/metrics/index.d.ts.map +1 -0
  184. package/dist/metrics/index.js +2 -0
  185. package/dist/metrics/index.js.map +1 -0
  186. package/dist/metrics/metrics.d.ts +88 -0
  187. package/dist/metrics/metrics.d.ts.map +1 -0
  188. package/dist/metrics/metrics.js +179 -0
  189. package/dist/metrics/metrics.js.map +1 -0
  190. package/dist/policy/index.d.ts +3 -0
  191. package/dist/policy/index.d.ts.map +1 -0
  192. package/dist/policy/index.js +2 -0
  193. package/dist/policy/index.js.map +1 -0
  194. package/dist/policy/policy.d.ts +119 -0
  195. package/dist/policy/policy.d.ts.map +1 -0
  196. package/dist/policy/policy.js +426 -0
  197. package/dist/policy/policy.js.map +1 -0
  198. package/dist/user/index.d.ts +3 -0
  199. package/dist/user/index.d.ts.map +1 -0
  200. package/dist/user/index.js +2 -0
  201. package/dist/user/index.js.map +1 -0
  202. package/dist/user/user.d.ts +102 -0
  203. package/dist/user/user.d.ts.map +1 -0
  204. package/dist/user/user.js +216 -0
  205. package/dist/user/user.js.map +1 -0
  206. package/dist/vault/crypto.d.ts +28 -0
  207. package/dist/vault/crypto.d.ts.map +1 -0
  208. package/dist/vault/crypto.js +44 -0
  209. package/dist/vault/crypto.js.map +1 -0
  210. package/dist/vault/index.d.ts +10 -0
  211. package/dist/vault/index.d.ts.map +1 -0
  212. package/dist/vault/index.js +6 -0
  213. package/dist/vault/index.js.map +1 -0
  214. package/dist/vault/seal.d.ts +68 -0
  215. package/dist/vault/seal.d.ts.map +1 -0
  216. package/dist/vault/seal.js +110 -0
  217. package/dist/vault/seal.js.map +1 -0
  218. package/dist/vault/shamir.d.ts +33 -0
  219. package/dist/vault/shamir.d.ts.map +1 -0
  220. package/dist/vault/shamir.js +174 -0
  221. package/dist/vault/shamir.js.map +1 -0
  222. package/dist/vault/vault-manager.d.ts +62 -0
  223. package/dist/vault/vault-manager.d.ts.map +1 -0
  224. package/dist/vault/vault-manager.js +151 -0
  225. package/dist/vault/vault-manager.js.map +1 -0
  226. package/dist/vault/vault.d.ts +104 -0
  227. package/dist/vault/vault.d.ts.map +1 -0
  228. package/dist/vault/vault.js +259 -0
  229. package/dist/vault/vault.js.map +1 -0
  230. package/dist/version.d.ts +3 -0
  231. package/dist/version.d.ts.map +1 -0
  232. package/dist/version.js +18 -0
  233. package/dist/version.js.map +1 -0
  234. package/dist/webhook/index.d.ts +3 -0
  235. package/dist/webhook/index.d.ts.map +1 -0
  236. package/dist/webhook/index.js +2 -0
  237. package/dist/webhook/index.js.map +1 -0
  238. package/dist/webhook/webhook.d.ts +114 -0
  239. package/dist/webhook/webhook.d.ts.map +1 -0
  240. package/dist/webhook/webhook.js +269 -0
  241. package/dist/webhook/webhook.js.map +1 -0
  242. package/package.json +12 -6
@@ -0,0 +1,426 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ const VALID_METHODS = new Set([
5
+ 'GET',
6
+ 'POST',
7
+ 'PUT',
8
+ 'PATCH',
9
+ 'DELETE',
10
+ 'HEAD',
11
+ 'OPTIONS',
12
+ ]);
13
+ // ─── Time format regex ────────────────────────────────────────────
14
+ const TIME_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)$/;
15
+ // ─── Rate limit format regex ──────────────────────────────────────
16
+ const RATE_LIMIT_PATTERN = /^\d+\/(second|sec|min|minute|hour|hr|day)$/;
17
+ // ─── Validation ───────────────────────────────────────────────────
18
+ /**
19
+ * Validate a single policy rule.
20
+ */
21
+ function validateRule(rule, index, errors) {
22
+ const prefix = `rules[${index}]`;
23
+ if (typeof rule !== 'object' || rule === null) {
24
+ errors.push({ message: `${prefix} must be an object`, path: prefix });
25
+ return;
26
+ }
27
+ const r = rule;
28
+ // service — required string
29
+ if (typeof r.service !== 'string' || r.service.trim().length === 0) {
30
+ errors.push({
31
+ message: `${prefix}.service is required and must be a non-empty string`,
32
+ path: `${prefix}.service`,
33
+ });
34
+ }
35
+ // methods — optional array of valid HTTP methods
36
+ if (r.methods !== undefined) {
37
+ if (!Array.isArray(r.methods)) {
38
+ errors.push({
39
+ message: `${prefix}.methods must be an array of HTTP methods`,
40
+ path: `${prefix}.methods`,
41
+ });
42
+ }
43
+ else {
44
+ for (let i = 0; i < r.methods.length; i++) {
45
+ const m = r.methods[i];
46
+ if (typeof m !== 'string' || !VALID_METHODS.has(m.toUpperCase())) {
47
+ errors.push({
48
+ message: `${prefix}.methods[${i}] "${String(m)}" is not a valid HTTP method. Allowed: ${[...VALID_METHODS].join(', ')}`,
49
+ path: `${prefix}.methods[${i}]`,
50
+ });
51
+ }
52
+ }
53
+ }
54
+ }
55
+ // paths — optional array of regex strings
56
+ if (r.paths !== undefined) {
57
+ if (!Array.isArray(r.paths)) {
58
+ errors.push({
59
+ message: `${prefix}.paths must be an array of regex pattern strings`,
60
+ path: `${prefix}.paths`,
61
+ });
62
+ }
63
+ else {
64
+ for (let i = 0; i < r.paths.length; i++) {
65
+ const p = r.paths[i];
66
+ if (typeof p !== 'string') {
67
+ errors.push({
68
+ message: `${prefix}.paths[${i}] must be a string`,
69
+ path: `${prefix}.paths[${i}]`,
70
+ });
71
+ }
72
+ else {
73
+ try {
74
+ new RegExp(p);
75
+ }
76
+ catch {
77
+ errors.push({
78
+ message: `${prefix}.paths[${i}] "${p}" is not a valid regular expression`,
79
+ path: `${prefix}.paths[${i}]`,
80
+ });
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ // rate_limit / rateLimit — optional string matching pattern
87
+ const rateLimit = r.rate_limit ?? r.rateLimit;
88
+ if (rateLimit !== undefined) {
89
+ if (typeof rateLimit !== 'string' || !RATE_LIMIT_PATTERN.test(rateLimit)) {
90
+ errors.push({
91
+ message: `${prefix}.rate_limit "${String(rateLimit)}" is invalid. Expected format: "<number>/<unit>" (e.g. "100/hour", "50/min")`,
92
+ path: `${prefix}.rate_limit`,
93
+ });
94
+ }
95
+ }
96
+ // time_window / timeWindow — optional object with start, end, timezone
97
+ const timeWindow = r.time_window ?? r.timeWindow;
98
+ if (timeWindow !== undefined) {
99
+ if (typeof timeWindow !== 'object' || timeWindow === null) {
100
+ errors.push({
101
+ message: `${prefix}.time_window must be an object with start, end, and timezone`,
102
+ path: `${prefix}.time_window`,
103
+ });
104
+ }
105
+ else {
106
+ const tw = timeWindow;
107
+ if (typeof tw.start !== 'string' || !TIME_PATTERN.test(tw.start)) {
108
+ errors.push({
109
+ message: `${prefix}.time_window.start must be in HH:MM 24-hour format (e.g. "09:00")`,
110
+ path: `${prefix}.time_window.start`,
111
+ });
112
+ }
113
+ if (typeof tw.end !== 'string' || !TIME_PATTERN.test(tw.end)) {
114
+ errors.push({
115
+ message: `${prefix}.time_window.end must be in HH:MM 24-hour format (e.g. "18:00")`,
116
+ path: `${prefix}.time_window.end`,
117
+ });
118
+ }
119
+ if (tw.timezone !== undefined && typeof tw.timezone !== 'string') {
120
+ errors.push({
121
+ message: `${prefix}.time_window.timezone must be a string (IANA timezone)`,
122
+ path: `${prefix}.time_window.timezone`,
123
+ });
124
+ }
125
+ // Validate timezone is a real IANA zone
126
+ if (typeof tw.timezone === 'string') {
127
+ try {
128
+ Intl.DateTimeFormat(undefined, { timeZone: tw.timezone });
129
+ }
130
+ catch {
131
+ errors.push({
132
+ message: `${prefix}.time_window.timezone "${tw.timezone}" is not a valid IANA timezone`,
133
+ path: `${prefix}.time_window.timezone`,
134
+ });
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ /**
141
+ * Parse and validate a raw YAML string into a Policy.
142
+ * Returns a validation result with errors (if any) and the parsed policy (if valid).
143
+ */
144
+ export function parsePolicy(yamlContent, filePath) {
145
+ const errors = [];
146
+ // Parse YAML
147
+ let raw;
148
+ try {
149
+ raw = parseYaml(yamlContent);
150
+ }
151
+ catch (err) {
152
+ const message = err instanceof Error ? err.message : String(err);
153
+ return {
154
+ valid: false,
155
+ errors: [{ file: filePath, message: `YAML parse error: ${message}` }],
156
+ filePath,
157
+ };
158
+ }
159
+ if (typeof raw !== 'object' || raw === null) {
160
+ return {
161
+ valid: false,
162
+ errors: [{ file: filePath, message: 'Policy must be a YAML object' }],
163
+ filePath,
164
+ };
165
+ }
166
+ const doc = raw;
167
+ // agent — required string
168
+ if (typeof doc.agent !== 'string' || doc.agent.trim().length === 0) {
169
+ errors.push({
170
+ file: filePath,
171
+ message: '"agent" is required and must be a non-empty string',
172
+ path: 'agent',
173
+ });
174
+ }
175
+ // rules — required non-empty array
176
+ if (!Array.isArray(doc.rules)) {
177
+ errors.push({
178
+ file: filePath,
179
+ message: '"rules" is required and must be an array',
180
+ path: 'rules',
181
+ });
182
+ }
183
+ else if (doc.rules.length === 0) {
184
+ errors.push({
185
+ file: filePath,
186
+ message: '"rules" must contain at least one rule',
187
+ path: 'rules',
188
+ });
189
+ }
190
+ else {
191
+ for (let i = 0; i < doc.rules.length; i++) {
192
+ validateRule(doc.rules[i], i, errors);
193
+ }
194
+ }
195
+ if (errors.length > 0) {
196
+ // Attach file to all errors
197
+ for (const err of errors) {
198
+ err.file = err.file ?? filePath;
199
+ }
200
+ return { valid: false, errors, filePath };
201
+ }
202
+ // Build the validated Policy object
203
+ const rules = doc.rules.map((r) => {
204
+ const rule = {
205
+ service: r.service,
206
+ };
207
+ if (r.methods) {
208
+ rule.methods = r.methods.map((m) => m.toUpperCase());
209
+ }
210
+ if (r.paths) {
211
+ rule.paths = r.paths;
212
+ }
213
+ const rateLimitVal = r.rate_limit ?? r.rateLimit;
214
+ if (rateLimitVal) {
215
+ rule.rateLimit = rateLimitVal;
216
+ }
217
+ const timeWindowVal = r.time_window ?? r.timeWindow;
218
+ if (timeWindowVal) {
219
+ const tw = timeWindowVal;
220
+ rule.timeWindow = {
221
+ start: tw.start,
222
+ end: tw.end,
223
+ timezone: tw.timezone ?? 'UTC',
224
+ };
225
+ }
226
+ return rule;
227
+ });
228
+ return {
229
+ valid: true,
230
+ errors: [],
231
+ policy: {
232
+ agent: doc.agent,
233
+ rules,
234
+ },
235
+ filePath,
236
+ };
237
+ }
238
+ /**
239
+ * Load and validate a single policy file from disk.
240
+ */
241
+ export function loadPolicyFile(filePath) {
242
+ let content;
243
+ try {
244
+ content = fs.readFileSync(filePath, 'utf-8');
245
+ }
246
+ catch (err) {
247
+ const message = err instanceof Error ? err.message : String(err);
248
+ return {
249
+ valid: false,
250
+ errors: [{ file: filePath, message: `Failed to read file: ${message}` }],
251
+ filePath,
252
+ };
253
+ }
254
+ return parsePolicy(content, filePath);
255
+ }
256
+ /**
257
+ * Load all policy files from a directory (*.yaml and *.yml).
258
+ * Returns an array of validation results, one per file.
259
+ */
260
+ export function loadPoliciesFromDirectory(dirPath) {
261
+ if (!fs.existsSync(dirPath)) {
262
+ return [
263
+ {
264
+ valid: false,
265
+ errors: [{ message: `Policy directory does not exist: ${dirPath}` }],
266
+ },
267
+ ];
268
+ }
269
+ const stat = fs.statSync(dirPath);
270
+ if (!stat.isDirectory()) {
271
+ return [
272
+ {
273
+ valid: false,
274
+ errors: [{ message: `Not a directory: ${dirPath}` }],
275
+ },
276
+ ];
277
+ }
278
+ const files = fs
279
+ .readdirSync(dirPath)
280
+ .filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))
281
+ .sort();
282
+ if (files.length === 0) {
283
+ return [];
284
+ }
285
+ const results = [];
286
+ for (const file of files) {
287
+ const fullPath = path.join(dirPath, file);
288
+ results.push(loadPolicyFile(fullPath));
289
+ }
290
+ // Check for duplicate agent names across files
291
+ const agentNames = new Map();
292
+ for (const result of results) {
293
+ if (result.valid && result.policy) {
294
+ const existing = agentNames.get(result.policy.agent);
295
+ if (existing) {
296
+ result.valid = false;
297
+ result.errors.push({
298
+ file: result.errors[0]?.file,
299
+ message: `Duplicate policy for agent "${result.policy.agent}" — already defined in ${existing}`,
300
+ path: 'agent',
301
+ });
302
+ }
303
+ else {
304
+ agentNames.set(result.policy.agent, result.errors[0]?.file ?? 'unknown');
305
+ }
306
+ }
307
+ }
308
+ return results;
309
+ }
310
+ /**
311
+ * Build a map of agent name → Policy from a set of validation results.
312
+ * Only includes valid policies.
313
+ */
314
+ export function buildPolicyMap(results) {
315
+ const map = new Map();
316
+ for (const result of results) {
317
+ if (result.valid && result.policy) {
318
+ map.set(result.policy.agent, result.policy);
319
+ }
320
+ }
321
+ return map;
322
+ }
323
+ /**
324
+ * Check if the current time falls within a time window.
325
+ *
326
+ * Handles midnight-spanning windows (e.g. 22:00 → 06:00).
327
+ */
328
+ function isWithinTimeWindow(timeWindow, now) {
329
+ // Get the current time in the specified timezone
330
+ const formatter = new Intl.DateTimeFormat('en-US', {
331
+ timeZone: timeWindow.timezone,
332
+ hour: '2-digit',
333
+ minute: '2-digit',
334
+ hour12: false,
335
+ });
336
+ const parts = formatter.formatToParts(now);
337
+ const hourPart = parts.find((p) => p.type === 'hour');
338
+ const minutePart = parts.find((p) => p.type === 'minute');
339
+ const currentHour = parseInt(hourPart?.value ?? '0', 10);
340
+ const currentMinute = parseInt(minutePart?.value ?? '0', 10);
341
+ const currentMinutes = currentHour * 60 + currentMinute;
342
+ const [startH, startM] = timeWindow.start.split(':').map(Number);
343
+ const [endH, endM] = timeWindow.end.split(':').map(Number);
344
+ const startMinutes = startH * 60 + startM;
345
+ const endMinutes = endH * 60 + endM;
346
+ if (startMinutes <= endMinutes) {
347
+ // Normal window: e.g. 09:00 → 18:00
348
+ return currentMinutes >= startMinutes && currentMinutes < endMinutes;
349
+ }
350
+ // Midnight-spanning window: e.g. 22:00 → 06:00
351
+ return currentMinutes >= startMinutes || currentMinutes < endMinutes;
352
+ }
353
+ /**
354
+ * Evaluate a request against a policy.
355
+ *
356
+ * Rules are matched by service name. If no rule matches the service,
357
+ * the request is denied. If a rule matches, method and path constraints
358
+ * are checked. If multiple rules match the same service, the request is
359
+ * allowed if ANY rule permits it.
360
+ *
361
+ * Returns an evaluation result indicating whether the request is allowed
362
+ * and, if not, why.
363
+ */
364
+ export function evaluatePolicy(policy, request) {
365
+ const now = request.now ?? new Date();
366
+ const method = request.method.toUpperCase();
367
+ // Find all rules matching this service
368
+ const matchingRules = policy.rules.filter((r) => r.service === request.service);
369
+ if (matchingRules.length === 0) {
370
+ return {
371
+ allowed: false,
372
+ reason: `No policy rule for service "${request.service}" — agent "${policy.agent}" is not permitted to access this service`,
373
+ violation: 'no_matching_rule',
374
+ };
375
+ }
376
+ // Try each matching rule — allowed if ANY rule permits the request
377
+ const denials = [];
378
+ for (const rule of matchingRules) {
379
+ // Check method restriction
380
+ if (rule.methods && !rule.methods.includes(method)) {
381
+ denials.push({
382
+ rule,
383
+ reason: `Method ${method} not allowed — permitted: ${rule.methods.join(', ')}`,
384
+ violation: 'method',
385
+ });
386
+ continue;
387
+ }
388
+ // Check path restriction
389
+ if (rule.paths) {
390
+ const pathMatch = rule.paths.some((pattern) => new RegExp(pattern).test(request.path));
391
+ if (!pathMatch) {
392
+ denials.push({
393
+ rule,
394
+ reason: `Path "${request.path}" does not match any allowed pattern: ${rule.paths.join(', ')}`,
395
+ violation: 'path',
396
+ });
397
+ continue;
398
+ }
399
+ }
400
+ // Check time window
401
+ if (rule.timeWindow) {
402
+ if (!isWithinTimeWindow(rule.timeWindow, now)) {
403
+ denials.push({
404
+ rule,
405
+ reason: `Request outside allowed time window (${rule.timeWindow.start}–${rule.timeWindow.end} ${rule.timeWindow.timezone})`,
406
+ violation: 'time_window',
407
+ });
408
+ continue;
409
+ }
410
+ }
411
+ // All checks passed — this rule allows the request
412
+ return {
413
+ allowed: true,
414
+ matchedRule: rule,
415
+ };
416
+ }
417
+ // No rule allowed the request — use the most specific denial
418
+ const denial = denials[0];
419
+ return {
420
+ allowed: false,
421
+ matchedRule: denial.rule,
422
+ reason: denial.reason,
423
+ violation: denial.violation,
424
+ };
425
+ }
426
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/policy/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAS1C,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC;IACjD,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;CACV,CAAC,CAAC;AAgEH,qEAAqE;AAErE,MAAM,YAAY,GAAG,6BAA6B,CAAC;AAEnD,qEAAqE;AAErE,MAAM,kBAAkB,GAAG,4CAA4C,CAAC;AAExE,qEAAqE;AAErE;;GAEG;AACH,SAAS,YAAY,CAAC,IAAa,EAAE,KAAa,EAAE,MAA+B;IACjF,MAAM,MAAM,GAAG,SAAS,KAAK,GAAG,CAAC;IAEjC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,oBAAoB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,IAA+B,CAAC;IAE1C,4BAA4B;IAC5B,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,GAAG,MAAM,qDAAqD;YACvE,IAAI,EAAE,GAAG,MAAM,UAAU;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,iDAAiD;IACjD,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,GAAG,MAAM,2CAA2C;gBAC7D,IAAI,EAAE,GAAG,MAAM,UAAU;aAC1B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;oBACjE,MAAM,CAAC,IAAI,CAAC;wBACV,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,0CAA0C,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;wBACvH,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC,GAAG;qBAChC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,GAAG,MAAM,kDAAkD;gBACpE,IAAI,EAAE,GAAG,MAAM,QAAQ;aACxB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;oBAC1B,MAAM,CAAC,IAAI,CAAC;wBACV,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC,oBAAoB;wBACjD,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,GAAG;qBAC9B,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC;wBACH,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;oBAChB,CAAC;oBAAC,MAAM,CAAC;wBACP,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,qCAAqC;4BACzE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,GAAG;yBAC9B,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC;IAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,GAAG,MAAM,gBAAgB,MAAM,CAAC,SAAS,CAAC,8EAA8E;gBACjI,IAAI,EAAE,GAAG,MAAM,aAAa;aAC7B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,CAAC;IACjD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,GAAG,MAAM,8DAA8D;gBAChF,IAAI,EAAE,GAAG,MAAM,cAAc;aAC9B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,UAAqC,CAAC;YAEjD,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjE,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,GAAG,MAAM,mEAAmE;oBACrF,IAAI,EAAE,GAAG,MAAM,oBAAoB;iBACpC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,OAAO,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7D,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,GAAG,MAAM,iEAAiE;oBACnF,IAAI,EAAE,GAAG,MAAM,kBAAkB;iBAClC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,EAAE,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,EAAE,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjE,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,GAAG,MAAM,wDAAwD;oBAC1E,IAAI,EAAE,GAAG,MAAM,uBAAuB;iBACvC,CAAC,CAAC;YACL,CAAC;YACD,wCAAwC;YACxC,IAAI,OAAO,EAAE,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACpC,IAAI,CAAC;oBACH,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC5D,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,IAAI,CAAC;wBACV,OAAO,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,QAAQ,gCAAgC;wBACvF,IAAI,EAAE,GAAG,MAAM,uBAAuB;qBACvC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,QAAiB;IAChE,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,aAAa;IACb,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,OAAO,EAAE,EAAE,CAAC;YACrE,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC;YACrE,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,0BAA0B;IAC1B,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,oDAAoD;YAC7D,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,0CAA0C;YACnD,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,wCAAwC;YACjD,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,4BAA4B;QAC5B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,QAAQ,CAAC;QAClC,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC5C,CAAC;IAED,oCAAoC;IACpC,MAAM,KAAK,GAAkB,GAAG,CAAC,KAAwC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAClF,MAAM,IAAI,GAAe;YACvB,OAAO,EAAE,CAAC,CAAC,OAAiB;SAC7B,CAAC;QAEF,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACd,IAAI,CAAC,OAAO,GAAI,CAAC,CAAC,OAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAgB,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAiB,CAAC;QACnC,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC;QACjD,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,SAAS,GAAG,YAAsB,CAAC;QAC1C,CAAC;QAED,MAAM,aAAa,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,CAAC;QACpD,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,EAAE,GAAG,aAAwC,CAAC;YACpD,IAAI,CAAC,UAAU,GAAG;gBAChB,KAAK,EAAE,EAAE,CAAC,KAAe;gBACzB,GAAG,EAAE,EAAE,CAAC,GAAa;gBACrB,QAAQ,EAAG,EAAE,CAAC,QAAmB,IAAI,KAAK;aAC3C,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,EAAE;QACV,MAAM,EAAE;YACN,KAAK,EAAE,GAAG,CAAC,KAAe;YAC1B,KAAK;SACN;QACD,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wBAAwB,OAAO,EAAE,EAAE,CAAC;YACxE,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,OAAO,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL;gBACE,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,oCAAoC,OAAO,EAAE,EAAE,CAAC;aACrE;SACF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,OAAO;YACL;gBACE,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,oBAAoB,OAAO,EAAE,EAAE,CAAC;aACrD;SACF,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,EAAE;SACb,WAAW,CAAC,OAAO,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;SACxD,IAAI,EAAE,CAAC;IAEV,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAA6B,EAAE,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,+CAA+C;IAC/C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;gBACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;oBACjB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI;oBAC5B,OAAO,EAAE,+BAA+B,MAAM,CAAC,MAAM,CAAC,KAAK,0BAA0B,QAAQ,EAAE;oBAC/F,IAAI,EAAE,OAAO;iBACd,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,SAAS,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAiC;IAC9D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAgCD;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,UAAsB,EAAE,GAAS;IAC3D,iDAAiD;IACjD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QACjD,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,MAAM,aAAa,GAAG,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,cAAc,GAAG,WAAW,GAAG,EAAE,GAAG,aAAa,CAAC;IAExD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC;IAEpC,IAAI,YAAY,IAAI,UAAU,EAAE,CAAC;QAC/B,oCAAoC;QACpC,OAAO,cAAc,IAAI,YAAY,IAAI,cAAc,GAAG,UAAU,CAAC;IACvE,CAAC;IACD,+CAA+C;IAC/C,OAAO,cAAc,IAAI,YAAY,IAAI,cAAc,GAAG,UAAU,CAAC;AACvE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAsB;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IAE5C,uCAAuC;IACvC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,+BAA+B,OAAO,CAAC,OAAO,cAAc,MAAM,CAAC,KAAK,2CAA2C;YAC3H,SAAS,EAAE,kBAAkB;SAC9B,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,MAAM,OAAO,GACX,EAAE,CAAC;IAEL,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,2BAA2B;QAC3B,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAoB,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI;gBACJ,MAAM,EAAE,UAAU,MAAM,6BAA6B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC9E,SAAS,EAAE,QAAQ;aACpB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,yBAAyB;QACzB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACvF,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI;oBACJ,MAAM,EAAE,SAAS,OAAO,CAAC,IAAI,yCAAyC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAC7F,SAAS,EAAE,MAAM;iBAClB,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI;oBACJ,MAAM,EAAE,wCAAwC,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;oBAC3H,SAAS,EAAE,aAAa;iBACzB,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI;SAClB,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO;QACL,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,MAAM,CAAC,IAAI;QACxB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { Permission, User, UserRole, UserWithToken } from './user.js';
2
+ export { getPermissions, hasPermission, UserRegistry, VALID_ROLES } from './user.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/user/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getPermissions, hasPermission, UserRegistry, VALID_ROLES } from './user.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/user/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,102 @@
1
+ import type Database from 'better-sqlite3-multiple-ciphers';
2
+ /**
3
+ * Aegis user roles — three tiers of access control:
4
+ * - **admin**: Full access — manage credentials, agents, policies, users, webhooks, vaults
5
+ * - **operator**: Operational access — start/stop Gate, view Ledger, manage agents
6
+ * - **viewer**: Read-only — view Ledger, stats, and credential metadata (no secrets)
7
+ */
8
+ export type UserRole = 'admin' | 'operator' | 'viewer';
9
+ export declare const VALID_ROLES: readonly UserRole[];
10
+ /**
11
+ * Permission categories that map to CLI commands/actions.
12
+ * Each role grants a different set of permissions.
13
+ */
14
+ export type Permission = 'vault:read' | 'vault:write' | 'vault:manage' | 'agent:read' | 'agent:write' | 'ledger:read' | 'ledger:export' | 'gate:start' | 'policy:read' | 'policy:write' | 'webhook:read' | 'webhook:write' | 'user:read' | 'user:write' | 'dashboard:view' | 'doctor:run';
15
+ /**
16
+ * Check if a role has a specific permission.
17
+ */
18
+ export declare function hasPermission(role: UserRole, permission: Permission): boolean;
19
+ /**
20
+ * Get all permissions for a role.
21
+ */
22
+ export declare function getPermissions(role: UserRole): ReadonlySet<Permission>;
23
+ export interface User {
24
+ id: string;
25
+ name: string;
26
+ role: UserRole;
27
+ tokenPrefix: string;
28
+ createdAt: string;
29
+ updatedAt: string;
30
+ }
31
+ export interface UserWithToken extends User {
32
+ token: string;
33
+ }
34
+ /**
35
+ * User Registry — manages user identities, authentication, and role-based access control.
36
+ *
37
+ * Users are authenticated via API keys (same pattern as agent tokens):
38
+ * - Token format: aegis_user_{uuid}_{hmac_prefix}
39
+ * - Tokens are SHA-256 hashed for fast lookup — hash-only, no recovery
40
+ * - Prefixed (first 17 chars: "aegis_user_" + 6) for safe logging
41
+ *
42
+ * Security: Same hash-only storage as agent tokens. If a token is lost,
43
+ * use regenerateToken() to issue a new one.
44
+ */
45
+ export declare class UserRegistry {
46
+ private db;
47
+ private derivedKey;
48
+ constructor(db: Database.Database, derivedKey: Buffer);
49
+ /**
50
+ * Register a new user. Returns the user with their API key (shown once).
51
+ *
52
+ * Token format: aegis_user_{uuid}_{hmac_prefix}
53
+ */
54
+ add(params: {
55
+ name: string;
56
+ role: UserRole;
57
+ }): UserWithToken;
58
+ /**
59
+ * List all registered users (without tokens).
60
+ */
61
+ list(): User[];
62
+ /**
63
+ * Get a user by name (without token).
64
+ */
65
+ getByName(name: string): User | null;
66
+ /**
67
+ * Validate a user API key. Returns the user if the token is valid, null otherwise.
68
+ *
69
+ * Uses SHA-256 hash comparison for O(1) lookup.
70
+ */
71
+ validateToken(token: string): User | null;
72
+ /**
73
+ * Remove a user by name.
74
+ */
75
+ remove(name: string): boolean;
76
+ /**
77
+ * Update a user's role.
78
+ */
79
+ updateRole(params: {
80
+ name: string;
81
+ role: UserRole;
82
+ }): User;
83
+ /**
84
+ * Regenerate a user's token. Issues a new token, invalidates the old one.
85
+ *
86
+ * The user keeps their identity (id, name, role).
87
+ * Only the token changes.
88
+ *
89
+ * Returns the user with the new token (shown once), or null if not found.
90
+ */
91
+ regenerateToken(name: string): UserWithToken | null;
92
+ /**
93
+ * Check if a user has a specific permission.
94
+ */
95
+ checkPermission(name: string, permission: Permission): boolean;
96
+ /**
97
+ * Count users. Used by init to determine if initial admin setup is needed.
98
+ */
99
+ count(): number;
100
+ private rowToUser;
101
+ }
102
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/user/user.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,iCAAiC,CAAC;AAI5D;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEvD,eAAO,MAAM,WAAW,EAAE,SAAS,QAAQ,EAA6C,CAAC;AAEzF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,aAAa,GACb,cAAc,GACd,YAAY,GACZ,aAAa,GACb,aAAa,GACb,eAAe,GACf,YAAY,GACZ,aAAa,GACb,cAAc,GACd,cAAc,GACd,eAAe,GACf,WAAW,GACX,YAAY,GACZ,gBAAgB,GAChB,YAAY,CAAC;AAwCjB;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAE7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAEtE;AAID,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI;IACzC,KAAK,EAAE,MAAM,CAAC;CACf;AAcD;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IAIrB,OAAO,CAAC,EAAE;IAHZ,OAAO,CAAC,UAAU,CAAS;gBAGjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAC7B,UAAU,EAAE,MAAM;IAKpB;;;;OAIG;IACH,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,GAAG,aAAa;IAsC5D;;OAEG;IACH,IAAI,IAAI,IAAI,EAAE;IAMd;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAOpC;;;;OAIG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IASzC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK7B;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI;IAqB1D;;;;;;;OAOG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IA6BnD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO;IAM9D;;OAEG;IACH,KAAK,IAAI,MAAM;IAOf,OAAO,CAAC,SAAS;CAUlB"}