@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.
- package/package.json +24 -7
- package/CHANGELOG.md +0 -55
- package/dist-client/actions/auth.js.map +0 -1
- package/dist-client/apply-domain-theme.js.map +0 -1
- package/dist-client/auth.js.map +0 -1
- package/dist-client/bootstrap.js.map +0 -1
- package/dist-client/directive/privileged.js.map +0 -1
- package/dist-client/domain-required.js.map +0 -1
- package/dist-client/index.js.map +0 -1
- package/dist-client/profiled.js.map +0 -1
- package/dist-client/reducers/auth.js.map +0 -1
- package/dist-client/tsconfig.tsbuildinfo +0 -1
- package/dist-client/verify-webauthn.js.map +0 -1
- package/dist-server/ai-entry/access-assistant.js.map +0 -1
- package/dist-server/ai-entry/access-entry-targets.js.map +0 -1
- package/dist-server/ai-entry/entry-target-shape.js.map +0 -1
- package/dist-server/constants/error-code.js.map +0 -1
- package/dist-server/constants/error-message.js.map +0 -1
- package/dist-server/constants/max-age.js.map +0 -1
- package/dist-server/controllers/access-request.js.map +0 -1
- package/dist-server/controllers/account-mail.js.map +0 -1
- package/dist-server/controllers/auth.js.map +0 -1
- package/dist-server/controllers/change-pwd.js.map +0 -1
- package/dist-server/controllers/confirm-identity.js.map +0 -1
- package/dist-server/controllers/delete-user.js.map +0 -1
- package/dist-server/controllers/passkey.js.map +0 -1
- package/dist-server/controllers/password-setup.js.map +0 -1
- package/dist-server/controllers/profile.js.map +0 -1
- package/dist-server/controllers/reset-password.js.map +0 -1
- package/dist-server/controllers/signin.js.map +0 -1
- package/dist-server/controllers/signup.js.map +0 -1
- package/dist-server/controllers/unlock-user.js.map +0 -1
- package/dist-server/controllers/utils/find-verification-token.js.map +0 -1
- package/dist-server/controllers/utils/make-verification-token.js.map +0 -1
- package/dist-server/controllers/utils/password-rule.js.map +0 -1
- package/dist-server/controllers/utils/save-verification-token.js.map +0 -1
- package/dist-server/controllers/verification.js.map +0 -1
- package/dist-server/errors/auth-error.js.map +0 -1
- package/dist-server/errors/index.js.map +0 -1
- package/dist-server/errors/user-domain-not-match-error.js.map +0 -1
- package/dist-server/index.js.map +0 -1
- package/dist-server/middlewares/audit-scope-middleware.js.map +0 -1
- package/dist-server/middlewares/authenticate-401-middleware.js.map +0 -1
- package/dist-server/middlewares/bypass-signin-middleware.js.map +0 -1
- package/dist-server/middlewares/domain-authenticate-middleware.js.map +0 -1
- package/dist-server/middlewares/graphql-authenticate-middleware.js.map +0 -1
- package/dist-server/middlewares/index.js.map +0 -1
- package/dist-server/middlewares/jwt-authenticate-middleware.js.map +0 -1
- package/dist-server/middlewares/signin-middleware.js.map +0 -1
- package/dist-server/middlewares/verify-recaptcha-middleware.js.map +0 -1
- package/dist-server/migrations/1548206416130-SeedUser.js.map +0 -1
- package/dist-server/migrations/1566805283882-SeedPrivilege.js.map +0 -1
- package/dist-server/migrations/1745000000000-MigrateDomainOwnersToTable.js.map +0 -1
- package/dist-server/migrations/index.js.map +0 -1
- package/dist-server/role-tasks.js.map +0 -1
- package/dist-server/router/auth-checkin-router.js.map +0 -1
- package/dist-server/router/auth-private-process-router.js.map +0 -1
- package/dist-server/router/auth-public-process-router.js.map +0 -1
- package/dist-server/router/auth-signin-router.js.map +0 -1
- package/dist-server/router/auth-signup-router.js.map +0 -1
- package/dist-server/router/index.js.map +0 -1
- package/dist-server/router/oauth2/index.js.map +0 -1
- package/dist-server/router/oauth2/oauth2-authorize-router.js.map +0 -1
- package/dist-server/router/oauth2/oauth2-router.js.map +0 -1
- package/dist-server/router/oauth2/oauth2-server.js.map +0 -1
- package/dist-server/router/oauth2/passport-oauth2-client-password.js.map +0 -1
- package/dist-server/router/oauth2/passport-refresh-token.js.map +0 -1
- package/dist-server/router/path-base-domain-router.js.map +0 -1
- package/dist-server/router/site-root-router.js.map +0 -1
- package/dist-server/router/webauthn-router.js.map +0 -1
- package/dist-server/routes.js.map +0 -1
- package/dist-server/service/access-request/access-request-mutation.js.map +0 -1
- package/dist-server/service/access-request/access-request-query.js.map +0 -1
- package/dist-server/service/access-request/access-request-types.js.map +0 -1
- package/dist-server/service/access-request/access-request.js.map +0 -1
- package/dist-server/service/access-request/index.js.map +0 -1
- package/dist-server/service/app-binding/app-binding-mutation.js.map +0 -1
- package/dist-server/service/app-binding/app-binding-query.js.map +0 -1
- package/dist-server/service/app-binding/app-binding-types.js.map +0 -1
- package/dist-server/service/app-binding/app-binding.js.map +0 -1
- package/dist-server/service/app-binding/index.js.map +0 -1
- package/dist-server/service/appliance/appliance-mutation.js.map +0 -1
- package/dist-server/service/appliance/appliance-query.js.map +0 -1
- package/dist-server/service/appliance/appliance-types.js.map +0 -1
- package/dist-server/service/appliance/appliance.js.map +0 -1
- package/dist-server/service/appliance/index.js.map +0 -1
- package/dist-server/service/application/application-mutation.js.map +0 -1
- package/dist-server/service/application/application-query.js.map +0 -1
- package/dist-server/service/application/application-types.js.map +0 -1
- package/dist-server/service/application/application.js.map +0 -1
- package/dist-server/service/application/index.js.map +0 -1
- package/dist-server/service/audit/audit-action.js.map +0 -1
- package/dist-server/service/audit/audit-kinds.js.map +0 -1
- package/dist-server/service/audit/audit-query.js.map +0 -1
- package/dist-server/service/audit/audit-recorder.js.map +0 -1
- package/dist-server/service/audit/audit-request.js.map +0 -1
- package/dist-server/service/audit/audit-retention.js.map +0 -1
- package/dist-server/service/audit/audit-subscriber.js.map +0 -1
- package/dist-server/service/audit/audit-target.js.map +0 -1
- package/dist-server/service/audit/audit-types.js.map +0 -1
- package/dist-server/service/audit/audit-work.js.map +0 -1
- package/dist-server/service/audit/index.js.map +0 -1
- package/dist-server/service/auth-provider/auth-provider-mutation.js.map +0 -1
- package/dist-server/service/auth-provider/auth-provider-parameter-spec.js.map +0 -1
- package/dist-server/service/auth-provider/auth-provider-query.js.map +0 -1
- package/dist-server/service/auth-provider/auth-provider-type.js.map +0 -1
- package/dist-server/service/auth-provider/auth-provider.js.map +0 -1
- package/dist-server/service/auth-provider/index.js.map +0 -1
- package/dist-server/service/domain-generator/domain-generator-mutation.js.map +0 -1
- package/dist-server/service/domain-generator/domain-generator-types.js.map +0 -1
- package/dist-server/service/domain-generator/index.js.map +0 -1
- package/dist-server/service/domain-link/domain-link-mutation.js.map +0 -1
- package/dist-server/service/domain-link/domain-link-query.js.map +0 -1
- package/dist-server/service/domain-link/domain-link-types.js.map +0 -1
- package/dist-server/service/domain-link/domain-link.js.map +0 -1
- package/dist-server/service/domain-link/index.js.map +0 -1
- package/dist-server/service/domain-owner/domain-owner-mutation.js.map +0 -1
- package/dist-server/service/domain-owner/domain-owner-query.js.map +0 -1
- package/dist-server/service/domain-owner/domain-owner.js.map +0 -1
- package/dist-server/service/domain-owner/index.js.map +0 -1
- package/dist-server/service/granted-role/granted-role-mutation.js.map +0 -1
- package/dist-server/service/granted-role/granted-role-query.js.map +0 -1
- package/dist-server/service/granted-role/granted-role.js.map +0 -1
- package/dist-server/service/granted-role/index.js.map +0 -1
- package/dist-server/service/identity-confirmation/identity-confirmation.js.map +0 -1
- package/dist-server/service/index.js.map +0 -1
- package/dist-server/service/open-fields.js.map +0 -1
- package/dist-server/service/partner/index.js.map +0 -1
- package/dist-server/service/partner/partner-mutation.js.map +0 -1
- package/dist-server/service/partner/partner-query.js.map +0 -1
- package/dist-server/service/partner/partner-types.js.map +0 -1
- package/dist-server/service/partner/partner.js.map +0 -1
- package/dist-server/service/password-history/index.js.map +0 -1
- package/dist-server/service/password-history/password-history.js.map +0 -1
- package/dist-server/service/privilege/index.js.map +0 -1
- package/dist-server/service/privilege/open-field-rule.js.map +0 -1
- package/dist-server/service/privilege/privilege-axis.js.map +0 -1
- package/dist-server/service/privilege/privilege-deprecation.js.map +0 -1
- package/dist-server/service/privilege/privilege-directive.js.map +0 -1
- package/dist-server/service/privilege/privilege-mutation.js.map +0 -1
- package/dist-server/service/privilege/privilege-query.js.map +0 -1
- package/dist-server/service/privilege/privilege-rejection.js.map +0 -1
- package/dist-server/service/privilege/privilege-sync.js.map +0 -1
- package/dist-server/service/privilege/privilege-types.js.map +0 -1
- package/dist-server/service/privilege/privilege.js.map +0 -1
- package/dist-server/service/role/index.js.map +0 -1
- package/dist-server/service/role/role-mutation.js.map +0 -1
- package/dist-server/service/role/role-privilege-query.js.map +0 -1
- package/dist-server/service/role/role-query.js.map +0 -1
- package/dist-server/service/role/role-types.js.map +0 -1
- package/dist-server/service/role/role.js.map +0 -1
- package/dist-server/service/role-template/index.js.map +0 -1
- package/dist-server/service/role-template/role-task.js.map +0 -1
- package/dist-server/service/role-template/role-template-gap-resolver.js.map +0 -1
- package/dist-server/service/role-template/role-template-mutation.js.map +0 -1
- package/dist-server/service/role-template/role-template-query.js.map +0 -1
- package/dist-server/service/role-template/role-template-types.js.map +0 -1
- package/dist-server/service/role-template/role-template.js.map +0 -1
- package/dist-server/service/user/domain-query.js.map +0 -1
- package/dist-server/service/user/index.js.map +0 -1
- package/dist-server/service/user/user-mutation.js.map +0 -1
- package/dist-server/service/user/user-query.js.map +0 -1
- package/dist-server/service/user/user-types.js.map +0 -1
- package/dist-server/service/user/user.js.map +0 -1
- package/dist-server/service/users-auth-providers/index.js.map +0 -1
- package/dist-server/service/users-auth-providers/users-auth-providers.js.map +0 -1
- package/dist-server/service/verification-token/index.js.map +0 -1
- package/dist-server/service/verification-token/verification-token.js.map +0 -1
- package/dist-server/service/web-auth-credential/index.js.map +0 -1
- package/dist-server/service/web-auth-credential/web-auth-credential-mutation.js.map +0 -1
- package/dist-server/service/web-auth-credential/web-auth-credential-query.js.map +0 -1
- package/dist-server/service/web-auth-credential/web-auth-credential.js.map +0 -1
- package/dist-server/tsconfig.tsbuildinfo +0 -1
- package/dist-server/types.js.map +0 -1
- package/dist-server/utils/accepts.js.map +0 -1
- package/dist-server/utils/access-request-review.js.map +0 -1
- package/dist-server/utils/access-token-cookie.js.map +0 -1
- package/dist-server/utils/account-lock-rule.js.map +0 -1
- package/dist-server/utils/assignable-roles.js.map +0 -1
- package/dist-server/utils/build-auth-url.js.map +0 -1
- package/dist-server/utils/can-user-checkin-domain.js.map +0 -1
- package/dist-server/utils/check-permission.js.map +0 -1
- package/dist-server/utils/check-user-belongs-domain.js.map +0 -1
- package/dist-server/utils/check-user-has-role.js.map +0 -1
- package/dist-server/utils/checkin-domain-facts.js.map +0 -1
- package/dist-server/utils/checkin-domain-rule.js.map +0 -1
- package/dist-server/utils/credential-at-rest.js.map +0 -1
- package/dist-server/utils/credential-features.js.map +0 -1
- package/dist-server/utils/credential-serial-rule.js.map +0 -1
- package/dist-server/utils/domain-ownership.js.map +0 -1
- package/dist-server/utils/encrypt-state.js.map +0 -1
- package/dist-server/utils/get-aes-256-key.js.map +0 -1
- package/dist-server/utils/get-domain-users.js.map +0 -1
- package/dist-server/utils/get-secret.js.map +0 -1
- package/dist-server/utils/get-user-domains.js.map +0 -1
- package/dist-server/utils/lock-duration.js.map +0 -1
- package/dist-server/utils/password-reset-rule.js.map +0 -1
- package/dist-server/utils/profile-user.js.map +0 -1
- package/dist-server/utils/refuse-role-name.js.map +0 -1
- package/dist-server/utils/role-name-standing.js.map +0 -1
- package/dist-server/utils/same-origin-redirect.js.map +0 -1
- package/dist-server/utils/verification-token-rule.js.map +0 -1
- package/spec/unit/checkin-domain.spec.ts +0 -307
- package/spec/unit/checkin-privilege.spec.ts +0 -205
- package/spec/unit/domain-owner-entity.spec.ts +0 -179
- package/spec/unit/domain-owner-granted.spec.ts +0 -215
- package/spec/unit/domain-owner-migration.spec.ts +0 -236
- package/spec/unit/domain-owner-mutation.spec.ts +0 -337
- package/spec/unit/domain-ownership.spec.ts +0 -188
- package/tests/access-assistant-db.test.ts +0 -155
- package/tests/access-entry-targets-db.test.ts +0 -176
- package/tests/access-request-db.test.ts +0 -394
- package/tests/access-request-pg.test.ts +0 -83
- package/tests/access-request-review.test.ts +0 -193
- package/tests/account-lock-db.test.ts +0 -216
- package/tests/account-lock-rule.test.ts +0 -141
- package/tests/account-mail.test.ts +0 -69
- package/tests/activate-page-case.test.ts +0 -53
- package/tests/add-user-gates.test.ts +0 -34
- package/tests/app-binding-db.test.ts +0 -210
- package/tests/app-binding-delete-db.test.ts +0 -188
- package/tests/appliance-credential-state-db.test.ts +0 -207
- package/tests/appliance-delete-db.test.ts +0 -119
- package/tests/appliance-revoke-db.test.ts +0 -294
- package/tests/appliance-schema.test.ts +0 -129
- package/tests/application-delete-db.test.ts +0 -190
- package/tests/application-token-payload-db.test.ts +0 -185
- package/tests/assignable-roles-db.test.ts +0 -219
- package/tests/audit-db.test.ts +0 -410
- package/tests/audit-work.test.ts +0 -58
- package/tests/auth-base-role-tasks.test.ts +0 -58
- package/tests/checkin-domain-rule.test.ts +0 -128
- package/tests/checkin-privilege-seam-db.test.ts +0 -158
- package/tests/compiled.ts +0 -41
- package/tests/confirm-identity-db.test.ts +0 -85
- package/tests/credential-at-rest-db.test.ts +0 -246
- package/tests/credential-features-off-db.test.ts +0 -189
- package/tests/credential-serial-rule.test.ts +0 -84
- package/tests/declare-privileges.test.ts +0 -29
- package/tests/domain-assignees-db.test.ts +0 -95
- package/tests/domain-inheritance-sentinel.test.ts +0 -93
- package/tests/domain-required.test.ts +0 -127
- package/tests/has-privilege-db.test.ts +0 -198
- package/tests/identity-confirmation.test.ts +0 -146
- package/tests/list-inheritance-db.test.ts +0 -127
- package/tests/lock-recovery.test.ts +0 -206
- package/tests/mail-request-answers-db.test.ts +0 -142
- package/tests/open-doors.test.ts +0 -121
- package/tests/open-fields-enforcement.test.ts +0 -215
- package/tests/open-fields-framework.test.ts +0 -212
- package/tests/open-redirect-db.test.ts +0 -143
- package/tests/passkey-authenticator.ts +0 -104
- package/tests/passkey-db.test.ts +0 -295
- package/tests/passkey-signin-route-db.test.ts +0 -139
- package/tests/password-hashing.test.ts +0 -131
- package/tests/password-persistence.test.ts +0 -147
- package/tests/password-reset-rule-db.test.ts +0 -159
- package/tests/password-setup-db.test.ts +0 -215
- package/tests/permission-gate.test.ts +0 -228
- package/tests/picture-reducer.test.ts +0 -25
- package/tests/privilege-axis.test.ts +0 -157
- package/tests/privilege-deprecation.test.ts +0 -65
- package/tests/privilege-directive.test.ts +0 -332
- package/tests/privilege-rejection.test.ts +0 -104
- package/tests/privilege-sync-db.test.ts +0 -58
- package/tests/profile-user.test.ts +0 -24
- package/tests/refusal-cause.test.ts +0 -80
- package/tests/refusals-have-korean.test.ts +0 -24
- package/tests/request-holds.test.ts +0 -53
- package/tests/role-inheritance-db.test.ts +0 -286
- package/tests/role-mutation-db.test.ts +0 -293
- package/tests/role-name-lookup-sentinel.test.ts +0 -79
- package/tests/role-name-standing.test.ts +0 -83
- package/tests/role-privileges-db.test.ts +0 -252
- package/tests/role-task.test.ts +0 -168
- package/tests/role-template-gap-db.test.ts +0 -268
- package/tests/role-template-seed-db.test.ts +0 -180
- package/tests/role-template.test.ts +0 -162
- package/tests/role-users-gate.test.ts +0 -22
- package/tests/signin-policy.test.ts +0 -200
- package/tests/signup-duplicate-db.test.ts +0 -68
- package/tests/token-issuance.test.ts +0 -244
- package/tests/user-roles-field-db.test.ts +0 -134
- 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
|
-
})
|