validateAgentFile validates that the custom agent file specified in imports exists
(workflowData *WorkflowData, markdownPath string)
| 61 | |
| 62 | // validateAgentFile validates that the custom agent file specified in imports exists |
| 63 | func (c *Compiler) validateAgentFile(workflowData *WorkflowData, markdownPath string) error { |
| 64 | // Check if agent file is specified in imports |
| 65 | if workflowData.AgentFile == "" { |
| 66 | return nil // No agent file specified, no validation needed |
| 67 | } |
| 68 | |
| 69 | agentPath := workflowData.AgentFile |
| 70 | agentValidationLog.Printf("Validating agent file exists: %s", agentPath) |
| 71 | |
| 72 | // Validate path characters to prevent shell injection via crafted filenames. |
| 73 | // Only alphanumeric characters, dots, underscores, hyphens, forward slashes, |
| 74 | // and spaces are permitted. Shell metacharacters are rejected. |
| 75 | if !agentFilePathRegex.MatchString(agentPath) { |
| 76 | return formatCompilerError(markdownPath, "error", |
| 77 | fmt.Sprintf("agent file path '%s' contains invalid characters. Only alphanumeric characters, dots, underscores, hyphens, forward slashes, and spaces are allowed.", agentPath), nil) |
| 78 | } |
| 79 | |
| 80 | var fullAgentPath string |
| 81 | |
| 82 | // Check if agentPath is already absolute |
| 83 | if filepath.IsAbs(agentPath) { |
| 84 | // Use the path as-is (for backward compatibility with tests) |
| 85 | fullAgentPath = agentPath |
| 86 | } else { |
| 87 | // Agent file path is relative to repository root (e.g., ".github/agents/file.md") |
| 88 | // Need to resolve it relative to the markdown file's directory |
| 89 | markdownDir := filepath.Dir(markdownPath) |
| 90 | // Navigate up from .github/workflows to repository root |
| 91 | repoRoot := filepath.Join(markdownDir, "..", "..") |
| 92 | fullAgentPath = filepath.Join(repoRoot, agentPath) |
| 93 | } |
| 94 | |
| 95 | // Check if the file exists |
| 96 | if _, err := os.Stat(fullAgentPath); err != nil { |
| 97 | if os.IsNotExist(err) { |
| 98 | return formatCompilerError(markdownPath, "error", |
| 99 | fmt.Sprintf("agent file '%s' does not exist. Ensure the file exists in the repository and is properly imported.", agentPath), nil) |
| 100 | } |
| 101 | // Other error (permissions, etc.) |
| 102 | return formatCompilerError(markdownPath, "error", |
| 103 | fmt.Sprintf("failed to access agent file '%s': %v", agentPath, err), err) |
| 104 | } |
| 105 | |
| 106 | if c.verbose { |
| 107 | fmt.Fprintln(os.Stderr, console.FormatInfoMessage( |
| 108 | "✓ Agent file exists: "+agentPath)) |
| 109 | } |
| 110 | |
| 111 | return nil |
| 112 | } |
| 113 | |
| 114 | // validateCapabilitySupport is a shared helper that checks whether an engine supports a |
| 115 | // required capability. It returns an error with a standard "not supported" message when |