(ctx context.Context)
| 395 | } |
| 396 | |
| 397 | func (s *ObjectTokenStore) syncAuthFromBucket(ctx context.Context) error { |
| 398 | // NOTE: We intentionally do NOT use os.RemoveAll here. |
| 399 | // Wiping the directory triggers file watcher delete events, which then |
| 400 | // propagate deletions to the remote object store (race condition). |
| 401 | // Instead, we just ensure the directory exists and overwrite files incrementally. |
| 402 | if err := os.MkdirAll(s.authDir, 0o700); err != nil { |
| 403 | return fmt.Errorf("object store: create auth directory: %w", err) |
| 404 | } |
| 405 | |
| 406 | prefix := s.prefixedKey(objectStoreAuthPrefix + "/") |
| 407 | objectCh := s.client.ListObjects(ctx, s.cfg.Bucket, minio.ListObjectsOptions{ |
| 408 | Prefix: prefix, |
| 409 | Recursive: true, |
| 410 | }) |
| 411 | for object := range objectCh { |
| 412 | if object.Err != nil { |
| 413 | return fmt.Errorf("object store: list auth objects: %w", object.Err) |
| 414 | } |
| 415 | rel := strings.TrimPrefix(object.Key, prefix) |
| 416 | if rel == "" || strings.HasSuffix(rel, "/") { |
| 417 | continue |
| 418 | } |
| 419 | relPath := filepath.FromSlash(rel) |
| 420 | if filepath.IsAbs(relPath) { |
| 421 | log.WithField("key", object.Key).Warn("object store: skip auth outside mirror") |
| 422 | continue |
| 423 | } |
| 424 | cleanRel := filepath.Clean(relPath) |
| 425 | if cleanRel == "." || cleanRel == ".." || strings.HasPrefix(cleanRel, ".."+string(os.PathSeparator)) { |
| 426 | log.WithField("key", object.Key).Warn("object store: skip auth outside mirror") |
| 427 | continue |
| 428 | } |
| 429 | local := filepath.Join(s.authDir, cleanRel) |
| 430 | if err := os.MkdirAll(filepath.Dir(local), 0o700); err != nil { |
| 431 | return fmt.Errorf("object store: prepare auth subdir: %w", err) |
| 432 | } |
| 433 | reader, errGet := s.client.GetObject(ctx, s.cfg.Bucket, object.Key, minio.GetObjectOptions{}) |
| 434 | if errGet != nil { |
| 435 | return fmt.Errorf("object store: download auth %s: %w", object.Key, errGet) |
| 436 | } |
| 437 | data, errRead := io.ReadAll(reader) |
| 438 | _ = reader.Close() |
| 439 | if errRead != nil { |
| 440 | return fmt.Errorf("object store: read auth %s: %w", object.Key, errRead) |
| 441 | } |
| 442 | if errWrite := os.WriteFile(local, data, 0o600); errWrite != nil { |
| 443 | return fmt.Errorf("object store: write auth %s: %w", local, errWrite) |
| 444 | } |
| 445 | } |
| 446 | return nil |
| 447 | } |
| 448 | |
| 449 | func (s *ObjectTokenStore) uploadAuth(ctx context.Context, path string) error { |
| 450 | if path == "" { |
no test coverage detected