onesvm-browser-server/server/internal/policy/engine.go
chii eb972dfa93 feat: 落地 browser-server 控制面并打通 mgr1 海外订阅
单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:05:12 +08:00

76 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package policy 对外门面:Guard + DomainTrie + RobotsChecker 组合与审计落点。
package policy
import (
"context"
"net/http"
"time"
"onesvm.com/onesvm/browser-server/internal/store"
)
// Engine 出站策略引擎(gateway 入队前 / httpx 每跳重验共用一个实例)。
type Engine struct {
Guard *Guard
Trie *DomainTrie
Robots *RobotsChecker
db *store.DB
robotsBypass map[string]bool // 特权 key 覆盖 robots 时打审计标记(首版预留)
}
// NewEngine 组装策略引擎(db 可为 nil:单测场景禁用审计落库)。
func NewEngine(db *store.DB, httpClient *http.Client) *Engine {
e := &Engine{
Guard: &Guard{},
Trie: NewDomainTrie(),
Robots: NewRobotsChecker(db, httpClient),
db: db,
}
// ITER-3 FIX-3:robots 拉取的每跳重验挂接(3xx 目标过 SSRF 门闩)。
e.Robots.SetRedirectCheck(e.RedirectCheck)
return e
}
// Reload 热载域名规则(rules 表 → trie)。
func (e *Engine) Reload() (int, error) {
return e.Trie.LoadFromStore(e.db)
}
// Authorize 综合放行判定:SSRF(含 DNS)→ 域名 trie。
// 任一拒绝即 DeniedError(含 rule_id,调用方落审计)。
func (e *Engine) Authorize(ctx context.Context, rawURL string) *DeniedError {
if d := e.Guard.CheckURL(rawURL); d != nil {
return d
}
host := parseHost(rawURL)
if a, ok := e.Trie.Lookup(host); ok && a == ActionDeny {
return &DeniedError{RuleID: "domain_deny", Reason: "域名黑名单命中"}
}
return nil
}
// Audit 合规拦截审计(denied 记录,design-arch §5.4 审计行)。
func (e *Engine) Audit(consumerID int64, url, ruleID string) {
if e.db == nil {
return
}
_ = e.db.AuditAppend(consumerID, url, ruleID)
}
// RedirectCheck 重定向每跳重验(ITER-3 FIX-3 接线:design-arch §5.4)。
// 供 httpx.Client CheckRedirect hook / robots 拉取 client 调用——新 URL 先 CheckURL
// 再 ResolveCheck(DNS 重解析比对私网)。出站面:robots 拉取 + 引擎内网调用;
// CDP 导航(lightpanda/headless-shell)不经 Go client,其重定向防护属引擎容器职责。
func (e *Engine) RedirectCheck(ctx context.Context, rawURL string) *DeniedError {
return e.Guard.CheckRedirect(ctx, rawURL)
}
// RobotsAllowed robots 判定(普通 key)。特权覆盖由 W2 调用方显式传 bypass 并打审计。
func (e *Engine) RobotsAllowed(ctx context.Context, rawURL string, bypass bool) (bool, error) {
if bypass {
return true, nil
}
cctx, cancel := context.WithTimeout(ctx, 12*time.Second)
defer cancel()
return e.Robots.Allowed(cctx, rawURL, "onesvm-browser-server")
}