// app/cmd/seed.go // Created: 2026-04-09 // Updated: 2026-04-09 — фиксированные credentials для demo-tenant (BYOC) // Автосид демо-данных при старте через SHARED_SQS_SEED_DEMO=true. // Создаёт тенанта demo-service с 5 очередями и демо-сообщениями. // // DEMO CREDENTIALS — только для тестового стенда. // Тенант demo-service изолирован: видит только свои очереди, не имеет доступа к // admin API и к очередям других тенантов. Credentials открыты намеренно — стенд публичный. package main import ( "crypto/md5" //nolint:gosec — MD5 используется для SQS-совместимости, не для безопасности "fmt" "time" "github.com/google/uuid" log "github.com/sirupsen/logrus" "shared-sqs/app/models" "shared-sqs/app/tenant" ) // Фиксированные credentials демо-тенанта. // Открыты намеренно — тестовый стенд. // Тенант ограничен 10 очередями и не имеет прав admin API. const ( demoTenantID = "t-demo-shared-sqs-ngcloud" demoAccessKey = "SSAK-demo-shared-sqs" demoSecretKey = "demo-secret-key-shared-sqs-ngcloud-2026" demoTenantName = "demo-service" demoMaxQueues = 10 ) // seedDemoData создаёт тенанта demo-service с очередями и сообщениями. // Вызывается при SHARED_SQS_SEED_DEMO=true при старте сервера. func seedDemoData(store *tenant.TenantStore) { t, err := store.CreateFixed(demoTenantName, demoMaxQueues, demoTenantID, demoAccessKey, demoSecretKey) if err != nil { log.Warnf("seed: не удалось создать demo-tenant: %v", err) return } log.Infof("seed: создан тенант %s (AccessKey=%s)", t.ID, t.AccessKey) // Демо-очереди с набором сообщений queues := []struct { name string msgs []string }{ { "orders", []string{ `{"order_id":"1001","amount":99.99,"status":"pending"}`, `{"order_id":"1002","amount":14.50,"status":"completed"}`, `{"order_id":"1003","amount":299.00,"status":"processing"}`, }, }, { "notifications", []string{ `{"to":"user@example.com","text":"Welcome to the service!"}`, `{"to":"admin@example.com","text":"New user signed up"}`, }, }, { "emails", []string{ `{"subject":"Invoice #42","body":"See attachment","to":"billing@example.com"}`, }, }, { "uploads", nil, }, { "user-events", []string{ `{"event":"login","user_id":"u-123","ts":1744000000}`, `{"event":"logout","user_id":"u-123","ts":1744003600}`, `{"event":"purchase","user_id":"u-456","item_id":"prod-7","ts":1744005000}`, }, }, } for _, q := range queues { key := t.AccessKey + ":" + q.name // URL и ARN формируем по тому же шаблону что gosqs/tenant_helpers.go:tenantQueueURL/tenantQueueARN // Иначе AWS CLI получает пустой QueueUrl в ListQueues и не может работать с очередью. env := models.CurrentEnvironment var queueURL string if env.Region != "" { queueURL = "http://" + env.Region + "." + env.Host + ":" + env.Port + "/" + t.ID + "/" + q.name } else { queueURL = "http://" + env.Host + ":" + env.Port + "/" + t.ID + "/" + q.name } queueARN := "arn:aws:sqs:" + env.Region + ":" + t.ID + ":" + q.name msgs := make([]models.SqsMessage, 0, len(q.msgs)) for _, body := range q.msgs { //nolint:gosec — MD5 здесь для совместимости с AWS SQS протоколом sum := md5.Sum([]byte(body)) //nolint:gosec msgs = append(msgs, models.SqsMessage{ MessageBody: body, Uuid: uuid.NewString(), MD5OfMessageBody: fmt.Sprintf("%x", sum), SentTime: time.Now(), }) } models.SyncQueues.Lock() models.SyncQueues.Queues[key] = &models.Queue{ Name: q.name, URL: queueURL, Arn: queueARN, VisibilityTimeout: 30, MaximumMessageSize: 262144, MessageRetentionPeriod: 345600, Messages: msgs, Duplicates: make(map[string]time.Time), } models.SyncQueues.Unlock() log.Infof("seed: очередь %s (%d сообщений)", q.name, len(q.msgs)) } log.Infof("seed: демо-данные готовы — тенант %s, 5 очередей", t.Name) }