CompileWorkflowDataWithValidation compiles from already-parsed WorkflowData with validation This avoids re-parsing when the workflow data has already been parsed
(ctx context.Context, compiler *workflow.Compiler, workflowData *workflow.WorkflowData, filePath string, opts CompileValidationOptions)
| 120 | // CompileWorkflowDataWithValidation compiles from already-parsed WorkflowData with validation |
| 121 | // This avoids re-parsing when the workflow data has already been parsed |
| 122 | func CompileWorkflowDataWithValidation(ctx context.Context, compiler *workflow.Compiler, workflowData *workflow.WorkflowData, filePath string, opts CompileValidationOptions) error { |
| 123 | compileValidationLog.Printf("Compiling from parsed WorkflowData: file=%s", filePath) |
| 124 | |
| 125 | compiler.SetContext(ctx) |
| 126 | |
| 127 | // Compile the workflow using already-parsed data |
| 128 | if err := compiler.CompileWorkflowData(workflowData, filePath); err != nil { |
| 129 | compileValidationLog.Printf("WorkflowData compilation failed: %v", err) |
| 130 | return err |
| 131 | } |
| 132 | |
| 133 | // Always validate that the generated lock file is valid YAML (CLI requirement) |
| 134 | lockFile := stringutil.MarkdownToLockFile(filePath) |
| 135 | if _, err := os.Stat(lockFile); err != nil { |
| 136 | compileValidationLog.Print("Lock file not found, skipping validation (likely no-emit mode)") |
| 137 | // Lock file doesn't exist (likely due to no-emit), skip YAML validation |
| 138 | return nil |
| 139 | } |
| 140 | |
| 141 | compileValidationLog.Print("Validating generated lock file YAML syntax") |
| 142 | |
| 143 | lockContent, err := os.ReadFile(lockFile) |
| 144 | if err != nil { |
| 145 | return fmt.Errorf("failed to read generated lock file for validation: %w", err) |
| 146 | } |
| 147 | |
| 148 | // Validate the lock file is valid YAML |
| 149 | var yamlValidationTest any |
| 150 | if err := yaml.Unmarshal(lockContent, &yamlValidationTest); err != nil { |
| 151 | return fmt.Errorf("generated lock file is not valid YAML: %w", err) |
| 152 | } |
| 153 | |
| 154 | // Validate action SHAs if requested |
| 155 | if opts.ValidateActionSHAs { |
| 156 | compileValidationLog.Print("Validating action SHAs in lock file") |
| 157 | // Use the compiler's shared action cache to benefit from cached resolutions |
| 158 | actionCache := compiler.GetSharedActionCache() |
| 159 | if err := workflow.ValidateActionSHAsInLockFile(ctx, lockFile, actionCache, opts.Verbose); err != nil { |
| 160 | // Action SHA validation warnings are non-fatal |
| 161 | compileValidationLog.Printf("Action SHA validation completed with warnings: %v", err) |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | // Run zizmor on the generated lock file if requested |
| 166 | if opts.RunZizmorPerFile { |
| 167 | if err := runZizmorOnFile(lockFile, opts.Verbose, opts.Strict); err != nil { |
| 168 | return fmt.Errorf("zizmor security scan failed: %w", err) |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // Run poutine on the generated lock file if requested |
| 173 | if opts.RunPoutinePerFile { |
| 174 | if err := runPoutineOnFile(lockFile, opts.Verbose, opts.Strict); err != nil { |
| 175 | return fmt.Errorf("poutine security scan failed: %w", err) |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // Run actionlint on the generated lock file if requested |