@things-factory/auth-base 10.1.278 → 10.1.280

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 (284) hide show
  1. package/package.json +24 -7
  2. package/CHANGELOG.md +0 -55
  3. package/dist-client/actions/auth.js.map +0 -1
  4. package/dist-client/apply-domain-theme.js.map +0 -1
  5. package/dist-client/auth.js.map +0 -1
  6. package/dist-client/bootstrap.js.map +0 -1
  7. package/dist-client/directive/privileged.js.map +0 -1
  8. package/dist-client/domain-required.js.map +0 -1
  9. package/dist-client/index.js.map +0 -1
  10. package/dist-client/profiled.js.map +0 -1
  11. package/dist-client/reducers/auth.js.map +0 -1
  12. package/dist-client/tsconfig.tsbuildinfo +0 -1
  13. package/dist-client/verify-webauthn.js.map +0 -1
  14. package/dist-server/ai-entry/access-assistant.js.map +0 -1
  15. package/dist-server/ai-entry/access-entry-targets.js.map +0 -1
  16. package/dist-server/ai-entry/entry-target-shape.js.map +0 -1
  17. package/dist-server/constants/error-code.js.map +0 -1
  18. package/dist-server/constants/error-message.js.map +0 -1
  19. package/dist-server/constants/max-age.js.map +0 -1
  20. package/dist-server/controllers/access-request.js.map +0 -1
  21. package/dist-server/controllers/account-mail.js.map +0 -1
  22. package/dist-server/controllers/auth.js.map +0 -1
  23. package/dist-server/controllers/change-pwd.js.map +0 -1
  24. package/dist-server/controllers/confirm-identity.js.map +0 -1
  25. package/dist-server/controllers/delete-user.js.map +0 -1
  26. package/dist-server/controllers/passkey.js.map +0 -1
  27. package/dist-server/controllers/password-setup.js.map +0 -1
  28. package/dist-server/controllers/profile.js.map +0 -1
  29. package/dist-server/controllers/reset-password.js.map +0 -1
  30. package/dist-server/controllers/signin.js.map +0 -1
  31. package/dist-server/controllers/signup.js.map +0 -1
  32. package/dist-server/controllers/unlock-user.js.map +0 -1
  33. package/dist-server/controllers/utils/find-verification-token.js.map +0 -1
  34. package/dist-server/controllers/utils/make-verification-token.js.map +0 -1
  35. package/dist-server/controllers/utils/password-rule.js.map +0 -1
  36. package/dist-server/controllers/utils/save-verification-token.js.map +0 -1
  37. package/dist-server/controllers/verification.js.map +0 -1
  38. package/dist-server/errors/auth-error.js.map +0 -1
  39. package/dist-server/errors/index.js.map +0 -1
  40. package/dist-server/errors/user-domain-not-match-error.js.map +0 -1
  41. package/dist-server/index.js.map +0 -1
  42. package/dist-server/middlewares/audit-scope-middleware.js.map +0 -1
  43. package/dist-server/middlewares/authenticate-401-middleware.js.map +0 -1
  44. package/dist-server/middlewares/bypass-signin-middleware.js.map +0 -1
  45. package/dist-server/middlewares/domain-authenticate-middleware.js.map +0 -1
  46. package/dist-server/middlewares/graphql-authenticate-middleware.js.map +0 -1
  47. package/dist-server/middlewares/index.js.map +0 -1
  48. package/dist-server/middlewares/jwt-authenticate-middleware.js.map +0 -1
  49. package/dist-server/middlewares/signin-middleware.js.map +0 -1
  50. package/dist-server/middlewares/verify-recaptcha-middleware.js.map +0 -1
  51. package/dist-server/migrations/1548206416130-SeedUser.js.map +0 -1
  52. package/dist-server/migrations/1566805283882-SeedPrivilege.js.map +0 -1
  53. package/dist-server/migrations/1745000000000-MigrateDomainOwnersToTable.js.map +0 -1
  54. package/dist-server/migrations/index.js.map +0 -1
  55. package/dist-server/role-tasks.js.map +0 -1
  56. package/dist-server/router/auth-checkin-router.js.map +0 -1
  57. package/dist-server/router/auth-private-process-router.js.map +0 -1
  58. package/dist-server/router/auth-public-process-router.js.map +0 -1
  59. package/dist-server/router/auth-signin-router.js.map +0 -1
  60. package/dist-server/router/auth-signup-router.js.map +0 -1
  61. package/dist-server/router/index.js.map +0 -1
  62. package/dist-server/router/oauth2/index.js.map +0 -1
  63. package/dist-server/router/oauth2/oauth2-authorize-router.js.map +0 -1
  64. package/dist-server/router/oauth2/oauth2-router.js.map +0 -1
  65. package/dist-server/router/oauth2/oauth2-server.js.map +0 -1
  66. package/dist-server/router/oauth2/passport-oauth2-client-password.js.map +0 -1
  67. package/dist-server/router/oauth2/passport-refresh-token.js.map +0 -1
  68. package/dist-server/router/path-base-domain-router.js.map +0 -1
  69. package/dist-server/router/site-root-router.js.map +0 -1
  70. package/dist-server/router/webauthn-router.js.map +0 -1
  71. package/dist-server/routes.js.map +0 -1
  72. package/dist-server/service/access-request/access-request-mutation.js.map +0 -1
  73. package/dist-server/service/access-request/access-request-query.js.map +0 -1
  74. package/dist-server/service/access-request/access-request-types.js.map +0 -1
  75. package/dist-server/service/access-request/access-request.js.map +0 -1
  76. package/dist-server/service/access-request/index.js.map +0 -1
  77. package/dist-server/service/app-binding/app-binding-mutation.js.map +0 -1
  78. package/dist-server/service/app-binding/app-binding-query.js.map +0 -1
  79. package/dist-server/service/app-binding/app-binding-types.js.map +0 -1
  80. package/dist-server/service/app-binding/app-binding.js.map +0 -1
  81. package/dist-server/service/app-binding/index.js.map +0 -1
  82. package/dist-server/service/appliance/appliance-mutation.js.map +0 -1
  83. package/dist-server/service/appliance/appliance-query.js.map +0 -1
  84. package/dist-server/service/appliance/appliance-types.js.map +0 -1
  85. package/dist-server/service/appliance/appliance.js.map +0 -1
  86. package/dist-server/service/appliance/index.js.map +0 -1
  87. package/dist-server/service/application/application-mutation.js.map +0 -1
  88. package/dist-server/service/application/application-query.js.map +0 -1
  89. package/dist-server/service/application/application-types.js.map +0 -1
  90. package/dist-server/service/application/application.js.map +0 -1
  91. package/dist-server/service/application/index.js.map +0 -1
  92. package/dist-server/service/audit/audit-action.js.map +0 -1
  93. package/dist-server/service/audit/audit-kinds.js.map +0 -1
  94. package/dist-server/service/audit/audit-query.js.map +0 -1
  95. package/dist-server/service/audit/audit-recorder.js.map +0 -1
  96. package/dist-server/service/audit/audit-request.js.map +0 -1
  97. package/dist-server/service/audit/audit-retention.js.map +0 -1
  98. package/dist-server/service/audit/audit-subscriber.js.map +0 -1
  99. package/dist-server/service/audit/audit-target.js.map +0 -1
  100. package/dist-server/service/audit/audit-types.js.map +0 -1
  101. package/dist-server/service/audit/audit-work.js.map +0 -1
  102. package/dist-server/service/audit/index.js.map +0 -1
  103. package/dist-server/service/auth-provider/auth-provider-mutation.js.map +0 -1
  104. package/dist-server/service/auth-provider/auth-provider-parameter-spec.js.map +0 -1
  105. package/dist-server/service/auth-provider/auth-provider-query.js.map +0 -1
  106. package/dist-server/service/auth-provider/auth-provider-type.js.map +0 -1
  107. package/dist-server/service/auth-provider/auth-provider.js.map +0 -1
  108. package/dist-server/service/auth-provider/index.js.map +0 -1
  109. package/dist-server/service/domain-generator/domain-generator-mutation.js.map +0 -1
  110. package/dist-server/service/domain-generator/domain-generator-types.js.map +0 -1
  111. package/dist-server/service/domain-generator/index.js.map +0 -1
  112. package/dist-server/service/domain-link/domain-link-mutation.js.map +0 -1
  113. package/dist-server/service/domain-link/domain-link-query.js.map +0 -1
  114. package/dist-server/service/domain-link/domain-link-types.js.map +0 -1
  115. package/dist-server/service/domain-link/domain-link.js.map +0 -1
  116. package/dist-server/service/domain-link/index.js.map +0 -1
  117. package/dist-server/service/domain-owner/domain-owner-mutation.js.map +0 -1
  118. package/dist-server/service/domain-owner/domain-owner-query.js.map +0 -1
  119. package/dist-server/service/domain-owner/domain-owner.js.map +0 -1
  120. package/dist-server/service/domain-owner/index.js.map +0 -1
  121. package/dist-server/service/granted-role/granted-role-mutation.js.map +0 -1
  122. package/dist-server/service/granted-role/granted-role-query.js.map +0 -1
  123. package/dist-server/service/granted-role/granted-role.js.map +0 -1
  124. package/dist-server/service/granted-role/index.js.map +0 -1
  125. package/dist-server/service/identity-confirmation/identity-confirmation.js.map +0 -1
  126. package/dist-server/service/index.js.map +0 -1
  127. package/dist-server/service/open-fields.js.map +0 -1
  128. package/dist-server/service/partner/index.js.map +0 -1
  129. package/dist-server/service/partner/partner-mutation.js.map +0 -1
  130. package/dist-server/service/partner/partner-query.js.map +0 -1
  131. package/dist-server/service/partner/partner-types.js.map +0 -1
  132. package/dist-server/service/partner/partner.js.map +0 -1
  133. package/dist-server/service/password-history/index.js.map +0 -1
  134. package/dist-server/service/password-history/password-history.js.map +0 -1
  135. package/dist-server/service/privilege/index.js.map +0 -1
  136. package/dist-server/service/privilege/open-field-rule.js.map +0 -1
  137. package/dist-server/service/privilege/privilege-axis.js.map +0 -1
  138. package/dist-server/service/privilege/privilege-deprecation.js.map +0 -1
  139. package/dist-server/service/privilege/privilege-directive.js.map +0 -1
  140. package/dist-server/service/privilege/privilege-mutation.js.map +0 -1
  141. package/dist-server/service/privilege/privilege-query.js.map +0 -1
  142. package/dist-server/service/privilege/privilege-rejection.js.map +0 -1
  143. package/dist-server/service/privilege/privilege-sync.js.map +0 -1
  144. package/dist-server/service/privilege/privilege-types.js.map +0 -1
  145. package/dist-server/service/privilege/privilege.js.map +0 -1
  146. package/dist-server/service/role/index.js.map +0 -1
  147. package/dist-server/service/role/role-mutation.js.map +0 -1
  148. package/dist-server/service/role/role-privilege-query.js.map +0 -1
  149. package/dist-server/service/role/role-query.js.map +0 -1
  150. package/dist-server/service/role/role-types.js.map +0 -1
  151. package/dist-server/service/role/role.js.map +0 -1
  152. package/dist-server/service/role-template/index.js.map +0 -1
  153. package/dist-server/service/role-template/role-task.js.map +0 -1
  154. package/dist-server/service/role-template/role-template-gap-resolver.js.map +0 -1
  155. package/dist-server/service/role-template/role-template-mutation.js.map +0 -1
  156. package/dist-server/service/role-template/role-template-query.js.map +0 -1
  157. package/dist-server/service/role-template/role-template-types.js.map +0 -1
  158. package/dist-server/service/role-template/role-template.js.map +0 -1
  159. package/dist-server/service/user/domain-query.js.map +0 -1
  160. package/dist-server/service/user/index.js.map +0 -1
  161. package/dist-server/service/user/user-mutation.js.map +0 -1
  162. package/dist-server/service/user/user-query.js.map +0 -1
  163. package/dist-server/service/user/user-types.js.map +0 -1
  164. package/dist-server/service/user/user.js.map +0 -1
  165. package/dist-server/service/users-auth-providers/index.js.map +0 -1
  166. package/dist-server/service/users-auth-providers/users-auth-providers.js.map +0 -1
  167. package/dist-server/service/verification-token/index.js.map +0 -1
  168. package/dist-server/service/verification-token/verification-token.js.map +0 -1
  169. package/dist-server/service/web-auth-credential/index.js.map +0 -1
  170. package/dist-server/service/web-auth-credential/web-auth-credential-mutation.js.map +0 -1
  171. package/dist-server/service/web-auth-credential/web-auth-credential-query.js.map +0 -1
  172. package/dist-server/service/web-auth-credential/web-auth-credential.js.map +0 -1
  173. package/dist-server/tsconfig.tsbuildinfo +0 -1
  174. package/dist-server/types.js.map +0 -1
  175. package/dist-server/utils/accepts.js.map +0 -1
  176. package/dist-server/utils/access-request-review.js.map +0 -1
  177. package/dist-server/utils/access-token-cookie.js.map +0 -1
  178. package/dist-server/utils/account-lock-rule.js.map +0 -1
  179. package/dist-server/utils/assignable-roles.js.map +0 -1
  180. package/dist-server/utils/build-auth-url.js.map +0 -1
  181. package/dist-server/utils/can-user-checkin-domain.js.map +0 -1
  182. package/dist-server/utils/check-permission.js.map +0 -1
  183. package/dist-server/utils/check-user-belongs-domain.js.map +0 -1
  184. package/dist-server/utils/check-user-has-role.js.map +0 -1
  185. package/dist-server/utils/checkin-domain-facts.js.map +0 -1
  186. package/dist-server/utils/checkin-domain-rule.js.map +0 -1
  187. package/dist-server/utils/credential-at-rest.js.map +0 -1
  188. package/dist-server/utils/credential-features.js.map +0 -1
  189. package/dist-server/utils/credential-serial-rule.js.map +0 -1
  190. package/dist-server/utils/domain-ownership.js.map +0 -1
  191. package/dist-server/utils/encrypt-state.js.map +0 -1
  192. package/dist-server/utils/get-aes-256-key.js.map +0 -1
  193. package/dist-server/utils/get-domain-users.js.map +0 -1
  194. package/dist-server/utils/get-secret.js.map +0 -1
  195. package/dist-server/utils/get-user-domains.js.map +0 -1
  196. package/dist-server/utils/lock-duration.js.map +0 -1
  197. package/dist-server/utils/password-reset-rule.js.map +0 -1
  198. package/dist-server/utils/profile-user.js.map +0 -1
  199. package/dist-server/utils/refuse-role-name.js.map +0 -1
  200. package/dist-server/utils/role-name-standing.js.map +0 -1
  201. package/dist-server/utils/same-origin-redirect.js.map +0 -1
  202. package/dist-server/utils/verification-token-rule.js.map +0 -1
  203. package/spec/unit/checkin-domain.spec.ts +0 -307
  204. package/spec/unit/checkin-privilege.spec.ts +0 -205
  205. package/spec/unit/domain-owner-entity.spec.ts +0 -179
  206. package/spec/unit/domain-owner-granted.spec.ts +0 -215
  207. package/spec/unit/domain-owner-migration.spec.ts +0 -236
  208. package/spec/unit/domain-owner-mutation.spec.ts +0 -337
  209. package/spec/unit/domain-ownership.spec.ts +0 -188
  210. package/tests/access-assistant-db.test.ts +0 -155
  211. package/tests/access-entry-targets-db.test.ts +0 -176
  212. package/tests/access-request-db.test.ts +0 -394
  213. package/tests/access-request-pg.test.ts +0 -83
  214. package/tests/access-request-review.test.ts +0 -193
  215. package/tests/account-lock-db.test.ts +0 -216
  216. package/tests/account-lock-rule.test.ts +0 -141
  217. package/tests/account-mail.test.ts +0 -69
  218. package/tests/activate-page-case.test.ts +0 -53
  219. package/tests/add-user-gates.test.ts +0 -34
  220. package/tests/app-binding-db.test.ts +0 -210
  221. package/tests/app-binding-delete-db.test.ts +0 -188
  222. package/tests/appliance-credential-state-db.test.ts +0 -207
  223. package/tests/appliance-delete-db.test.ts +0 -119
  224. package/tests/appliance-revoke-db.test.ts +0 -294
  225. package/tests/appliance-schema.test.ts +0 -129
  226. package/tests/application-delete-db.test.ts +0 -190
  227. package/tests/application-token-payload-db.test.ts +0 -185
  228. package/tests/assignable-roles-db.test.ts +0 -219
  229. package/tests/audit-db.test.ts +0 -410
  230. package/tests/audit-work.test.ts +0 -58
  231. package/tests/auth-base-role-tasks.test.ts +0 -58
  232. package/tests/checkin-domain-rule.test.ts +0 -128
  233. package/tests/checkin-privilege-seam-db.test.ts +0 -158
  234. package/tests/compiled.ts +0 -41
  235. package/tests/confirm-identity-db.test.ts +0 -85
  236. package/tests/credential-at-rest-db.test.ts +0 -246
  237. package/tests/credential-features-off-db.test.ts +0 -189
  238. package/tests/credential-serial-rule.test.ts +0 -84
  239. package/tests/declare-privileges.test.ts +0 -29
  240. package/tests/domain-assignees-db.test.ts +0 -95
  241. package/tests/domain-inheritance-sentinel.test.ts +0 -93
  242. package/tests/domain-required.test.ts +0 -127
  243. package/tests/has-privilege-db.test.ts +0 -198
  244. package/tests/identity-confirmation.test.ts +0 -146
  245. package/tests/list-inheritance-db.test.ts +0 -127
  246. package/tests/lock-recovery.test.ts +0 -206
  247. package/tests/mail-request-answers-db.test.ts +0 -142
  248. package/tests/open-doors.test.ts +0 -121
  249. package/tests/open-fields-enforcement.test.ts +0 -215
  250. package/tests/open-fields-framework.test.ts +0 -212
  251. package/tests/open-redirect-db.test.ts +0 -143
  252. package/tests/passkey-authenticator.ts +0 -104
  253. package/tests/passkey-db.test.ts +0 -295
  254. package/tests/passkey-signin-route-db.test.ts +0 -139
  255. package/tests/password-hashing.test.ts +0 -131
  256. package/tests/password-persistence.test.ts +0 -147
  257. package/tests/password-reset-rule-db.test.ts +0 -159
  258. package/tests/password-setup-db.test.ts +0 -215
  259. package/tests/permission-gate.test.ts +0 -228
  260. package/tests/picture-reducer.test.ts +0 -25
  261. package/tests/privilege-axis.test.ts +0 -157
  262. package/tests/privilege-deprecation.test.ts +0 -65
  263. package/tests/privilege-directive.test.ts +0 -332
  264. package/tests/privilege-rejection.test.ts +0 -104
  265. package/tests/privilege-sync-db.test.ts +0 -58
  266. package/tests/profile-user.test.ts +0 -24
  267. package/tests/refusal-cause.test.ts +0 -80
  268. package/tests/refusals-have-korean.test.ts +0 -24
  269. package/tests/request-holds.test.ts +0 -53
  270. package/tests/role-inheritance-db.test.ts +0 -286
  271. package/tests/role-mutation-db.test.ts +0 -293
  272. package/tests/role-name-lookup-sentinel.test.ts +0 -79
  273. package/tests/role-name-standing.test.ts +0 -83
  274. package/tests/role-privileges-db.test.ts +0 -252
  275. package/tests/role-task.test.ts +0 -168
  276. package/tests/role-template-gap-db.test.ts +0 -268
  277. package/tests/role-template-seed-db.test.ts +0 -180
  278. package/tests/role-template.test.ts +0 -162
  279. package/tests/role-users-gate.test.ts +0 -22
  280. package/tests/signin-policy.test.ts +0 -200
  281. package/tests/signup-duplicate-db.test.ts +0 -68
  282. package/tests/token-issuance.test.ts +0 -244
  283. package/tests/user-roles-field-db.test.ts +0 -134
  284. package/tests/verification-token-db.test.ts +0 -285
@@ -1,215 +0,0 @@
1
- /**
2
- * domainOwnerGranted 권한 체크 로직 테스트
3
- *
4
- * 실제 함수(`process.domainOwnerGranted`)는 `@things-factory/shell`의
5
- * getRepository(Domain)을 사용하므로 테스트 환경에서 직접 호출하기 어렵다.
6
- * 동일한 동작을 하는 로직을 재현해 양쪽 경로(legacy cache + join table)를
7
- * 모두 검증한다.
8
- */
9
-
10
- import { EntityManager } from 'typeorm'
11
- import { TestDatabase } from '../../../../test/test-database'
12
- import { withTestTransaction } from '../../../../test/test-context'
13
- import {
14
- domainFactory,
15
- userFactory,
16
- domainOwnerFactory
17
- } from '../../../../test/factories'
18
- import { Domain, User } from '../../../../test/entities/schemas'
19
-
20
- /**
21
- * `packages/auth-base/server/middlewares/domain-authenticate-middleware.ts`
22
- * 의 `process.domainOwnerGranted` 와 동일한 로직.
23
- */
24
- async function domainOwnerGranted(
25
- manager: EntityManager,
26
- domain: Domain | null | undefined,
27
- user: User | null | undefined
28
- ): Promise<boolean> {
29
- if (!user || !domain) return false
30
- if (domain.owner === user.id) return true
31
-
32
- return manager
33
- .createQueryBuilder()
34
- .select('ow')
35
- .from('DomainOwner', 'ow')
36
- .where('ow.domain_id = :domainId AND ow.user_id = :userId', {
37
- domainId: domain.id,
38
- userId: user.id
39
- })
40
- .getExists()
41
- }
42
-
43
- describe('domainOwnerGranted 권한 체크', () => {
44
- let testDb: TestDatabase
45
-
46
- beforeAll(() => {
47
- testDb = TestDatabase.getInstance()
48
- })
49
-
50
- describe('Null/빈 값 방어', () => {
51
- it('user가 없으면 false', async () => {
52
- await withTestTransaction(async context => {
53
- const { tx, domain } = context.state
54
- expect(await domainOwnerGranted(tx, domain, null)).toBe(false)
55
- expect(await domainOwnerGranted(tx, domain, undefined)).toBe(false)
56
- })
57
- })
58
-
59
- it('domain이 없으면 false', async () => {
60
- await withTestTransaction(async context => {
61
- const { tx, user } = context.state
62
- expect(await domainOwnerGranted(tx, null, user)).toBe(false)
63
- expect(await domainOwnerGranted(tx, undefined, user)).toBe(false)
64
- })
65
- })
66
-
67
- it('둘 다 없으면 false', async () => {
68
- await withTestTransaction(async context => {
69
- const { tx } = context.state
70
- expect(await domainOwnerGranted(tx, null, null)).toBe(false)
71
- })
72
- })
73
- })
74
-
75
- describe('(1) 하위 호환: Domain.owner 캐시 필드', () => {
76
- it('Domain.owner === user.id 이면 true', async () => {
77
- await withTestTransaction(async context => {
78
- const { tx } = context.state
79
-
80
- const user = await userFactory.create({}, tx)
81
- const domain = await domainFactory.create({ owner: user.id }, tx)
82
-
83
- expect(await domainOwnerGranted(tx, domain, user)).toBe(true)
84
- })
85
- })
86
-
87
- it('Domain.owner 와 user.id 가 다르고 join 테이블에도 없으면 false', async () => {
88
- await withTestTransaction(async context => {
89
- const { tx } = context.state
90
-
91
- const ownerUser = await userFactory.create({ name: 'owner' }, tx)
92
- const otherUser = await userFactory.create({ name: 'other' }, tx)
93
- const domain = await domainFactory.create({ owner: ownerUser.id }, tx)
94
-
95
- expect(await domainOwnerGranted(tx, domain, otherUser)).toBe(false)
96
- })
97
- })
98
- })
99
-
100
- describe('(2) DomainOwner 조인 테이블', () => {
101
- it('테이블에 엔트리가 있으면 true (legacy cache 없이도)', async () => {
102
- await withTestTransaction(async context => {
103
- const { tx } = context.state
104
-
105
- const domain = await domainFactory.create({}, tx) // owner = null
106
- const user = await userFactory.create({}, tx)
107
- await domainOwnerFactory.grant(domain, user, {}, tx)
108
-
109
- expect(await domainOwnerGranted(tx, domain, user)).toBe(true)
110
- })
111
- })
112
-
113
- it('엔트리가 없으면 false', async () => {
114
- await withTestTransaction(async context => {
115
- const { tx } = context.state
116
-
117
- const domain = await domainFactory.create({}, tx)
118
- const user = await userFactory.create({}, tx)
119
-
120
- expect(await domainOwnerGranted(tx, domain, user)).toBe(false)
121
- })
122
- })
123
-
124
- it('다른 도메인의 owner 엔트리로는 현재 도메인 owner 권한이 생기지 않는다', async () => {
125
- await withTestTransaction(async context => {
126
- const { tx } = context.state
127
-
128
- const domainA = await domainFactory.create({ name: 'A' }, tx)
129
- const domainB = await domainFactory.create({ name: 'B' }, tx)
130
- const user = await userFactory.create({}, tx)
131
-
132
- await domainOwnerFactory.grant(domainA, user, {}, tx)
133
-
134
- expect(await domainOwnerGranted(tx, domainA, user)).toBe(true)
135
- expect(await domainOwnerGranted(tx, domainB, user)).toBe(false)
136
- })
137
- })
138
-
139
- it('같은 도메인의 다른 user는 owner가 아니다', async () => {
140
- await withTestTransaction(async context => {
141
- const { tx } = context.state
142
-
143
- const domain = await domainFactory.create({}, tx)
144
- const ownerUser = await userFactory.create({ name: 'owner' }, tx)
145
- const memberUser = await userFactory.create({ name: 'member' }, tx)
146
-
147
- await domainOwnerFactory.grant(domain, ownerUser, {}, tx)
148
-
149
- expect(await domainOwnerGranted(tx, domain, ownerUser)).toBe(true)
150
- expect(await domainOwnerGranted(tx, domain, memberUser)).toBe(false)
151
- })
152
- })
153
-
154
- it('멀티 오너 — 각각이 독립적으로 owner로 인정된다', async () => {
155
- await withTestTransaction(async context => {
156
- const { tx } = context.state
157
-
158
- const domain = await domainFactory.create({}, tx)
159
- const u1 = await userFactory.create({ name: 'U1' }, tx)
160
- const u2 = await userFactory.create({ name: 'U2' }, tx)
161
- const u3 = await userFactory.create({ name: 'U3' }, tx)
162
-
163
- await domainOwnerFactory.grant(domain, u1, {}, tx)
164
- await domainOwnerFactory.grant(domain, u2, {}, tx)
165
- await domainOwnerFactory.grant(domain, u3, {}, tx)
166
-
167
- expect(await domainOwnerGranted(tx, domain, u1)).toBe(true)
168
- expect(await domainOwnerGranted(tx, domain, u2)).toBe(true)
169
- expect(await domainOwnerGranted(tx, domain, u3)).toBe(true)
170
- })
171
- })
172
- })
173
-
174
- describe('양쪽 경로 OR 동작', () => {
175
- it('legacy cache 경로만 만족해도 true', async () => {
176
- await withTestTransaction(async context => {
177
- const { tx } = context.state
178
-
179
- const user = await userFactory.create({}, tx)
180
- const domain = await domainFactory.create({ owner: user.id }, tx)
181
- // join table에 엔트리 없음
182
-
183
- expect(await domainOwnerGranted(tx, domain, user)).toBe(true)
184
- })
185
- })
186
-
187
- it('join table 경로만 만족해도 true (cache가 다른 user여도)', async () => {
188
- await withTestTransaction(async context => {
189
- const { tx } = context.state
190
-
191
- const cachedUser = await userFactory.create({ name: 'cached' }, tx)
192
- const newOwner = await userFactory.create({ name: 'new-owner' }, tx)
193
- const domain = await domainFactory.create({ owner: cachedUser.id }, tx)
194
-
195
- await domainOwnerFactory.grant(domain, newOwner, {}, tx)
196
-
197
- expect(await domainOwnerGranted(tx, domain, newOwner)).toBe(true)
198
- // 기존 캐시된 유저도 여전히 owner
199
- expect(await domainOwnerGranted(tx, domain, cachedUser)).toBe(true)
200
- })
201
- })
202
-
203
- it('양쪽 모두 만족하면 true (중복 허용 — cache와 table에 같은 사람)', async () => {
204
- await withTestTransaction(async context => {
205
- const { tx } = context.state
206
-
207
- const user = await userFactory.create({}, tx)
208
- const domain = await domainFactory.create({ owner: user.id }, tx)
209
- await domainOwnerFactory.grant(domain, user, {}, tx)
210
-
211
- expect(await domainOwnerGranted(tx, domain, user)).toBe(true)
212
- })
213
- })
214
- })
215
- })
@@ -1,236 +0,0 @@
1
- /**
2
- * MigrateDomainOwnersToTable 마이그레이션 로직 테스트
3
- *
4
- * 마이그레이션의 핵심 동작:
5
- * - Domain.owner가 있는 모든 도메인을 순회
6
- * - DomainOwner 테이블에 동일 (domain, user) 쌍이 없으면 삽입
7
- * - 이미 존재하면 skip (idempotent)
8
- * - Domain.owner 는 건드리지 않음 (데이터 유실 방지)
9
- *
10
- * 실제 마이그레이션 클래스는 `@things-factory/shell` 의 getRepository에
11
- * 의존하므로, 동일한 로직을 테스트 스키마 기반으로 재현한다.
12
- */
13
-
14
- import { EntityManager } from 'typeorm'
15
- import { TestDatabase } from '../../../../test/test-database'
16
- import {
17
- domainFactory,
18
- userFactory,
19
- domainOwnerFactory
20
- } from '../../../../test/factories'
21
- import { Domain, DomainOwner, User } from '../../../../test/entities/schemas'
22
-
23
- const MIGRATION_REASON = 'migrated from legacy single-owner field'
24
-
25
- /** up: legacy Domain.owner → DomainOwner 테이블 이관 */
26
- async function migrationUp(
27
- manager: EntityManager
28
- ): Promise<{ migrated: number; skipped: number }> {
29
- const domainRepo = manager.getRepository<Domain>('Domain')
30
- const ownerRepo = manager.getRepository<DomainOwner>('DomainOwner')
31
-
32
- const domains = await domainRepo
33
- .createQueryBuilder('d')
34
- .where('d.owner IS NOT NULL')
35
- .getMany()
36
-
37
- let migrated = 0
38
- let skipped = 0
39
-
40
- for (const domain of domains) {
41
- if (!domain.owner) continue
42
-
43
- const existing = await ownerRepo.findOne({
44
- where: { domain: { id: domain.id }, user: { id: domain.owner } }
45
- })
46
- if (existing) {
47
- skipped++
48
- continue
49
- }
50
-
51
- const entry = ownerRepo.create({
52
- domain: { id: domain.id } as Domain,
53
- user: { id: domain.owner } as unknown as User,
54
- reason: MIGRATION_REASON
55
- } as Partial<DomainOwner>)
56
- await ownerRepo.save(entry)
57
- migrated++
58
- }
59
-
60
- return { migrated, skipped }
61
- }
62
-
63
- /** down: reason 이 'migrated from legacy...'인 엔트리만 삭제 */
64
- async function migrationDown(manager: EntityManager): Promise<number> {
65
- const result = await manager
66
- .createQueryBuilder()
67
- .delete()
68
- .from('DomainOwner')
69
- .where('reason = :reason', { reason: MIGRATION_REASON })
70
- .execute()
71
- return result.affected ?? 0
72
- }
73
-
74
- describe('MigrateDomainOwnersToTable', () => {
75
- let testDb: TestDatabase
76
-
77
- beforeAll(() => {
78
- testDb = TestDatabase.getInstance()
79
- })
80
-
81
- describe('up()', () => {
82
- it('Domain.owner 가 있는 도메인을 DomainOwner 테이블에 이관한다', async () => {
83
- const ds = testDb.getDataSource()
84
-
85
- const u1 = await userFactory.create({ name: 'legacy-owner-1' })
86
- const u2 = await userFactory.create({ name: 'legacy-owner-2' })
87
- await domainFactory.create({ name: 'D1', owner: u1.id })
88
- await domainFactory.create({ name: 'D2', owner: u2.id })
89
-
90
- const result = await migrationUp(ds.manager)
91
-
92
- expect(result.migrated).toBeGreaterThanOrEqual(2)
93
-
94
- const total = await ds.manager.count('DomainOwner', {
95
- where: { reason: MIGRATION_REASON }
96
- })
97
- expect(total).toBeGreaterThanOrEqual(2)
98
- })
99
-
100
- it('Domain.owner 가 null인 도메인은 건드리지 않는다', async () => {
101
- const ds = testDb.getDataSource()
102
-
103
- await domainFactory.create({ name: 'no-owner-domain', owner: null as any })
104
-
105
- const beforeCount = await ds.manager.count('DomainOwner')
106
- await migrationUp(ds.manager)
107
- const afterCount = await ds.manager.count('DomainOwner')
108
-
109
- // no-owner-domain 에 대해서는 아무것도 생성되지 않음
110
- expect(afterCount).toBe(beforeCount)
111
- })
112
-
113
- it('이미 DomainOwner 엔트리가 있는 경우 skip 된다 (idempotent)', async () => {
114
- const ds = testDb.getDataSource()
115
-
116
- const user = await userFactory.create({ name: 'already-migrated' })
117
- const domain = await domainFactory.create({
118
- name: 'idempotent-domain',
119
- owner: user.id
120
- })
121
- await domainOwnerFactory.grant(domain, user, { reason: 'added manually' })
122
-
123
- const result = await migrationUp(ds.manager)
124
- expect(result.skipped).toBeGreaterThanOrEqual(1)
125
-
126
- // 엔트리 수는 하나로 유지 (중복 생성 안 됨)
127
- const count = await ds.manager.count('DomainOwner', {
128
- where: {
129
- domain: { id: domain.id },
130
- user: { id: user.id }
131
- }
132
- })
133
- expect(count).toBe(1)
134
- })
135
-
136
- it('두 번 연속 실행해도 안전하다 (진정한 idempotency)', async () => {
137
- const ds = testDb.getDataSource()
138
-
139
- const user = await userFactory.create({ name: 'twice-migrated' })
140
- await domainFactory.create({ name: 'twice-domain', owner: user.id })
141
-
142
- const first = await migrationUp(ds.manager)
143
- const totalAfterFirst = await ds.manager.count('DomainOwner')
144
-
145
- const second = await migrationUp(ds.manager)
146
- const totalAfterSecond = await ds.manager.count('DomainOwner')
147
-
148
- expect(second.migrated).toBe(0)
149
- expect(totalAfterSecond).toBe(totalAfterFirst)
150
- expect(first.migrated).toBeGreaterThan(0)
151
- })
152
- })
153
-
154
- describe('down()', () => {
155
- it("reason이 'migrated from legacy single-owner field' 인 엔트리만 삭제한다", async () => {
156
- const ds = testDb.getDataSource()
157
-
158
- const user = await userFactory.create({ name: 'mixed-reason-user' })
159
- const domain = await domainFactory.create({
160
- name: 'mixed-reason-domain',
161
- owner: user.id
162
- })
163
- // 마이그레이션으로 생성된 엔트리
164
- await migrationUp(ds.manager)
165
- // 다른 reason 으로 수동 추가된 엔트리
166
- const otherUser = await userFactory.create({ name: 'manual' })
167
- await domainOwnerFactory.grant(domain, otherUser, { reason: 'manually added by admin' })
168
-
169
- const beforeMigrated = await ds.manager.count('DomainOwner', {
170
- where: { reason: MIGRATION_REASON }
171
- })
172
- const beforeOther = await ds.manager.count('DomainOwner', {
173
- where: { reason: 'manually added by admin' }
174
- })
175
-
176
- expect(beforeMigrated).toBeGreaterThanOrEqual(1)
177
- expect(beforeOther).toBe(1)
178
-
179
- await migrationDown(ds.manager)
180
-
181
- const afterMigrated = await ds.manager.count('DomainOwner', {
182
- where: { reason: MIGRATION_REASON }
183
- })
184
- const afterOther = await ds.manager.count('DomainOwner', {
185
- where: { reason: 'manually added by admin' }
186
- })
187
-
188
- expect(afterMigrated).toBe(0)
189
- expect(afterOther).toBe(1) // 수동 추가된 엔트리는 보존
190
- })
191
-
192
- it('Domain.owner 필드는 down() 에서 건드리지 않는다 (데이터 유실 없음)', async () => {
193
- const ds = testDb.getDataSource()
194
-
195
- const user = await userFactory.create({ name: 'preserved' })
196
- const domain = await domainFactory.create({
197
- name: 'preserved-domain',
198
- owner: user.id
199
- })
200
-
201
- await migrationUp(ds.manager)
202
- await migrationDown(ds.manager)
203
-
204
- const reloaded = await ds.manager.findOne<Domain>('Domain', {
205
- where: { id: domain.id }
206
- })
207
- expect(reloaded?.owner).toBe(user.id)
208
- })
209
- })
210
-
211
- describe('up → down → up 왕복', () => {
212
- it('왕복 후 일관성 유지', async () => {
213
- const ds = testDb.getDataSource()
214
-
215
- const user = await userFactory.create({ name: 'roundtrip' })
216
- await domainFactory.create({ name: 'roundtrip-domain', owner: user.id })
217
-
218
- await migrationUp(ds.manager)
219
- const afterUp1 = await ds.manager.count('DomainOwner', {
220
- where: { reason: MIGRATION_REASON }
221
- })
222
-
223
- await migrationDown(ds.manager)
224
- const afterDown = await ds.manager.count('DomainOwner', {
225
- where: { reason: MIGRATION_REASON }
226
- })
227
- expect(afterDown).toBe(0)
228
-
229
- await migrationUp(ds.manager)
230
- const afterUp2 = await ds.manager.count('DomainOwner', {
231
- where: { reason: MIGRATION_REASON }
232
- })
233
- expect(afterUp2).toBe(afterUp1)
234
- })
235
- })
236
- })