fix: run DWH verification with read-only registry access

This commit is contained in:
User
2026-08-21 02:14:50 +02:00
parent 419c3440d7
commit 134dc1977c
6 changed files with 291 additions and 14 deletions
+61 -5
View File
@@ -47,6 +47,8 @@ var (
ErrConflict = errors.New("credential record already exists")
// ErrIntegrity means an unsafe or malformed registry object was observed.
ErrIntegrity = errors.New("registry integrity failure")
// ErrReadOnly means a runtime reader was asked to mutate registry state.
ErrReadOnly = errors.New("registry is read-only")
)
// PublicRecord is the redacted inventory form of a persisted record.
@@ -64,11 +66,12 @@ type PublicRecord struct {
// Store owns protected descriptors for one registry root.
type Store struct {
mu sync.RWMutex
now func() time.Time
root *securefile.Dir
active *securefile.Dir
revoked *securefile.Dir
mu sync.RWMutex
now func() time.Time
root *securefile.Dir
active *securefile.Dir
revoked *securefile.Dir
readOnly bool
}
type storedRecord struct {
@@ -94,9 +97,56 @@ func Open(root string) (*Store, error) {
_ = rootDir.Close()
return nil, integrity(err)
}
lock, err := rootDir.Lock(registryLockName)
if err != nil {
_ = revoked.Close()
_ = active.Close()
_ = rootDir.Close()
return nil, integrity(err)
}
if err := lock.Close(); err != nil {
_ = revoked.Close()
_ = active.Close()
_ = rootDir.Close()
return nil, integrity(err)
}
return &Store{root: rootDir, active: active, revoked: revoked, now: time.Now}, nil
}
// OpenReadOnly opens only a complete preprovisioned protected registry. It
// neither creates registry paths nor permits mutations through the Store.
func OpenReadOnly(root string) (*Store, error) {
rootDir, err := securefile.OpenDir(root)
if err != nil {
return nil, integrity(err)
}
active, err := rootDir.OpenDir(string(StateActive))
if err != nil {
_ = rootDir.Close()
return nil, integrity(err)
}
revoked, err := rootDir.OpenDir(string(StateRevoked))
if err != nil {
_ = active.Close()
_ = rootDir.Close()
return nil, integrity(err)
}
lock, err := rootDir.LockShared(registryLockName)
if err != nil {
_ = revoked.Close()
_ = active.Close()
_ = rootDir.Close()
return nil, integrity(err)
}
if err := lock.Close(); err != nil {
_ = revoked.Close()
_ = active.Close()
_ = rootDir.Close()
return nil, integrity(err)
}
return &Store{root: rootDir, active: active, revoked: revoked, now: time.Now, readOnly: true}, nil
}
// Close closes descriptors held by the store.
func (s *Store) Close() error {
if s == nil {
@@ -119,6 +169,9 @@ func (s *Store) Close() error {
// Add validates and atomically publishes one active record. Existing active or
// revoked records cannot be overwritten or resurrected.
func (s *Store) Add(value record.Record) error {
if s != nil && s.readOnly {
return ErrReadOnly
}
if err := validateForState(value, StateActive); err != nil {
return err
}
@@ -261,6 +314,9 @@ func (s *Store) listUnlocked() ([]PublicRecord, error) {
// Revoke publishes a validated revoked record and fsyncs it before removing the
// active record. If deletion then fails, Find still returns ErrRevoked.
func (s *Store) Revoke(keyID, reason string, at time.Time) error {
if s != nil && s.readOnly {
return ErrReadOnly
}
if !validKeyID(keyID) {
return ErrNotFound
}