feat: 添加 WireGuard 设备管理并完善客户端分流
实现独立加密设备身份、网关 agent、持久生命周期任务和 Surge/FlClash 专属订阅凭证。 完善 Shadowrocket 规则转换与 Clash AI DNS,增加 Surge FFSB 适配、规则快照、运维工具及验收文档。
This commit is contained in:
53
scripts/ffsb/test_overlay.py
Normal file
53
scripts/ffsb/test_overlay.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import unittest
|
||||
from overlay import build, sections
|
||||
|
||||
DOMAINS = ['*.anthropic.com','*.clau.de','*.claude.com','*.claudemcpclient.com','*.claudemcpcontent.com','*.claudeusercontent.com','*.ffsb.sg','a.claude.ai','anthropic.com','api.anthropic.com','api.ipify.org','assets.claude.ai','clau.de','claude.ai','claude.com','claudemcpclient.com','claudemcpcontent.com','claudeusercontent.com','ffsb.sg','icanhazip.com','ifconfig.me','ip.net.coffee','join.fufeishangban.com','pivot.claude.ai','www.claude.ai']
|
||||
BASE = '''[General]
|
||||
always-real-ip = *.example.ts.net
|
||||
[Proxy]
|
||||
Node = http, 127.0.0.1, 9999
|
||||
[Proxy Group]
|
||||
Claude = select, Node
|
||||
AI = select, Node
|
||||
[Rule]
|
||||
DOMAIN-SUFFIX,claude.ai,Claude
|
||||
DOMAIN,anthropic.auth0.com,Claude
|
||||
DOMAIN-SUFFIX,openai.com,AI
|
||||
FINAL,DIRECT
|
||||
[Host]
|
||||
*.claude.ai = server:https://1.0.0.1/dns-query
|
||||
'''
|
||||
|
||||
class OverlayTests(unittest.TestCase):
|
||||
def test_on_preserves_exact_ffsb_scope_and_extra_fallback(self):
|
||||
s = sections(build(BASE, DOMAINS, True))
|
||||
self.assertEqual(sum(x.endswith(',Claude') for x in s['Rule']), 25)
|
||||
self.assertIn('DOMAIN,claude.ai,Claude', s['Rule'])
|
||||
self.assertNotIn('DOMAIN-SUFFIX,claude.ai,Claude', s['Rule'])
|
||||
self.assertIn('DOMAIN-SUFFIX,claude.ai,"🦀 Claude"', s['Rule'])
|
||||
self.assertIn('DOMAIN,anthropic.auth0.com,"🦀 Claude"', s['Rule'])
|
||||
self.assertIn('DOMAIN-SUFFIX,openai.com,AI', s['Rule'])
|
||||
self.assertTrue(s['Rule'][0].startswith('PROCESS-NAME,'))
|
||||
self.assertEqual([x for x in s['Rule'] if x.startswith('FINAL,')], ['FINAL,DIRECT'])
|
||||
self.assertIn('*.example.ts.net', '\n'.join(s['General']))
|
||||
self.assertEqual(sum('server:100.70.255.254' in x for x in s['Host']), 25)
|
||||
|
||||
def test_off_removes_tunnel_dns_and_selection(self):
|
||||
s = sections(build(BASE, DOMAINS, False))
|
||||
self.assertNotIn('100.70.255.254', '\n'.join(s['Host']))
|
||||
self.assertIn('Claude = fallback, "🦀 Claude", interval=5', s['Proxy Group'])
|
||||
self.assertEqual(s['General'][0], 'always-real-ip = *.example.ts.net')
|
||||
self.assertIn('*.claude.ai = server:https://1.0.0.1/dns-query',s['Host'])
|
||||
|
||||
def test_production_renamed_group(self):
|
||||
renamed = BASE.replace('Claude = select', '🦀 Claude = select').replace(',Claude', ',"🦀 Claude"')
|
||||
result = build(renamed, DOMAINS, True)
|
||||
self.assertEqual(result.count('🦀 Claude = select'), 1)
|
||||
self.assertIn('DOMAIN,anthropic.auth0.com,"🦀 Claude"', result)
|
||||
|
||||
def test_drift_rejected(self):
|
||||
with self.assertRaises(ValueError): build(BASE, DOMAINS[:-1], True)
|
||||
with self.assertRaises(ValueError): build(BASE.replace('Claude = select, Node','Other = select, Node'), DOMAINS, True)
|
||||
with self.assertRaises(ValueError): build(BASE, DOMAINS[:-1]+[DOMAINS[0]], True)
|
||||
|
||||
if __name__ == '__main__': unittest.main()
|
||||
Reference in New Issue
Block a user