errors: report build-facing paths on read failure

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 12bf293e5feee7393e971a1d22a191dff7f6e7f8)
(cherry picked from commit 5a01794b79c7af91a961b1236b0e0661975161d7)
This commit is contained in:
Tonis Tiigi authored and CrazyMax committed 2026-09-30 15:12:24 +02:00
1 parent edc2718b4b
commit 71dc7cfbd6
6 files changed
+83 -22

No files matched your search

+12 -7
View File
@@ -23,7 +23,15 @@ type FileRange struct {
Length int
}
func ReadFile(ctx context.Context, root string, req ReadRequest) ([]byte, error) {
func ReadFile(ctx context.Context, root string, req ReadRequest) (_ []byte, retErr error) {
// paths below are internal to the mount, report the one that was requested
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = req.Filename
}
}()
fp, err := fs.RootPath(root, req.Filename)
if err != nil {
return nil, errors.WithStack(err)
@@ -31,18 +39,15 @@ func ReadFile(ctx context.Context, root string, req ReadRequest) ([]byte, error)
f, err := openfile.Regular(fp)
if err != nil {
// The filename here is internal to the mount, so we can restore
// the request base path for error reporting.
pe := &os.PathError{}
if errors.As(err, &pe) {
pe.Path = req.Filename
}
return nil, err
}
defer f.Close()
var rdr io.Reader = f
if req.Range != nil {
if req.Range.Offset < 0 || req.Range.Length < 0 {
return nil, errors.Errorf("invalid range for %s", req.Filename)
}
rdr = io.NewSectionReader(f, int64(req.Range.Offset), int64(req.Range.Length))
}
dt, err := io.ReadAll(rdr)
+13 -3
View File
@@ -3,6 +3,7 @@ package oci
import (
"context"
"io"
"os"
"slices"
"strconv"
"strings"
@@ -71,8 +72,17 @@ func ParseUIDGID(str string) (uid uint32, gid uint32, err error) {
return
}
func openUserFile(root, p string) (io.ReadCloser, error) {
p, err := fs.RootPath(root, p)
func openUserFile(root, orig string) (_ io.ReadCloser, retErr error) {
// paths below are daemon-side locations, report the path as the build
// asked for it
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = orig
}
}()
p, err := fs.RootPath(root, orig)
if err != nil {
return nil, errors.WithStack(err)
}
@@ -85,7 +95,7 @@ func openUserFile(root, p string) (io.ReadCloser, error) {
return &limitedReadCloser{
ReadCloser: f,
r: &io.LimitedReader{R: f, N: maxUserFileBytes + 1},
name: p,
name: orig,
}, nil
}
+18 -4
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"io"
"os"
"github.com/containerd/continuity/fs"
intoto "github.com/in-toto/in-toto-golang/in_toto"
@@ -20,7 +21,15 @@ import (
const maxAttestationBytes int64 = 80 << 20
// ReadAll reads the content of an attestation.
func ReadAll(ctx context.Context, s session.Group, att exporter.Attestation) ([]byte, error) {
func ReadAll(ctx context.Context, s session.Group, att exporter.Attestation) (_ []byte, retErr error) {
// paths below are daemon-side locations, report the attestation path
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = att.Path
}
}()
var content []byte
if att.ContentFunc != nil {
data, err := att.ContentFunc(ctx)
@@ -44,7 +53,7 @@ func ReadAll(ctx context.Context, s session.Group, att exporter.Attestation) ([]
if err != nil {
return nil, err
}
content, err = readRegularFile(p)
content, err = readRegularFile(p, att.Path)
if err != nil {
return nil, errors.Wrap(err, "cannot read in-toto attestation")
}
@@ -57,14 +66,19 @@ func ReadAll(ctx context.Context, s session.Group, att exporter.Attestation) ([]
return content, nil
}
func readRegularFile(p string) ([]byte, error) {
func readRegularFile(p, name string) ([]byte, error) {
f, err := openfile.Regular(p)
if err != nil {
// the resolved path is a daemon-side location
var pathErr *os.PathError
if errors.As(err, &pathErr) {
pathErr.Path = name
}
return nil, err
}
defer f.Close()
dt, err := readAllLimited(f, p, maxAttestationBytes)
dt, err := readAllLimited(f, name, maxAttestationBytes)
if err != nil {
return nil, err
}
+18 -4
View File
@@ -117,28 +117,42 @@ func sort(atts []exporter.Attestation) []exporter.Attestation {
return result
}
func unbundle(root string, bundle exporter.Attestation) ([]exporter.Attestation, error) {
func unbundle(root string, bundle exporter.Attestation) (_ []exporter.Attestation, retErr error) {
// paths below are daemon-side locations, report the bundle path
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = bundle.Path
}
}()
dir, err := fs.RootPath(root, bundle.Path)
if err != nil {
return nil, err
}
entries, err := os.ReadDir(dir)
if err != nil {
return nil, err
return nil, errors.WithStack(err)
}
var unbundled []exporter.Attestation
for _, entry := range entries {
name := path.Join(bundle.Path, entry.Name())
p, err := fs.RootPath(dir, entry.Name())
if err != nil {
return nil, err
}
f, err := openfile.Regular(p)
if err != nil {
// p is a daemon-side location, report the bundle entry
var pathErr *os.PathError
if errors.As(err, &pathErr) {
pathErr.Path = name
}
return nil, err
}
var stmt intoto.Statement
stmt, err = decodeStatement(f, p)
stmt, err = decodeStatement(f, name)
f.Close()
if err != nil {
return nil, err
@@ -163,7 +177,7 @@ func unbundle(root string, bundle exporter.Attestation) ([]exporter.Attestation,
unbundled = append(unbundled, exporter.Attestation{
Kind: gatewaypb.AttestationKind_InToto,
Metadata: bundle.Metadata,
Path: path.Join(bundle.Path, entry.Name()),
Path: name,
ContentFunc: func(context.Context) ([]byte, error) { return predicate, nil },
InToto: result.InTotoAttestation{
PredicateType: stmt.PredicateType,
+10 -1
View File
@@ -3,6 +3,7 @@ package ops
import (
"context"
"encoding/json"
"os"
"github.com/containerd/continuity/fs"
"github.com/moby/buildkit/client/llb"
@@ -111,6 +112,14 @@ func (b *BuildOp) Exec(ctx context.Context, job solver.JobContext, inputs []solv
fn = override
}
// paths below are daemon-side locations, report the requested filename
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = fn
}
}()
newfn, err := fs.RootPath(root, fn)
if err != nil {
return nil, errors.Wrapf(err, "working dir %s points to invalid target", fn)
@@ -118,7 +127,7 @@ func (b *BuildOp) Exec(ctx context.Context, job solver.JobContext, inputs []solv
f, err := openfile.Regular(newfn)
if err != nil {
return nil, errors.Wrapf(err, "failed to open %s", newfn)
return nil, err
}
def, err := llb.ReadFrom(f)
+12 -3
View File
@@ -119,8 +119,17 @@ func readUser(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error)
return &us, nil
}
func openUserFile(root, p string) (io.ReadCloser, error) {
p, err := fs.RootPath(root, p)
func openUserFile(root, orig string) (_ io.ReadCloser, retErr error) {
// paths below are daemon-side locations, report the path as the build
// asked for it
defer func() {
var pathErr *os.PathError
if errors.As(retErr, &pathErr) {
pathErr.Path = orig
}
}()
p, err := fs.RootPath(root, orig)
if err != nil {
return nil, errors.WithStack(err)
}
@@ -133,7 +142,7 @@ func openUserFile(root, p string) (io.ReadCloser, error) {
return &limitedReadCloser{
ReadCloser: f,
r: &io.LimitedReader{R: f, N: maxUserFileBytes + 1},
name: p,
name: orig,
}, nil
}