cc-haha/adapters/common/__tests__/permission.test.ts
程序员阿江(Relakkes) 7ca25687fd feat: make IM permission approval mobile-friendly
Text-only IM channels forced users to copy long permission request IDs from mobile chat, which made approval slow and error-prone. This keeps the requestId-based authorization protocol intact while adding short replies for the single-pending-request case and preserving full command fallbacks for ambiguous cases.

Constraint: IM authorization must still resolve through the existing requestId permission_response path
Rejected: Replace request IDs with global numeric IDs | concurrent permission prompts would make numeric IDs ambiguous across chats
Confidence: high
Scope-risk: moderate
Directive: Do not allow short numeric replies when more than one permission request is pending in the chat
Tested: cd adapters && bun test common/ telegram/ feishu/ dingtalk/ wechat/
Tested: cd adapters && bunx tsc --noEmit
Tested: bun run check:adapters
Not-tested: Real WeChat or Telegram account end-to-end message delivery
2026-05-05 21:06:58 +08:00

44 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'bun:test'
import {
formatPermissionDecisionStatus,
formatPermissionInstructions,
parsePermissionCommand,
parsePermitCallbackData,
} from '../permission.js'
describe('permission helpers', () => {
it('parses text permission commands', () => {
expect(parsePermissionCommand('/allow req-1')).toEqual({ requestId: 'req-1', allowed: true })
expect(parsePermissionCommand('/always req-2')).toEqual({ requestId: 'req-2', allowed: true, rule: 'always' })
expect(parsePermissionCommand('/allow-always req-3')).toEqual({ requestId: 'req-3', allowed: true, rule: 'always' })
expect(parsePermissionCommand('/deny req-4')).toEqual({ requestId: 'req-4', allowed: false })
})
it('parses short replies when one permission is pending', () => {
const pending = new Set(['req-1'])
expect(parsePermissionCommand('1', pending)).toEqual({ requestId: 'req-1', allowed: true })
expect(parsePermissionCommand('2', pending)).toEqual({ requestId: 'req-1', allowed: true, rule: 'always' })
expect(parsePermissionCommand('3', pending)).toEqual({ requestId: 'req-1', allowed: false })
expect(parsePermissionCommand('/always', pending)).toEqual({ requestId: 'req-1', allowed: true, rule: 'always' })
expect(parsePermissionCommand('永久允许', pending)).toEqual({ requestId: 'req-1', allowed: true, rule: 'always' })
})
it('does not parse short replies when multiple permissions are pending', () => {
expect(parsePermissionCommand('1', new Set(['req-1', 'req-2']))).toBeNull()
})
it('parses callback permission actions', () => {
expect(parsePermitCallbackData('permit:req-1:yes')).toEqual({ requestId: 'req-1', allowed: true })
expect(parsePermitCallbackData('permit:req-2:always')).toEqual({ requestId: 'req-2', allowed: true, rule: 'always' })
expect(parsePermitCallbackData('permit:req-3:no')).toEqual({ requestId: 'req-3', allowed: false })
expect(parsePermitCallbackData('permit:req-4:unknown')).toBeNull()
})
it('formats text fallback and status labels', () => {
expect(formatPermissionInstructions('req-1')).toContain('回复 1')
expect(formatPermissionInstructions('req-1')).toContain('/always req-1')
expect(formatPermissionDecisionStatus({ allowed: true, rule: 'always' })).toContain('永久允许')
expect(formatPermissionDecisionStatus({ allowed: false })).toContain('拒绝')
})
})