Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

251 lines
8.7 KiB
Go

package agentextension
import (
"context"
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
tuttitypes "github.com/tutti-os/tutti/services/tuttid/types"
)
func TestReleaseDownloadsRejectIntermediateHTTPSDowngradeRedirect(t *testing.T) {
for _, test := range []struct {
name string
payload string
download func(*Manager, string) error
}{
{
name: "release metadata",
payload: `{"schemaVersion":"test"}`,
download: func(manager *Manager, rawURL string) error {
var target map[string]any
return manager.getJSON(context.Background(), rawURL, 1024, &target)
},
},
{
name: "release artifact",
payload: "artifact bytes",
download: func(manager *Manager, rawURL string) error {
_, err := manager.getBytes(context.Background(), rawURL, 1024)
return err
},
},
} {
t.Run(test.name, func(t *testing.T) {
var secure *httptest.Server
insecure := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
http.Redirect(w, request, secure.URL+"/final", http.StatusFound)
}))
defer insecure.Close()
secure = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
switch request.URL.Path {
case "/redirect":
http.Redirect(w, request, insecure.URL+"/redirect", http.StatusFound)
case "/final":
_, _ = w.Write([]byte(test.payload))
default:
http.NotFound(w, request)
}
}))
defer secure.Close()
manager := &Manager{Client: secure.Client()}
err := test.download(manager, secure.URL+"/redirect")
if err == nil || !strings.Contains(err.Error(), "redirected away from HTTPS") {
t.Fatalf("intermediate HTTPS downgrade error = %v", err)
}
})
}
}
func TestReleaseDownloadsPreserveConfiguredRedirectPolicy(t *testing.T) {
policyError := errors.New("configured redirect policy")
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
if request.URL.Path == "/redirect" {
http.Redirect(w, request, "/final", http.StatusFound)
return
}
_, _ = w.Write([]byte("release"))
}))
defer server.Close()
client := server.Client()
client.CheckRedirect = func(*http.Request, []*http.Request) error { return policyError }
manager := &Manager{Client: client}
_, err := manager.getBytes(context.Background(), server.URL+"/redirect", 1024)
if !errors.Is(err, policyError) {
t.Fatalf("configured redirect policy error = %v", err)
}
}
func TestReleaseDownloadsRejectConfiguredRedirectPolicyHTTPSDowngrade(t *testing.T) {
insecureRequests := 0
insecure := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
insecureRequests++
_, _ = w.Write([]byte("insecure release"))
}))
defer insecure.Close()
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
http.Redirect(w, request, "/final", http.StatusFound)
}))
defer server.Close()
client := server.Client()
client.CheckRedirect = func(request *http.Request, _ []*http.Request) error {
replacement, err := http.NewRequest(http.MethodGet, insecure.URL, nil)
if err != nil {
t.Fatalf("create insecure replacement request: %v", err)
}
request.URL = replacement.URL
return nil
}
manager := &Manager{Client: client}
_, err := manager.getBytes(context.Background(), server.URL, 1024)
if err == nil || !strings.Contains(err.Error(), "redirected away from HTTPS") {
t.Fatalf("configured redirect policy downgrade error = %v", err)
}
if insecureRequests != 0 {
t.Fatalf("insecure redirect target received %d requests", insecureRequests)
}
}
func TestVerifyReleasePreservesSignedOptionalManifestFields(t *testing.T) {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
document := map[string]any{
"schemaVersion": releaseSchema,
"agentKey": "grok",
"version": "0.1.2",
"artifactUrl": "https://example.test/grok-0.1.2.zip",
"artifactSha256": "abc",
"artifactSizeBytes": 1,
"publishedAt": "2026-07-21T00:00:00Z",
"gitSha": "test",
"manifest": map[string]any{
"schemaVersion": "tutti.agent.manifest.v2",
"agentKey": "grok",
"version": "0.1.2",
"name": "Grok Build",
"icon": map[string]any{"type": "asset", "src": "assets/icon.svg"},
"runtime": map[string]any{
"kind": "standard-acp",
"install": map[string]any{"runner": "binary"},
"launch": map[string]any{"executable": "grok", "args": []string{"agent", "stdio"}},
},
"profiles": map[string]any{"discovery": "profiles/discovery.json"},
},
"signature": map[string]any{
"algorithm": "ed25519",
"keyId": "test-grok-key",
"value": "",
},
}
payload, err := releasePayloadFromJSON(mustJSON(t, document))
if err != nil {
t.Fatal(err)
}
document["signature"].(map[string]any)["value"] = base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, payload))
var release Release
if err := json.Unmarshal(mustJSON(t, document), &release); err != nil {
t.Fatal(err)
}
source := tuttitypes.AgentExtensionSource{
Key: "grok", SigningKeyID: "test-grok-key", SigningPublicKey: publicKeyPEM(t, publicKey),
}
if err := verifyRelease(release, source); err != nil {
t.Fatalf("verifyRelease() error = %v", err)
}
path := filepath.Join(t.TempDir(), "release.json")
if err := writeJSONAtomic(path, release); err != nil {
t.Fatal(err)
}
var persisted Release
if err := readJSON(path, &persisted); err != nil {
t.Fatal(err)
}
if err := verifyRelease(persisted, source); err != nil {
t.Fatalf("verifyRelease() after persistence error = %v", err)
}
}
func TestSelectVersionUsesClientPinnedRelease(t *testing.T) {
document := Versions{
SchemaVersion: versionsSchema,
AgentKey: "gemini",
Versions: []VersionRecord{
{Version: "2.0.0", MinTuttiVersion: "0.2.0", Status: "active"},
{Version: "1.0.0", MinTuttiVersion: "0.1.0", Status: "active", Release: Release{Version: "1.0.0"}},
},
}
record, err := selectVersion(document, "gemini", "0.3.0", "1.0.0", false)
if err != nil {
t.Fatal(err)
}
if record.Version != "1.0.0" {
t.Fatalf("selected version = %q, want client pin 1.0.0", record.Version)
}
}
func TestSelectVersionRejectsUnavailableClientPin(t *testing.T) {
base := Versions{
SchemaVersion: versionsSchema,
AgentKey: "gemini",
Versions: []VersionRecord{{Version: "1.0.0", MinTuttiVersion: "0.2.0", Status: "active"}},
}
tests := []struct {
name string
document Versions
appVersion string
pin string
want string
}{
{name: "missing pin", document: base, appVersion: "0.3.0", pin: "2.0.0", want: "missing"},
{name: "invalid pin", document: base, appVersion: "0.3.0", pin: "latest", want: "pin is invalid"},
{name: "old client", document: base, appVersion: "0.1.0", pin: "1.0.0", want: "not active or compatible"},
{name: "inactive", document: Versions{SchemaVersion: versionsSchema, AgentKey: "gemini", Versions: []VersionRecord{{Version: "1.0.0", MinTuttiVersion: "0.0.0", Status: "withdrawn"}}}, appVersion: "0.3.0", pin: "1.0.0", want: "not active or compatible"},
{name: "unsupported capabilities", document: Versions{SchemaVersion: versionsSchema, AgentKey: "gemini", Versions: []VersionRecord{{Version: "1.0.0", MinTuttiVersion: "0.0.0", Status: "active", RequiredHostCapabilities: []string{"future"}}}}, appVersion: "0.3.0", pin: "1.0.0", want: "not active or compatible"},
{name: "mismatched release identity", document: Versions{SchemaVersion: versionsSchema, AgentKey: "gemini", Versions: []VersionRecord{{Version: "1.0.0", MinTuttiVersion: "0.0.0", Status: "active", Release: Release{Version: "2.0.0"}}}}, appVersion: "0.3.0", pin: "1.0.0", want: "release identity"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := selectVersion(test.document, "gemini", test.appVersion, test.pin, false)
if err == nil || !strings.Contains(err.Error(), test.want) {
t.Fatalf("selectVersion() error = %v, want %q", err, test.want)
}
})
}
}
func TestSelectVersionAllowsPinnedReleaseForDevelopmentClient(t *testing.T) {
document := Versions{
SchemaVersion: versionsSchema,
AgentKey: "hermes",
Versions: []VersionRecord{{
Version: "1.0.8",
MinTuttiVersion: "0.2.23",
Status: "active",
Release: Release{Version: "1.0.8"},
}},
}
if _, err := selectVersion(document, "hermes", "0.0.0", "1.0.8", true); err != nil {
t.Fatalf("development client should select the pinned release: %v", err)
}
if _, err := selectVersion(document, "hermes", "0.0.0", "1.0.8", false); err == nil {
t.Fatal("production client unexpectedly bypassed the minimum Tutti version")
}
}