fix(ssf): 允许同一配对恢复未完成连接

首次创建 SSF Stream 失败后,恢复管理器会因缺少尚未生成的 Audience 而将同一 Revision 误判为凭据交接冲突。现在仅对同一 owner、Transmitter、机器客户端且尚未绑定 Stream 的可恢复状态放行重试,跨 Revision 与不完整绑定配置仍保持安全拒绝。\n\n验证:gofmt、go vet ./...、env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1。
This commit is contained in:
2026-07-28 04:48:15 +08:00
parent 9e8722dc9f
commit 1b48a91af0
2 changed files with 114 additions and 0 deletions
@@ -183,6 +183,9 @@ func NewConnectionManager(ctx context.Context, repository ConnectionRepository,
}
} else if hasRevisionBindingExpectation(config) {
if err := manager.validateConnectionBinding(connection); err != nil {
if manager.recoverableIncompleteConnectionBinding(connection) {
return manager, nil
}
// A recovery manager may inspect a foreign singleton connection, but
// it must not activate it: activate() would combine the old persisted
// Secret with the new Revision's token endpoint.
@@ -257,6 +260,22 @@ func (m *ConnectionManager) validateConnectionBinding(connection store.SecurityE
return nil
}
func (m *ConnectionManager) recoverableIncompleteConnectionBinding(connection store.SecurityEventConnection) bool {
expectedIssuer := strings.TrimRight(strings.TrimSpace(m.config.ExpectedTransmitterIssuer), "/")
expectedAudience := strings.TrimSpace(m.config.ExpectedAudience)
expectedClientID := strings.TrimSpace(m.config.ManagementClientID)
expectedOwner := strings.TrimSpace(m.config.ExpectedOwnerKey)
if expectedIssuer == "" || expectedAudience == "" || expectedClientID == "" || expectedOwner == "" {
return false
}
return connection.StreamID == nil &&
connection.Audience == nil &&
resumableConnectionLifecycle(connection.LifecycleStatus) &&
strings.TrimRight(strings.TrimSpace(connection.TransmitterIssuer), "/") == expectedIssuer &&
strings.TrimSpace(connection.ManagementClientID) == expectedClientID &&
strings.TrimSpace(connection.IdempotencyKey) == expectedOwner
}
func (m *ConnectionManager) Get(ctx context.Context) (ConnectionView, error) {
connection, err := m.repository.SecurityEventConnection(ctx)
if err != nil {