From 0a01f36f1b761e8a25b32c1d13889349f6caab68 Mon Sep 17 00:00:00 2001 From: gongzhiyong Date: Sat, 2 May 2026 23:29:33 +0800 Subject: [PATCH] omx(team): auto-checkpoint worker-2 [2] --- .../controller/agnet_control_plane_test.go | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 heicode/controller/agnet_control_plane_test.go diff --git a/heicode/controller/agnet_control_plane_test.go b/heicode/controller/agnet_control_plane_test.go new file mode 100644 index 0000000..a9e0526 --- /dev/null +++ b/heicode/controller/agnet_control_plane_test.go @@ -0,0 +1,182 @@ +package controller + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/gin-gonic/gin" + "github.com/heicode/manager/common" + "github.com/stretchr/testify/require" +) + +type agnetCreateTestEnvelope struct { + Success bool `json:"success"` + Message string `json:"message"` + Error agnetTestError `json:"error"` +} + +type agnetTestError struct { + Code string `json:"code"` + Message string `json:"message"` +} + +func resetAgnetControlPlaneState(t *testing.T) { + t.Helper() + + agnetMu.Lock() + defer agnetMu.Unlock() + agnetDeployments = make(map[string]agnetDeploymentRecord) + agnetEvents = make(map[string][]agnetEvent) + agnetSnapshots = make(map[string][]agnetSKSnapshot) +} + +func baseAgnetResourceGrantPlan() agnetOrchestrationPlan { + return agnetOrchestrationPlan{ + IntentID: "intent-resource-grant", + TemplateHint: "manager-resource-binding", + Objective: "Grant bounded resources to a child Agnet role", + RiskLevel: agnetRiskLow, + Budget: agnetBudget{ + MaxTokens: 10000, + MaxCostUSD: 10, + MaxDurationSec: 3600, + }, + Agents: []agnetAgentPlan{ + { + RoleTemplate: "builder", + Goal: "Use granted resources without receiving plaintext credentials", + DefaultModelID: "gpt-resource-test", + ResourceGrants: []agnetResourceGrant{ + { + GrantID: "grant-git-builder", + ResourceID: "res-git-main", + ResourceType: agnetResourceGit, + TenantID: "tenant-p1", + ProjectID: "project-p1", + TargetRole: "builder", + TargetAgentRef: "agent-builder-1", + PermissionScope: []string{"repo:read", "repo:write:feature-branches"}, + Constraints: map[string]string{ + "allowed_paths": "src/**,docs/**", + "ref": "main", + }, + Metadata: map[string]string{ + "provider": "gitee", + "repo_url": "https://example.invalid/acme/project.git", + }, + Status: agnetGrantStatusActive, + SecretRef: "vault://tenant-p1/project-p1/git/res-git-main", + Audit: map[string]string{ + "created_by": "manager-test", + }, + }, + { + GrantID: "grant-doc-builder", + ResourceID: "res-doc-plan", + ResourceType: agnetResourceProjectDoc, + TenantID: "tenant-p1", + ProjectID: "project-p1", + TargetRole: "builder", + TargetAgentRef: "agent-builder-1", + PermissionScope: []string{"doc:read"}, + Metadata: map[string]string{ + "doc_ref": "docs/heicode.md", + }, + Status: agnetGrantStatusActive, + }, + }, + }, + }, + Constraints: agnetConstraints{AllowedModelIDs: []string{"gpt-resource-test"}}, + Metadata: agnetMetadata{ + TenantID: "tenant-p1", + ProjectID: "project-p1", + CorrelationID: "corr-p1-resource-grant", + }, + } +} + +func postAgnetCreateDeployment(t *testing.T, plan agnetOrchestrationPlan) (*httptest.ResponseRecorder, agnetCreateTestEnvelope) { + t.Helper() + + gin.SetMode(gin.TestMode) + body, err := common.Marshal(agnetDeploymentRequest{Plan: plan}) + require.NoError(t, err) + + recorder := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(recorder) + ctx.Request = httptest.NewRequest(http.MethodPost, "/api/agnet/deployments", strings.NewReader(string(body))) + ctx.Request.Header.Set("Content-Type", "application/json") + ctx.Request.Header.Set("X-Tenant-Id", plan.Metadata.TenantID) + + AgnetCreateDeployment(ctx) + + var envelope agnetCreateTestEnvelope + require.NoError(t, common.Unmarshal(recorder.Body.Bytes(), &envelope)) + return recorder, envelope +} + +func TestAgnetCreateDeploymentAcceptsP1ResourceGrantModel(t *testing.T) { + resetAgnetControlPlaneState(t) + + recorder, envelope := postAgnetCreateDeployment(t, baseAgnetResourceGrantPlan()) + + require.Equal(t, http.StatusOK, recorder.Code) + require.True(t, envelope.Success) + + agnetMu.RLock() + require.Len(t, agnetDeployments, 1) + var stored agnetDeploymentRecord + for _, record := range agnetDeployments { + stored = record + } + agnetMu.RUnlock() + + grants := stored.Plan.Agents[0].ResourceGrants + require.Len(t, grants, 2) + require.Equal(t, agnetResourceGit, grants[0].ResourceType) + require.Equal(t, "tenant-p1", grants[0].TenantID) + require.Equal(t, "project-p1", grants[0].ProjectID) + require.Equal(t, "builder", grants[0].TargetRole) + require.Equal(t, "agent-builder-1", grants[0].TargetAgentRef) + require.Equal(t, "vault://tenant-p1/project-p1/git/res-git-main", grants[0].SecretRef) + require.Empty(t, grants[1].SecretRef, "project document grants should not require credential material") +} + +func TestAgnetCreateDeploymentRejectsPlaintextResourceGrantCredentialFields(t *testing.T) { + resetAgnetControlPlaneState(t) + plan := baseAgnetResourceGrantPlan() + plan.Agents[0].ResourceGrants[0].Metadata["access_token"] = "must-not-be-stored" + + _, envelope := postAgnetCreateDeployment(t, plan) + + require.False(t, envelope.Success) + require.Equal(t, "RESOURCE_GRANT_SECRET_REJECTED", envelope.Error.Code) + require.Empty(t, agnetDeployments) +} + +func TestAgnetCreateDeploymentRejectsResourceGrantWithoutSecretRef(t *testing.T) { + resetAgnetControlPlaneState(t) + plan := baseAgnetResourceGrantPlan() + plan.Agents[0].ResourceGrants[0].SecretRef = "" + + _, envelope := postAgnetCreateDeployment(t, plan) + + require.False(t, envelope.Success) + require.Equal(t, "RESOURCE_GRANT_SECRET_REF_REQUIRED", envelope.Error.Code) + require.Empty(t, agnetDeployments) +} + +func TestAgnetCreateDeploymentRejectsCrossTenantResourceGrant(t *testing.T) { + resetAgnetControlPlaneState(t) + plan := baseAgnetResourceGrantPlan() + plan.Agents[0].ResourceGrants[0].TenantID = "tenant-other" + + _, envelope := postAgnetCreateDeployment(t, plan) + + require.False(t, envelope.Success) + require.Equal(t, "RESOURCE_GRANT_INVALID", envelope.Error.Code) + require.Empty(t, agnetDeployments) +}