MCPcopy Create free account
hub / github.com/chainloop-dev/chainloop / uploadAndCraft

Function uploadAndCraft

pkg/attestation/crafter/materials/materials.go:114–187  ·  view source on GitHub ↗

uploadAndCraft uploads the artifact to CAS and crafts the material this function is used by all the uploadable artifacts crafters (SBOMs, JUnit, and more in the future)

(ctx context.Context, input *schemaapi.CraftingSchema_Material, backend *casclient.CASBackend, artifactPath string, l *zerolog.Logger)

Source from the content-addressed store, hash-verified

112// uploadAndCraft uploads the artifact to CAS and crafts the material
113// this function is used by all the uploadable artifacts crafters (SBOMs, JUnit, and more in the future)
114func uploadAndCraft(ctx context.Context, input *schemaapi.CraftingSchema_Material, backend *casclient.CASBackend, artifactPath string, l *zerolog.Logger) (*api.Attestation_Material, error) {
115 // 1 - Check the file can be stored in the provided CAS backend
116 result, err := fileStats(artifactPath)
117 if err != nil {
118 return nil, fmt.Errorf("getting file stats: %w", err)
119 }
120 defer result.r.Close()
121
122 if result.size == 0 {
123 return nil, fmt.Errorf("%w: %w", ErrBaseUploadAndCraft, errors.New("file is empty"))
124 }
125
126 // Determine if we should skip the upload based on contract setting
127 shouldSkipUpload := input.SkipUpload
128
129 l.Debug().Str("filename", result.filename).Str("digest", result.digest).Str("path", artifactPath).
130 Str("size", bytefmt.ByteSize(uint64(result.size))).
131 Str("max_size", bytefmt.ByteSize(uint64(backend.MaxSize))).
132 Str("backend", backend.Name).Bool("skip_upload", shouldSkipUpload).Msg("crafting file")
133
134 // If there is a max size set and the file is bigger than that, return an error
135 // Only check size if we're actually going to upload (not skipped)
136 if !shouldSkipUpload && backend.MaxSize > 0 && result.size > backend.MaxSize {
137 return nil, fmt.Errorf("%w: %w", ErrBaseUploadAndCraft, fmt.Errorf("this file is too big for the %s CAS backend, please contact your administrator: fileSize=%s, maxSize=%s", backend.Name, bytefmt.ByteSize(uint64(result.size)), bytefmt.ByteSize(uint64(backend.MaxSize))))
138 }
139
140 material := &api.Attestation_Material{
141 MaterialType: input.Type,
142 M: &api.Attestation_Material_Artifact_{
143 Artifact: &api.Attestation_Material_Artifact{
144 // TODO: remove once we know servers are not running server-side validation
145 Id: input.Name,
146 Name: result.filename,
147 Digest: result.digest,
148 IsSubject: input.Output,
149 },
150 },
151 }
152
153 // 2 - Upload the file to CAS (unless skipped or inline backend)
154 switch {
155 case shouldSkipUpload:
156 l.Debug().Str("backend", backend.Name).Msg("skipping upload per contract configuration")
157 // Material is not uploaded, only metadata (digest, filename) is recorded
158 material.UploadedToCas = false
159 case backend.Uploader != nil:
160 l.Debug().Str("backend", backend.Name).Msg("uploading")
161
162 // Reuse the already-open, already-hashed reader from fileStats
163 // to avoid a redundant SHA256 pass inside Uploader.UploadFile.
164 _, err = backend.Uploader.Upload(ctx, result.r, result.filename, result.digest)
165 if err != nil {
166 return nil, fmt.Errorf("%w: %w", ErrBaseUploadAndCraft, fmt.Errorf("uploading material: %w", err))
167 }
168
169 material.UploadedToCas = true
170 default:
171 l.Debug().Str("backend", backend.Name).Msg("storing inline")

Callers 15

CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85
CraftMethod · 0.85

Calls 6

GetArtifactMethod · 0.95
fileStatsFunction · 0.85
BoolMethod · 0.80
UploadMethod · 0.65
CloseMethod · 0.45
DebugMethod · 0.45

Tested by

no test coverage detected