| 207 | } |
| 208 | |
| 209 | func (b *Backend) Download(ctx context.Context, w io.Writer, digest string) error { |
| 210 | exists, err := b.Exists(ctx, digest) |
| 211 | if err != nil { |
| 212 | return err |
| 213 | } else if !exists { |
| 214 | return backend.NewErrNotFound("artifact") |
| 215 | } |
| 216 | |
| 217 | key, err := b.keyFor(ctx, digest) |
| 218 | if err != nil { |
| 219 | return err |
| 220 | } |
| 221 | downloader := manager.NewDownloader(b.s3Client, func(d *manager.Downloader) { |
| 222 | // Force sequential downloads so the fakeWriterAt below can |
| 223 | // safely ignore the offset argument. |
| 224 | d.Concurrency = 1 |
| 225 | }) |
| 226 | _, err = downloader.Download(ctx, fakeWriterAt{w}, &s3.GetObjectInput{ |
| 227 | Bucket: aws.String(b.creds.AccessPointARN), |
| 228 | Key: aws.String(key), |
| 229 | }) |
| 230 | return err |
| 231 | } |
| 232 | |
| 233 | // CheckWritePermissions verifies that the calling org can actually mint a |
| 234 | // scoped session and put/get an object through its AP. Unlike the regular |