From 30e0b0b4c6984328117bba4485c71007e970e71d Mon Sep 17 00:00:00 2001 From: gongzhiyong Date: Sat, 2 May 2026 23:28:32 +0800 Subject: [PATCH] omx(team): auto-checkpoint worker-2 [2] --- heicode/controller/agnet_control_plane.go | 118 ++++++++++++++++++++-- 1 file changed, 110 insertions(+), 8 deletions(-) diff --git a/heicode/controller/agnet_control_plane.go b/heicode/controller/agnet_control_plane.go index 5930379..44d1781 100644 --- a/heicode/controller/agnet_control_plane.go +++ b/heicode/controller/agnet_control_plane.go @@ -6,14 +6,25 @@ import ( "sync" "time" - "github.com/heicode/manager/common" "github.com/gin-gonic/gin" + "github.com/heicode/manager/common" ) const ( agnetRiskLow = "low" agnetRiskMedium = "medium" agnetRiskHigh = "high" + + agnetResourceGit = "git" + agnetResourceSK = "sk" + agnetResourceProjectDoc = "project_doc" + agnetResourceCloudAccount = "cloud_account" + agnetResourceCloudResource = "cloud_resource" + + agnetGrantStatusPending = "pending" + agnetGrantStatusActive = "active" + agnetGrantStatusDisabled = "disabled" + agnetGrantStatusRevoked = "revoked" ) type agnetBudget struct { @@ -51,13 +62,32 @@ type agnetSKAccessPolicy struct { InheritDeploymentDefaults bool `json:"inherit_deployment_defaults"` } +// agnetResourceGrant is the Manager-side resource binding envelope from docs/heicode.md P1. +// It deliberately carries only metadata, scoped permissions and secret_ref, never plaintext secrets. +type agnetResourceGrant struct { + GrantID string `json:"grant_id"` + ResourceID string `json:"resource_id"` + ResourceType string `json:"resource_type"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + TargetRole string `json:"target_role"` + TargetAgentRef string `json:"target_agent_ref"` + PermissionScope []string `json:"permission_scope"` + Constraints map[string]string `json:"constraints"` + Metadata map[string]string `json:"metadata"` + Status string `json:"status"` + SecretRef string `json:"secret_ref"` + Audit map[string]string `json:"audit"` +} + type agnetAgentPlan struct { - RoleTemplate string `json:"role_template"` - Goal string `json:"goal"` - DefaultModelID string `json:"default_model_id"` - SKSources []agnetSKSource `json:"sk_sources"` - RuntimeExecution agnetRuntimeExecution `json:"runtime_execution"` - SKAccessPolicy agnetSKAccessPolicy `json:"sk_access_policy"` + RoleTemplate string `json:"role_template"` + Goal string `json:"goal"` + DefaultModelID string `json:"default_model_id"` + SKSources []agnetSKSource `json:"sk_sources"` + RuntimeExecution agnetRuntimeExecution `json:"runtime_execution"` + SKAccessPolicy agnetSKAccessPolicy `json:"sk_access_policy"` + ResourceGrants []agnetResourceGrant `json:"resource_grants"` } type agnetConstraints struct { @@ -158,6 +188,30 @@ func containsString(values []string, target string) bool { return false } +func containsSensitiveGrantField(values map[string]string) bool { + for key := range values { + normalized := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(key), "-", "_")) + if strings.Contains(normalized, "password") || + strings.Contains(normalized, "token") || + strings.Contains(normalized, "secret") || + strings.Contains(normalized, "private_key") || + strings.Contains(normalized, "access_key") || + strings.Contains(normalized, "credential") { + return true + } + } + return false +} + +func agnetResourceTypeNeedsSecretRef(resourceType string) bool { + switch resourceType { + case agnetResourceGit, agnetResourceSK, agnetResourceCloudAccount, agnetResourceCloudResource: + return true + default: + return false + } +} + func agnetRuntimePartiallySet(r agnetRuntimeExecution) bool { return strings.TrimSpace(r.ProfileID) != "" || len(r.CloudPrincipalRefs) > 0 || @@ -235,7 +289,50 @@ func validateAgentSKAccessPolicy(c *gin.Context, agent agnetAgentPlan) bool { return true } if strings.TrimSpace(p.PolicyRef) == "" && !p.InheritDeploymentDefaults { - agnetError(c, "SK_POLICY_REJECTED", "sk_access_policy.policy_ref or inherit_deployment_defaults is required when deny_skill_ids is set") + agnetError(c, "SK_POLICY_REJECTED", "sk_access_policy.policy_ref or inherit_deployment_defaults is required when deny_skill_ids set") + return false + } + return true +} + +func validateResourceGrant(c *gin.Context, plan agnetOrchestrationPlan, agent agnetAgentPlan, grant agnetResourceGrant) bool { + resourceType := strings.TrimSpace(grant.ResourceType) + switch resourceType { + case agnetResourceGit, agnetResourceSK, agnetResourceProjectDoc, agnetResourceCloudAccount, agnetResourceCloudResource: + default: + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants.resource_type must be git/sk/project_doc/cloud_account/cloud_resource") + return false + } + + if strings.TrimSpace(grant.GrantID) == "" || strings.TrimSpace(grant.ResourceID) == "" || + strings.TrimSpace(grant.TargetRole) == "" || strings.TrimSpace(grant.TargetAgentRef) == "" { + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants require grant_id/resource_id/target_role/target_agent_ref") + return false + } + if strings.TrimSpace(grant.TenantID) != plan.Metadata.TenantID || strings.TrimSpace(grant.ProjectID) != plan.Metadata.ProjectID { + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants tenant_id/project_id must match orchestration metadata") + return false + } + if strings.TrimSpace(grant.TargetRole) != strings.TrimSpace(agent.RoleTemplate) { + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants.target_role must match the assigned agent role") + return false + } + if len(grant.PermissionScope) == 0 { + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants.permission_scope must not be empty") + return false + } + switch strings.TrimSpace(grant.Status) { + case agnetGrantStatusPending, agnetGrantStatusActive, agnetGrantStatusDisabled, agnetGrantStatusRevoked: + default: + agnetError(c, "RESOURCE_GRANT_INVALID", "resource_grants.status must be pending/active/disabled/revoked") + return false + } + if agnetResourceTypeNeedsSecretRef(resourceType) && strings.TrimSpace(grant.SecretRef) == "" { + agnetError(c, "RESOURCE_GRANT_SECRET_REF_REQUIRED", "resource_grants.secret_ref is required for credential-backed resources") + return false + } + if containsSensitiveGrantField(grant.Metadata) || containsSensitiveGrantField(grant.Constraints) || containsSensitiveGrantField(grant.Audit) { + agnetError(c, "RESOURCE_GRANT_SECRET_REJECTED", "resource_grants metadata/constraints/audit must not contain plaintext credential fields") return false } return true @@ -300,6 +397,11 @@ func validateOrchestrationPlan(c *gin.Context, plan agnetOrchestrationPlan) bool if !validateAgentSKAccessPolicy(c, agent) { return false } + for _, grant := range agent.ResourceGrants { + if !validateResourceGrant(c, plan, agent, grant) { + return false + } + } } return true