修复部署验收回归问题

This commit is contained in:
smail 2026-09-22 06:33:03 +08:00
parent 6c35fcffc2
commit 5ad2b9d63b
3 changed files with 61 additions and 27 deletions

View File

@ -126,6 +126,22 @@ func retainPreviousSSL(root string, next *SSLConfig, previous SSLConfig) {
} }
} }
func removeFlatSSLFile(directory, path string) error {
info, err := os.Lstat(path)
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() || hasMultipleFileLinks(path) {
return ErrUnsafeSSLFile
}
storage, err := os.OpenRoot(directory)
if err != nil {
return err
}
defer storage.Close()
return storage.Remove(filepath.Base(path))
}
func pruneFlatSSLLocked(root string, protected []SSLConfig) error { func pruneFlatSSLLocked(root string, protected []SSLConfig) error {
// 当前材料不可用时暂停回收,避免丢失仍可恢复的历史证书。 // 当前材料不可用时暂停回收,避免丢失仍可恢复的历史证书。
if len(protected) == 0 { if len(protected) == 0 {
@ -165,11 +181,6 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error {
keep[publicPath] = true keep[publicPath] = true
} }
} }
storage, err := os.OpenRoot(directory)
if err != nil {
return err
}
defer storage.Close()
for _, entry := range entries { for _, entry := range entries {
publicPath := filepath.Join(directory, entry.Name()) publicPath := filepath.Join(directory, entry.Name())
privatePath := strings.TrimSuffix(publicPath, ".crt") + ".key" privatePath := strings.TrimSuffix(publicPath, ".crt") + ".key"
@ -189,7 +200,7 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error {
if err != nil { if err != nil {
// 先删私钥、后删证书;中断留下的孤立证书可在下轮安全重试。 // 先删私钥、后删证书;中断留下的孤立证书可在下轮安全重试。
if _, statErr := os.Lstat(privatePath); os.IsNotExist(statErr) { if _, statErr := os.Lstat(privatePath); os.IsNotExist(statErr) {
if err := storage.Remove(filepath.Base(publicPath)); err != nil { if err := removeFlatSSLFile(directory, publicPath); err != nil {
return err return err
} }
} }
@ -209,9 +220,9 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error {
} }
continue continue
} }
err = storage.Remove(filepath.Base(privatePath)) err = removeFlatSSLFile(directory, privatePath)
if err == nil { if err == nil {
err = storage.Remove(filepath.Base(publicPath)) err = removeFlatSSLFile(directory, publicPath)
} }
unlock() unlock()
if err := errors.Join(err, lease.Close()); err != nil { if err := errors.Join(err, lease.Close()); err != nil {

View File

@ -149,28 +149,26 @@ func pruneManagedSSLLocked(root string, protected []SSLConfig) error {
} }
// 磁盘引用也必须保留,避免其他管理器实例或已提交未发布的候选被删除。 // 磁盘引用也必须保留,避免其他管理器实例或已提交未发布的候选被删除。
configRoot, err := os.OpenRoot(filepath.Join(root, "config")) configRoot, err := os.OpenRoot(filepath.Join(root, "config"))
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
data, err := configRoot.ReadFile("ssl.json")
_ = configRoot.Close()
if err == nil { if err == nil {
var section SSLSectionConfig data, readErr := configRoot.ReadFile("ssl.json")
if err := ParseStrict(data, &section); err != nil { _ = configRoot.Close()
return err if readErr == nil {
} var section SSLSectionConfig
if section.TLS.CertificateRef != "" { if err := ParseStrict(data, &section); err != nil {
protected = append(protected, section.TLS)
reference, err := resolveManagedSSLPathsAtRoot(root, section.TLS)
if err != nil {
return err return err
} }
if legacyManagedSSLReference(section.TLS.CertificateRef) { if section.TLS.CertificateRef != "" {
keep[filepath.Dir(reference.CertificatePath)] = true protected = append(protected, section.TLS)
reference, err := resolveManagedSSLPathsAtRoot(root, section.TLS)
if err != nil {
return err
}
if legacyManagedSSLReference(section.TLS.CertificateRef) {
keep[filepath.Dir(reference.CertificatePath)] = true
}
} }
} else if !os.IsNotExist(readErr) {
return readErr
} }
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
return err return err

View File

@ -338,7 +338,7 @@ func (s *TransactionStore) Recover() error {
return ErrTransactionPhase return ErrTransactionPhase
} }
} }
return nil return cleanupEmptyTransactionStaging(transactions)
} }
func (s *TransactionStore) beforePhase(phase TransactionPhase) error { func (s *TransactionStore) beforePhase(phase TransactionPhase) error {
@ -619,6 +619,31 @@ func secureTransactionStagingDirectory(transactions string) (string, error) {
return directory, nil return directory, nil
} }
func cleanupEmptyTransactionStaging(transactions string) error {
directory := filepath.Join(filepath.Dir(transactions), "transaction-staging")
info, err := os.Lstat(directory)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
return ErrTransactionInvalid
}
entries, err := os.ReadDir(directory)
if err != nil {
return err
}
if len(entries) != 0 {
return nil
}
if err := os.Remove(directory); err != nil {
return err
}
return atomicfile.SyncDirectory(filepath.Dir(transactions))
}
func validateTransactionDirectory(directory string) error { func validateTransactionDirectory(directory string) error {
if err := ensureDirectory(directory); err != nil { if err := ensureDirectory(directory); err != nil {
return err return err