@things-factory/ai-assistant 10.1.37 → 10.1.39
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/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/chat-message/chat-message-broadcast.d.ts +15 -0
- package/dist-server/service/chat-message/chat-message-broadcast.js +23 -0
- package/dist-server/service/chat-message/chat-message-broadcast.js.map +1 -1
- package/dist-server/service/chat-message/chat-message-room.d.ts +22 -0
- package/dist-server/service/chat-message/chat-message-room.js +43 -0
- package/dist-server/service/chat-message/chat-message-room.js.map +1 -0
- package/dist-server/service/chat-message/chat-message-subscription.js +17 -4
- package/dist-server/service/chat-message/chat-message-subscription.js.map +1 -1
- package/dist-server/service/chat-session/session-activity-subscription.js +1 -2
- package/dist-server/service/chat-session/session-activity-subscription.js.map +1 -1
- package/dist-server/service/index.d.ts +0 -1
- package/dist-server/service/index.js +0 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/testing/mode-conformance.js +6 -5
- package/dist-server/service/testing/mode-conformance.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/server/service/chat-message/chat-message-broadcast.ts +43 -0
- package/server/service/chat-message/chat-message-room.test.ts +140 -0
- package/server/service/chat-message/chat-message-room.ts +48 -0
- package/server/service/chat-message/chat-message-subscription.ts +21 -5
- package/server/service/chat-session/session-activity-subscription.ts +1 -2
- package/server/service/index.ts +0 -1
- package/server/service/testing/conversation-script.test.ts +1 -1
- package/server/service/testing/mode-conformance.test.ts +2 -2
- package/server/service/testing/mode-conformance.ts +6 -5
- package/server/tool-registry-boot-report.test.ts +13 -5
- package/test/open-doors.test.ts +132 -0
- package/dist-server/service/subscribe-auth.d.ts +0 -14
- package/dist-server/service/subscribe-auth.js +0 -33
- package/dist-server/service/subscribe-auth.js.map +0 -1
- package/server/service/subscribe-auth.test.ts +0 -57
- package/server/service/subscribe-auth.ts +0 -34
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 구독 도메인 인증 게이트 — 단위 테스트 (보안 핵심: 도메인 격리).
|
|
3
|
-
* board-patch / chat-message 양쪽 spine 이 공유하는 게이트.
|
|
4
|
-
*
|
|
5
|
-
* 회귀 방지: process.superUserGranted 는 async 다. 동기 `!process.superUserGranted(...)` 로
|
|
6
|
-
* 평가하면 `!Promise` = 항상 false → membership throw 가 죽는다(fail-open). 게이트는 반드시
|
|
7
|
-
* await 로 평가해야 한다. 아래 superUser 분기 테스트가 그 회귀를 박는다.
|
|
8
|
-
*/
|
|
9
|
-
import { assertDomainSubscribeAllowed } from './subscribe-auth'
|
|
10
|
-
|
|
11
|
-
const never = async () => false // superUser 아님 (async — 실제 process.superUserGranted 와 동일)
|
|
12
|
-
const always = async () => true // superUser (async)
|
|
13
|
-
|
|
14
|
-
const domain = { id: 'd1', subdomain: 'acme' }
|
|
15
|
-
const userInDomain = { email: 'a@x.io', domains: [{ subdomain: 'acme' }, { subdomain: 'other' }] }
|
|
16
|
-
const userOutDomain = { email: 'b@x.io', domains: [{ subdomain: 'other' }] }
|
|
17
|
-
|
|
18
|
-
describe('assertDomainSubscribeAllowed (도메인 격리 게이트)', () => {
|
|
19
|
-
it('domain 없으면 → reject (domain required)', async () => {
|
|
20
|
-
await expect(assertDomainSubscribeAllowed(undefined, userInDomain, never)).rejects.toThrow('domain required')
|
|
21
|
-
await expect(assertDomainSubscribeAllowed(null, userInDomain, never)).rejects.toThrow('domain required')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('user 가 해당 subdomain 소속 → 통과 (superUser 검사 불필요)', async () => {
|
|
25
|
-
await expect(assertDomainSubscribeAllowed(domain, userInDomain, never)).resolves.toBeUndefined()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('user 가 미소속 + superUser 아님 → reject (격리 — 핵심)', async () => {
|
|
29
|
-
await expect(assertDomainSubscribeAllowed(domain, userOutDomain, never)).rejects.toThrow(
|
|
30
|
-
'domain(acme) is not working for user(b@x.io).'
|
|
31
|
-
)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('user 가 미소속이어도 superUser(async resolve true) 면 → 통과 (await 회귀 방지)', async () => {
|
|
35
|
-
await expect(assertDomainSubscribeAllowed(domain, userOutDomain, always)).resolves.toBeUndefined()
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('user.domains 없음 + superUser 아님 → reject', async () => {
|
|
39
|
-
await expect(assertDomainSubscribeAllowed(domain, { email: 'c@x.io' }, never)).rejects.toThrow(
|
|
40
|
-
'domain(acme) is not working for user(c@x.io).'
|
|
41
|
-
)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('user.domains 없음 + superUser → 통과', async () => {
|
|
45
|
-
await expect(assertDomainSubscribeAllowed(domain, { email: 'c@x.io' }, always)).resolves.toBeUndefined()
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('isSuperUser 는 domain+user 를 받아 호출되고 await 된다', async () => {
|
|
49
|
-
const calls: any[] = []
|
|
50
|
-
const spy = async (d: any, u: any) => {
|
|
51
|
-
calls.push([d, u])
|
|
52
|
-
return true
|
|
53
|
-
}
|
|
54
|
-
await assertDomainSubscribeAllowed(domain, userOutDomain, spy)
|
|
55
|
-
expect(calls).toEqual([[domain, userOutDomain]])
|
|
56
|
-
})
|
|
57
|
-
})
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 구독 도메인 인증 게이트 — 순수 로직 (데코레이터·pubsub 없음 → 테스트 가능).
|
|
3
|
-
*
|
|
4
|
-
* 실시간 구독(@Subscription)은 같은 도메인 구성원만 허용해야 한다(도메인 격리 = 보안 핵심).
|
|
5
|
-
* 이 게이트는 board-patch / chat-message 양쪽 spine 의 subscribe 클로저가 공유한다
|
|
6
|
-
* (reuse — fork 금지). superUserGranted 는 process 전역 의존이라 주입받아 순수성 유지.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 구독 허용 여부 단언. 불가 시 throw (graphql-ws 가 구독 거부).
|
|
11
|
-
* - domain 없음 → 거부.
|
|
12
|
-
* - user 가 해당 subdomain 의 도메인 소속이 아니고 superUser 도 아니면 → 거부.
|
|
13
|
-
*
|
|
14
|
-
* 주의(버그 수정): process.superUserGranted 는 async(Promise<boolean>) 다. 기존 양쪽 spine 은
|
|
15
|
-
* `!process.superUserGranted(...)` 로 동기 평가해 `!Promise` = 항상 false → membership throw 가
|
|
16
|
-
* 발동하지 않는 fail-open 상태였다. 여기서는 await 로 제대로 평가한다 → subscribe 는 async.
|
|
17
|
-
*
|
|
18
|
-
* @param domain context.state.domain
|
|
19
|
-
* @param user context.state.user (domains[] / email 사용)
|
|
20
|
-
* @param isSuperUser (domain, user) → boolean | Promise<boolean> (process.superUserGranted 주입)
|
|
21
|
-
*/
|
|
22
|
-
export async function assertDomainSubscribeAllowed(
|
|
23
|
-
domain: any,
|
|
24
|
-
user: any,
|
|
25
|
-
isSuperUser: (domain: any, user: any) => boolean | Promise<boolean>
|
|
26
|
-
): Promise<void> {
|
|
27
|
-
if (!domain) {
|
|
28
|
-
throw new Error('domain required')
|
|
29
|
-
}
|
|
30
|
-
const subdomain = domain?.subdomain
|
|
31
|
-
if (!user?.domains?.find((d: any) => d.subdomain === subdomain) && !(await isSuperUser(domain, user))) {
|
|
32
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user?.email}).`)
|
|
33
|
-
}
|
|
34
|
-
}
|