Files
Agent-System/internal/auth/store_factory.go
weichenandCursor 514db3a086 feat(auth): fail-closed IAM store unless dev/test opt-in
Refuse MemoryStore fallback for main/empty/unknown env or missing
ALLOW_IN_MEMORY so production cannot silently use in-memory authority.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 09:42:07 +00:00

56 lines
1.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package auth
import (
"context"
"fmt"
"strings"
"github.com/jackc/pgx/v5/pgxpool"
"chat-agent-system/internal/config"
)
// Stores 认证账户存储与会话存储组合。
type Stores struct {
Auth AuthStore
Sessions SessionStore
}
func allowInMemoryAuthFallback(cfg *config.Config) bool {
if cfg == nil || !cfg.AllowInMemory {
return false
}
env := strings.ToLower(strings.TrimSpace(cfg.Env))
return env == "dev" || env == "test"
}
// NewStores 根据数据库与 IAM 迁移状态选择 PG 或内存实现。
// 仅当环境明确为 dev/test 且 AllowInMemory 时允许 MemoryStore;
// 环境空值、未知值、main/prod、pool 缺失或 IAM 表未就绪时 fail closed。
func NewStores(ctx context.Context, pool *pgxpool.Pool, cfg *config.Config) (*Stores, error) {
if pool != nil && IAMTablesReady(ctx, pool) {
pg, err := NewPgStore(pool, cfg)
if err != nil {
return nil, err
}
if err := BootstrapIAM(ctx, pool, pg, cfg); err != nil {
return nil, err
}
return &Stores{Auth: pg, Sessions: pg}, nil
}
if allowInMemoryAuthFallback(cfg) {
mem := NewMemoryStore(cfg)
return &Stores{Auth: mem, Sessions: NewMemorySessionStore()}, nil
}
env := ""
if cfg != nil {
env = strings.TrimSpace(cfg.Env)
}
reason := "IAM tables not ready or database pool unavailable"
if pool == nil {
reason = "database pool is nil"
} else if !IAMTablesReady(ctx, pool) {
reason = "IAM tables not ready"
}
return nil, fmt.Errorf("auth store fail-closed: %s (env=%q); memory IAM fallback requires env=dev|test and ALLOW_IN_MEMORY=true", reason, env)
}