修复 credentials_saved 状态无法恢复、配对与激活并发冲突,以及 SSF 和身份 Secret 生命周期不完整的问题。新增持久化协调器、取消与清理状态机、事务级并发门禁、受控 SSF 凭据交接、禁用后的延迟 Secret 清理,并对生产环境统一认证及 Discovery 端点强制 HTTPS。 验证:go test ./...;go test -race ./internal/auth ./internal/identity ./internal/identityruntime ./internal/securityevents ./internal/httpapi ./internal/store -count=1;go vet ./...;真实 PostgreSQL 并发及清理成功/冲突回滚测试;pnpm openapi。
53 lines
1.6 KiB
Go
53 lines
1.6 KiB
Go
package securityevents
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
|
|
)
|
|
|
|
const (
|
|
identitySecretCleanupInterval = time.Minute
|
|
identitySecretCleanupLease = 5 * time.Minute
|
|
identitySecretCleanupBatch = 100
|
|
)
|
|
|
|
type IdentitySecretCleanupRepository interface {
|
|
ClaimIdentitySecretCleanups(context.Context, int, time.Duration) ([]store.IdentitySecretCleanupClaim, error)
|
|
CompleteIdentitySecretCleanup(context.Context, string, string) (bool, error)
|
|
}
|
|
|
|
// RunIdentitySecretCleanupWorker owns cleanup at the server lifecycle rather
|
|
// than at any individual Active or Prepared identity Runtime. PostgreSQL claim
|
|
// tokens make running one worker per server replica safe.
|
|
func RunIdentitySecretCleanupWorker(ctx context.Context, repository IdentitySecretCleanupRepository, secrets SecretStore) {
|
|
if repository == nil || secrets == nil {
|
|
return
|
|
}
|
|
ticker := time.NewTicker(identitySecretCleanupInterval)
|
|
defer ticker.Stop()
|
|
for {
|
|
cleanupClaimedIdentitySecrets(ctx, repository, secrets)
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
}
|
|
}
|
|
}
|
|
|
|
func cleanupClaimedIdentitySecrets(ctx context.Context, repository IdentitySecretCleanupRepository, secrets SecretStore) {
|
|
claims, err := repository.ClaimIdentitySecretCleanups(ctx, identitySecretCleanupBatch, identitySecretCleanupLease)
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, claim := range claims {
|
|
if err := secrets.Delete(ctx, claim.Reference); err != nil && !errors.Is(err, ErrSecretNotFound) {
|
|
continue
|
|
}
|
|
_, _ = repository.CompleteIdentitySecretCleanup(ctx, claim.Reference, claim.ClaimToken)
|
|
}
|
|
}
|