mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
In a gated scope, the two HTTP clients the platform owns connect only to addresses that a pin or a stored exemption covers at the moment of the connection, on every hop. - intercept.PinnedDialer(tool, scoped): the DialContext of both clients. It reads the target scope from the context net/http passes to the dial. Gate off, or no scope in a client built without one: plain dial, as today. A client built for a scope whose scope is missing at the dial fails closed with TARGET_GATE_UNAVAILABLE. - dialTarget runs the gate decision on the dialled host:port with a fresh lookup (block rules first, exemptions, pins, port precedence) and connects only to the addresses it compared, never to the name. Derived exemptions and name-only pins dial the address as received. An address no pin covers finds or opens the request (new_ip / no_pin, wait 0) and fails at once with TARGET_APPROVAL_PENDING. Redirect hops are dialled against the hop's own (host, port). - WebFetch (withWebFetch, now given the run context): DialContext set on every agent kind; DisableDirectRetry when the run's scope is gated. - Custom http tool: a direct call in a gated scope gets a DefaultTransport clone with the pinned dialer, no environment proxy and keep-alive off. Proxied calls are unchanged (the recording proxy is step 2.2). - Name-only: request reason says the platform does not bind the connection; the first-use pin_match row records the effective state. - Derived exemptions: a proxy URL without a port is listed with the port net/http dials (1080 for socks5) (OPEN-9). - go.mod: Norma v0.4.8 (DialContext, DisableDirectRetry).
28 lines
1.4 KiB
Go
28 lines
1.4 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/Autumn-27/artex/intercept"
|
|
actool "github.com/Autumn-27/norma/tool"
|
|
)
|
|
|
|
// withWebFetch returns tools plus the WebFetch tool of an agent session. Every
|
|
// agent kind builds WebFetch here, one tool per run, so that its configuration
|
|
// can depend on the run: every redirect hop goes through the target gate
|
|
// (intercept.RedirectCheck), and every connection through the pinned dialer
|
|
// (intercept.PinnedDialer), on the client that uses proxy and on the direct
|
|
// retry client alike. ctx is the context of the run: when it carries a target
|
|
// scope the dialer never connects without one, and when that scope's gate is
|
|
// on the direct retry is turned off for the run, since it would leave without
|
|
// the proxy. The tool is added after the session's own tools, where agentcore
|
|
// adds it, so the tool list keeps its order. caCert is the recording proxy's
|
|
// CA, trusted to verify the HTTPS it re-signs. tools is not modified.
|
|
func withWebFetch(ctx context.Context, tools []actool.CoreTool, proxy, caCert string) []actool.CoreTool {
|
|
scope, scoped := intercept.TargetScopeFromContext(ctx)
|
|
gated := scoped && scope.Enabled != nil && scope.Enabled()
|
|
webFetch := actool.NewWebFetch(actool.WebFetchConfig{Proxy: proxy, CACert: caCert, CheckRedirect: intercept.RedirectCheck("WebFetch"),
|
|
DialContext: intercept.PinnedDialer("WebFetch", scoped), DisableDirectRetry: gated})
|
|
return append(tools[:len(tools):len(tools)], webFetch)
|
|
}
|