| 228 | } |
| 229 | |
| 230 | func processFile(ctx context.Context, file string, project *types.Project, extFiles map[string]string, envFiles map[string]string) ([]byte, error) { |
| 231 | f, err := os.ReadFile(file) |
| 232 | if err != nil { |
| 233 | return nil, err |
| 234 | } |
| 235 | |
| 236 | base, err := loader.LoadWithContext(ctx, types.ConfigDetails{ |
| 237 | WorkingDir: project.WorkingDir, |
| 238 | Environment: project.Environment, |
| 239 | ConfigFiles: []types.ConfigFile{ |
| 240 | { |
| 241 | Filename: file, |
| 242 | Content: f, |
| 243 | }, |
| 244 | }, |
| 245 | }, func(options *loader.Options) { |
| 246 | options.SkipValidation = true |
| 247 | options.SkipExtends = true |
| 248 | options.SkipConsistencyCheck = true |
| 249 | options.ResolvePaths = true |
| 250 | options.SkipInclude = true |
| 251 | options.Profiles = project.Profiles |
| 252 | }) |
| 253 | if err != nil { |
| 254 | return nil, err |
| 255 | } |
| 256 | for name, service := range base.Services { |
| 257 | for i, envFile := range service.EnvFiles { |
| 258 | // A real stat failure (e.g. permissions) is fatal, but a missing file is not: |
| 259 | // the project loader already rejects missing required env files before we get |
| 260 | // here, so an absent file at this point is an optional one. |
| 261 | _, statErr := os.Stat(envFile.Path) |
| 262 | if statErr != nil && !os.IsNotExist(statErr) { |
| 263 | return nil, fmt.Errorf("failed to access env file %s: %w", envFile.Path, statErr) |
| 264 | } |
| 265 | // The hash is derived from the path string alone, so the env_file is always |
| 266 | // rewritten to its opaque <hash>.env placeholder, even for a missing optional |
| 267 | // file, so the published artifact never leaks the local path. Only files that |
| 268 | // exist are registered for upload, mirroring the extends handling below. |
| 269 | hash := fmt.Sprintf("%x.env", sha256.Sum256([]byte(envFile.Path))) |
| 270 | if statErr == nil { |
| 271 | envFiles[envFile.Path] = hash |
| 272 | } |
| 273 | f, err = transform.ReplaceEnvFile(f, name, i, hash) |
| 274 | if err != nil { |
| 275 | return nil, err |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | if service.Extends == nil { |
| 280 | continue |
| 281 | } |
| 282 | xf := service.Extends.File |
| 283 | if xf == "" { |
| 284 | continue |
| 285 | } |
| 286 | if _, err = os.Stat(service.Extends.File); os.IsNotExist(err) { |
| 287 | // No local file, while we loaded the project successfully: This is actually a remote resource |