Merge pull request #56 from xmindlab-heicode/feat/agent-endpoint-security-scheme

feat(agent): return A2A endpoint security scheme/profile (#55)
This commit is contained in:
Fasthei
2026-06-10 16:27:34 +08:00
committed by GitHub
3 changed files with 57 additions and 1 deletions
@@ -0,0 +1,24 @@
package controller
import "testing"
// #55: agent endpoint 安全级别推断 —— 明文/裸主机 = none(客户端生产可拒),显式 https = tls。
func TestAgentEndpointSecurity(t *testing.T) {
cases := []struct {
in string
scheme, prof string
secure bool
}{
{"https://dep-x.agents.example", "https", "tls", true},
{"http://dep-x.agents.example", "http", "none", false},
{"dep-x.taijiagnet.com", "http", "none", false}, // 裸主机:AM 当前明文
{" HTTPS://Dep.Example ", "https", "tls", true},
{"", "http", "none", false},
}
for _, c := range cases {
sc, pr, se := agentEndpointSecurity(c.in)
if sc != c.scheme || pr != c.prof || se != c.secure {
t.Errorf("agentEndpointSecurity(%q) = (%s,%s,%v), want (%s,%s,%v)", c.in, sc, pr, se, c.scheme, c.prof, c.secure)
}
}
}
@@ -111,6 +111,7 @@ func templateAgentResponse(row model.AgentDeployment) gin.H {
if strings.TrimSpace(row.BindingIDsJSON) != "" {
_ = common.UnmarshalJsonStr(row.BindingIDsJSON, &bindingIDs)
}
scheme, profile, secure := agentEndpointSecurity(row.Subdomain)
return gin.H{
"agent_id": row.DeploymentID,
"template_id": row.TemplateID,
@@ -121,6 +122,30 @@ func templateAgentResponse(row model.AgentDeployment) gin.H {
"runtime_id": row.RuntimeDeploymentID,
"created_at": row.CreatedAtText,
"updated_at": row.UpdatedAtText,
// #55: A2A 直连安全元数据。客户端据此在生产强制 HTTPS(HEICODE_AGENT_REQUIRE_SECURE):
// scheme=http/https,security_profile=none/tls,secure=profile!=none。AM 启用 HTTPS/
// mTLS listener 是 AM(azgy)的事;HM 只如实回传当前子域安全级别,明文 http →
// security_profile=none,客户端可拒绝并提示(元数据不含任何 secret_ref)。
"security": gin.H{
"scheme": scheme,
"security_profile": profile,
"secure": secure,
},
}
}
// agentEndpointSecurity 从子域字符串推断 A2A 直连的安全级别(#55)。纯函数,可单测。
// 显式 https:// → (https, tls, true);显式 http:// 或裸主机(AM 当前默认明文) → (http, none, false)。
// 保守口径:无法确证 TLS 即视为 none,宁可让客户端在生产拒绝,也不回传"看似安全"的明文端点。
func agentEndpointSecurity(subdomain string) (scheme, profile string, secure bool) {
s := strings.TrimSpace(strings.ToLower(subdomain))
switch {
case strings.HasPrefix(s, "https://"):
return "https", "tls", true
case strings.HasPrefix(s, "http://"):
return "http", "none", false
default:
return "http", "none", false // 裸主机:AM 当前明文 HTTP,保守标 none
}
}