Verify bounded real AI and OSS access without dialing

This commit is contained in:
2026-10-03 20:20:26 +08:00
parent 0355590389
commit 3bf0ac628d
3 changed files with 70 additions and 17 deletions
@@ -0,0 +1,8 @@
# One authorized real-provider diagnostic — 2026-10-03
Scope: one real AI request and one new OSS object, using synthetic test data. **No call, customer audio, carrier, real SaaS, or production acceptance.** The user authorized this bounded test; no existing object was overwritten or deleted.
- Existing private inputs: `.local/provider-ai.env` and `aliyun-oss.env`, both mode `0600`. Only required fields were mapped in process memory; credential values, signed URLs, object names, prompt/response text and raw provider errors were not printed or committed. These legacy files are **not** current approved SaaS task/provider snapshots or Dispatcher OSS JSON configuration.
- **AI:** one HTTPS OpenAI-compatible Bailian `qwen-plus` request through the current `ai.Binding.Complete` SDK path, with SDK retries disabled, an explicit 16-token limit and harmless synthetic text. Passed in 0.32 s; reply length 2 bytes, SHA-256 `565339bc4d33d72817b583024112eb7f5cdf3e5eef0252d6ec1b9c9a94e12bb3`. This checks real LLM credentials and connectivity only; it does **not** verify ASR, TTS, their compatibility with the current approved provider schema, or an actual call.
- **OSS:** one HTTPS presigned PUT using the existing official OSS v2 signer and Agent uploader. A cryptographically unique key under the isolated integration-test prefix prevented replacement of any previous object. The synthetic 27,648-byte payload was accepted, and the uploader confirmed local SHA-256 `c6fce42774195e84f761abfbb0d8cbb6a94c7a00d85479cd170faf819f6c22e2`. The test object is retained; no GET, deletion, real recording, or SaaS receipt was claimed. The test has a 45-second deadline and does not blindly retry an uncertain PUT.
- `make check` passed; business unit coverage **70.5%**. Its Mock checks do **not** run these separately opted-in external requests. Current real-call entry remains Mock-only, the current test host lacks tcpdump and ARI/HTTP configuration, and the required capture gate still forbids dialing. Historical `agent --call-once` and its ARI runtime were removed; this diagnostic does not restore them.
@@ -0,0 +1,47 @@
package ai
import (
"context"
"crypto/sha256"
"net/url"
"os"
"strings"
"testing"
"time"
"git.ipao.vip/rogee/go-sip/internal/configread"
)
// This opt-in diagnostic checks one real provider SDK request. It is not a
// business call, an approved SaaS task, or evidence of ASR/TTS availability.
func TestRealBailianDiagnosticOnce(t *testing.T) {
if os.Getenv("AGENT_CALL_REAL_AI_INTEGRATION") != "1" {
t.Skip("real AI diagnostic requires explicit opt-in")
}
endpoint := os.Getenv("BAILIAN_BASE_URL")
credential := os.Getenv("BAILIAN_API_KEY")
parsed, err := url.Parse(endpoint)
if err != nil || parsed.Scheme != "https" || parsed.Host == "" || parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" || credential == "" {
t.Fatal("real AI diagnostic requires a private API key and plain HTTPS endpoint")
}
maxTokens := int64(16)
temperature := 0.0
bound := Binding{
Mode: "full_ai",
Prompt: "This is a harmless connectivity test. Respond briefly.",
LLM: &LLMConfig{
Provider: configread.Provider{Endpoint: endpoint, Credential: credential},
Model: "qwen-plus", Temperature: &temperature, MaxTokens: &maxTokens, Timeout: 30 * time.Second,
},
}
ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second)
defer cancel()
reply, err := bound.Complete(ctx, "Respond with OK.")
if err != nil {
t.Fatalf("real AI diagnostic failed: type=%T error_sha256=%x", err, sha256.Sum256([]byte(err.Error())))
}
if strings.TrimSpace(reply) == "" {
t.Fatal("real AI diagnostic returned no text")
}
t.Logf("real LLM response: bytes=%d sha256=%x", len(reply), sha256.Sum256([]byte(reply)))
}
+15 -17
View File
@@ -2,8 +2,10 @@ package oss_test
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
"os"
"strings"
"testing"
@@ -29,15 +31,18 @@ func TestAlibabaOSSGrantPutIntegration(t *testing.T) {
}
client, err := ossclient.NewClient(config)
if err != nil {
t.Fatal(err)
t.Fatal("OSS integration configuration is invalid")
}
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
payload := []byte(strings.Repeat("agent-call-oss-integration\n", 1024))
digest := sha256.Sum256(payload)
checksum := hex.EncodeToString(digest[:])
objectKey := "agent-call/integration-tests/" + checksum + ".txt"
grant, err := client.Grant(context.Background(), "integration-"+checksum[:16], objectKey, checksum, int64(len(payload)), time.Now())
uniqueID := "integration-" + rand.Text()
objectKey := config.KeyPrefix + "/" + uniqueID + "-" + checksum[:16] + ".txt"
grant, err := client.Grant(ctx, uniqueID, objectKey, checksum, int64(len(payload)), time.Now())
if err != nil {
t.Fatal(err)
t.Fatalf("OSS presign failed: type=%T error_sha256=%x", err, sha256.Sum256([]byte(err.Error())))
}
file, err := os.CreateTemp(t.TempDir(), "oss-upload-*.txt")
if err != nil {
@@ -51,22 +56,15 @@ func TestAlibabaOSSGrantPutIntegration(t *testing.T) {
t.Fatal(err)
}
uploader := agent.UploadClient{Now: time.Now, AllowedHosts: map[string]struct{}{}}
result, err := uploader.UploadFile(context.Background(), grant, file.Name())
result, err := uploader.UploadFile(ctx, grant, file.Name())
if err != nil {
t.Fatalf("upload failed without exposing the presigned URL: %s", redactError(err, config.AccessKeyID))
var httpErr *agent.UploadHTTPError
if errors.As(err, &httpErr) {
t.Fatalf("OSS PUT failed: HTTP %d", httpErr.StatusCode)
}
t.Fatalf("OSS PUT failed: type=%T error_sha256=%x", err, sha256.Sum256([]byte(err.Error())))
}
if result.SizeBytes != int64(len(payload)) || !strings.EqualFold(result.SHA256, checksum) {
t.Fatalf("upload result mismatch: %+v", result)
}
}
func redactError(err error, accessKeyID string) string {
if err == nil {
return ""
}
message := err.Error()
if accessKeyID != "" {
message = strings.ReplaceAll(message, accessKeyID, "<access-key-id>")
}
return message
}