Skip to content

Commit 43eddce

Browse files
committed
fix(crafter): treat ENOTDIR as a non-archive in detectByMagic
A non-file material value whose first path segment is an existing regular file (e.g. a CONTAINER_IMAGE ref like "registry/app:v1") yields ENOTDIR on open rather than not-found. Swallow it alongside fs.ErrNotExist so such values detect as non-archive instead of failing detection; genuine permission/I/O errors still surface. Assisted-by: Claude Code Signed-off-by: Javier Rodriguez <javier@chainloop.dev> Chainloop-Trace-Sessions: da72e107-14e9-4da1-add0-28004f542628, ef6d3cdb-5a23-445c-b39a-510b659023e4
1 parent 8f4f513 commit 43eddce

2 files changed

Lines changed: 13 additions & 5 deletions

File tree

pkg/attestation/crafter/materials/archive.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"os"
2828
"path"
2929
"strings"
30+
"syscall"
3031

3132
schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
3233
)
@@ -62,11 +63,13 @@ func DetectArchive(path string) (ArchiveFormat, error) {
6263
func detectByMagic(path string) (ArchiveFormat, error) {
6364
f, err := os.Open(path)
6465
if err != nil {
65-
// A not-found error means the value is not a file path at all (e.g.
66-
// "hello world" for STRING or "registry/app:v1" for CONTAINER_IMAGE);
67-
// treat that as a non-archive so callers passing non-file values are not
68-
// surprised. Any other error (permissions, I/O) is real and must surface.
69-
if errors.Is(err, fs.ErrNotExist) {
66+
// These errors mean the value is not a file path at all (e.g. "hello
67+
// world" for STRING, or "registry/app:v1" for CONTAINER_IMAGE where
68+
// "registry" happens to be a regular file in the working directory, which
69+
// yields ENOTDIR); treat them as a non-archive so callers passing non-file
70+
// values are not surprised. Any other error (permissions, I/O) is real and
71+
// must surface.
72+
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
7073
return ArchiveNone, nil
7174
}
7275
return ArchiveNone, fmt.Errorf("opening %q: %w", path, err)

pkg/attestation/crafter/materials/archive_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ func TestDetectArchive(t *testing.T) {
107107
{"tgz by extension", tgzShortPath, ArchiveTarGz},
108108
{"plain file", plain, ArchiveNone},
109109
{"zip without extension via magic", noExt, ArchiveZip},
110+
// Non-file values must detect as non-archive without erroring.
111+
{"non-existent value", filepath.Join(dir, "nope"), ArchiveNone},
112+
// A value whose first path segment is an existing regular file yields
113+
// ENOTDIR on open (e.g. CONTAINER_IMAGE "registry/app:v1"); still a non-archive.
114+
{"path segment is a file (ENOTDIR)", filepath.Join(plain, "app:v1"), ArchiveNone},
110115
}
111116
for _, tc := range tests {
112117
t.Run(tc.name, func(t *testing.T) {

0 commit comments

Comments
 (0)