package opsconfig import ( "context" "encoding/json" "errors" "fmt" "regexp" "strings" "time" "data-terminal-cloud/internal/audit" "data-terminal-cloud/internal/idempotency" "data-terminal-cloud/internal/identity" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" ) var ErrPublishGate = errors.New("runtime configuration publish gate failed") const ( EvidenceTypeGeneric = "GENERIC" EvidenceTypeAgentQualityV1 = "AGENT_QUALITY_V1" ) type RolloutInput struct { ScopeType string `json:"scope_type"` ScopeID string `json:"scope_id,omitempty"` RolloutPercent int `json:"rollout_percent"` MaxConcurrentCalls int `json:"max_concurrent_calls"` } type PublishInput struct { Reason string `json:"reason"` Rollout RolloutInput `json:"rollout"` } type ResourceReference struct { ID string `json:"id"` TenantID string `json:"tenant_id"` ResourceType string `json:"resource_type"` ReferenceName string `json:"reference_name"` DisplayName string `json:"display_name"` Status string `json:"status"` VerifiedAt time.Time `json:"verified_at"` LastRotatedAt *time.Time `json:"last_rotated_at,omitempty"` ExpiresAt *time.Time `json:"expires_at,omitempty"` CreatedBy string `json:"created_by"` RowVersion int64 `json:"row_version"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type Evaluation struct { ID string `json:"id"` ConfigVersionID string `json:"config_version_id"` EvidenceType string `json:"evidence_type"` SuiteVersion string `json:"suite_version"` Result string `json:"result"` Metrics map[string]any `json:"metrics"` ReportRef string `json:"report_ref"` EvaluatedBy string `json:"evaluated_by"` EvaluatedAt time.Time `json:"evaluated_at"` } type DeviceGroup struct { ID string `json:"id"` TenantID string `json:"tenant_id"` Name string `json:"name"` Selector map[string]any `json:"selector"` Status string `json:"status"` DeviceIDs []string `json:"device_ids"` CreatedBy string `json:"created_by"` RowVersion int64 `json:"row_version"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type Rollout struct { ID string `json:"id"` ConfigVersionID string `json:"config_version_id"` ConfigKey string `json:"config_key"` ScopeType string `json:"scope_type"` ScopeID *string `json:"scope_id,omitempty"` RolloutPercent int `json:"rollout_percent"` MaxConcurrentCalls int `json:"max_concurrent_calls"` Status string `json:"status"` Reason string `json:"reason"` ActivatedBy string `json:"activated_by"` ActivatedAt time.Time `json:"activated_at"` PausedAt *time.Time `json:"paused_at,omitempty"` EndedAt *time.Time `json:"ended_at,omitempty"` RowVersion int64 `json:"row_version"` } func (s *Service) CreateResourceReference(ctx context.Context, principal identity.Principal, tenantPublicID, key, requestID, resourceType, referenceName, displayName string, verifiedAt time.Time, expiresAt *time.Time) (ResourceReference, bool, error) { resourceType = strings.ToUpper(strings.TrimSpace(resourceType)) referenceName = strings.TrimSpace(referenceName) displayName = strings.TrimSpace(displayName) if !referencePattern.MatchString(referenceName) || displayName == "" || verifiedAt.IsZero() || verifiedAt.After(time.Now().UTC().Add(5*time.Minute)) { return ResourceReference{}, false, ErrInvalid } if resourceType != "PROVIDER_CREDENTIAL" && resourceType != "VOICE_RESOURCE" && resourceType != "MODEL_RESOURCE" && resourceType != "CERTIFICATE" { return ResourceReference{}, false, ErrInvalid } if (resourceType == "CERTIFICATE") != (expiresAt != nil) || (expiresAt != nil && !expiresAt.After(verifiedAt)) { return ResourceReference{}, false, ErrInvalid } currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_operator", "ops_approver", "ops_admin") if err != nil { return ResourceReference{}, false, err } requestBody, _ := json.Marshal(map[string]any{"resource_type": resourceType, "reference_name": referenceName, "display_name": displayName, "verified_at": verifiedAt.UTC(), "expires_at": expiresAt}) result, err := s.idem.Execute(ctx, idempotency.Request{TenantID: ¤tActor.tenantID, ActorKey: "ops:" + currentActor.userPublicID, Scope: "POST /api/v1/ops/resource-references", Key: key, RequestHash: idempotency.Hash(requestBody), ExpiresAfter: 24 * time.Hour}, func(operationContext context.Context, tx pgx.Tx) (idempotency.Result, error) { publicID := uuid.NewString() var internalID string err := tx.QueryRow(operationContext, `INSERT INTO ops_resource_reference(public_id,tenant_id,resource_type,reference_name,display_name,verified_at,expires_at,created_by) VALUES($1::uuid,$2::uuid,$3,$4,$5,$6,$7,$8::uuid) RETURNING id::text`, publicID, currentActor.tenantID, resourceType, referenceName, displayName, verifiedAt.UTC(), expiresAt, currentActor.userID).Scan(&internalID) if err != nil { return idempotency.Result{}, err } if err = s.audit.Record(operationContext, tx, audit.Event{TenantID: ¤tActor.tenantID, ActorType: "user", ActorPublicID: ¤tActor.userPublicID, Action: "ops.resource_reference.create", ResourceType: "ops_resource_reference", ResourceID: &internalID, RequestID: requestID, Purpose: "register verified resource reference", Result: "success", Detail: map[string]any{"resource_type": resourceType, "reference_name": referenceName}}); err != nil { return idempotency.Result{}, err } item, err := getResourceReferenceTx(operationContext, tx, currentActor.tenantID, publicID) if err != nil { return idempotency.Result{}, err } body, _ := json.Marshal(item) return idempotency.Result{StatusCode: 201, Body: body, ResourceID: &internalID}, nil }) if err != nil { return ResourceReference{}, false, err } var item ResourceReference if err = json.Unmarshal(result.Body, &item); err != nil { return ResourceReference{}, false, err } return item, !result.Replayed, nil } func (s *Service) ListResourceReferences(ctx context.Context, principal identity.Principal, tenantPublicID string) ([]ResourceReference, error) { currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_viewer", "ops_operator", "ops_approver", "ops_admin") if err != nil { return nil, err } rows, err := s.pool.Query(ctx, resourceReferenceSelect+` WHERE rr.tenant_id=$1::uuid ORDER BY rr.resource_type,rr.reference_name LIMIT 500`, currentActor.tenantID) if err != nil { return nil, err } defer rows.Close() items := []ResourceReference{} for rows.Next() { item, scanErr := scanResourceReference(rows) if scanErr != nil { return nil, scanErr } items = append(items, item) } return items, rows.Err() } func (s *Service) RevokeResourceReference(ctx context.Context, principal identity.Principal, tenantPublicID, publicID, requestID, reason string, expectedVersion int64) (ResourceReference, error) { reason = strings.TrimSpace(reason) if reason == "" || len([]rune(reason)) > 500 { return ResourceReference{}, ErrInvalid } currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_operator", "ops_approver", "ops_admin") if err != nil { return ResourceReference{}, err } tx, err := s.pool.BeginTx(ctx, pgx.TxOptions{}) if err != nil { return ResourceReference{}, err } defer func() { _ = tx.Rollback(context.Background()) }() var internalID, status string var rowVersion int64 err = tx.QueryRow(ctx, `SELECT id::text,status,row_version FROM ops_resource_reference WHERE tenant_id=$1::uuid AND public_id=$2::uuid FOR UPDATE`, currentActor.tenantID, publicID).Scan(&internalID, &status, &rowVersion) if errors.Is(err, pgx.ErrNoRows) { return ResourceReference{}, ErrNotFound } if err != nil { return ResourceReference{}, err } if rowVersion != expectedVersion { return ResourceReference{}, ErrVersionConflict } if status != "ACTIVE" { return ResourceReference{}, ErrStateConflict } if _, err = tx.Exec(ctx, `UPDATE ops_resource_reference SET status='REVOKED',row_version=row_version+1,updated_at=now() WHERE id=$1::uuid`, internalID); err != nil { return ResourceReference{}, err } if err = s.audit.Record(ctx, tx, audit.Event{TenantID: ¤tActor.tenantID, ActorType: "user", ActorPublicID: ¤tActor.userPublicID, Action: "ops.resource_reference.revoke", ResourceType: "ops_resource_reference", ResourceID: &internalID, RequestID: requestID, Purpose: reason, Result: "success"}); err != nil { return ResourceReference{}, err } item, err := getResourceReferenceTx(ctx, tx, currentActor.tenantID, publicID) if err == nil { err = tx.Commit(ctx) } return item, err } func (s *Service) CreateEvaluation(ctx context.Context, principal identity.Principal, tenantPublicID, configPublicID, key, requestID, evidenceType, suiteVersion, result, reportRef string, metrics map[string]any) (Evaluation, bool, error) { evidenceType = strings.ToUpper(strings.TrimSpace(evidenceType)) if evidenceType == "" { evidenceType = EvidenceTypeGeneric } suiteVersion = strings.TrimSpace(suiteVersion) result = strings.ToUpper(strings.TrimSpace(result)) reportRef = strings.TrimSpace(reportRef) encodedMetrics, _ := json.Marshal(metrics) if suiteVersion == "" || len([]rune(suiteVersion)) > 100 || (result != "PASSED" && result != "FAILED") || reportRef == "" || len([]rune(reportRef)) > 300 || metrics == nil || len(encodedMetrics) > 32768 || !validEvaluationMetrics(evidenceType, result, metrics) { return Evaluation{}, false, ErrInvalid } currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_operator", "ops_approver", "ops_admin") if err != nil { return Evaluation{}, false, err } requestBody, _ := json.Marshal(map[string]any{"config_id": configPublicID, "evidence_type": evidenceType, "suite_version": suiteVersion, "result": result, "report_ref": reportRef, "metrics": metrics}) idemResult, err := s.idem.Execute(ctx, idempotency.Request{TenantID: ¤tActor.tenantID, ActorKey: "ops:" + currentActor.userPublicID, Scope: "POST /api/v1/ops/config-versions/evaluations", Key: key, RequestHash: idempotency.Hash(requestBody), ExpiresAfter: 24 * time.Hour}, func(operationContext context.Context, tx pgx.Tx) (idempotency.Result, error) { var configID, status, configKind string var configPayloadJSON []byte if queryErr := tx.QueryRow(operationContext, `SELECT id::text,status,config_kind,payload FROM runtime_config_version WHERE tenant_id=$1::uuid AND public_id=$2::uuid FOR UPDATE`, currentActor.tenantID, configPublicID).Scan(&configID, &status, &configKind, &configPayloadJSON); errors.Is(queryErr, pgx.ErrNoRows) { return idempotency.Result{}, ErrNotFound } else if queryErr != nil { return idempotency.Result{}, queryErr } if status != "DRAFT" && status != "PENDING_APPROVAL" { return idempotency.Result{}, ErrStateConflict } if evidenceType == EvidenceTypeAgentQualityV1 && configKind != "AGENT_BUNDLE" { return idempotency.Result{}, ErrInvalid } if evidenceType == EvidenceTypeAgentQualityV1 { boundConfigID, bound := metrics["config_version_id"].(string) if !bound || strings.TrimSpace(boundConfigID) != configPublicID { return idempotency.Result{}, ErrInvalid } var configPayload map[string]any if queryErr := json.Unmarshal(configPayloadJSON, &configPayload); queryErr != nil { return idempotency.Result{}, queryErr } modelVersionID, modelExists := configPayload["model_version_id"].(string) modelConfigRef, refExists := metrics["model_config_ref"].(string) if !modelExists || !refExists || modelConfigRef != "runtime-config-version:"+modelVersionID { return idempotency.Result{}, ErrInvalid } } publicID := uuid.NewString() var internalID string if queryErr := tx.QueryRow(operationContext, `INSERT INTO ops_config_evaluation(public_id,tenant_id,config_version_id,evidence_type,suite_version,result,metrics,report_ref,evaluated_by) VALUES($1::uuid,$2::uuid,$3::uuid,$4,$5,$6,$7::jsonb,$8,$9::uuid) RETURNING id::text`, publicID, currentActor.tenantID, configID, evidenceType, suiteVersion, result, encodedMetrics, reportRef, currentActor.userID).Scan(&internalID); queryErr != nil { return idempotency.Result{}, queryErr } if queryErr := s.audit.Record(operationContext, tx, audit.Event{TenantID: ¤tActor.tenantID, ActorType: "user", ActorPublicID: ¤tActor.userPublicID, Action: "ops.config.evaluate", ResourceType: "ops_config_evaluation", ResourceID: &internalID, RequestID: requestID, Purpose: suiteVersion, Result: "success", Detail: map[string]any{"config_version_id": configPublicID, "evidence_type": evidenceType, "evaluation_result": result, "report_ref": reportRef}}); queryErr != nil { return idempotency.Result{}, queryErr } item, queryErr := getEvaluationTx(operationContext, tx, currentActor.tenantID, publicID) if queryErr != nil { return idempotency.Result{}, queryErr } body, _ := json.Marshal(item) return idempotency.Result{StatusCode: 201, Body: body, ResourceID: &internalID}, nil }) if err != nil { return Evaluation{}, false, err } var item Evaluation if err = json.Unmarshal(idemResult.Body, &item); err != nil { return Evaluation{}, false, err } return item, !idemResult.Replayed, nil } func validEvaluationMetrics(evidenceType, result string, metrics map[string]any) bool { if evidenceType == EvidenceTypeGeneric { return true } if evidenceType != EvidenceTypeAgentQualityV1 { return false } reportSchema, schemaOK := metrics["report_schema"].(string) suiteDigest, digestOK := metrics["suite_sha256"].(string) agentVersion, agentOK := metrics["agent_version"].(string) modelConfigRef, configOK := metrics["model_config_ref"].(string) environment, environmentOK := metrics["environment"].(string) executedAt, executedOK := metrics["executed_at"].(string) if !schemaOK || reportSchema != "agent-eval-report-v1" || !digestOK || !regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(suiteDigest) || !agentOK || strings.TrimSpace(agentVersion) == "" || !configOK || strings.TrimSpace(modelConfigRef) == "" || !environmentOK || (environment != "mock" && environment != "real") || !executedOK { return false } if _, err := time.Parse(time.RFC3339, executedAt); err != nil { return false } casesTotal, totalOK := integerMetric(metrics, "cases_total") casesPassed, passedOK := integerMetric(metrics, "cases_passed") failedChecks, failedOK := integerMetric(metrics, "failed_check_count") fabricatedFacts, fabricatedOK := integerMetric(metrics, "fabricated_facts") firstResponseP95, latencyOK := numberMetric(metrics, "first_response_p95_ms") averageResponseChars, lengthOK := numberMetric(metrics, "average_response_chars") if !totalOK || !passedOK || !failedOK || !fabricatedOK || !latencyOK || !lengthOK || casesTotal < 10 || casesPassed < 0 || casesPassed > casesTotal || failedChecks < 0 || fabricatedFacts < 0 || firstResponseP95 < 0 || averageResponseChars < 0 { return false } for _, key := range []string{"conversation_success_rate", "interruption_recovery_rate", "salutation_accuracy", "memory_accuracy", "story_source_completeness", "sensitive_information_handling_rate"} { value, ok := numberMetric(metrics, key) if !ok || value < 0 || value > 1 { return false } } if result == "PASSED" && (casesPassed != casesTotal || failedChecks != 0) { return false } if result == "FAILED" && failedChecks == 0 { return false } return true } func numberMetric(metrics map[string]any, key string) (float64, bool) { switch value := metrics[key].(type) { case float64: return value, true case float32: return float64(value), true case int: return float64(value), true case int64: return float64(value), true case json.Number: parsed, err := value.Float64() return parsed, err == nil default: return 0, false } } func integerMetric(metrics map[string]any, key string) (int64, bool) { value, ok := numberMetric(metrics, key) if !ok || value != float64(int64(value)) { return 0, false } return int64(value), true } func (s *Service) ListEvaluations(ctx context.Context, principal identity.Principal, tenantPublicID, configPublicID string) ([]Evaluation, error) { currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_viewer", "ops_operator", "ops_approver", "ops_admin") if err != nil { return nil, err } rows, err := s.pool.Query(ctx, ` SELECT e.public_id::text,rcv.public_id::text,e.evidence_type,e.suite_version,e.result,e.metrics, e.report_ref,ua.public_id::text,e.evaluated_at FROM ops_config_evaluation e JOIN runtime_config_version rcv ON rcv.id=e.config_version_id AND rcv.tenant_id=e.tenant_id JOIN user_account ua ON ua.id=e.evaluated_by AND ua.tenant_id=e.tenant_id WHERE e.tenant_id=$1::uuid AND rcv.public_id=$2::uuid ORDER BY e.evaluated_at DESC,e.id DESC LIMIT 500`, currentActor.tenantID, configPublicID) if err != nil { return nil, err } defer rows.Close() items := []Evaluation{} for rows.Next() { var item Evaluation var metrics []byte if err = rows.Scan(&item.ID, &item.ConfigVersionID, &item.EvidenceType, &item.SuiteVersion, &item.Result, &metrics, &item.ReportRef, &item.EvaluatedBy, &item.EvaluatedAt); err != nil { return nil, err } if err = json.Unmarshal(metrics, &item.Metrics); err != nil { return nil, err } items = append(items, item) } return items, rows.Err() } func (s *Service) CreateDeviceGroup(ctx context.Context, principal identity.Principal, tenantPublicID, key, requestID, name string, selector map[string]any, devicePublicIDs []string) (DeviceGroup, bool, error) { name = strings.TrimSpace(name) selectorJSON, _ := json.Marshal(selector) if name == "" || len([]rune(name)) > 200 || selector == nil || len(selectorJSON) > 8192 || len(devicePublicIDs) == 0 || len(devicePublicIDs) > 1000 { return DeviceGroup{}, false, ErrInvalid } seen := map[string]struct{}{} for _, id := range devicePublicIDs { if _, err := uuid.Parse(id); err != nil { return DeviceGroup{}, false, ErrInvalid } seen[id] = struct{}{} } devicePublicIDs = devicePublicIDs[:0] for id := range seen { devicePublicIDs = append(devicePublicIDs, id) } currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_operator", "ops_approver", "ops_admin") if err != nil { return DeviceGroup{}, false, err } requestBody, _ := json.Marshal(map[string]any{"name": name, "selector": selector, "device_ids": devicePublicIDs}) idemResult, err := s.idem.Execute(ctx, idempotency.Request{TenantID: ¤tActor.tenantID, ActorKey: "ops:" + currentActor.userPublicID, Scope: "POST /api/v1/ops/device-groups", Key: key, RequestHash: idempotency.Hash(requestBody), ExpiresAfter: 24 * time.Hour}, func(operationContext context.Context, tx pgx.Tx) (idempotency.Result, error) { publicID := uuid.NewString() var internalID string if queryErr := tx.QueryRow(operationContext, `INSERT INTO ops_device_group(public_id,tenant_id,name,selector,created_by) VALUES($1::uuid,$2::uuid,$3,$4::jsonb,$5::uuid) RETURNING id::text`, publicID, currentActor.tenantID, name, selectorJSON, currentActor.userID).Scan(&internalID); queryErr != nil { return idempotency.Result{}, queryErr } tag, queryErr := tx.Exec(operationContext, `INSERT INTO ops_device_group_member(group_id,tenant_id,device_id) SELECT $1::uuid,$2::uuid,d.id FROM device d WHERE d.tenant_id=$2::uuid AND d.public_id=ANY($3::uuid[])`, internalID, currentActor.tenantID, devicePublicIDs) if queryErr != nil { return idempotency.Result{}, queryErr } if tag.RowsAffected() != int64(len(devicePublicIDs)) { return idempotency.Result{}, ErrAccessDenied } if queryErr = s.audit.Record(operationContext, tx, audit.Event{TenantID: ¤tActor.tenantID, ActorType: "user", ActorPublicID: ¤tActor.userPublicID, Action: "ops.device_group.create", ResourceType: "ops_device_group", ResourceID: &internalID, RequestID: requestID, Purpose: name, Result: "success", Detail: map[string]any{"device_count": len(devicePublicIDs)}}); queryErr != nil { return idempotency.Result{}, queryErr } item, queryErr := getDeviceGroupTx(operationContext, tx, currentActor.tenantID, publicID) if queryErr != nil { return idempotency.Result{}, queryErr } body, _ := json.Marshal(item) return idempotency.Result{StatusCode: 201, Body: body, ResourceID: &internalID}, nil }) if err != nil { return DeviceGroup{}, false, err } var item DeviceGroup if err = json.Unmarshal(idemResult.Body, &item); err != nil { return DeviceGroup{}, false, err } return item, !idemResult.Replayed, nil } func (s *Service) ListDeviceGroups(ctx context.Context, principal identity.Principal, tenantPublicID string) ([]DeviceGroup, error) { currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_viewer", "ops_operator", "ops_approver", "ops_admin") if err != nil { return nil, err } rows, err := s.pool.Query(ctx, deviceGroupSelect+` WHERE dg.tenant_id=$1::uuid GROUP BY dg.id,t.id,ua.id ORDER BY dg.name LIMIT 500`, currentActor.tenantID) if err != nil { return nil, err } defer rows.Close() items := []DeviceGroup{} for rows.Next() { item, scanErr := scanDeviceGroup(rows) if scanErr != nil { return nil, scanErr } items = append(items, item) } return items, rows.Err() } func (s *Service) ListRollouts(ctx context.Context, principal identity.Principal, tenantPublicID, configKey string) ([]Rollout, error) { currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_viewer", "ops_operator", "ops_approver", "ops_admin") if err != nil { return nil, err } configKey = strings.TrimSpace(configKey) if configKey != "" && !regexp.MustCompile(`^[a-z][a-z0-9_.-]{2,99}$`).MatchString(configKey) { return nil, ErrInvalid } rows, err := s.pool.Query(ctx, rolloutSelect+` WHERE rr.tenant_id=$1::uuid AND ($2='' OR rr.config_key=$2) ORDER BY CASE rr.status WHEN 'ACTIVE' THEN 1 WHEN 'PAUSED' THEN 2 ELSE 3 END,rr.activated_at DESC,rr.id DESC LIMIT 1000`, currentActor.tenantID, configKey) if err != nil { return nil, err } defer rows.Close() items := []Rollout{} for rows.Next() { item, scanErr := scanRollout(rows) if scanErr != nil { return nil, scanErr } items = append(items, item) } return items, rows.Err() } func (s *Service) PauseRollout(ctx context.Context, principal identity.Principal, tenantPublicID, publicID, requestID, reason string, expectedVersion int64) (Rollout, error) { return s.transitionRollout(ctx, principal, tenantPublicID, publicID, requestID, reason, expectedVersion, "ACTIVE", "PAUSED") } func (s *Service) ResumeRollout(ctx context.Context, principal identity.Principal, tenantPublicID, publicID, requestID, reason string, expectedVersion int64) (Rollout, error) { return s.transitionRollout(ctx, principal, tenantPublicID, publicID, requestID, reason, expectedVersion, "PAUSED", "ACTIVE") } func (s *Service) transitionRollout(ctx context.Context, principal identity.Principal, tenantPublicID, publicID, requestID, reason string, expectedVersion int64, fromStatus, toStatus string) (Rollout, error) { reason = strings.TrimSpace(reason) if _, err := uuid.Parse(publicID); err != nil || reason == "" || len([]rune(reason)) > 500 || expectedVersion < 1 { return Rollout{}, ErrInvalid } currentActor, err := s.resolveActor(ctx, principal, tenantPublicID, "ops_approver", "ops_admin") if err != nil { return Rollout{}, err } tx, err := s.pool.Begin(ctx) if err != nil { return Rollout{}, err } defer tx.Rollback(ctx) var internalID, status, configStatus string var rowVersion int64 err = tx.QueryRow(ctx, `SELECT rr.id::text,rr.status,rr.row_version,rcv.status FROM runtime_config_rollout rr JOIN runtime_config_version rcv ON rcv.id=rr.config_version_id AND rcv.tenant_id=rr.tenant_id WHERE rr.tenant_id=$1::uuid AND rr.public_id=$2::uuid FOR UPDATE OF rr`, currentActor.tenantID, publicID).Scan(&internalID, &status, &rowVersion, &configStatus) if errors.Is(err, pgx.ErrNoRows) { return Rollout{}, ErrNotFound } if err != nil { return Rollout{}, err } if rowVersion != expectedVersion { return Rollout{}, ErrVersionConflict } if status != fromStatus || (toStatus == "ACTIVE" && configStatus != "PUBLISHED") { return Rollout{}, ErrStateConflict } var commandTag pgconn.CommandTag if toStatus == "PAUSED" { commandTag, err = tx.Exec(ctx, `UPDATE runtime_config_rollout SET status='PAUSED',paused_at=now(),row_version=row_version+1,updated_at=now() WHERE id=$1::uuid`, internalID) } else { commandTag, err = tx.Exec(ctx, `UPDATE runtime_config_rollout SET status='ACTIVE',paused_at=NULL,row_version=row_version+1,updated_at=now() WHERE id=$1::uuid AND NOT EXISTS(SELECT 1 FROM runtime_config_rollout active WHERE active.tenant_id=runtime_config_rollout.tenant_id AND active.config_key=runtime_config_rollout.config_key AND active.status='ACTIVE' AND active.scope_type=runtime_config_rollout.scope_type AND ((active.scope_type='TENANT') OR (active.scope_type='SUBJECT' AND active.subject_id=runtime_config_rollout.subject_id) OR (active.scope_type='DEVICE_GROUP' AND active.device_group_id=runtime_config_rollout.device_group_id)))`, internalID) } if err != nil { var pgErr *pgconn.PgError if errors.As(err, &pgErr) && pgErr.Code == "23505" { return Rollout{}, ErrStateConflict } return Rollout{}, err } if commandTag.RowsAffected() != 1 { return Rollout{}, ErrStateConflict } item, err := getRolloutTx(ctx, tx, currentActor.tenantID, publicID) if err != nil { return Rollout{}, err } if item.Status != toStatus { return Rollout{}, ErrStateConflict } action := "ops.config_rollout.pause" if toStatus == "ACTIVE" { action = "ops.config_rollout.resume" } resourceID := internalID if err = s.audit.Record(ctx, tx, audit.Event{TenantID: ¤tActor.tenantID, ActorType: "user", ActorPublicID: ¤tActor.userPublicID, Action: action, ResourceType: "runtime_config_rollout", ResourceID: &resourceID, RequestID: requestID, Purpose: reason, Result: "success", Detail: map[string]any{"config_key": item.ConfigKey, "scope_type": item.ScopeType, "row_version": item.RowVersion}}); err != nil { return Rollout{}, err } if err = tx.Commit(ctx); err != nil { return Rollout{}, err } return item, nil } func validateRollout(input RolloutInput) error { input.ScopeType = strings.ToUpper(strings.TrimSpace(input.ScopeType)) if input.RolloutPercent < 1 || input.RolloutPercent > 100 || input.MaxConcurrentCalls < 1 || input.MaxConcurrentCalls > 100000 { return ErrInvalid } switch input.ScopeType { case "TENANT": if strings.TrimSpace(input.ScopeID) != "" { return ErrInvalid } case "SUBJECT": if input.RolloutPercent != 100 { return ErrInvalid } fallthrough case "DEVICE_GROUP": if _, err := uuid.Parse(input.ScopeID); err != nil { return ErrInvalid } default: return ErrInvalid } return nil } func (s *Service) checkPublishGatesTx(ctx context.Context, tx pgx.Tx, tenantID, configInternalID string, item Version) error { if item.ConfigKind == "AGENT_BUNDLE" { if _, err := validateAgentBundleComponentsTx(ctx, tx, tenantID, item); err != nil { return ErrPublishGate } } var passed bool if err := tx.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM ops_config_evaluation WHERE tenant_id=$1::uuid AND config_version_id=$2::uuid AND result='PASSED' AND ($3<>'AGENT_BUNDLE' OR evidence_type='AGENT_QUALITY_V1'))`, tenantID, configInternalID, item.ConfigKind).Scan(&passed); err != nil { return err } if !passed { return ErrPublishGate } refs := make(map[string]string, len(item.SecretRefs)+1) for _, ref := range item.SecretRefs { refs[ref] = "PROVIDER_CREDENTIAL" } if item.ConfigKind == "VOICE" { if ref, ok := item.Payload["voice_resource_ref"].(string); ok { refs[ref] = "VOICE_RESOURCE" } } if item.ConfigKind == "MODEL" { if ref, ok := item.Payload["model_id"].(string); ok { refs[ref] = "MODEL_RESOURCE" } } for ref, resourceType := range refs { var active bool if err := tx.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM ops_resource_reference WHERE tenant_id=$1::uuid AND reference_name=$2 AND resource_type=$3 AND status='ACTIVE' AND verified_at>now()-interval '180 days')`, tenantID, ref, resourceType).Scan(&active); err != nil { return err } if !active { return ErrPublishGate } } return nil } func (s *Service) activateRolloutTx(ctx context.Context, tx pgx.Tx, currentActor actor, configInternalID string, item Version, rollout RolloutInput, reason string) (string, *string, error) { rollout.ScopeType = strings.ToUpper(strings.TrimSpace(rollout.ScopeType)) var subjectID, groupID *string switch rollout.ScopeType { case "SUBJECT": var id string if err := tx.QueryRow(ctx, `SELECT id::text FROM subject_profile WHERE tenant_id=$1::uuid AND public_id=$2::uuid AND status='active'`, currentActor.tenantID, rollout.ScopeID).Scan(&id); errors.Is(err, pgx.ErrNoRows) { return "", nil, ErrAccessDenied } else if err != nil { return "", nil, err } subjectID = &id case "DEVICE_GROUP": var id string if err := tx.QueryRow(ctx, `SELECT id::text FROM ops_device_group WHERE tenant_id=$1::uuid AND public_id=$2::uuid AND status='ACTIVE'`, currentActor.tenantID, rollout.ScopeID).Scan(&id); errors.Is(err, pgx.ErrNoRows) { return "", nil, ErrAccessDenied } else if err != nil { return "", nil, err } groupID = &id } endSQL := `UPDATE runtime_config_rollout SET status='ENDED',ended_at=now(),row_version=row_version+1,updated_at=now() WHERE tenant_id=$1::uuid AND config_key=$2 AND status IN ('ACTIVE','PAUSED') AND scope_type=$3 AND (($3='TENANT') OR ($3='SUBJECT' AND subject_id=$4::uuid) OR ($3='DEVICE_GROUP' AND device_group_id=$5::uuid)) RETURNING config_version_id::text` rows, err := tx.Query(ctx, endSQL, currentActor.tenantID, item.ConfigKey, rollout.ScopeType, subjectID, groupID) if err != nil { return "", nil, err } endedVersions := []string{} for rows.Next() { var id string if err = rows.Scan(&id); err != nil { rows.Close() return "", nil, err } endedVersions = append(endedVersions, id) } rows.Close() for _, endedID := range endedVersions { if _, err = tx.Exec(ctx, `UPDATE runtime_config_version SET status='RETIRED',retired_at=now(),row_version=row_version+1,updated_at=now() WHERE id=$1::uuid AND NOT EXISTS(SELECT 1 FROM runtime_config_rollout WHERE config_version_id=$1::uuid AND status='ACTIVE')`, endedID); err != nil { return "", nil, err } } publicID := uuid.NewString() cohortSeed := int(time.Now().UnixNano() & 0x7fffffff) _, err = tx.Exec(ctx, `INSERT INTO runtime_config_rollout(public_id,tenant_id,config_version_id,config_key,scope_type,subject_id,device_group_id,rollout_percent,max_concurrent_calls,cohort_seed,reason,activated_by) VALUES($1::uuid,$2::uuid,$3::uuid,$4,$5,$6::uuid,$7::uuid,$8,$9,$10,$11,$12::uuid)`, publicID, currentActor.tenantID, configInternalID, item.ConfigKey, rollout.ScopeType, subjectID, groupID, rollout.RolloutPercent, rollout.MaxConcurrentCalls, cohortSeed, reason, currentActor.userID) if err != nil { return "", nil, err } if len(endedVersions) == 0 { return publicID, nil, nil } return publicID, &endedVersions[0], nil } const resourceReferenceSelect = `SELECT rr.public_id::text,t.public_id::text,rr.resource_type,rr.reference_name,rr.display_name,rr.status,rr.verified_at,rr.last_rotated_at,rr.expires_at,ua.public_id::text,rr.row_version,rr.created_at,rr.updated_at FROM ops_resource_reference rr JOIN tenant t ON t.id=rr.tenant_id JOIN user_account ua ON ua.id=rr.created_by` const rolloutSelect = `SELECT rr.public_id::text,rcv.public_id::text,rr.config_key,rr.scope_type, CASE rr.scope_type WHEN 'SUBJECT' THEN sp.public_id::text WHEN 'DEVICE_GROUP' THEN dg.public_id::text END, rr.rollout_percent,rr.max_concurrent_calls,rr.status,rr.reason,ua.public_id::text, rr.activated_at,rr.paused_at,rr.ended_at,rr.row_version FROM runtime_config_rollout rr JOIN runtime_config_version rcv ON rcv.id=rr.config_version_id AND rcv.tenant_id=rr.tenant_id JOIN user_account ua ON ua.id=rr.activated_by AND ua.tenant_id=rr.tenant_id LEFT JOIN subject_profile sp ON sp.id=rr.subject_id AND sp.tenant_id=rr.tenant_id LEFT JOIN ops_device_group dg ON dg.id=rr.device_group_id AND dg.tenant_id=rr.tenant_id` func scanRollout(row rowScanner) (Rollout, error) { var item Rollout err := row.Scan(&item.ID, &item.ConfigVersionID, &item.ConfigKey, &item.ScopeType, &item.ScopeID, &item.RolloutPercent, &item.MaxConcurrentCalls, &item.Status, &item.Reason, &item.ActivatedBy, &item.ActivatedAt, &item.PausedAt, &item.EndedAt, &item.RowVersion) return item, err } func getRolloutTx(ctx context.Context, tx pgx.Tx, tenantID, publicID string) (Rollout, error) { return scanRollout(tx.QueryRow(ctx, rolloutSelect+` WHERE rr.tenant_id=$1::uuid AND rr.public_id=$2::uuid`, tenantID, publicID)) } func scanResourceReference(row rowScanner) (ResourceReference, error) { var item ResourceReference err := row.Scan(&item.ID, &item.TenantID, &item.ResourceType, &item.ReferenceName, &item.DisplayName, &item.Status, &item.VerifiedAt, &item.LastRotatedAt, &item.ExpiresAt, &item.CreatedBy, &item.RowVersion, &item.CreatedAt, &item.UpdatedAt) return item, err } func getResourceReferenceTx(ctx context.Context, tx pgx.Tx, tenantID, publicID string) (ResourceReference, error) { item, err := scanResourceReference(tx.QueryRow(ctx, resourceReferenceSelect+` WHERE rr.tenant_id=$1::uuid AND rr.public_id=$2::uuid`, tenantID, publicID)) return item, err } func getEvaluationTx(ctx context.Context, tx pgx.Tx, tenantID, publicID string) (Evaluation, error) { var item Evaluation var metrics []byte err := tx.QueryRow(ctx, `SELECT e.public_id::text,rcv.public_id::text,e.evidence_type,e.suite_version,e.result,e.metrics,e.report_ref,ua.public_id::text,e.evaluated_at FROM ops_config_evaluation e JOIN runtime_config_version rcv ON rcv.id=e.config_version_id JOIN user_account ua ON ua.id=e.evaluated_by WHERE e.tenant_id=$1::uuid AND e.public_id=$2::uuid`, tenantID, publicID).Scan(&item.ID, &item.ConfigVersionID, &item.EvidenceType, &item.SuiteVersion, &item.Result, &metrics, &item.ReportRef, &item.EvaluatedBy, &item.EvaluatedAt) if err == nil { err = json.Unmarshal(metrics, &item.Metrics) } return item, err } const deviceGroupSelect = `SELECT dg.public_id::text,t.public_id::text,dg.name,dg.selector,dg.status,COALESCE(array_agg(d.public_id::text ORDER BY d.public_id) FILTER(WHERE d.id IS NOT NULL),'{}'),ua.public_id::text,dg.row_version,dg.created_at,dg.updated_at FROM ops_device_group dg JOIN tenant t ON t.id=dg.tenant_id JOIN user_account ua ON ua.id=dg.created_by LEFT JOIN ops_device_group_member dgm ON dgm.group_id=dg.id LEFT JOIN device d ON d.id=dgm.device_id` func scanDeviceGroup(row rowScanner) (DeviceGroup, error) { var item DeviceGroup var selector []byte err := row.Scan(&item.ID, &item.TenantID, &item.Name, &selector, &item.Status, &item.DeviceIDs, &item.CreatedBy, &item.RowVersion, &item.CreatedAt, &item.UpdatedAt) if err == nil { err = json.Unmarshal(selector, &item.Selector) } return item, err } func getDeviceGroupTx(ctx context.Context, tx pgx.Tx, tenantID, publicID string) (DeviceGroup, error) { return scanDeviceGroup(tx.QueryRow(ctx, deviceGroupSelect+` WHERE dg.tenant_id=$1::uuid AND dg.public_id=$2::uuid GROUP BY dg.id,t.id,ua.id`, tenantID, publicID)) } func (r RolloutInput) String() string { return fmt.Sprintf("%s:%s:%d%%/%d", r.ScopeType, r.ScopeID, r.RolloutPercent, r.MaxConcurrentCalls) }