@actsecurity/iam-lens 0.1.156

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 (383) hide show
  1. package/LICENSE.txt +661 -0
  2. package/README.md +203 -0
  3. package/dist/cjs/cli.d.ts +3 -0
  4. package/dist/cjs/cli.d.ts.map +1 -0
  5. package/dist/cjs/cli.js +206 -0
  6. package/dist/cjs/cli.js.map +1 -0
  7. package/dist/cjs/collect/client.d.ts +550 -0
  8. package/dist/cjs/collect/client.d.ts.map +1 -0
  9. package/dist/cjs/collect/client.js +1119 -0
  10. package/dist/cjs/collect/client.js.map +1 -0
  11. package/dist/cjs/collect/collect.d.ts +44 -0
  12. package/dist/cjs/collect/collect.d.ts.map +1 -0
  13. package/dist/cjs/collect/collect.js +55 -0
  14. package/dist/cjs/collect/collect.js.map +1 -0
  15. package/dist/cjs/collect/inMemoryClient.d.ts +6 -0
  16. package/dist/cjs/collect/inMemoryClient.d.ts.map +1 -0
  17. package/dist/cjs/collect/inMemoryClient.js +11 -0
  18. package/dist/cjs/collect/inMemoryClient.js.map +1 -0
  19. package/dist/cjs/index.d.ts +13 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +28 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/package.json +3 -0
  24. package/dist/cjs/principalCan/permission.d.ts +125 -0
  25. package/dist/cjs/principalCan/permission.d.ts.map +1 -0
  26. package/dist/cjs/principalCan/permission.js +1229 -0
  27. package/dist/cjs/principalCan/permission.js.map +1 -0
  28. package/dist/cjs/principalCan/permissionSet.d.ts +140 -0
  29. package/dist/cjs/principalCan/permissionSet.d.ts.map +1 -0
  30. package/dist/cjs/principalCan/permissionSet.js +437 -0
  31. package/dist/cjs/principalCan/permissionSet.js.map +1 -0
  32. package/dist/cjs/principalCan/principalCan.d.ts +26 -0
  33. package/dist/cjs/principalCan/principalCan.d.ts.map +1 -0
  34. package/dist/cjs/principalCan/principalCan.js +195 -0
  35. package/dist/cjs/principalCan/principalCan.js.map +1 -0
  36. package/dist/cjs/principalCan/principalConstraints.d.ts +147 -0
  37. package/dist/cjs/principalCan/principalConstraints.d.ts.map +1 -0
  38. package/dist/cjs/principalCan/principalConstraints.js +472 -0
  39. package/dist/cjs/principalCan/principalConstraints.js.map +1 -0
  40. package/dist/cjs/principalCan/resources/actions.d.ts +9 -0
  41. package/dist/cjs/principalCan/resources/actions.d.ts.map +1 -0
  42. package/dist/cjs/principalCan/resources/actions.js +27 -0
  43. package/dist/cjs/principalCan/resources/actions.js.map +1 -0
  44. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.d.ts +31 -0
  45. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.d.ts.map +1 -0
  46. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.js +114 -0
  47. package/dist/cjs/principalCan/resources/resourceTypes/iamRoles.js.map +1 -0
  48. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.d.ts +30 -0
  49. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.d.ts.map +1 -0
  50. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.js +110 -0
  51. package/dist/cjs/principalCan/resources/resourceTypes/kmsKeys.js.map +1 -0
  52. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.d.ts +18 -0
  53. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.d.ts.map +1 -0
  54. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.js +123 -0
  55. package/dist/cjs/principalCan/resources/resourceTypes/s3Buckets.js.map +1 -0
  56. package/dist/cjs/principalCan/resources/statements.d.ts +27 -0
  57. package/dist/cjs/principalCan/resources/statements.d.ts.map +1 -0
  58. package/dist/cjs/principalCan/resources/statements.js +119 -0
  59. package/dist/cjs/principalCan/resources/statements.js.map +1 -0
  60. package/dist/cjs/principalIndex/makePrincipalIndex.d.ts +8 -0
  61. package/dist/cjs/principalIndex/makePrincipalIndex.d.ts.map +1 -0
  62. package/dist/cjs/principalIndex/makePrincipalIndex.js +105 -0
  63. package/dist/cjs/principalIndex/makePrincipalIndex.js.map +1 -0
  64. package/dist/cjs/principals.d.ts +54 -0
  65. package/dist/cjs/principals.d.ts.map +1 -0
  66. package/dist/cjs/principals.js +143 -0
  67. package/dist/cjs/principals.js.map +1 -0
  68. package/dist/cjs/resources.d.ts +32 -0
  69. package/dist/cjs/resources.d.ts.map +1 -0
  70. package/dist/cjs/resources.js +71 -0
  71. package/dist/cjs/resources.js.map +1 -0
  72. package/dist/cjs/simulate/contextKeys.d.ts +68 -0
  73. package/dist/cjs/simulate/contextKeys.d.ts.map +1 -0
  74. package/dist/cjs/simulate/contextKeys.js +293 -0
  75. package/dist/cjs/simulate/contextKeys.js.map +1 -0
  76. package/dist/cjs/simulate/simulate.d.ts +72 -0
  77. package/dist/cjs/simulate/simulate.d.ts.map +1 -0
  78. package/dist/cjs/simulate/simulate.js +296 -0
  79. package/dist/cjs/simulate/simulate.js.map +1 -0
  80. package/dist/cjs/test-datasets/testClient.d.ts +17 -0
  81. package/dist/cjs/test-datasets/testClient.d.ts.map +1 -0
  82. package/dist/cjs/test-datasets/testClient.js +58 -0
  83. package/dist/cjs/test-datasets/testClient.js.map +1 -0
  84. package/dist/cjs/utils/arn.d.ts +22 -0
  85. package/dist/cjs/utils/arn.d.ts.map +1 -0
  86. package/dist/cjs/utils/arn.js +49 -0
  87. package/dist/cjs/utils/arn.js.map +1 -0
  88. package/dist/cjs/utils/bitset.d.ts +45 -0
  89. package/dist/cjs/utils/bitset.d.ts.map +1 -0
  90. package/dist/cjs/utils/bitset.js +149 -0
  91. package/dist/cjs/utils/bitset.js.map +1 -0
  92. package/dist/cjs/utils/dynamicImport.d.ts +31 -0
  93. package/dist/cjs/utils/dynamicImport.d.ts.map +1 -0
  94. package/dist/cjs/utils/dynamicImport.js +64 -0
  95. package/dist/cjs/utils/dynamicImport.js.map +1 -0
  96. package/dist/cjs/utils/packageVersion.d.ts +5 -0
  97. package/dist/cjs/utils/packageVersion.d.ts.map +1 -0
  98. package/dist/cjs/utils/packageVersion.js +25 -0
  99. package/dist/cjs/utils/packageVersion.js.map +1 -0
  100. package/dist/cjs/utils/readPackageFile.d.ts +3 -0
  101. package/dist/cjs/utils/readPackageFile.d.ts.map +1 -0
  102. package/dist/cjs/utils/readPackageFile.js +16 -0
  103. package/dist/cjs/utils/readPackageFile.js.map +1 -0
  104. package/dist/cjs/utils/s3Abac.d.ts +3 -0
  105. package/dist/cjs/utils/s3Abac.d.ts.map +1 -0
  106. package/dist/cjs/utils/s3Abac.js +5 -0
  107. package/dist/cjs/utils/s3Abac.js.map +1 -0
  108. package/dist/cjs/utils/stringOrFileArgument.d.ts +9 -0
  109. package/dist/cjs/utils/stringOrFileArgument.d.ts.map +1 -0
  110. package/dist/cjs/utils/stringOrFileArgument.js +25 -0
  111. package/dist/cjs/utils/stringOrFileArgument.js.map +1 -0
  112. package/dist/cjs/utils/sts.d.ts +2 -0
  113. package/dist/cjs/utils/sts.d.ts.map +1 -0
  114. package/dist/cjs/utils/sts.js +9 -0
  115. package/dist/cjs/utils/sts.js.map +1 -0
  116. package/dist/cjs/utils/testUtils.d.ts +56 -0
  117. package/dist/cjs/utils/testUtils.d.ts.map +1 -0
  118. package/dist/cjs/utils/testUtils.js +95 -0
  119. package/dist/cjs/utils/testUtils.js.map +1 -0
  120. package/dist/cjs/utils/workerScript.d.ts +8 -0
  121. package/dist/cjs/utils/workerScript.d.ts.map +1 -0
  122. package/dist/cjs/utils/workerScript.js +23 -0
  123. package/dist/cjs/utils/workerScript.js.map +1 -0
  124. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts +73 -0
  125. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
  126. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js +80 -0
  127. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js.map +1 -0
  128. package/dist/cjs/whoCan/WhoCanProcessor.d.ts +400 -0
  129. package/dist/cjs/whoCan/WhoCanProcessor.d.ts.map +1 -0
  130. package/dist/cjs/whoCan/WhoCanProcessor.js +1088 -0
  131. package/dist/cjs/whoCan/WhoCanProcessor.js.map +1 -0
  132. package/dist/cjs/whoCan/WhoCanWorker.d.ts +87 -0
  133. package/dist/cjs/whoCan/WhoCanWorker.d.ts.map +1 -0
  134. package/dist/cjs/whoCan/WhoCanWorker.js +201 -0
  135. package/dist/cjs/whoCan/WhoCanWorker.js.map +1 -0
  136. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
  137. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
  138. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js +189 -0
  139. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
  140. package/dist/cjs/whoCan/principalArnFilter.d.ts +84 -0
  141. package/dist/cjs/whoCan/principalArnFilter.d.ts.map +1 -0
  142. package/dist/cjs/whoCan/principalArnFilter.js +258 -0
  143. package/dist/cjs/whoCan/principalArnFilter.js.map +1 -0
  144. package/dist/cjs/whoCan/principalScope.d.ts +35 -0
  145. package/dist/cjs/whoCan/principalScope.d.ts.map +1 -0
  146. package/dist/cjs/whoCan/principalScope.js +104 -0
  147. package/dist/cjs/whoCan/principalScope.js.map +1 -0
  148. package/dist/cjs/whoCan/requestAnalysis.d.ts +73 -0
  149. package/dist/cjs/whoCan/requestAnalysis.d.ts.map +1 -0
  150. package/dist/cjs/whoCan/requestAnalysis.js +87 -0
  151. package/dist/cjs/whoCan/requestAnalysis.js.map +1 -0
  152. package/dist/cjs/whoCan/untrustingActions.d.ts +7 -0
  153. package/dist/cjs/whoCan/untrustingActions.d.ts.map +1 -0
  154. package/dist/cjs/whoCan/untrustingActions.js +30 -0
  155. package/dist/cjs/whoCan/untrustingActions.js.map +1 -0
  156. package/dist/cjs/whoCan/whoCan.d.ts +295 -0
  157. package/dist/cjs/whoCan/whoCan.d.ts.map +1 -0
  158. package/dist/cjs/whoCan/whoCan.js +574 -0
  159. package/dist/cjs/whoCan/whoCan.js.map +1 -0
  160. package/dist/cjs/whoCan/workerBootstrapPlugin.d.ts +17 -0
  161. package/dist/cjs/whoCan/workerBootstrapPlugin.d.ts.map +1 -0
  162. package/dist/cjs/whoCan/workerBootstrapPlugin.js +3 -0
  163. package/dist/cjs/whoCan/workerBootstrapPlugin.js.map +1 -0
  164. package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts +15 -0
  165. package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
  166. package/dist/cjs/workers/ArrayStreamingWorkQueue.js +35 -0
  167. package/dist/cjs/workers/ArrayStreamingWorkQueue.js.map +1 -0
  168. package/dist/cjs/workers/JobRunner.d.ts +47 -0
  169. package/dist/cjs/workers/JobRunner.d.ts.map +1 -0
  170. package/dist/cjs/workers/JobRunner.js +101 -0
  171. package/dist/cjs/workers/JobRunner.js.map +1 -0
  172. package/dist/cjs/workers/RingQueue.d.ts +14 -0
  173. package/dist/cjs/workers/RingQueue.d.ts.map +1 -0
  174. package/dist/cjs/workers/RingQueue.js +43 -0
  175. package/dist/cjs/workers/RingQueue.js.map +1 -0
  176. package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts +10 -0
  177. package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
  178. package/dist/cjs/workers/SharedArrayBufferMainCache.js +37 -0
  179. package/dist/cjs/workers/SharedArrayBufferMainCache.js.map +1 -0
  180. package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
  181. package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
  182. package/dist/cjs/workers/SharedArrayBufferWorkerCache.js +49 -0
  183. package/dist/cjs/workers/SharedArrayBufferWorkerCache.js.map +1 -0
  184. package/dist/cjs/workers/StreamingWorkQueue.d.ts +18 -0
  185. package/dist/cjs/workers/StreamingWorkQueue.d.ts.map +1 -0
  186. package/dist/cjs/workers/StreamingWorkQueue.js +67 -0
  187. package/dist/cjs/workers/StreamingWorkQueue.js.map +1 -0
  188. package/dist/cjs/workers/buffers.d.ts +4 -0
  189. package/dist/cjs/workers/buffers.d.ts.map +1 -0
  190. package/dist/cjs/workers/buffers.js +26 -0
  191. package/dist/cjs/workers/buffers.js.map +1 -0
  192. package/dist/esm/cli.d.ts +3 -0
  193. package/dist/esm/cli.d.ts.map +1 -0
  194. package/dist/esm/cli.js +204 -0
  195. package/dist/esm/cli.js.map +1 -0
  196. package/dist/esm/collect/client.d.ts +550 -0
  197. package/dist/esm/collect/client.d.ts.map +1 -0
  198. package/dist/esm/collect/client.js +1114 -0
  199. package/dist/esm/collect/client.js.map +1 -0
  200. package/dist/esm/collect/collect.d.ts +44 -0
  201. package/dist/esm/collect/collect.d.ts.map +1 -0
  202. package/dist/esm/collect/collect.js +51 -0
  203. package/dist/esm/collect/collect.js.map +1 -0
  204. package/dist/esm/collect/inMemoryClient.d.ts +6 -0
  205. package/dist/esm/collect/inMemoryClient.d.ts.map +1 -0
  206. package/dist/esm/collect/inMemoryClient.js +8 -0
  207. package/dist/esm/collect/inMemoryClient.js.map +1 -0
  208. package/dist/esm/index.d.ts +13 -0
  209. package/dist/esm/index.d.ts.map +1 -0
  210. package/dist/esm/index.js +11 -0
  211. package/dist/esm/index.js.map +1 -0
  212. package/dist/esm/package.json +3 -0
  213. package/dist/esm/principalCan/permission.d.ts +125 -0
  214. package/dist/esm/principalCan/permission.d.ts.map +1 -0
  215. package/dist/esm/principalCan/permission.js +1212 -0
  216. package/dist/esm/principalCan/permission.js.map +1 -0
  217. package/dist/esm/principalCan/permissionSet.d.ts +140 -0
  218. package/dist/esm/principalCan/permissionSet.d.ts.map +1 -0
  219. package/dist/esm/principalCan/permissionSet.js +429 -0
  220. package/dist/esm/principalCan/permissionSet.js.map +1 -0
  221. package/dist/esm/principalCan/principalCan.d.ts +26 -0
  222. package/dist/esm/principalCan/principalCan.d.ts.map +1 -0
  223. package/dist/esm/principalCan/principalCan.js +193 -0
  224. package/dist/esm/principalCan/principalCan.js.map +1 -0
  225. package/dist/esm/principalCan/principalConstraints.d.ts +147 -0
  226. package/dist/esm/principalCan/principalConstraints.d.ts.map +1 -0
  227. package/dist/esm/principalCan/principalConstraints.js +456 -0
  228. package/dist/esm/principalCan/principalConstraints.js.map +1 -0
  229. package/dist/esm/principalCan/resources/actions.d.ts +9 -0
  230. package/dist/esm/principalCan/resources/actions.d.ts.map +1 -0
  231. package/dist/esm/principalCan/resources/actions.js +24 -0
  232. package/dist/esm/principalCan/resources/actions.js.map +1 -0
  233. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.d.ts +31 -0
  234. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.d.ts.map +1 -0
  235. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.js +110 -0
  236. package/dist/esm/principalCan/resources/resourceTypes/iamRoles.js.map +1 -0
  237. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.d.ts +30 -0
  238. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.d.ts.map +1 -0
  239. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.js +106 -0
  240. package/dist/esm/principalCan/resources/resourceTypes/kmsKeys.js.map +1 -0
  241. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.d.ts +18 -0
  242. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.d.ts.map +1 -0
  243. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.js +120 -0
  244. package/dist/esm/principalCan/resources/resourceTypes/s3Buckets.js.map +1 -0
  245. package/dist/esm/principalCan/resources/statements.d.ts +27 -0
  246. package/dist/esm/principalCan/resources/statements.d.ts.map +1 -0
  247. package/dist/esm/principalCan/resources/statements.js +117 -0
  248. package/dist/esm/principalCan/resources/statements.js.map +1 -0
  249. package/dist/esm/principalIndex/makePrincipalIndex.d.ts +8 -0
  250. package/dist/esm/principalIndex/makePrincipalIndex.d.ts.map +1 -0
  251. package/dist/esm/principalIndex/makePrincipalIndex.js +104 -0
  252. package/dist/esm/principalIndex/makePrincipalIndex.js.map +1 -0
  253. package/dist/esm/principals.d.ts +54 -0
  254. package/dist/esm/principals.d.ts.map +1 -0
  255. package/dist/esm/principals.js +133 -0
  256. package/dist/esm/principals.js.map +1 -0
  257. package/dist/esm/resources.d.ts +32 -0
  258. package/dist/esm/resources.d.ts.map +1 -0
  259. package/dist/esm/resources.js +69 -0
  260. package/dist/esm/resources.js.map +1 -0
  261. package/dist/esm/simulate/contextKeys.d.ts +68 -0
  262. package/dist/esm/simulate/contextKeys.d.ts.map +1 -0
  263. package/dist/esm/simulate/contextKeys.js +287 -0
  264. package/dist/esm/simulate/contextKeys.js.map +1 -0
  265. package/dist/esm/simulate/simulate.d.ts +72 -0
  266. package/dist/esm/simulate/simulate.d.ts.map +1 -0
  267. package/dist/esm/simulate/simulate.js +295 -0
  268. package/dist/esm/simulate/simulate.js.map +1 -0
  269. package/dist/esm/test-datasets/testClient.d.ts +17 -0
  270. package/dist/esm/test-datasets/testClient.d.ts.map +1 -0
  271. package/dist/esm/test-datasets/testClient.js +56 -0
  272. package/dist/esm/test-datasets/testClient.js.map +1 -0
  273. package/dist/esm/utils/arn.d.ts +22 -0
  274. package/dist/esm/utils/arn.d.ts.map +1 -0
  275. package/dist/esm/utils/arn.js +43 -0
  276. package/dist/esm/utils/arn.js.map +1 -0
  277. package/dist/esm/utils/bitset.d.ts +45 -0
  278. package/dist/esm/utils/bitset.d.ts.map +1 -0
  279. package/dist/esm/utils/bitset.js +141 -0
  280. package/dist/esm/utils/bitset.js.map +1 -0
  281. package/dist/esm/utils/dynamicImport.d.ts +31 -0
  282. package/dist/esm/utils/dynamicImport.d.ts.map +1 -0
  283. package/dist/esm/utils/dynamicImport.js +60 -0
  284. package/dist/esm/utils/dynamicImport.js.map +1 -0
  285. package/dist/esm/utils/packageVersion.d.ts +5 -0
  286. package/dist/esm/utils/packageVersion.d.ts.map +1 -0
  287. package/dist/esm/utils/packageVersion.js +22 -0
  288. package/dist/esm/utils/packageVersion.js.map +1 -0
  289. package/dist/esm/utils/readPackageFile.d.ts +3 -0
  290. package/dist/esm/utils/readPackageFile.d.ts.map +1 -0
  291. package/dist/esm/utils/readPackageFile.js +15 -0
  292. package/dist/esm/utils/readPackageFile.js.map +1 -0
  293. package/dist/esm/utils/readPackageFileEsm.d.ts.map +1 -0
  294. package/dist/esm/utils/s3Abac.d.ts +3 -0
  295. package/dist/esm/utils/s3Abac.d.ts.map +1 -0
  296. package/dist/esm/utils/s3Abac.js +2 -0
  297. package/dist/esm/utils/s3Abac.js.map +1 -0
  298. package/dist/esm/utils/stringOrFileArgument.d.ts +9 -0
  299. package/dist/esm/utils/stringOrFileArgument.d.ts.map +1 -0
  300. package/dist/esm/utils/stringOrFileArgument.js +22 -0
  301. package/dist/esm/utils/stringOrFileArgument.js.map +1 -0
  302. package/dist/esm/utils/sts.d.ts +2 -0
  303. package/dist/esm/utils/sts.d.ts.map +1 -0
  304. package/dist/esm/utils/sts.js +6 -0
  305. package/dist/esm/utils/sts.js.map +1 -0
  306. package/dist/esm/utils/testUtils.d.ts +56 -0
  307. package/dist/esm/utils/testUtils.d.ts.map +1 -0
  308. package/dist/esm/utils/testUtils.js +90 -0
  309. package/dist/esm/utils/testUtils.js.map +1 -0
  310. package/dist/esm/utils/workerScript.d.ts +8 -0
  311. package/dist/esm/utils/workerScript.d.ts.map +1 -0
  312. package/dist/esm/utils/workerScript.js +18 -0
  313. package/dist/esm/utils/workerScript.js.map +1 -0
  314. package/dist/esm/utils/workerScriptEsm.d.ts.map +1 -0
  315. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts +73 -0
  316. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
  317. package/dist/esm/whoCan/WhoCanMainThreadWorker.js +81 -0
  318. package/dist/esm/whoCan/WhoCanMainThreadWorker.js.map +1 -0
  319. package/dist/esm/whoCan/WhoCanProcessor.d.ts +400 -0
  320. package/dist/esm/whoCan/WhoCanProcessor.d.ts.map +1 -0
  321. package/dist/esm/whoCan/WhoCanProcessor.js +1080 -0
  322. package/dist/esm/whoCan/WhoCanProcessor.js.map +1 -0
  323. package/dist/esm/whoCan/WhoCanWorker.d.ts +87 -0
  324. package/dist/esm/whoCan/WhoCanWorker.d.ts.map +1 -0
  325. package/dist/esm/whoCan/WhoCanWorker.js +198 -0
  326. package/dist/esm/whoCan/WhoCanWorker.js.map +1 -0
  327. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
  328. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
  329. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js +193 -0
  330. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
  331. package/dist/esm/whoCan/principalArnFilter.d.ts +84 -0
  332. package/dist/esm/whoCan/principalArnFilter.d.ts.map +1 -0
  333. package/dist/esm/whoCan/principalArnFilter.js +253 -0
  334. package/dist/esm/whoCan/principalArnFilter.js.map +1 -0
  335. package/dist/esm/whoCan/principalScope.d.ts +35 -0
  336. package/dist/esm/whoCan/principalScope.d.ts.map +1 -0
  337. package/dist/esm/whoCan/principalScope.js +102 -0
  338. package/dist/esm/whoCan/principalScope.js.map +1 -0
  339. package/dist/esm/whoCan/requestAnalysis.d.ts +73 -0
  340. package/dist/esm/whoCan/requestAnalysis.d.ts.map +1 -0
  341. package/dist/esm/whoCan/requestAnalysis.js +83 -0
  342. package/dist/esm/whoCan/requestAnalysis.js.map +1 -0
  343. package/dist/esm/whoCan/untrustingActions.d.ts +7 -0
  344. package/dist/esm/whoCan/untrustingActions.d.ts.map +1 -0
  345. package/dist/esm/whoCan/untrustingActions.js +27 -0
  346. package/dist/esm/whoCan/untrustingActions.js.map +1 -0
  347. package/dist/esm/whoCan/whoCan.d.ts +295 -0
  348. package/dist/esm/whoCan/whoCan.d.ts.map +1 -0
  349. package/dist/esm/whoCan/whoCan.js +571 -0
  350. package/dist/esm/whoCan/whoCan.js.map +1 -0
  351. package/dist/esm/whoCan/workerBootstrapPlugin.d.ts +17 -0
  352. package/dist/esm/whoCan/workerBootstrapPlugin.d.ts.map +1 -0
  353. package/dist/esm/whoCan/workerBootstrapPlugin.js +2 -0
  354. package/dist/esm/whoCan/workerBootstrapPlugin.js.map +1 -0
  355. package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts +15 -0
  356. package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
  357. package/dist/esm/workers/ArrayStreamingWorkQueue.js +31 -0
  358. package/dist/esm/workers/ArrayStreamingWorkQueue.js.map +1 -0
  359. package/dist/esm/workers/JobRunner.d.ts +47 -0
  360. package/dist/esm/workers/JobRunner.d.ts.map +1 -0
  361. package/dist/esm/workers/JobRunner.js +94 -0
  362. package/dist/esm/workers/JobRunner.js.map +1 -0
  363. package/dist/esm/workers/RingQueue.d.ts +14 -0
  364. package/dist/esm/workers/RingQueue.d.ts.map +1 -0
  365. package/dist/esm/workers/RingQueue.js +36 -0
  366. package/dist/esm/workers/RingQueue.js.map +1 -0
  367. package/dist/esm/workers/SharedArrayBufferMainCache.d.ts +10 -0
  368. package/dist/esm/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
  369. package/dist/esm/workers/SharedArrayBufferMainCache.js +34 -0
  370. package/dist/esm/workers/SharedArrayBufferMainCache.js.map +1 -0
  371. package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
  372. package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
  373. package/dist/esm/workers/SharedArrayBufferWorkerCache.js +46 -0
  374. package/dist/esm/workers/SharedArrayBufferWorkerCache.js.map +1 -0
  375. package/dist/esm/workers/StreamingWorkQueue.d.ts +18 -0
  376. package/dist/esm/workers/StreamingWorkQueue.d.ts.map +1 -0
  377. package/dist/esm/workers/StreamingWorkQueue.js +61 -0
  378. package/dist/esm/workers/StreamingWorkQueue.js.map +1 -0
  379. package/dist/esm/workers/buffers.d.ts +4 -0
  380. package/dist/esm/workers/buffers.d.ts.map +1 -0
  381. package/dist/esm/workers/buffers.js +21 -0
  382. package/dist/esm/workers/buffers.js.map +1 -0
  383. package/package.json +132 -0
@@ -0,0 +1,1229 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Permission = void 0;
4
+ exports.unionConditions = unionConditions;
5
+ exports.intersectConditions = intersectConditions;
6
+ exports.normalizeConditionKeys = normalizeConditionKeys;
7
+ exports.invertConditions = invertConditions;
8
+ exports.applyDenyConditionsToAllow = applyDenyConditionsToAllow;
9
+ const principalConstraints_js_1 = require("./principalConstraints.js");
10
+ /**
11
+ * Convert an AWS wildcard ARN pattern (e.g. "arn:aws:s3:::bucket/*") into a RegExp.
12
+ */
13
+ function wildcardToRegex(pattern) {
14
+ const parts = pattern.split('*').map((s) => s.replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&'));
15
+ return new RegExp('^' + parts.join('.*') + '$');
16
+ }
17
+ /**
18
+ * An immutable representation of a single permission for a specific action.
19
+ *
20
+ * This will eventually have methods like "merge with another permission",
21
+ * "check if overlaps with another permission", "subtract a deny permission",
22
+ * etc and those will all return a new Permission instance.
23
+ */
24
+ class Permission {
25
+ effect;
26
+ service;
27
+ action;
28
+ resource;
29
+ notResource;
30
+ conditions;
31
+ principal;
32
+ notPrincipal;
33
+ constructor(effect, service, action, resource, notResource, conditions, principal = undefined, notPrincipal = undefined) {
34
+ this.effect = effect;
35
+ this.service = service;
36
+ this.action = action;
37
+ this.resource = resource;
38
+ this.notResource = notResource;
39
+ this.conditions = conditions;
40
+ this.principal = principal;
41
+ this.notPrincipal = notPrincipal;
42
+ if (resource !== undefined && notResource !== undefined) {
43
+ throw new Error('Permission must have a resource or notResource, not both.');
44
+ }
45
+ else if (resource === undefined && notResource === undefined) {
46
+ throw new Error('Permission must have a resource or notResource, one must be defined.');
47
+ }
48
+ (0, principalConstraints_js_1.normalizePrincipalConstraint)(principal, notPrincipal);
49
+ }
50
+ /**
51
+ * Return this permission's principal constraint normalized for set algebra.
52
+ *
53
+ * @returns The normalized principal constraint.
54
+ */
55
+ principalConstraint() {
56
+ return (0, principalConstraints_js_1.normalizePrincipalConstraint)(this.principal, this.notPrincipal);
57
+ }
58
+ /**
59
+ * Returns true if this Permission completely includes the other Permission.
60
+ * Only supports merging of "Allow" permissions (same effect, service, action).
61
+ */
62
+ includes(other) {
63
+ // 1. Effects, service, and action must match
64
+ if (this.effect !== other.effect ||
65
+ this.service !== other.service ||
66
+ this.action !== other.action) {
67
+ return false;
68
+ }
69
+ if (!(0, principalConstraints_js_1.principalIncludes)(this.principalConstraint(), other.principalConstraint())) {
70
+ return false;
71
+ }
72
+ // 2. Conditions: every condition in this must be implied by the other permission’s conditions
73
+ // That is, for each operator and context key in this.conditions, other.conditions must have it,
74
+ // and the values must satisfy inclusion logic per operator.
75
+ const condsA = normalizeConditionKeys(this.conditions || {});
76
+ const condsB = normalizeConditionKeys(other.conditions || {});
77
+ for (const op of Object.keys(condsA)) {
78
+ if (!(op in condsB))
79
+ return false;
80
+ const keysA = Object.keys(condsA[op]);
81
+ const keysB = Object.keys(condsB[op]);
82
+ // Every key in A must appear in B
83
+ for (const key of keysA) {
84
+ if (!keysB.includes(key))
85
+ return false;
86
+ const valsA = condsA[op][key];
87
+ const valsB = condsB[op][key];
88
+ const baseOp = conditionBaseOperator(op);
89
+ switch (baseOp) {
90
+ case 'stringequals':
91
+ case 'stringlike':
92
+ case 'arnequals':
93
+ case 'arnlike':
94
+ // other must be at least as restrictive: B_vals ⊆ A_vals
95
+ if (!valsB.every((v) => valsA.includes(v)))
96
+ return false;
97
+ break;
98
+ case 'stringnotequals':
99
+ case 'stringnotlike':
100
+ case 'arnnotequals':
101
+ case 'arnnotlike':
102
+ // other must exclude at least what A excludes: A_vals ⊆ B_vals
103
+ if (!valsA.every((v) => valsB.includes(v)))
104
+ return false;
105
+ break;
106
+ case 'numericlessthan':
107
+ case 'numericlessthanequals':
108
+ // other boundary <= this boundary
109
+ const numA = Number(valsA[0]);
110
+ const numB = Number(valsB[0]);
111
+ if (isNaN(numA) || isNaN(numB))
112
+ return false;
113
+ if (numB > numA)
114
+ return false;
115
+ break;
116
+ case 'numericgreaterthan':
117
+ case 'numericgreaterthanequals':
118
+ // other boundary >= this boundary
119
+ const ngA = Number(valsA[0]);
120
+ const ngB = Number(valsB[0]);
121
+ if (isNaN(ngA) || isNaN(ngB))
122
+ return false;
123
+ if (ngB < ngA)
124
+ return false;
125
+ break;
126
+ case 'bool':
127
+ // other must have the same boolean value
128
+ if (valsA[0] !== valsB[0])
129
+ return false;
130
+ break;
131
+ case 'ipaddress':
132
+ case 'notipaddress':
133
+ // every CIDR in B must be contained in some CIDR in A
134
+ for (const cidrB of valsB) {
135
+ if (!valsA.some((cidrA) => cidrA === cidrB)) {
136
+ return false;
137
+ }
138
+ }
139
+ break;
140
+ case 'datelessthan':
141
+ case 'datelessthanequals':
142
+ // other date <= this date lexically (ISO)
143
+ const dA = valsA[0];
144
+ const dB = valsB[0];
145
+ if (dB > dA)
146
+ return false;
147
+ break;
148
+ case 'dategreaterthan':
149
+ case 'dategreaterthanequals':
150
+ // other date >= this date
151
+ const dgA = valsA[0];
152
+ const dgB = valsB[0];
153
+ if (dgB < dgA)
154
+ return false;
155
+ break;
156
+ default:
157
+ return false;
158
+ }
159
+ }
160
+ }
161
+ // 3. Resources / NotResources
162
+ const thisResource = this.resource;
163
+ const thisNotResource = this.notResource;
164
+ const otherResource = other.resource;
165
+ const otherNotResource = other.notResource;
166
+ // 3a. If both have resource[]
167
+ if (thisResource !== undefined && otherResource !== undefined) {
168
+ return otherResource.every((r2) => thisResource.some((r1) => wildcardToRegex(r1).test(r2)));
169
+ }
170
+ // 3b. Both have notResource[]
171
+ if (thisNotResource !== undefined && otherNotResource !== undefined) {
172
+ return thisNotResource.every((n1) => otherNotResource.some((n2) => wildcardToRegex(n1).test(n2)));
173
+ }
174
+ // 3c. A.resource & B.notResource -> B allows almost all, A allows only R1 -> true iff every N2 is matched by some R1
175
+ if (thisResource !== undefined && otherNotResource !== undefined) {
176
+ return otherNotResource.every((n2) => thisResource.some((r1) => wildcardToRegex(r1).test(n2)));
177
+ }
178
+ // 3d. A.notResource & B.resource -> every r2 ∉ N1
179
+ if (thisNotResource !== undefined && otherResource !== undefined) {
180
+ return otherResource.every((r2) => !thisNotResource.some((n1) => wildcardToRegex(n1).test(r2)));
181
+ }
182
+ return false;
183
+ }
184
+ /**
185
+ * Returns the union of this Permission with another.
186
+ * If one includes the other, return the including Permission.
187
+ * Otherwise, attempt to merge conditions and resource/notResource.
188
+ * If merge yields a single Permission, return it; else return both.
189
+ */
190
+ union(other) {
191
+ // 1. Ensure same effect, service, and action
192
+ if (this.effect !== other.effect ||
193
+ this.service !== other.service ||
194
+ this.action !== other.action) {
195
+ return [this, other];
196
+ }
197
+ // 2. If one includes the other, return the including one
198
+ if (this.includes(other)) {
199
+ return [this];
200
+ }
201
+ if (other.includes(this)) {
202
+ return [other];
203
+ }
204
+ // 3. Attempt to combine conditions
205
+ const condsA = this.conditions || {};
206
+ const condsB = other.conditions || {};
207
+ const mergedConds = unionConditions(condsA, condsB);
208
+ if (mergedConds === null) {
209
+ return [this, other];
210
+ }
211
+ const principalUnions = (0, principalConstraints_js_1.unionPrincipalConstraints)(this.principalConstraint(), other.principalConstraint());
212
+ if (principalUnions.length !== 1) {
213
+ return [this, other];
214
+ }
215
+ const principalArgs = (0, principalConstraints_js_1.principalArgsForConstraint)(principalUnions[0]);
216
+ // 4. Combine resource/notResource (constructor enforces exclusivity)
217
+ const thisResource = this.resource;
218
+ const thisNotResource = this.notResource;
219
+ const otherResource = other.resource;
220
+ const otherNotResource = other.notResource;
221
+ const eff = this.effect;
222
+ const svc = this.service;
223
+ const act = this.action;
224
+ const conds = Object.keys(mergedConds).length > 0 ? mergedConds : undefined;
225
+ // Both have resource[]
226
+ if (thisResource !== undefined && otherResource !== undefined) {
227
+ const union = Array.from(new Set([...thisResource, ...otherResource]));
228
+ return [
229
+ new Permission(eff, svc, act, union, undefined, conds, principalArgs.principal, principalArgs.notPrincipal)
230
+ ];
231
+ }
232
+ // Both have notResource[]
233
+ if (thisNotResource !== undefined && otherNotResource !== undefined) {
234
+ // Intersection of both notResource arrays
235
+ const intersection = thisNotResource.filter((n) => otherNotResource.includes(n));
236
+ return [
237
+ new Permission(eff, svc, act, undefined, intersection, conds, principalArgs.principal, principalArgs.notPrincipal)
238
+ ];
239
+ }
240
+ // One has resource, other has notResource
241
+ if (thisResource !== undefined && otherNotResource !== undefined) {
242
+ return [
243
+ new Permission(eff, svc, act, thisResource, undefined, conds, principalArgs.principal, principalArgs.notPrincipal),
244
+ new Permission(eff, svc, act, undefined, otherNotResource, conds, principalArgs.principal, principalArgs.notPrincipal)
245
+ ];
246
+ }
247
+ if (otherResource !== undefined && thisNotResource !== undefined) {
248
+ return [
249
+ new Permission(eff, svc, act, otherResource, undefined, conds, principalArgs.principal, principalArgs.notPrincipal),
250
+ new Permission(eff, svc, act, undefined, thisNotResource, conds, principalArgs.principal, principalArgs.notPrincipal)
251
+ ];
252
+ }
253
+ // Otherwise cannot combine, return both
254
+ return [this, other];
255
+ }
256
+ /**
257
+ * Returns all representable intersections of this Permission with another.
258
+ *
259
+ * @param other The other Permission to intersect with.
260
+ * @returns New Permissions representing the overlap, or an empty array if there is no intersection.
261
+ */
262
+ intersections(other) {
263
+ const principalIntersections = (0, principalConstraints_js_1.intersectPrincipalConstraints)(this.principalConstraint(), other.principalConstraint());
264
+ const results = [];
265
+ for (const principalIntersection of principalIntersections) {
266
+ const principalArgs = (0, principalConstraints_js_1.principalArgsForConstraint)(principalIntersection);
267
+ const permissionWithIntersectionPrincipal = new Permission(this.effect, this.service, this.action, this.resource, this.notResource, this.conditions, principalArgs.principal, principalArgs.notPrincipal);
268
+ const intersection = permissionWithIntersectionPrincipal.intersection(other);
269
+ if (intersection) {
270
+ results.push(intersection);
271
+ }
272
+ }
273
+ return results;
274
+ }
275
+ /**
276
+ * Returns one intersection of this Permission with another.
277
+ *
278
+ * Prefer {@link intersections} when correctness depends on all possible overlaps. This
279
+ * compatibility method returns at most one Permission and may omit additional representable
280
+ * intersections if future principal algebra produces multiple principal residuals.
281
+ *
282
+ * @param other The other Permission to intersect with.
283
+ * @returns A new Permission representing one intersection of other and this, or undefined if there is no intersection.
284
+ */
285
+ intersection(other) {
286
+ // 1. Must match effect, service, and action
287
+ if (this.effect !== other.effect ||
288
+ this.service !== other.service ||
289
+ this.action !== other.action) {
290
+ // No overlap at all—return a "zero-resource" permission
291
+ return undefined;
292
+ }
293
+ const principalIntersections = (0, principalConstraints_js_1.intersectPrincipalConstraints)(this.principalConstraint(), other.principalConstraint());
294
+ if (principalIntersections.length === 0) {
295
+ return undefined;
296
+ }
297
+ const principalArgs = (0, principalConstraints_js_1.principalArgsForConstraint)(principalIntersections[0]);
298
+ if (this.resource != undefined && other.resource != undefined) {
299
+ // 2. If one includes the other, return the narrower one unless both are NotResource
300
+ if (this.includes(other)) {
301
+ return other;
302
+ }
303
+ if (other.includes(this)) {
304
+ return this;
305
+ }
306
+ }
307
+ // 3. Attempt to intersect/merge conditions
308
+ const a = normalizeConditionKeys(this.conditions || {});
309
+ const b = normalizeConditionKeys(other.conditions || {});
310
+ const allOps = Array.from(new Set([...Object.keys(a), ...Object.keys(b)]));
311
+ const intersectedConds = {};
312
+ for (const op of allOps) {
313
+ const condA = a[op] || {};
314
+ const condB = b[op] || {};
315
+ const allKeys = Array.from(new Set([...Object.keys(condA), ...Object.keys(condB)]));
316
+ intersectedConds[op] = {};
317
+ for (const key of allKeys) {
318
+ const valsA = condA[key] || [];
319
+ const valsB = condB[key] || [];
320
+ // If key appears in both, intersect or combine based on operator
321
+ if (key in condA && key in condB) {
322
+ switch (conditionBaseOperator(op)) {
323
+ case 'stringequals':
324
+ case 'stringlike':
325
+ case 'arnequals':
326
+ case 'arnlike': {
327
+ // Intersection of string lists
328
+ const common = valsA.filter((v) => valsB.includes(v));
329
+ if (common.length === 0) {
330
+ return undefined;
331
+ }
332
+ intersectedConds[op][key] = common;
333
+ break;
334
+ }
335
+ case 'stringnotequals':
336
+ case 'stringnotlike':
337
+ case 'arnnotequals':
338
+ case 'arnnotlike': {
339
+ // Union of exclusions
340
+ intersectedConds[op][key] = Array.from(new Set([...valsA, ...valsB]));
341
+ break;
342
+ }
343
+ case 'numericlessthan':
344
+ case 'numericlessthanequals': {
345
+ const numA = Number(valsA[0]);
346
+ const numB = Number(valsB[0]);
347
+ if (isNaN(numA) || isNaN(numB)) {
348
+ return undefined;
349
+ }
350
+ const boundary = Math.min(numA, numB);
351
+ intersectedConds[op][key] = [String(boundary)];
352
+ break;
353
+ }
354
+ case 'numericgreaterthan':
355
+ case 'numericgreaterthanequals': {
356
+ const ngA = Number(valsA[0]);
357
+ const ngB = Number(valsB[0]);
358
+ if (isNaN(ngA) || isNaN(ngB)) {
359
+ return undefined;
360
+ }
361
+ const boundary = Math.max(ngA, ngB);
362
+ intersectedConds[op][key] = [String(boundary)];
363
+ break;
364
+ }
365
+ case 'bool': {
366
+ if (valsA[0] !== valsB[0]) {
367
+ return undefined;
368
+ }
369
+ intersectedConds[op][key] = [valsA[0]];
370
+ break;
371
+ }
372
+ case 'ipaddress':
373
+ case 'notipaddress': {
374
+ const common = valsA.filter((cidr) => valsB.includes(cidr));
375
+ if (common.length === 0) {
376
+ return undefined;
377
+ }
378
+ intersectedConds[op][key] = common;
379
+ break;
380
+ }
381
+ case 'datelessthan':
382
+ case 'datelessthanequals': {
383
+ const dA = valsA[0];
384
+ const dB = valsB[0];
385
+ intersectedConds[op][key] = [dA < dB ? dA : dB];
386
+ break;
387
+ }
388
+ case 'dategreaterthan':
389
+ case 'dategreaterthanequals': {
390
+ const dgA = valsA[0];
391
+ const dgB = valsB[0];
392
+ intersectedConds[op][key] = [dgA > dgB ? dgA : dgB];
393
+ break;
394
+ }
395
+ default:
396
+ return undefined;
397
+ }
398
+ }
399
+ else {
400
+ // Key only in one side: carry it through
401
+ intersectedConds[op][key] = key in condA ? Array.from(valsA) : Array.from(valsB);
402
+ }
403
+ }
404
+ }
405
+ // 4. Combine resource/notResource:
406
+ const thisResource = this.resource;
407
+ const thisNotResource = this.notResource;
408
+ const otherResource = other.resource;
409
+ const otherNotResource = other.notResource;
410
+ const eff = this.effect;
411
+ const svc = this.service;
412
+ const act = this.action;
413
+ const conds = Object.keys(intersectedConds).length > 0 ? intersectedConds : undefined;
414
+ // Both have resource[] => intersect patterns
415
+ if (thisResource !== undefined && otherResource !== undefined) {
416
+ // Keep any R1 that matches something in R2, and any R2 that matches something in R1
417
+ const part1 = thisResource.filter((r1) => otherResource.some((r2) => wildcardToRegex(r2).test(r1)));
418
+ const part2 = otherResource.filter((r2) => thisResource.some((r1) => wildcardToRegex(r1).test(r2)));
419
+ const intersectR = Array.from(new Set([...part1, ...part2]));
420
+ if (intersectR.length === 0) {
421
+ return undefined;
422
+ }
423
+ return new Permission(eff, svc, act, intersectR, undefined, conds, principalArgs.principal, principalArgs.notPrincipal);
424
+ }
425
+ // Both have notResource[] => union of exclusions (more restrictive), but remove subsumed patterns
426
+ if (thisNotResource !== undefined && otherNotResource !== undefined) {
427
+ // Compute union of both exclusion lists
428
+ const combined = Array.from(new Set([...thisNotResource, ...otherNotResource]));
429
+ // Remove any pattern that is subsumed by a more general pattern
430
+ const filtered = combined.filter((pat) => !combined.some((otherPat) => otherPat !== pat && wildcardToRegex(otherPat).test(pat)));
431
+ return new Permission(eff, svc, act, undefined, filtered, conds, principalArgs.principal, principalArgs.notPrincipal);
432
+ }
433
+ // One has resource, other has notResource
434
+ const resource = thisResource || otherResource;
435
+ const notResource = thisNotResource || otherNotResource;
436
+ if (resource !== undefined || notResource !== undefined) {
437
+ const filtered = resource.filter((r1) => !notResource.some((n2) => wildcardToRegex(n2).test(r1)));
438
+ if (filtered.length === 0) {
439
+ return undefined;
440
+ }
441
+ return new Permission(eff, svc, act, filtered, undefined, conds, principalArgs.principal, principalArgs.notPrincipal);
442
+ }
443
+ // This should never happen
444
+ return undefined;
445
+ }
446
+ /**
447
+ * Subtract a Deny permission from this Allow permission.
448
+ *
449
+ * Returns the resulting permissions, this can be:
450
+ * - An empty array if the Allow is fully denied by the Deny
451
+ * - A modified Allow permission or multiple Allow permissions
452
+ * - It could also return the original Allow and Deny permission if subtraction cannot be expressed purely in Allow statements
453
+ *
454
+ * @param other the Deny permission to subtract
455
+ */
456
+ subtract(other) {
457
+ // Only subtract Deny from Allow for the same service/action
458
+ if (this.effect !== 'Allow' ||
459
+ other.effect !== 'Deny' ||
460
+ this.service !== other.service ||
461
+ this.action !== other.action) {
462
+ // No subtraction applies
463
+ return [this];
464
+ }
465
+ const allowCondsNorm = normalizeConditionKeys(this.conditions || {});
466
+ const denyCondsNorm = normalizeConditionKeys(other.conditions || {});
467
+ const conditionsMatch = JSON.stringify(allowCondsNorm) === JSON.stringify(denyCondsNorm);
468
+ const allowPrincipalConstraint = this.principalConstraint();
469
+ const denyPrincipalConstraint = other.principalConstraint();
470
+ if (!(0, principalConstraints_js_1.principalConstraintsOverlap)(allowPrincipalConstraint, denyPrincipalConstraint)) {
471
+ return [this];
472
+ }
473
+ const allowResource = this.resource;
474
+ const allowNotResource = this.notResource;
475
+ const denyResource = other.resource;
476
+ const denyNotResource = other.notResource;
477
+ const eff = this.effect;
478
+ const svc = this.service;
479
+ const act = this.action;
480
+ const principalResiduals = (0, principalConstraints_js_1.subtractPrincipalConstraint)(allowPrincipalConstraint, denyPrincipalConstraint);
481
+ const sameResourceShape = JSON.stringify([...(allowResource ?? [])].sort()) ===
482
+ JSON.stringify([...(denyResource ?? [])].sort()) &&
483
+ JSON.stringify([...(allowNotResource ?? [])].sort()) ===
484
+ JSON.stringify([...(denyNotResource ?? [])].sort());
485
+ const denyFullyCoversPrincipal = (0, principalConstraints_js_1.principalIncludes)(denyPrincipalConstraint, allowPrincipalConstraint);
486
+ const allowPrincipalArgs = (0, principalConstraints_js_1.principalArgsForConstraint)(allowPrincipalConstraint);
487
+ const denyPrincipalArgs = (0, principalConstraints_js_1.principalArgsForConstraint)(denyPrincipalConstraint);
488
+ if (!denyFullyCoversPrincipal && sameResourceShape && conditionsMatch) {
489
+ const principalResidualsEqualAllow = principalResiduals.length === 1 &&
490
+ JSON.stringify((0, principalConstraints_js_1.principalArgsForConstraint)(principalResiduals[0])) ===
491
+ JSON.stringify(allowPrincipalArgs);
492
+ if (principalResidualsEqualAllow) {
493
+ return [this, other];
494
+ }
495
+ return principalResiduals.map((constraint) => {
496
+ const args = (0, principalConstraints_js_1.principalArgsForConstraint)(constraint);
497
+ return new Permission(eff, svc, act, allowResource, allowNotResource, this.conditions, args.principal, args.notPrincipal);
498
+ });
499
+ }
500
+ if (!denyFullyCoversPrincipal) {
501
+ return [this, other];
502
+ }
503
+ // Case: Allow.resource & Deny.resource
504
+ if (allowResource !== undefined && denyResource !== undefined) {
505
+ const overlappingResources = allowResource.some((a) => {
506
+ return denyResource.some((d) => {
507
+ return wildcardToRegex(d).test(a) || wildcardToRegex(a).test(d);
508
+ });
509
+ });
510
+ // If the resources in the allow and deny do not overlap, return the allow as is
511
+ if (!overlappingResources) {
512
+ return [this];
513
+ }
514
+ // Categories for allows, a single allow could be more than one, because the deny could have multiple
515
+ // Without Conditions:
516
+ //1. Exactly the same as a deny - remove the allow
517
+ //2. A subset of a deny - remove the allow
518
+ //3. A superset of a deny - keep the allow and the deny
519
+ //4. No overlap with any deny - keep the allow as is
520
+ //
521
+ // With Conditions:
522
+ //1. Exactly the same as a deny - invert the conditions and keep the allow
523
+ //2. A subset of a deny - invert the conditions and keep the allow
524
+ //3. A superset of a deny - keep the allow and the deny
525
+ //4. No overlap with any deny - keep the allow as is
526
+ const allowMatches = [];
527
+ const allowSubsets = [];
528
+ const allowSupersets = [];
529
+ const allowNoOverlap = [];
530
+ const denySubsets = [];
531
+ for (const allowedResource of allowResource) {
532
+ let isMatch = false;
533
+ let isSubset = false;
534
+ let isSuperset = false;
535
+ for (const deniedResource of denyResource) {
536
+ if (deniedResource === allowedResource) {
537
+ isMatch = true;
538
+ break;
539
+ }
540
+ if (wildcardToRegex(deniedResource).test(allowedResource)) {
541
+ isSubset = true;
542
+ break;
543
+ }
544
+ if (wildcardToRegex(allowedResource).test(deniedResource)) {
545
+ isSuperset = true;
546
+ denySubsets.push(deniedResource);
547
+ }
548
+ }
549
+ if (isMatch) {
550
+ allowMatches.push(allowedResource);
551
+ }
552
+ else if (isSubset) {
553
+ allowSubsets.push(allowedResource);
554
+ }
555
+ else if (isSuperset) {
556
+ allowSupersets.push(allowedResource);
557
+ }
558
+ else {
559
+ allowNoOverlap.push(allowedResource);
560
+ }
561
+ }
562
+ const permissionsToReturn = [];
563
+ if (allowNoOverlap.length > 0) {
564
+ permissionsToReturn.push(new Permission(eff, svc, act, allowNoOverlap, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
565
+ }
566
+ if (allowSupersets.length > 0) {
567
+ permissionsToReturn.push(new Permission(eff, svc, act, allowSupersets, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
568
+ }
569
+ if (allowMatches.length > 0 || allowSubsets.length > 0) {
570
+ // If conditions are identical, these are fully dropped from the Allow. If not, they need to be kept with inverted conditions
571
+ if (!conditionsMatch) {
572
+ const newAllow = new Permission(eff, svc, act, [...allowMatches, ...allowSubsets], undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal);
573
+ permissionsToReturn.push(...applyDenyConditionsToAllow(newAllow, other));
574
+ }
575
+ }
576
+ if (denySubsets.length > 0) {
577
+ permissionsToReturn.push(new Permission('Deny', svc, act, denySubsets, undefined, other.conditions, denyPrincipalArgs.principal, denyPrincipalArgs.notPrincipal));
578
+ }
579
+ return permissionsToReturn;
580
+ }
581
+ // Case: Allow.resource & Deny.notResource
582
+ // =======================================================================
583
+ // SEMANTICS:
584
+ // Deny.notResource means: "deny everything EXCEPT these patterns"
585
+ // So the deny APPLIES to resources that do NOT match denyNotResource patterns
586
+ // And the deny does NOT apply to resources that DO match denyNotResource patterns
587
+ // =======================================================================
588
+ if (allowResource !== undefined && denyNotResource !== undefined) {
589
+ // STEP 1: Categorize each allow resource based on relationship to denyNotResource patterns
590
+ //
591
+ // Categories:
592
+ // ExcludedFromDeny - Matches a denyNotResource pattern (deny doesn't apply to these)
593
+ // AffectedByDeny - Does NOT match any denyNotResource (deny applies to these)
594
+ // Superset - Covers (is broader than) a denyNotResource pattern
595
+ //
596
+ // Also track which denyNotResource patterns are covered by superset allow resources
597
+ const excludedFromDeny = [];
598
+ const affectedByDeny = [];
599
+ const supersets = [];
600
+ const coveredDenyNotResourcePatterns = [];
601
+ for (const allowedResource of allowResource) {
602
+ let isExcluded = false;
603
+ let isSuperset = false;
604
+ for (const deniedNotResource of denyNotResource) {
605
+ // Check if allowResource exactly matches or is covered by denyNotResource pattern
606
+ if (allowedResource === deniedNotResource ||
607
+ wildcardToRegex(deniedNotResource).test(allowedResource)) {
608
+ isExcluded = true;
609
+ break;
610
+ }
611
+ // Check if allowResource covers (is broader than) denyNotResource pattern
612
+ if (wildcardToRegex(allowedResource).test(deniedNotResource)) {
613
+ isSuperset = true;
614
+ if (!coveredDenyNotResourcePatterns.includes(deniedNotResource)) {
615
+ coveredDenyNotResourcePatterns.push(deniedNotResource);
616
+ }
617
+ }
618
+ }
619
+ if (isExcluded) {
620
+ excludedFromDeny.push(allowedResource);
621
+ }
622
+ else if (isSuperset) {
623
+ supersets.push(allowedResource);
624
+ }
625
+ else {
626
+ affectedByDeny.push(allowedResource);
627
+ }
628
+ }
629
+ // STEP 2: Early exit - if all allow resources are excluded from deny, return unchanged
630
+ if (excludedFromDeny.length === allowResource.length) {
631
+ return [this];
632
+ }
633
+ const denyHasConditions = other.conditions && Object.keys(other.conditions).length > 0;
634
+ // STEP 3: Build output permissions by category
635
+ const permissionsToReturn = [];
636
+ // ExcludedFromDeny: Keep as-is with original conditions (deny doesn't touch these)
637
+ if (excludedFromDeny.length > 0) {
638
+ permissionsToReturn.push(new Permission(eff, svc, act, excludedFromDeny, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
639
+ }
640
+ // Superset: Allow resource is broader than denyNotResource patterns
641
+ // - The covered denyNotResource patterns are excluded from deny (allow unconditionally)
642
+ // - The superset allow resources are affected by deny (apply inverted conditions)
643
+ if (supersets.length > 0) {
644
+ // First: Allow the covered patterns unconditionally (they're excluded from deny)
645
+ if (coveredDenyNotResourcePatterns.length > 0) {
646
+ permissionsToReturn.push(new Permission(eff, svc, act, coveredDenyNotResourcePatterns, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
647
+ }
648
+ // Second: Apply inverted deny conditions to the superset resources
649
+ if (denyHasConditions && !conditionsMatch) {
650
+ const supersetAllow = new Permission(eff, svc, act, supersets, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal);
651
+ permissionsToReturn.push(...applyDenyConditionsToAllow(supersetAllow, other));
652
+ }
653
+ // If no conditions or conditions match, the superset is fully denied (nothing to add)
654
+ }
655
+ // AffectedByDeny: These resources are hit by the deny
656
+ if (affectedByDeny.length > 0) {
657
+ // If there are no conditions on deny - these are fully denied (drop them)
658
+ // If the conditions match - these are fully denied (drop them)
659
+ if (denyHasConditions && !conditionsMatch) {
660
+ // Different conditions - keep with inverted deny conditions
661
+ const newAllow = new Permission(eff, svc, act, affectedByDeny, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal);
662
+ permissionsToReturn.push(...applyDenyConditionsToAllow(newAllow, other));
663
+ }
664
+ }
665
+ return permissionsToReturn;
666
+ }
667
+ // Scenario 3: Allow.notResource & Deny.resource
668
+ if (allowNotResource !== undefined && denyResource !== undefined) {
669
+ // STEP 1: Categorize relationships and track which denyResources are already covered
670
+ const coveredDenyResources = new Set(); // denyResources already excluded by allowNotResource
671
+ const uncoveredDenyResources = []; // denyResources that affect allowed resources
672
+ const subsetReplacements = [];
673
+ // For each denyResource, check if it's covered by any allowNotResource
674
+ for (const denyPattern of denyResource) {
675
+ let isCovered = false;
676
+ for (const allowPattern of allowNotResource) {
677
+ // ExactMatch or Superset - denyResource is already excluded
678
+ if (allowPattern === denyPattern || wildcardToRegex(allowPattern).test(denyPattern)) {
679
+ isCovered = true;
680
+ coveredDenyResources.add(denyPattern);
681
+ break;
682
+ }
683
+ }
684
+ if (!isCovered) {
685
+ uncoveredDenyResources.push(denyPattern);
686
+ }
687
+ }
688
+ // Check for Subset patterns (denyResource covers allowNotResource)
689
+ for (const allowPattern of allowNotResource) {
690
+ for (const denyPattern of denyResource) {
691
+ if (wildcardToRegex(denyPattern).test(allowPattern) && allowPattern !== denyPattern) {
692
+ subsetReplacements.push({ allowPattern, denyPattern });
693
+ }
694
+ }
695
+ }
696
+ // Filter out subset deny patterns from uncoveredDenyResources to get true NoOverlap patterns
697
+ const subsetDenyPatternsSet = new Set(subsetReplacements.map((s) => s.denyPattern));
698
+ const noOverlapDenyResources = uncoveredDenyResources.filter((dr) => !subsetDenyPatternsSet.has(dr));
699
+ // STEP 2: If all denyResources are covered, deny has no effect
700
+ if (noOverlapDenyResources.length === 0 && subsetReplacements.length === 0) {
701
+ return [this];
702
+ }
703
+ // STEP 3: Build output permissions
704
+ const denyHasConditions = other.conditions && Object.keys(other.conditions).length > 0;
705
+ // Build the expanded notResource (original + noOverlap deny resources + subset replacements)
706
+ const subsetAllowPatterns = new Set(subsetReplacements.map((s) => s.allowPattern));
707
+ const keptPatterns = allowNotResource.filter((p) => !subsetAllowPatterns.has(p));
708
+ const subsetDenyPatterns = Array.from(new Set(subsetReplacements.map((s) => s.denyPattern)));
709
+ const expandedNotResource = Array.from(new Set([...keptPatterns, ...subsetDenyPatterns, ...noOverlapDenyResources]));
710
+ // Same conditions or no deny conditions: simply expand notResource
711
+ if (conditionsMatch || !denyHasConditions) {
712
+ return [
713
+ new Permission(eff, svc, act, undefined, expandedNotResource, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal)
714
+ ];
715
+ }
716
+ // Different conditions: handle Subset and NoOverlap cases separately
717
+ const permissionsToReturn = [];
718
+ const hasSubsetReplacements = subsetReplacements.length > 0;
719
+ const hasNoOverlapAdditions = noOverlapDenyResources.length > 0;
720
+ // Part 1: Original allowNotResource with inverted deny conditions
721
+ // (when deny condition is NOT met, original allow applies)
722
+ const originalAllow = new Permission(eff, svc, act, undefined, allowNotResource, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal);
723
+ permissionsToReturn.push(...applyDenyConditionsToAllow(originalAllow, other));
724
+ // Part 2a: For SUBSET replacements - expanded notResource WITH deny conditions
725
+ // (replacing smaller exclusion with larger one, only valid when condition is met)
726
+ if (hasSubsetReplacements) {
727
+ // Build notResource with just the subset replacements (not the noOverlap additions)
728
+ const subsetExpandedNotResource = Array.from(new Set([...keptPatterns, ...subsetDenyPatterns]));
729
+ const subsetConditions = intersectConditions(this.conditions || {}, other.conditions || {});
730
+ permissionsToReturn.push(new Permission(eff, svc, act, undefined, subsetExpandedNotResource, subsetConditions || other.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
731
+ }
732
+ // Part 2b: For NO OVERLAP additions - expanded notResource WITHOUT conditions
733
+ // (adding new exclusion is always safe, no condition needed)
734
+ if (hasNoOverlapAdditions) {
735
+ permissionsToReturn.push(new Permission(eff, svc, act, undefined, expandedNotResource, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
736
+ }
737
+ return permissionsToReturn;
738
+ }
739
+ // ═══════════════════════════════════════════════════════════════════════════
740
+ // SCENARIO 4: Allow.NotResource & Deny.NotResource
741
+ // ═══════════════════════════════════════════════════════════════════════════
742
+ //
743
+ // Semantics:
744
+ // Allow.notResource = [A]: allow ALL resources EXCEPT those matching A
745
+ // Deny.notResource = [D]: deny ALL resources EXCEPT those matching D
746
+ //
747
+ // The deny blocks everything except D (the "safe zone").
748
+ // The allow permits everything except A.
749
+ //
750
+ // Surviving resources = (allowed) ∩ (not denied)
751
+ // = (NOT in A) ∩ (in D)
752
+ // = resources in D that are not covered by A
753
+ //
754
+ // Result: resource: [D patterns not covered by A]
755
+ //
756
+ // ═══════════════════════════════════════════════════════════════════════════
757
+ if (allowNotResource !== undefined && denyNotResource !== undefined) {
758
+ const denyHasConditions = other.conditions && Object.keys(other.conditions).length > 0;
759
+ // Helper: Check if pattern A covers pattern B (A is superset of or equal to B)
760
+ const patternCovers = (a, b) => {
761
+ return a === b || wildcardToRegex(a).test(b);
762
+ };
763
+ // Find D patterns that survive (not covered by any A pattern)
764
+ // These are the resources that are both allowed AND protected from deny
765
+ const survivingResources = denyNotResource.filter((dPattern) => !allowNotResource.some((aPattern) => patternCovers(aPattern, dPattern)));
766
+ // If nothing survives, return empty
767
+ if (survivingResources.length === 0) {
768
+ return [];
769
+ }
770
+ // Handle conditions
771
+ if (!denyHasConditions || conditionsMatch) {
772
+ // No deny conditions or same conditions: apply directly
773
+ return [
774
+ new Permission(eff, svc, act, survivingResources, undefined, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal)
775
+ ];
776
+ }
777
+ // Different conditions: split into two parts
778
+ const permissionsToReturn = [];
779
+ // Part 1: When deny condition is NOT met → original allow applies
780
+ const originalAllow = new Permission(eff, svc, act, undefined, allowNotResource, this.conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal);
781
+ permissionsToReturn.push(...applyDenyConditionsToAllow(originalAllow, other));
782
+ // Part 2: When deny condition IS met → surviving resources with deny's condition
783
+ const denyConditionCount = Object.values(other.conditions || {}).reduce((sum, keyMap) => sum + Object.keys(keyMap).length, 0);
784
+ const part2Conditions = denyConditionCount === 1 ? other.conditions : undefined;
785
+ permissionsToReturn.push(new Permission(eff, svc, act, survivingResources, undefined, part2Conditions, allowPrincipalArgs.principal, allowPrincipalArgs.notPrincipal));
786
+ return permissionsToReturn;
787
+ }
788
+ // This should never happen
789
+ throw new Error('Permission.subtract: This should never happen—invalid state.');
790
+ }
791
+ }
792
+ exports.Permission = Permission;
793
+ /**
794
+ * Attempt to union two sets of permission conditions.
795
+ *
796
+ * If the conditions can be merged into a single block that allows all cases allowed by either,
797
+ * returns the merged conditions. If they cannot be merged cleanly (e.g., differing operators
798
+ * or incompatible numeric boundaries), returns null.
799
+ *
800
+ * @param a First set of conditions
801
+ * @param b Second set of conditions
802
+ * @returns Merged conditions or null if they cannot be merged
803
+ */
804
+ function unionConditions(a, b) {
805
+ // 1. If the set of operators in 'a' differs from the set in 'b', return null.
806
+ a = normalizeConditionKeys(a);
807
+ b = normalizeConditionKeys(b);
808
+ const opsA = Object.keys(a).sort();
809
+ const opsB = Object.keys(b).sort();
810
+ if (JSON.stringify(opsA) !== JSON.stringify(opsB)) {
811
+ return null;
812
+ }
813
+ const merged = {};
814
+ // 2. For each operator op that appears in both:
815
+ for (const op of opsA) {
816
+ const keysA = Object.keys(a[op]).sort();
817
+ const keysB = Object.keys(b[op]).sort();
818
+ // If the set of context‐keys under this operator differs, we can't merge as one block
819
+ if (JSON.stringify(keysA) !== JSON.stringify(keysB)) {
820
+ return null;
821
+ }
822
+ // Now we know op and its context keys align. Build the merged set for this operator:
823
+ merged[op] = {};
824
+ for (const key of keysA) {
825
+ const valsA = a[op][key];
826
+ const valsB = b[op][key];
827
+ // How we combine depends on operator semantics:
828
+ switch (conditionBaseOperator(op)) {
829
+ case 'stringequals':
830
+ case 'stringlike':
831
+ case 'stringnotequals':
832
+ case 'stringnotlike':
833
+ case 'arnequals':
834
+ case 'arnlike':
835
+ case 'arnnotequals':
836
+ case 'arnnotlike':
837
+ // String‐based operators: just union the value arrays
838
+ merged[op][key] = Array.from(new Set([...valsA, ...valsB]));
839
+ break;
840
+ case 'numericlessthan':
841
+ case 'numericlessthanequals':
842
+ case 'numericgreaterthan':
843
+ case 'numericgreaterthanequals':
844
+ case 'numericequals':
845
+ case 'numericnotequals':
846
+ // Numeric operators: pick the “widest” comparison that still covers both sets
847
+ // For simplicity, convert all valsA/valsB to numbers; find the min or max
848
+ const numsA = valsA.map((v) => Number(v));
849
+ const numsB = valsB.map((v) => Number(v));
850
+ if (numsA.some(isNaN) || numsB.some(isNaN)) {
851
+ // Malformed number—cannot merge
852
+ return null;
853
+ }
854
+ if (op === 'numericlessthan' || op === 'numericlessthanequals') {
855
+ // We want the largest boundary
856
+ const candidate = Math.max(...numsA, ...numsB);
857
+ merged[op][key] = [String(candidate)];
858
+ }
859
+ else if (op === 'numericgreaterthan' || op === 'numericgreaterthanequals') {
860
+ // We want the smallest boundary
861
+ const candidate = Math.min(...numsA, ...numsB);
862
+ merged[op][key] = [String(candidate)];
863
+ }
864
+ else if (op === 'numericequals' || op === 'numericnotequals') {
865
+ // Union the sets of allowed/not‐allowed numbers
866
+ merged[op][key] = Array.from(new Set([...valsA.map(String), ...valsB.map(String)]));
867
+ }
868
+ break;
869
+ case 'datelessthan':
870
+ case 'datelessthanequals':
871
+ case 'dategreaterthan':
872
+ case 'dategreaterthanequals':
873
+ // Similar idea: choose the “widest” date limit
874
+ // Assume ISO‐8601 strings so lex‐compare works
875
+ if (op === 'datelessthan' || op === 'datelessthanequals') {
876
+ // pick the LARGEST date (latest) because “< latest” covers “< earlier”
877
+ const candidate = [...valsA, ...valsB].sort().reverse()[0];
878
+ merged[op][key] = [candidate];
879
+ }
880
+ else {
881
+ // "DateGreaterThan"/"DateGreaterThanEquals": pick the EARLIEST date
882
+ const candidate = [...valsA, ...valsB].sort()[0];
883
+ merged[op][key] = [candidate];
884
+ }
885
+ break;
886
+ case 'bool':
887
+ // Typically valsA and valsB are ["true"] or ["false"].
888
+ // If either contains "true", then the union is ["true","false"]? No—
889
+ // Bool doesn't make sense with an array. In IAM, Bool only works with a single value.
890
+ // If values differ (one says ["true"], the other says ["false"]), you cannot
891
+ // express (Bool==true OR Bool==false) as a single Bool. You’d need two separate
892
+ // statements. So bail out.
893
+ if (valsA[0] === valsB[0]) {
894
+ merged[op][key] = [valsA[0]];
895
+ }
896
+ else {
897
+ return null;
898
+ }
899
+ break;
900
+ case 'ipaddress':
901
+ case 'notipaddress':
902
+ // You can pass multiple CIDR blocks under a single IpAddress. So union them.
903
+ merged[op][key] = Array.from(new Set([...valsA, ...valsB]));
904
+ break;
905
+ // Any other operators (e.g., “ArnNotLike” etc.) behave similarly to their base type
906
+ default:
907
+ // If we don’t explicitly handle the operator, reject merging
908
+ return null;
909
+ }
910
+ }
911
+ }
912
+ return merged;
913
+ }
914
+ /**
915
+ * Intersect two sets of permission conditions.
916
+ *
917
+ * Attempt to find the intersection of two sets of IAM condition clauses. This will
918
+ * combine condition operators and context keys, retaining only values that satisfy
919
+ * both sets of conditions. If the intersection is empty or cannot be expressed
920
+ * cleanly, returns null.
921
+ *
922
+ * @param conditionsA First set of conditions
923
+ * @param conditionsB Second set of conditions
924
+ * @returns Intersected conditions or null if intersection is empty or cannot be expressed
925
+ */
926
+ function intersectConditions(a, b) {
927
+ // Normalize both condition sets to lowercase operators and keys
928
+ const normalizedA = normalizeConditionKeys(a);
929
+ const normalizedB = normalizeConditionKeys(b);
930
+ // Collect all unique operators from both sides
931
+ const allOperators = Array.from(new Set([...Object.keys(normalizedA), ...Object.keys(normalizedB)]));
932
+ const result = {};
933
+ for (const operator of allOperators) {
934
+ const keysA = normalizedA[operator] || {};
935
+ const keysB = normalizedB[operator] || {};
936
+ // Collect all unique context keys for this operator
937
+ const allContextKeys = Array.from(new Set([...Object.keys(keysA), ...Object.keys(keysB)]));
938
+ result[operator] = {};
939
+ for (const contextKey of allContextKeys) {
940
+ const valsA = keysA[contextKey];
941
+ const valsB = keysB[contextKey];
942
+ // If key exists in both sides, apply intersection logic based on operator type
943
+ if (valsA !== undefined && valsB !== undefined) {
944
+ const intersectedValues = intersectValuesForOperator(operator, valsA, valsB);
945
+ if (intersectedValues === null) {
946
+ // Empty intersection means no overlap - return null
947
+ return null;
948
+ }
949
+ result[operator][contextKey] = intersectedValues;
950
+ }
951
+ else {
952
+ // Key only exists in one side - carry it through (both conditions must be satisfied)
953
+ result[operator][contextKey] = valsA !== undefined ? Array.from(valsA) : Array.from(valsB);
954
+ }
955
+ }
956
+ // Remove empty operator objects
957
+ if (Object.keys(result[operator]).length === 0) {
958
+ delete result[operator];
959
+ }
960
+ }
961
+ const merged = mergeComplementaryConditions(result);
962
+ // Check if any values array became empty after merging complementary conditions
963
+ // (e.g., StringEquals: ['a'] merged with StringNotEquals: ['a'] results in StringEquals: [])
964
+ for (const [, keyMap] of Object.entries(merged)) {
965
+ for (const [, values] of Object.entries(keyMap)) {
966
+ if (values.length === 0) {
967
+ return null;
968
+ }
969
+ }
970
+ }
971
+ return merged;
972
+ }
973
+ /**
974
+ * Intersect values for a specific operator type.
975
+ *
976
+ * Returns the intersected values, or null if the intersection is empty
977
+ * (meaning the conditions are mutually exclusive).
978
+ */
979
+ function intersectValuesForOperator(operator, valsA, valsB) {
980
+ const baseOp = conditionBaseOperator(operator);
981
+ switch (baseOp) {
982
+ // String/ARN equality operators: intersection of allowed values
983
+ case 'stringequals':
984
+ case 'stringlike':
985
+ case 'arnequals':
986
+ case 'arnlike': {
987
+ const common = valsA.filter((v) => valsB.includes(v));
988
+ return common.length > 0 ? common : null;
989
+ }
990
+ // String/ARN negation operators: union of exclusions (more restrictive)
991
+ case 'stringnotequals':
992
+ case 'stringnotlike':
993
+ case 'arnnotequals':
994
+ case 'arnnotlike': {
995
+ return Array.from(new Set([...valsA, ...valsB]));
996
+ }
997
+ // Numeric less-than operators: take the minimum (more restrictive)
998
+ case 'numericlessthan':
999
+ case 'numericlessthanequals': {
1000
+ const numA = Number(valsA[0]);
1001
+ const numB = Number(valsB[0]);
1002
+ if (isNaN(numA) || isNaN(numB)) {
1003
+ return null;
1004
+ }
1005
+ return [String(Math.min(numA, numB))];
1006
+ }
1007
+ // Numeric greater-than operators: take the maximum (more restrictive)
1008
+ case 'numericgreaterthan':
1009
+ case 'numericgreaterthanequals': {
1010
+ const numA = Number(valsA[0]);
1011
+ const numB = Number(valsB[0]);
1012
+ if (isNaN(numA) || isNaN(numB)) {
1013
+ return null;
1014
+ }
1015
+ return [String(Math.max(numA, numB))];
1016
+ }
1017
+ // Boolean operators: values must match exactly
1018
+ case 'bool':
1019
+ case 'null': {
1020
+ if (valsA[0]?.toLowerCase() !== valsB[0]?.toLowerCase()) {
1021
+ return null;
1022
+ }
1023
+ return [valsA[0]];
1024
+ }
1025
+ // IP address operators: intersection of CIDR blocks
1026
+ case 'ipaddress':
1027
+ case 'notipaddress': {
1028
+ const common = valsA.filter((cidr) => valsB.includes(cidr));
1029
+ return common.length > 0 ? common : null;
1030
+ }
1031
+ // Date less-than operators: take the earlier date (more restrictive)
1032
+ case 'datelessthan':
1033
+ case 'datelessthanequals': {
1034
+ const dateA = valsA[0];
1035
+ const dateB = valsB[0];
1036
+ return [dateA < dateB ? dateA : dateB];
1037
+ }
1038
+ // Date greater-than operators: take the later date (more restrictive)
1039
+ case 'dategreaterthan':
1040
+ case 'dategreaterthanequals': {
1041
+ const dateA = valsA[0];
1042
+ const dateB = valsB[0];
1043
+ return [dateA > dateB ? dateA : dateB];
1044
+ }
1045
+ // Unknown operator - cannot handle
1046
+ default:
1047
+ return null;
1048
+ }
1049
+ }
1050
+ /**
1051
+ * Checks if an IAM condition operator ends with "IfExists".
1052
+ *
1053
+ * @param op the IAM condition operator, e.g., "StringEqualsIfExists"
1054
+ * @returns true if the operator ends with "IfExists", false otherwise.
1055
+ */
1056
+ function isIfExists(op) {
1057
+ // Check if the operator ends with "IfExists"
1058
+ return op.toLowerCase().endsWith('ifexists');
1059
+ }
1060
+ /**
1061
+ * Get the set operator from an IAM condition operator such as "ForAllValues" or "ForAnyValue".
1062
+ *
1063
+ * @param op the IAM condition operator, e.g., "ForAllValues:StringEquals"
1064
+ * @returns the set operator, e.g., "forallvalues" or "foranyvalue", or undefined if no set operator is present.
1065
+ */
1066
+ function conditionSetOperator(op) {
1067
+ return op.includes(':') ? op.split(':')[0].toLowerCase() : undefined;
1068
+ }
1069
+ /**
1070
+ * Gets the base operator name from an IAM condition operator. Removes any set operator prefix or
1071
+ * "IfExists" suffix.
1072
+ *
1073
+ * @param op the IAM condition operator, e.g., "ForAllValues:StringEqualsIfExists"
1074
+ * @returns the base operator name, e.g., "stringequals" or "arnequals".
1075
+ */
1076
+ function conditionBaseOperator(op) {
1077
+ // Return the base operator name for IAM condition operators
1078
+ return op
1079
+ .split(':')
1080
+ .at(-1)
1081
+ .toLowerCase()
1082
+ .replace(/ifexists$/, '');
1083
+ }
1084
+ /**
1085
+ * Returns a new PermissionConditions object with all operator and context keys lowercased.
1086
+ */
1087
+ function normalizeConditionKeys(conds) {
1088
+ const result = {};
1089
+ for (const [op, keyMap] of Object.entries(conds)) {
1090
+ const lowerOp = op.toLowerCase();
1091
+ result[lowerOp] = {};
1092
+ for (const [contextKey, values] of Object.entries(keyMap)) {
1093
+ const lowerContextKey = contextKey.toLowerCase();
1094
+ result[lowerOp][lowerContextKey] = Array.from(values);
1095
+ }
1096
+ }
1097
+ return result;
1098
+ }
1099
+ const invertOperatorMap = {
1100
+ stringequals: 'StringNotEquals',
1101
+ stringlike: 'StringNotLike',
1102
+ arnequals: 'ArnNotEquals',
1103
+ arnlike: 'ArnNotLike',
1104
+ stringnotequals: 'StringEquals',
1105
+ stringnotlike: 'StringLike',
1106
+ arnnotequals: 'ArnEquals',
1107
+ arnnotlike: 'ArnLike',
1108
+ numericlessthan: 'NumericGreaterThanEquals',
1109
+ numericlessthanequals: 'NumericGreaterThan',
1110
+ numericgreaterthan: 'NumericLessThanEquals',
1111
+ numericgreaterthanequals: 'NumericLessThan',
1112
+ numericequals: 'NumericNotEquals',
1113
+ numericnotequals: 'NumericEquals',
1114
+ datelessthan: 'DateGreaterThanEquals',
1115
+ datelessthanequals: 'DateGreaterThan',
1116
+ dategreaterthan: 'DateLessThanEquals',
1117
+ dategreaterthanequals: 'DateLessThan',
1118
+ bool: 'Bool',
1119
+ ipaddress: 'NotIpAddress',
1120
+ notipaddress: 'IpAddress'
1121
+ };
1122
+ const invertedSetOperatorMap = {
1123
+ forallvalues: 'ForAnyValue',
1124
+ foranyvalue: 'ForAllValues'
1125
+ };
1126
+ /**
1127
+ * Invert a set of IAM condition clauses for Deny → allow inversion.
1128
+ * Preserves ForAllValues:/ForAnyValue: prefixes and IfExists suffixes.
1129
+ *
1130
+ * @param conds the condition clauses to invert
1131
+ * @return a new set of inverted conditions
1132
+ */
1133
+ function invertConditions(conds) {
1134
+ const normalized = normalizeConditionKeys(conds);
1135
+ const inverted = {};
1136
+ for (const [op, keyMap] of Object.entries(normalized)) {
1137
+ const setOperator = conditionSetOperator(op) || undefined;
1138
+ const setOperatorPrefix = setOperator ? invertedSetOperatorMap[setOperator] + ':' : '';
1139
+ const hasIfExists = isIfExists(op);
1140
+ const coreOp = conditionBaseOperator(op);
1141
+ const invertedCore = invertOperatorMap[coreOp] || coreOp;
1142
+ const invertedOp = `${setOperatorPrefix}${invertedCore}${hasIfExists ? 'IfExists' : ''}`.toLowerCase();
1143
+ inverted[invertedOp] = {};
1144
+ for (const [key, vals] of Object.entries(keyMap)) {
1145
+ if (coreOp === 'bool' || coreOp === 'null') {
1146
+ inverted[invertedOp][key] = vals.map((v) => (v.toLowerCase() === 'true' ? 'false' : 'true'));
1147
+ }
1148
+ else {
1149
+ inverted[invertedOp][key] = Array.from(vals);
1150
+ }
1151
+ }
1152
+ }
1153
+ return inverted;
1154
+ }
1155
+ function mergeComplementaryConditions(c) {
1156
+ const complement = {
1157
+ stringequals: 'stringnotequals',
1158
+ stringlike: 'stringnotlike',
1159
+ arnequals: 'arnnotequals',
1160
+ arnlike: 'arnnotlike',
1161
+ numericequals: 'numericnotequals',
1162
+ numericnotequals: 'numericequals',
1163
+ numericlessthan: 'numericgreaterthanequals',
1164
+ numericgreaterthanequals: 'numericlessthan',
1165
+ numericlessthanequals: 'numericgreaterthan',
1166
+ numericgreaterthan: 'numericlessthanequals',
1167
+ datelessthan: 'dategreaterthanequals',
1168
+ dategreaterthanequals: 'datelessthan',
1169
+ datelessthanequals: 'dategreaterthan',
1170
+ dategreaterthan: 'datelessthanequals',
1171
+ ipaddress: 'notipaddress',
1172
+ notipaddress: 'ipaddress'
1173
+ // bool: 'bool'
1174
+ };
1175
+ const out = structuredClone(c);
1176
+ for (const [base, comp] of Object.entries(complement)) {
1177
+ if (out[base] && out[comp]) {
1178
+ for (const key of Object.keys(out[base])) {
1179
+ if (key in out[comp]) {
1180
+ out[base][key] = out[base][key].filter((v) => !out[comp][key].includes(v));
1181
+ delete out[comp][key];
1182
+ }
1183
+ }
1184
+ if (out[comp] && Object.keys(out[comp]).length === 0)
1185
+ delete out[comp];
1186
+ }
1187
+ }
1188
+ return out;
1189
+ }
1190
+ /**
1191
+ * Apply Deny conditions to an Allow permission.
1192
+ *
1193
+ * A Deny permission with conditions (whether multiple operators or multiple keys under one
1194
+ * operator) acts as an AND, meaning the Allow needs to escape ANY one of them (OR when inverted).
1195
+ * Each condition key-value pair is inverted and creates a separate Allow permission.
1196
+ *
1197
+ * It is possible for any given condition to fully deny the Allow, in which case
1198
+ * that condition will produce no resulting Allow permission. The result is an array
1199
+ * of Allow permissions that apply after each Deny condition is applied.
1200
+ *
1201
+ * This may result in multiple Allow permission or an empty array if all are denied.
1202
+ *
1203
+ * @param allow the Allow permission
1204
+ * @param deny the Deny permission
1205
+ * @returns an array of resulting Allow permissions after applying Deny conditions
1206
+ */
1207
+ function applyDenyConditionsToAllow(allow, deny) {
1208
+ // If Deny has no conditions, it fully denies the Allow
1209
+ if (!deny.conditions || Object.keys(deny.conditions).length === 0) {
1210
+ return [allow];
1211
+ }
1212
+ const results = [];
1213
+ // Each Deny condition key-value pair creates a separate inverted condition for Allow
1214
+ // (multiple keys under the same operator are each inverted separately)
1215
+ for (const [operator, keyMap] of Object.entries(deny.conditions || {})) {
1216
+ for (const [contextKey, values] of Object.entries(keyMap)) {
1217
+ // Invert this specific condition
1218
+ const singleCondition = { [operator]: { [contextKey]: values } };
1219
+ const invertedCondition = invertConditions(singleCondition);
1220
+ // Merge with the original Allow conditions
1221
+ const mergedConditions = intersectConditions(allow.conditions || {}, invertedCondition);
1222
+ if (mergedConditions !== null) {
1223
+ results.push(new Permission(allow.effect, allow.service, allow.action, allow.resource, allow.notResource, mergedConditions, allow.principal, allow.notPrincipal));
1224
+ }
1225
+ }
1226
+ }
1227
+ return results;
1228
+ }
1229
+ //# sourceMappingURL=permission.js.map