Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/daily-team-status.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,7 @@ test-runs/
gosec-report.json
gosec-results.sarif
govulncheck-results.sarif
trivy-results.sarif
trivy-results.sarif

# Generated action files
actions/setup-safe-outputs/js/
4 changes: 2 additions & 2 deletions actions/setup-safe-outputs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ steps:

## Development

This action is built from source files in `src/` using the build tooling:
This action uses a bash script to copy JavaScript files from the `js/` directory. The files are generated during the build process:

```bash
make actions-build
```

The build process embeds all required JavaScript files into the bundled `index.js`.
The build process copies all required JavaScript files from `pkg/workflow/js/` to `actions/setup-safe-outputs/js/`, and the bash script (`copy-files.sh`) copies them to the destination at runtime.
9 changes: 7 additions & 2 deletions actions/setup-safe-outputs/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ outputs:
description: 'Number of files copied'

runs:
using: 'node20'
main: 'index.js'
using: 'composite'
steps:
- name: Copy safe-outputs files
shell: bash
run: ${{ github.action_path }}/copy-files.sh
env:
INPUT_DESTINATION: ${{ inputs.destination }}

branding:
icon: 'copy'
Expand Down
48 changes: 48 additions & 0 deletions actions/setup-safe-outputs/copy-files.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
# Safe Outputs Copy Action
# Copies safe-outputs MCP server files to the agent environment

set -e

# Get destination from input or use default
DESTINATION="${INPUT_DESTINATION:-/tmp/gh-aw/safeoutputs}"

echo "Copying safe-outputs files to ${DESTINATION}"

# Create destination directory if it doesn't exist
mkdir -p "${DESTINATION}"
echo "Created directory: ${DESTINATION}"

# Define the list of files to copy
FILES=(
"safe_outputs_mcp_server.cjs"
"safe_outputs_bootstrap.cjs"
"safe_outputs_tools_loader.cjs"
"safe_outputs_config.cjs"
"safe_outputs_handlers.cjs"
"safe_outputs_tools.json"
"mcp_server_core.cjs"
"mcp_logger.cjs"
"messages.cjs"
)

# Source directory for the JavaScript files
# When running in GitHub Actions, these files are in the workflow/js directory
SOURCE_DIR="${GITHUB_ACTION_PATH}/js"

FILE_COUNT=0

# Copy each file
for file in "${FILES[@]}"; do
if [ -f "${SOURCE_DIR}/${file}" ]; then
cp "${SOURCE_DIR}/${file}" "${DESTINATION}/${file}"
echo "Copied: ${file}"
FILE_COUNT=$((FILE_COUNT + 1))
else
echo "Warning: File not found: ${SOURCE_DIR}/${file}"
fi
done

# Set output
echo "files-copied=${FILE_COUNT}" >> "${GITHUB_OUTPUT}"
echo "✓ Successfully copied ${FILE_COUNT} files"
51 changes: 0 additions & 51 deletions actions/setup-safe-outputs/index.js

This file was deleted.

43 changes: 0 additions & 43 deletions actions/setup-safe-outputs/src/index.js

This file was deleted.

83 changes: 72 additions & 11 deletions pkg/cli/actions_build_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,28 @@ func ActionsCleanCommand() error {

cleanedCount := 0
for _, actionName := range actionDirs {
indexPath := filepath.Join(actionsDir, actionName, "index.js")
if _, err := os.Stat(indexPath); err == nil {
if err := os.Remove(indexPath); err != nil {
return fmt.Errorf("failed to remove %s: %w", indexPath, err)
// Clean index.js for actions that use it
if actionName != "setup-safe-outputs" {
indexPath := filepath.Join(actionsDir, actionName, "index.js")
if _, err := os.Stat(indexPath); err == nil {
if err := os.Remove(indexPath); err != nil {
return fmt.Errorf("failed to remove %s: %w", indexPath, err)
}
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" ✓ Removed %s/index.js", actionName)))
cleanedCount++
}
}

// Clean js/ directory for setup-safe-outputs
if actionName == "setup-safe-outputs" {
jsDir := filepath.Join(actionsDir, actionName, "js")
if _, err := os.Stat(jsDir); err == nil {
if err := os.RemoveAll(jsDir); err != nil {
return fmt.Errorf("failed to remove %s: %w", jsDir, err)
}
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" ✓ Removed %s/js/", actionName)))
cleanedCount++
}
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" ✓ Removed %s/index.js", actionName)))
cleanedCount++
}
}

Expand Down Expand Up @@ -164,9 +179,12 @@ func validateActionYml(actionPath string) error {
}
}

// Check that it's a node20 action
if !strings.Contains(contentStr, "using: 'node20'") && !strings.Contains(contentStr, "using: \"node20\"") {
return fmt.Errorf("action must use 'node20' runtime")
// Check that it's either a node20 or composite action
isNode20 := strings.Contains(contentStr, "using: 'node20'") || strings.Contains(contentStr, "using: \"node20\"")
isComposite := strings.Contains(contentStr, "using: 'composite'") || strings.Contains(contentStr, "using: \"composite\"")

if !isNode20 && !isComposite {
return fmt.Errorf("action must use either 'node20' or 'composite' runtime")
}

return nil
Expand All @@ -179,15 +197,21 @@ func buildAction(actionsDir, actionName string) error {
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\n📦 Building action: %s", actionName)))

actionPath := filepath.Join(actionsDir, actionName)
srcPath := filepath.Join(actionPath, "src", "index.js")
outputPath := filepath.Join(actionPath, "index.js")

// Validate action.yml
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(" ✓ Validating action.yml"))
if err := validateActionYml(actionPath); err != nil {
return err
}

// Special handling for setup-safe-outputs: copy files instead of embedding
if actionName == "setup-safe-outputs" {
return buildSetupSafeOutputsAction(actionsDir, actionName)
}

srcPath := filepath.Join(actionPath, "src", "index.js")
outputPath := filepath.Join(actionPath, "index.js")

// Check if source file exists
if _, err := os.Stat(srcPath); os.IsNotExist(err) {
return fmt.Errorf("source file not found: %s", srcPath)
Expand Down Expand Up @@ -243,6 +267,43 @@ func buildAction(actionsDir, actionName string) error {
return nil
}

// buildSetupSafeOutputsAction builds the setup-safe-outputs action by copying JavaScript files
func buildSetupSafeOutputsAction(actionsDir, actionName string) error {
actionPath := filepath.Join(actionsDir, actionName)
jsDir := filepath.Join(actionPath, "js")

// Get dependencies for this action
dependencies := getActionDependencies(actionName)
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" ✓ Found %d dependencies", len(dependencies))))

// Get all JavaScript sources
sources := workflow.GetJavaScriptSources()

// Create js directory if it doesn't exist
if err := os.MkdirAll(jsDir, 0755); err != nil {
return fmt.Errorf("failed to create js directory: %w", err)
}

// Copy each dependency file to the js directory
copiedCount := 0
for _, dep := range dependencies {
if content, ok := sources[dep]; ok {
destPath := filepath.Join(jsDir, dep)
if err := os.WriteFile(destPath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write %s: %w", dep, err)
}
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" - %s", dep)))
copiedCount++
} else {
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf(" ⚠ Warning: Could not find %s", dep)))
}
}

fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf(" ✓ Copied %d files to js/", copiedCount)))

return nil
}

// getActionDependencies returns the list of JavaScript dependencies for an action
// This mapping defines which files from pkg/workflow/js/ are needed for each action
func getActionDependencies(actionName string) []string {
Expand Down
4 changes: 2 additions & 2 deletions pkg/workflow/compiler_activation_jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (c *Compiler) buildPreActivationJob(data *WorkflowData, needsPermissionChec
steps = append(steps, " sparse-checkout: |\n")
steps = append(steps, " actions\n")
}

steps = append(steps, " - name: Setup Activation Scripts\n")
steps = append(steps, fmt.Sprintf(" uses: %s\n", setupActivationActionRef))
steps = append(steps, " with:\n")
Expand Down Expand Up @@ -347,7 +347,7 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate
steps = append(steps, " sparse-checkout: |\n")
steps = append(steps, " actions\n")
}

steps = append(steps, " - name: Setup Activation Scripts\n")
steps = append(steps, fmt.Sprintf(" uses: %s\n", setupActivationActionRef))
steps = append(steps, " with:\n")
Expand Down