@jantstack/adonis-authz 2.0.0-alpha.1 → 2.4.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +693 -36
  2. package/build/commands/authz_catalog_diff.js +1 -1
  3. package/build/commands/authz_catalog_diff.js.map +1 -1
  4. package/build/commands/authz_catalog_prune_orphans.d.ts +78 -0
  5. package/build/commands/authz_catalog_prune_orphans.d.ts.map +1 -0
  6. package/build/commands/authz_catalog_prune_orphans.js +136 -0
  7. package/build/commands/authz_catalog_prune_orphans.js.map +1 -0
  8. package/build/commands/authz_catalog_sync.d.ts +17 -0
  9. package/build/commands/authz_catalog_sync.d.ts.map +1 -1
  10. package/build/commands/authz_catalog_sync.js +27 -4
  11. package/build/commands/authz_catalog_sync.js.map +1 -1
  12. package/build/commands/authz_freeze.d.ts +44 -0
  13. package/build/commands/authz_freeze.d.ts.map +1 -0
  14. package/build/commands/authz_freeze.js +95 -0
  15. package/build/commands/authz_freeze.js.map +1 -0
  16. package/build/commands/authz_reconcile.d.ts +102 -0
  17. package/build/commands/authz_reconcile.d.ts.map +1 -0
  18. package/build/commands/authz_reconcile.js +294 -0
  19. package/build/commands/authz_reconcile.js.map +1 -0
  20. package/build/commands/authz_relations_reconcile.d.ts +97 -0
  21. package/build/commands/authz_relations_reconcile.d.ts.map +1 -0
  22. package/build/commands/authz_relations_reconcile.js +313 -0
  23. package/build/commands/authz_relations_reconcile.js.map +1 -0
  24. package/build/commands/authz_scopes_relay.d.ts +47 -0
  25. package/build/commands/authz_scopes_relay.d.ts.map +1 -0
  26. package/build/commands/authz_scopes_relay.js +141 -0
  27. package/build/commands/authz_scopes_relay.js.map +1 -0
  28. package/build/commands/authz_unfreeze.d.ts +37 -0
  29. package/build/commands/authz_unfreeze.d.ts.map +1 -0
  30. package/build/commands/authz_unfreeze.js +92 -0
  31. package/build/commands/authz_unfreeze.js.map +1 -0
  32. package/build/commands/main.d.ts +6 -1
  33. package/build/commands/main.d.ts.map +1 -1
  34. package/build/commands/main.js +6 -1
  35. package/build/commands/main.js.map +1 -1
  36. package/build/commands/openfga_provision.d.ts +46 -4
  37. package/build/commands/openfga_provision.d.ts.map +1 -1
  38. package/build/commands/openfga_provision.js +90 -7
  39. package/build/commands/openfga_provision.js.map +1 -1
  40. package/build/configure.d.ts +11 -0
  41. package/build/configure.d.ts.map +1 -1
  42. package/build/configure.js +37 -1
  43. package/build/configure.js.map +1 -1
  44. package/build/index.d.ts +50 -10
  45. package/build/index.d.ts.map +1 -1
  46. package/build/index.js +45 -6
  47. package/build/index.js.map +1 -1
  48. package/build/providers/authz_provider.d.ts +26 -2
  49. package/build/providers/authz_provider.d.ts.map +1 -1
  50. package/build/providers/authz_provider.js +55 -2
  51. package/build/providers/authz_provider.js.map +1 -1
  52. package/build/services/relations.d.ts +14 -0
  53. package/build/services/relations.d.ts.map +1 -0
  54. package/build/services/relations.js +17 -0
  55. package/build/services/relations.js.map +1 -0
  56. package/build/src/{catalog.d.ts → catalog/catalog.d.ts} +41 -2
  57. package/build/src/catalog/catalog.d.ts.map +1 -0
  58. package/build/src/{catalog.js → catalog/catalog.js} +120 -14
  59. package/build/src/catalog/catalog.js.map +1 -0
  60. package/build/src/{catalog_cache.d.ts → catalog/catalog_cache.d.ts} +46 -22
  61. package/build/src/catalog/catalog_cache.d.ts.map +1 -0
  62. package/build/src/{catalog_cache.js → catalog/catalog_cache.js} +53 -43
  63. package/build/src/catalog/catalog_cache.js.map +1 -0
  64. package/build/src/define_config.d.ts +137 -3
  65. package/build/src/define_config.d.ts.map +1 -1
  66. package/build/src/define_config.js.map +1 -1
  67. package/build/src/drivers/database_driver.d.ts +128 -7
  68. package/build/src/drivers/database_driver.d.ts.map +1 -1
  69. package/build/src/drivers/database_driver.js +510 -24
  70. package/build/src/drivers/database_driver.js.map +1 -1
  71. package/build/src/drivers/database_relations_driver.d.ts +113 -0
  72. package/build/src/drivers/database_relations_driver.d.ts.map +1 -0
  73. package/build/src/drivers/database_relations_driver.js +679 -0
  74. package/build/src/drivers/database_relations_driver.js.map +1 -0
  75. package/build/src/drivers/openfga_driver.d.ts +729 -122
  76. package/build/src/drivers/openfga_driver.d.ts.map +1 -1
  77. package/build/src/drivers/openfga_driver.js +2083 -476
  78. package/build/src/drivers/openfga_driver.js.map +1 -1
  79. package/build/src/drivers/openfga_facts.d.ts +384 -0
  80. package/build/src/drivers/openfga_facts.d.ts.map +1 -0
  81. package/build/src/drivers/openfga_facts.js +836 -0
  82. package/build/src/drivers/openfga_facts.js.map +1 -0
  83. package/build/src/drivers/openfga_relations_driver.d.ts +141 -0
  84. package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -0
  85. package/build/src/drivers/openfga_relations_driver.js +590 -0
  86. package/build/src/drivers/openfga_relations_driver.js.map +1 -0
  87. package/build/src/errors.d.ts +290 -5
  88. package/build/src/errors.d.ts.map +1 -1
  89. package/build/src/errors.js +296 -7
  90. package/build/src/errors.js.map +1 -1
  91. package/build/src/freeze.d.ts +141 -0
  92. package/build/src/freeze.d.ts.map +1 -0
  93. package/build/src/freeze.js +217 -0
  94. package/build/src/freeze.js.map +1 -0
  95. package/build/src/http/app_access_middleware.d.ts.map +1 -0
  96. package/build/src/http/app_access_middleware.js.map +1 -0
  97. package/build/src/http/resource_access_middleware.d.ts +105 -0
  98. package/build/src/http/resource_access_middleware.d.ts.map +1 -0
  99. package/build/src/http/resource_access_middleware.js +81 -0
  100. package/build/src/http/resource_access_middleware.js.map +1 -0
  101. package/build/src/identity.d.ts +74 -1
  102. package/build/src/identity.d.ts.map +1 -1
  103. package/build/src/identity.js +100 -2
  104. package/build/src/identity.js.map +1 -1
  105. package/build/src/manager.d.ts +330 -4
  106. package/build/src/manager.d.ts.map +1 -1
  107. package/build/src/manager.js +1285 -188
  108. package/build/src/manager.js.map +1 -1
  109. package/build/src/models/authz_assignment.d.ts +7 -7
  110. package/build/src/models/authz_assignment.d.ts.map +1 -1
  111. package/build/src/models/authz_deny.d.ts +7 -7
  112. package/build/src/models/authz_deny.d.ts.map +1 -1
  113. package/build/src/models/authz_permission.d.ts +7 -7
  114. package/build/src/models/authz_permission.d.ts.map +1 -1
  115. package/build/src/models/authz_role.d.ts +7 -7
  116. package/build/src/models/authz_role.d.ts.map +1 -1
  117. package/build/src/models/authz_role_permission.d.ts +7 -7
  118. package/build/src/models/authz_role_permission.d.ts.map +1 -1
  119. package/build/src/openfga.d.ts +18 -2
  120. package/build/src/openfga.d.ts.map +1 -1
  121. package/build/src/openfga.js +15 -1
  122. package/build/src/openfga.js.map +1 -1
  123. package/build/src/reconcile.d.ts +37 -0
  124. package/build/src/reconcile.d.ts.map +1 -0
  125. package/build/src/reconcile.js +69 -0
  126. package/build/src/reconcile.js.map +1 -0
  127. package/build/src/relation_partition_trigger.d.ts +8 -0
  128. package/build/src/relation_partition_trigger.d.ts.map +1 -0
  129. package/build/src/relation_partition_trigger.js +93 -0
  130. package/build/src/relation_partition_trigger.js.map +1 -0
  131. package/build/src/relations/define_relations_config.d.ts +75 -0
  132. package/build/src/relations/define_relations_config.d.ts.map +1 -0
  133. package/build/src/relations/define_relations_config.js +173 -0
  134. package/build/src/relations/define_relations_config.js.map +1 -0
  135. package/build/src/relations/manager.d.ts +60 -0
  136. package/build/src/relations/manager.d.ts.map +1 -0
  137. package/build/src/relations/manager.js +213 -0
  138. package/build/src/relations/manager.js.map +1 -0
  139. package/build/src/relations/reconcile.d.ts +111 -0
  140. package/build/src/relations/reconcile.d.ts.map +1 -0
  141. package/build/src/relations/reconcile.js +200 -0
  142. package/build/src/relations/reconcile.js.map +1 -0
  143. package/build/src/relations_config_store.d.ts +22 -0
  144. package/build/src/relations_config_store.d.ts.map +1 -0
  145. package/build/src/relations_config_store.js +74 -0
  146. package/build/src/relations_config_store.js.map +1 -0
  147. package/build/src/scope_outbox.d.ts +69 -0
  148. package/build/src/scope_outbox.d.ts.map +1 -0
  149. package/build/src/scope_outbox.js +298 -0
  150. package/build/src/scope_outbox.js.map +1 -0
  151. package/build/src/{drivers → shared}/backend_guard.d.ts +42 -0
  152. package/build/src/shared/backend_guard.d.ts.map +1 -0
  153. package/build/src/{drivers → shared}/backend_guard.js +78 -1
  154. package/build/src/shared/backend_guard.js.map +1 -0
  155. package/build/src/shared/sql_expiry.d.ts.map +1 -0
  156. package/build/src/shared/sql_expiry.js.map +1 -0
  157. package/build/src/shared/transaction_guard.d.ts +50 -0
  158. package/build/src/shared/transaction_guard.d.ts.map +1 -0
  159. package/build/src/shared/transaction_guard.js +60 -0
  160. package/build/src/shared/transaction_guard.js.map +1 -0
  161. package/build/src/sql_descendants.d.ts +47 -1
  162. package/build/src/sql_descendants.d.ts.map +1 -1
  163. package/build/src/sql_descendants.js +75 -1
  164. package/build/src/sql_descendants.js.map +1 -1
  165. package/build/src/testing/contract.d.ts +129 -4
  166. package/build/src/testing/contract.d.ts.map +1 -1
  167. package/build/src/testing/contract.js +912 -177
  168. package/build/src/testing/contract.js.map +1 -1
  169. package/build/src/testing/main.d.ts +8 -2
  170. package/build/src/testing/main.d.ts.map +1 -1
  171. package/build/src/testing/main.js +4 -1
  172. package/build/src/testing/main.js.map +1 -1
  173. package/build/src/testing/migration_contract.d.ts +284 -0
  174. package/build/src/testing/migration_contract.d.ts.map +1 -0
  175. package/build/src/testing/migration_contract.js +586 -0
  176. package/build/src/testing/migration_contract.js.map +1 -0
  177. package/build/src/testing/relations_contract.d.ts +73 -0
  178. package/build/src/testing/relations_contract.d.ts.map +1 -0
  179. package/build/src/testing/relations_contract.js +1069 -0
  180. package/build/src/testing/relations_contract.js.map +1 -0
  181. package/build/src/testing/relations_reconcile_contract.d.ts +24 -0
  182. package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -0
  183. package/build/src/testing/relations_reconcile_contract.js +220 -0
  184. package/build/src/testing/relations_reconcile_contract.js.map +1 -0
  185. package/build/src/traits/authz_scopes.js +1 -1
  186. package/build/src/traits/authz_scopes.js.map +1 -1
  187. package/build/src/traits/has_uuid.d.ts +8 -8
  188. package/build/src/traits/has_uuid.d.ts.map +1 -1
  189. package/build/src/types.d.ts +1053 -83
  190. package/build/src/types.d.ts.map +1 -1
  191. package/build/src/types.js +10 -0
  192. package/build/src/types.js.map +1 -1
  193. package/build/stubs/config/authorization.stub +104 -4
  194. package/build/stubs/migration.stub +136 -0
  195. package/build/stubs/scopes_outbox_migration.stub +57 -0
  196. package/package.json +4 -2
  197. package/build/commands/openfga_import.d.ts +0 -34
  198. package/build/commands/openfga_import.d.ts.map +0 -1
  199. package/build/commands/openfga_import.js +0 -97
  200. package/build/commands/openfga_import.js.map +0 -1
  201. package/build/src/catalog.d.ts.map +0 -1
  202. package/build/src/catalog.js.map +0 -1
  203. package/build/src/catalog_cache.d.ts.map +0 -1
  204. package/build/src/catalog_cache.js.map +0 -1
  205. package/build/src/drivers/backend_guard.d.ts.map +0 -1
  206. package/build/src/drivers/backend_guard.js.map +0 -1
  207. package/build/src/drivers/sql_expiry.d.ts.map +0 -1
  208. package/build/src/drivers/sql_expiry.js.map +0 -1
  209. package/build/src/middleware/app_access_middleware.d.ts.map +0 -1
  210. package/build/src/middleware/app_access_middleware.js.map +0 -1
  211. /package/build/src/{middleware → http}/app_access_middleware.d.ts +0 -0
  212. /package/build/src/{middleware → http}/app_access_middleware.js +0 -0
  213. /package/build/src/{drivers → shared}/sql_expiry.d.ts +0 -0
  214. /package/build/src/{drivers → shared}/sql_expiry.js +0 -0
@@ -6,8 +6,14 @@
6
6
  * Requiere Japa en el proyecto consumidor (es donde vive la base de datos
7
7
  * real contra la que tiene sentido ejecutarla).
8
8
  */
9
- export { runAuthorizationDriverContract } from './contract.js';
10
- export type { DriverContractHarness, DriverCapabilities, ContractLevel } from './contract.js';
9
+ export { runAuthorizationDriverContract, lucidContractTransactions } from './contract.js';
10
+ export type { DriverContractHarness, DriverCapabilities, ContractLevel, ContractTransactions } from './contract.js';
11
11
  export { memoryScopeTree, resolveChainFrom, descendantsFrom } from './scope_tree.js';
12
+ export { runMigrationContract, registerMigrationContract, runMigrationDirection, makeMigrationSeed, migrationQuestions, plantMigrationFacts, plantMigrationTree, MIGRATION_CATALOG, MIGRATION_PERMISSIONS, MIGRATION_ROLES, MIGRATION_QUESTION_COUNT, } from './migration_contract.js';
13
+ export type { MigrationContractHarness, MigrationDirection, MigrationQuestion, MigrationSeed, MigrationVerdict, ExpectedLoss, } from './migration_contract.js';
12
14
  export type { ContractScopeTree } from './scope_tree.js';
15
+ export { runRelationsDriverContract, registerRelationsDriverContract, makeRelationsDriver, contractRelationsConfig, RELATIONS_HOLDER_TYPES, lucidRelationsContractTransactions, } from './relations_contract.js';
16
+ export type { RelationsDriverContractHarness, RelationsContractTransactions, MakeRelationsDriverOptions, } from './relations_contract.js';
17
+ export { runRelationsReconcileContract, registerRelationsReconcileContract, } from './relations_reconcile_contract.js';
18
+ export type { RelationsReconcileHarness } from './relations_reconcile_contract.js';
13
19
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/testing/main.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAA;AAC9D,YAAY,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7F,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACpF,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/testing/main.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,8BAA8B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAA;AACzF,YAAY,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACnH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,yBAAyB,CAAA;AAChC,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EACL,0BAA0B,EAC1B,+BAA+B,EAC/B,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,8BAA8B,EAC9B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,GACnC,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA"}
@@ -6,6 +6,9 @@
6
6
  * Requiere Japa en el proyecto consumidor (es donde vive la base de datos
7
7
  * real contra la que tiene sentido ejecutarla).
8
8
  */
9
- export { runAuthorizationDriverContract } from './contract.js';
9
+ export { runAuthorizationDriverContract, lucidContractTransactions } from './contract.js';
10
10
  export { memoryScopeTree, resolveChainFrom, descendantsFrom } from './scope_tree.js';
11
+ export { runMigrationContract, registerMigrationContract, runMigrationDirection, makeMigrationSeed, migrationQuestions, plantMigrationFacts, plantMigrationTree, MIGRATION_CATALOG, MIGRATION_PERMISSIONS, MIGRATION_ROLES, MIGRATION_QUESTION_COUNT, } from './migration_contract.js';
12
+ export { runRelationsDriverContract, registerRelationsDriverContract, makeRelationsDriver, contractRelationsConfig, RELATIONS_HOLDER_TYPES, lucidRelationsContractTransactions, } from './relations_contract.js';
13
+ export { runRelationsReconcileContract, registerRelationsReconcileContract, } from './relations_reconcile_contract.js';
11
14
  //# sourceMappingURL=main.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/testing/main.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAA;AAE9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/testing/main.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,8BAA8B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAUhC,OAAO,EACL,0BAA0B,EAC1B,+BAA+B,EAC/B,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,yBAAyB,CAAA;AAMhC,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,GACnC,MAAM,mCAAmC,CAAA"}
@@ -0,0 +1,284 @@
1
+ /**
2
+ * **El contrato de MIGRACIÓN** (3b-3b · B3) — la pieza que convierte «migra»
3
+ * en «migra sin perder nada que no esté declarado».
4
+ *
5
+ * import { runMigrationContract } from '@jantstack/adonis-authz/testing'
6
+ *
7
+ * Se publica junto al resto de la suite de contrato porque un driver de
8
+ * TERCEROS tiene que poder correrlo: el paquete promete migración idempotente
9
+ * y bidireccional entre drivers, y esa promesa no la puede sostener un test
10
+ * privado del paquete.
11
+ *
12
+ * Cómo funciona, y por qué así:
13
+ *
14
+ * 1. **Siembra FIJA** — 7 nodos, 6 holders, 4 roles, 14 grants, 5
15
+ * caducidades y 6 denies, escritos siempre con la API del driver. Fija a
16
+ * propósito: un fixture que cambia con cada corrida no permite comparar
17
+ * dos versiones del paquete, y el juez del panel 2 pedía «un set fijo de
18
+ * preguntas».
19
+ * 2. **448 preguntas idénticas** en origen y destino: 168 `authorize`
20
+ * (6 holders × 7 scopes × 4 permisos), 168 `hasRole` (× 4 roles), 42
21
+ * `listRoles`, 24 `listScopes`, 28 `listSubjects` y 18 `listRoleScopes`.
22
+ * Se preguntan ANTES de migrar sobre el origen y DESPUÉS sobre el
23
+ * destino, y las respuestas tienen que coincidir.
24
+ * 3. **`expectedLosses`** — la migración **no es sin pérdida** (panel 2,
25
+ * requisito 3 del dueño: *«posible con pérdidas declaradas y con
26
+ * ventana»*), así que las pérdidas se declaran DE ANTEMANO y el contrato
27
+ * las cruza en las dos direcciones:
28
+ * - una pérdida declarada tiene que aparecer **contada en
29
+ * `report.skipped`**; si no aparece, el contrato FALLA (una pérdida
30
+ * que nunca ocurre es una línea falsa en el README);
31
+ * - una respuesta que cambia y que NINGUNA pérdida declarada explica
32
+ * hace FALLAR el contrato. Ese es todo el punto: **nunca se ignora
33
+ * ninguna**.
34
+ * 4. **El CENSO de la siembra** (lote 3b-4 · C1) — y esto es lo que hace
35
+ * que el punto 3 sea una garantía y no un formulario. Las dos caras de
36
+ * `expectedLosses` cruzan `Object.keys(report.skipped)`, o sea **lo que
37
+ * el driver se auto-declara**: cierran las omisiones DESCUIDADAS, no las
38
+ * silenciosas. Un driver que tira un hecho sin contarlo no puebla
39
+ * `skipped` y, si esa pérdida no mueve ninguna de las 448, pasaba.
40
+ * Medido, y no es teórico: los denies solo se observan por `authorize`,
41
+ * que no distingue un deny en su sitio de uno reubicado a otro scope de
42
+ * la misma cadena.
43
+ * El censo no le pregunta al driver qué se dejó: mira el destino **hecho
44
+ * a hecho** (los 20 de la siembra: 14 asignaciones + 6 denies) por el
45
+ * camino DIRECTO del puerto —`listRoles`/`listDenies`, invariante 7— y
46
+ * una ausencia sin motivo declarado **y contado** hace FALLAR el
47
+ * contrato. `listDenies` es opcional en el puerto: un driver que no lo
48
+ * traiga deja sus denies observados solo por `authorize`, y el veredicto
49
+ * lo dice en `censusLimits` en vez de callárselo.
50
+ * 5. **El CRUCE DE CADUCIDADES** — ninguna de las 448 devuelve un
51
+ * `expiresAt` y el contrato no adelanta ningún reloj, así que perder la
52
+ * caducidad de un grant VIVO (convertirlo en permanente: fail-OPEN) era
53
+ * invisible. Se cruza por el único camino de solo-lectura-efectiva que
54
+ * hay en el puerto: `grant` con `expiresAt` OMITIDO devuelve
55
+ * `previousExpiresAt` (invariante 10).
56
+ * 6. **Tres combinaciones**: ida, vuelta e ida-y-vuelta (con `--prune`, que
57
+ * es la que demuestra que el viaje redondo no inventa ni pierde).
58
+ *
59
+ * **El límite de `a→b→a`, dicho en voz alta** (tester Fase 3b · M3): las 448
60
+ * de la vuelta se le preguntan al ORIGEN, y **nadie lo vacía** entre los dos
61
+ * tramos. Así que esa combinación observa lo que el tramo de vuelta DESTRUYE
62
+ * (un `--prune` que se lleva de más) y **no** lo que deja de escribir: con el
63
+ * origen ya lleno, «todo `unchanged`» es la respuesta correcta y un tramo
64
+ * omisivo es indistinguible de uno bueno. Quien migra de verdad (vacía el
65
+ * origen y lo reconstruye) está cubierto por las combinaciones `a→b` y `b→a`,
66
+ * que sí preguntan al destino recién llenado. Cerrar el hueco pide un gancho
67
+ * nuevo en el harness («vacía los hechos de este extremo»), que es una
68
+ * decisión del dueño y no se toma aquí.
69
+ *
70
+ * El motor está separado del registro de casos (`runMigrationDirection` /
71
+ * `runMigrationContract`) para que el propio paquete pueda comprobar que el
72
+ * contrato **sabe fallar**: un contrato que no falla no es una garantía.
73
+ */
74
+ import type { AuthorizationDriver, CatalogSpec, ReconcileReport, ScopeRef, SubjectRef } from '../types.js';
75
+ import type { ContractScopeTree } from './scope_tree.js';
76
+ import type { ContractTestApi } from './contract.js';
77
+ /** Las tres combinaciones que el plan exige. */
78
+ export type MigrationDirection = 'a→b' | 'b→a' | 'a→b→a';
79
+ /** Una pregunta del set fijo, ya identificada por su texto. */
80
+ export interface MigrationQuestion {
81
+ id: string;
82
+ kind: 'authorize' | 'hasRole' | 'listRoles' | 'listScopes' | 'listSubjects' | 'listRoleScopes';
83
+ ask(driver: AuthorizationDriver): Promise<string>;
84
+ }
85
+ /**
86
+ * Una pérdida DECLARADA de la migración. Declararla es un compromiso en las
87
+ * dos direcciones: tiene que ocurrir (salir contada en `skipped`) y solo
88
+ * puede explicar las respuestas que diga `changesAnswer`.
89
+ */
90
+ export interface ExpectedLoss {
91
+ /** El motivo, tal y como sale en `report.skipped` (`expired`, `unknown-scope`, `folded-scope`…). */
92
+ reason: string;
93
+ /** Por qué se pierde y **dónde se mide**. Va al informe y al README; no es decorativo. */
94
+ why: string;
95
+ /** En qué combinaciones se espera. Default: las tres. */
96
+ directions?: MigrationDirection[];
97
+ /**
98
+ * Qué preguntas puede cambiar de respuesta. **Default: ninguna** — lo
99
+ * normal es que una pérdida no cambie ninguna (una asignación ya caducada
100
+ * no concedía nada), y decir «cambia cualquiera» sería una declaración sin
101
+ * contenido: taparía cualquier bug.
102
+ */
103
+ changesAnswer?(question: MigrationQuestion): boolean;
104
+ }
105
+ export interface MigrationContractHarness {
106
+ name: string;
107
+ /** Los dos extremos, por su clave en `drivers` del manager que devuelve `setup`. */
108
+ a: string;
109
+ b: string;
110
+ /** El árbol del CONSUMIDOR. Es compartido y **no se migra**. Default: `memoryScopeTree()`. */
111
+ makeTree?(): Promise<ContractScopeTree>;
112
+ /** Materializa el catálogo del contrato (siempre local, en `authz_*`). */
113
+ seedCatalog(catalog: CatalogSpec): Promise<unknown>;
114
+ /**
115
+ * Construye los dos drivers sobre ese árbol y devuelve el manager que los
116
+ * conoce por `a`/`b` (es quien congela, resuelve el origen y llama a
117
+ * `reconcile`). `drivers` son las MISMAS instancias, para preguntarles.
118
+ */
119
+ setup(tree: ContractScopeTree): Promise<{
120
+ reconcile(options: {
121
+ to: string;
122
+ from?: string;
123
+ prune?: boolean;
124
+ }): Promise<ReconcileReport>;
125
+ drivers: Record<string, AuthorizationDriver>;
126
+ }>;
127
+ /** Borra hechos y catálogo entre combinaciones. */
128
+ cleanup(): Promise<void>;
129
+ /** Las pérdidas, declaradas de antemano. Una lista vacía es un compromiso fuerte. */
130
+ expectedLosses: ExpectedLoss[];
131
+ }
132
+ /** Los 4 permisos del contrato de migración. `admin:all` no lo lleva ningún rol: hay preguntas que son `false` en todas partes. */
133
+ export declare const MIGRATION_PERMISSIONS: readonly ["docs:read", "docs:write", "billing:read", "admin:all"];
134
+ /** Los 4 roles, uno por nivel útil (dos a `app`, para que el nivel no sea la única variable). */
135
+ export declare const MIGRATION_ROLES: readonly ["mig-editor", "mig-viewer", "mig-lead", "mig-auditor"];
136
+ export declare const MIGRATION_CATALOG: CatalogSpec;
137
+ /** Los 7 nodos y los 6 holders de una corrida (uuids nuevos por corrida; la FORMA es la fija). */
138
+ export interface MigrationSeed {
139
+ scopes: {
140
+ app: ScopeRef;
141
+ org1: ScopeRef;
142
+ org2: ScopeRef;
143
+ unit1: ScopeRef;
144
+ unit2: ScopeRef;
145
+ unit3: ScopeRef;
146
+ unit4: ScopeRef;
147
+ };
148
+ holders: SubjectRef[];
149
+ /** El instante de la corrida: las caducidades se colocan alrededor. */
150
+ now: Date;
151
+ }
152
+ export declare function makeMigrationSeed(now?: Date): MigrationSeed;
153
+ /** El árbol: 7 nodos con profundidad 4 (`app → org1 → unit1 → unit4`). */
154
+ export declare function plantMigrationTree(tree: ContractScopeTree, seed: MigrationSeed): Promise<void>;
155
+ /**
156
+ * Los 14 grants (5 con caducidad: 4 vivas y **1 ya pasada**, que es la
157
+ * pérdida declarada `expired`) y los 6 denies, escritos con la API del
158
+ * driver — nunca a mano: lo que se migra tiene que ser lo que el motor
159
+ * escribe.
160
+ */
161
+ export interface MigrationGrant {
162
+ holder: SubjectRef;
163
+ role: string;
164
+ scope: ScopeRef;
165
+ /** Omitido = sin caducidad; una `Date` = la caducidad exacta sembrada. */
166
+ expiresAt?: Date;
167
+ /** La única ya vencida: es la pérdida declarada `expired`. */
168
+ expired?: true;
169
+ }
170
+ /** Un deny de la siembra. Tabla, y no una lista suelta, por lo mismo que los grants. */
171
+ export interface MigrationDeny {
172
+ holder: SubjectRef;
173
+ permission: string;
174
+ scope: ScopeRef;
175
+ }
176
+ /**
177
+ * **Los 14 grants, en una tabla** — para que la siembra y el CRUCE DE
178
+ * CADUCIDADES salgan del mismo sitio: dos listas paralelas se separan al
179
+ * primer cambio y el cruce dejaría de comprobar lo que se sembró.
180
+ */
181
+ export declare function migrationGrants(seed: MigrationSeed): MigrationGrant[];
182
+ /**
183
+ * **Los 6 denies, en una tabla** — misma razón que los grants: el CENSO
184
+ * (abajo) tiene que preguntar por lo que se sembró, y dos listas paralelas se
185
+ * separan al primer cambio.
186
+ */
187
+ export declare function migrationDenies(seed: MigrationSeed): MigrationDeny[];
188
+ export declare function plantMigrationFacts(driver: AuthorizationDriver, seed: MigrationSeed): Promise<void>;
189
+ /**
190
+ * Un hecho de la siembra tal como el CENSO lo busca en el destino. Es la
191
+ * lista contra la que se comprueba que la migración no perdió nada: no
192
+ * depende de que alguna de las 448 respuestas se mueva, ni de que el driver
193
+ * se auto-declare nada.
194
+ */
195
+ export interface MigrationFact {
196
+ kind: 'assignment' | 'deny';
197
+ holder: SubjectRef;
198
+ scope: ScopeRef;
199
+ /** `assignment`: el slug del rol. `deny`: el slug del permiso. */
200
+ name: string;
201
+ /**
202
+ * El motivo DECLARADO que justifica que este hecho NO llegue al destino.
203
+ * Sin él, que falte es una pérdida **silenciosa** y el contrato falla —
204
+ * cuente el driver lo que cuente en `report.skipped`.
205
+ */
206
+ expectedLoss?: string;
207
+ }
208
+ /** Los 20 hechos de la siembra (14 asignaciones + 6 denies), en un solo sitio. */
209
+ export declare function migrationFacts(seed: MigrationSeed): MigrationFact[];
210
+ /** Cómo se nombra un hecho en el informe del contrato. */
211
+ export declare function describeMigrationFact(fact: MigrationFact): string;
212
+ export interface MigrationCensus {
213
+ present: MigrationFact[];
214
+ missing: MigrationFact[];
215
+ /** Lo que ESTE driver no deja censar, dicho en voz alta (nunca un hueco callado). */
216
+ limits: string[];
217
+ }
218
+ /**
219
+ * **El censo** (lote 3b-4 · C1): pregunta al destino, hecho a hecho, si lo
220
+ * que se sembró está. Se lee por el camino DIRECTO del puerto —invariante 7,
221
+ * hechos directos del scope exacto—: `listRoles` para las asignaciones y
222
+ * `listDenies` para los denies. No mira `report.skipped`, no compara
223
+ * respuestas y no depende de que la pérdida cambie ninguna de las 448.
224
+ *
225
+ * `listDenies` es OPCIONAL en el puerto: un driver que no lo trae deja sus
226
+ * denies censados solo por `authorize` (lo dice `limits`, y está escrito en
227
+ * el README). Los dos drivers del paquete lo implementan.
228
+ */
229
+ export declare function censusMigrationFacts(driver: AuthorizationDriver, seed: MigrationSeed): Promise<MigrationCensus>;
230
+ /**
231
+ * Las 448: **168 + 168 + 42 + 24 + 28 + 18**. No es un número redondo por
232
+ * casualidad — es el producto de la siembra fija, y por eso el contrato
233
+ * puede afirmar «448 preguntas idénticas» y no «unas cuantas».
234
+ */
235
+ export declare function migrationQuestions(seed: MigrationSeed): MigrationQuestion[];
236
+ /** Cuántas preguntas tiene el set fijo. Es una CIFRA del contrato, no un detalle. */
237
+ export declare const MIGRATION_QUESTION_COUNT = 448;
238
+ export interface MigrationVerdict {
239
+ direction: MigrationDirection;
240
+ /** Los reportes de cada tramo (dos en `a→b→a`). */
241
+ reports: ReconcileReport[];
242
+ questions: number;
243
+ /** Respuestas que cambiaron, con la pérdida declarada que las explica (o `null`). */
244
+ mismatches: Array<{
245
+ question: string;
246
+ before: string;
247
+ after: string;
248
+ explainedBy: string | null;
249
+ }>;
250
+ /** Motivos declarados que NO aparecieron contados en `skipped`. */
251
+ declaredButAbsent: string[];
252
+ /** Caducidades que el destino no conservó (tester Fase 3b · M1). */
253
+ expiryMismatches: Array<{
254
+ grant: string;
255
+ before: string;
256
+ after: string;
257
+ }>;
258
+ /**
259
+ * Hechos de la SIEMBRA que el destino no tiene y que NADIE declaró (lote
260
+ * 3b-4 · C1). Es el censo, no `report.skipped`: aquí caen las pérdidas que
261
+ * el driver no cuenta.
262
+ */
263
+ silentLosses: Array<{
264
+ fact: string;
265
+ at: string;
266
+ }>;
267
+ /** Lo que el driver no deja censar, dicho en voz alta (nunca un hueco callado). */
268
+ censusLimits: string[];
269
+ /** Todo lo que hace fallar el contrato, en texto. Vacío = verde. */
270
+ failures: string[];
271
+ }
272
+ /**
273
+ * Corre UNA combinación de punta a punta y devuelve el veredicto. Es el
274
+ * motor: `runMigrationContract` solo lo envuelve en tres casos de Japa, y el
275
+ * paquete lo usa directamente para demostrar que el contrato **sabe fallar**.
276
+ */
277
+ export declare function runMigrationDirection(harness: MigrationContractHarness, direction: MigrationDirection): Promise<MigrationVerdict>;
278
+ /**
279
+ * Registra las tres combinaciones como casos de Japa. Llámala en el TOP LEVEL
280
+ * del spec (Japa descarta los grupos registrados tarde).
281
+ */
282
+ export declare function runMigrationContract(harness: MigrationContractHarness): void;
283
+ export declare function registerMigrationContract(harness: MigrationContractHarness, api: ContractTestApi): void;
284
+ //# sourceMappingURL=migration_contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration_contract.d.ts","sourceRoot":"","sources":["../../../src/testing/migration_contract.ts"],"names":[],"mappings":"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"}