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
106 changes: 106 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# GitHub Actions Workflows

This directory contains GitHub Actions workflows for the Azure TypeScript LangChainJS repository.

## Available Workflows

### 1. Validate Workflows (`validate-workflows.yml`)

This workflow automatically validates all GitHub Actions workflows in the repository to ensure they are properly configured and using up-to-date actions.

**Features:**
- **Syntax Validation**: Uses `actionlint` to validate workflow YAML syntax and check for common issues
- **Action Availability Check**: Verifies that all referenced GitHub Actions are still available
- **Version Tracking**: Lists all actions and their versions in use
- **Automated Reports**: Generates a detailed report of all actions and their status

**When it runs:**
- On push/pull request when workflow files are modified
- Weekly on Mondays at 9:00 AM UTC (scheduled check for outdated actions)
- Manually via workflow dispatch

**Jobs:**
1. **validate-workflows**: Runs actionlint to check syntax and best practices
2. **detect-outdated-actions**: Extracts and analyzes all actions used in workflows, checks availability, and compares with latest versions
3. **summary**: Provides a consolidated summary of all validation jobs

**Outputs:**
- A downloadable report artifact containing all actions and versions in use
- GitHub step summary with validation results

### 2. CI (`ci.yml`)

Continuous integration workflow that builds and tests the project.

**When it runs:**
- On push to the `main` branch
- On pull requests to the `main` branch
- Manually via workflow dispatch

**Jobs:**
1. **build**: Installs dependencies and builds the project

## Validation Tools

### actionlint
A static checker for GitHub Actions workflow files. It catches common mistakes and enforces best practices.

**Installation:**
```bash
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
```

**Usage:**
```bash
actionlint .github/workflows/*.yml
```

## Best Practices

1. **Pin Actions to Specific Versions**: Always use specific commit SHAs or version tags (e.g., `actions/checkout@v4`) instead of branches
2. **Keep Actions Updated**: Regularly review and update actions to their latest versions
3. **Test Workflow Changes**: Use workflow dispatch or create test branches to validate changes before merging
4. **Review Weekly Reports**: Check the scheduled validation runs to identify outdated actions

## Adding New Workflows

When adding new workflows:

1. Create your workflow file in `.github/workflows/`
2. Ensure it passes `actionlint` validation locally:
```bash
actionlint .github/workflows/your-new-workflow.yml
```
3. Commit and push - the validate-workflows workflow will automatically check your new file
4. Review the validation results in the GitHub Actions tab

## Troubleshooting

### Workflow Validation Failures

If the validate-workflows workflow fails:

1. Check the job logs for specific error messages
2. Run `actionlint` locally to get detailed error information
3. Fix the issues and push the changes
4. The validation will run automatically on your next push

### Common Issues

- **Syntax Errors**: Check YAML indentation and syntax
- **Deprecated Actions**: Update to the latest version of the action
- **Unknown Actions**: Verify the action name and that the repository is public
- **Shell Script Issues**: Ensure proper quoting and use of variables in shell scripts

## Security Considerations

- Only use actions from trusted sources (verified creators or well-known organizations)
- Pin actions to specific commit SHAs for maximum security
- Review action source code before using new actions
- Keep actions updated to receive security patches

## Resources

- [GitHub Actions Documentation](https://docs.github.com/en/actions)
- [actionlint Repository](https://github.com/rhysd/actionlint)
- [GitHub Actions Security Best Practices](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions)
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Build project
run: npm run build
220 changes: 220 additions & 0 deletions .github/workflows/validate-workflows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
name: Validate GitHub Actions Workflows

on:
push:
paths:
- '.github/workflows/**'
pull_request:
paths:
- '.github/workflows/**'
workflow_dispatch:
schedule:
# Run weekly on Monday at 9:00 AM UTC to check for outdated actions
- cron: '0 9 * * 1'

permissions:
contents: read

jobs:
validate-workflows:
name: Validate Workflow Files
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install actionlint
run: |
# Download actionlint v1.7.9 (pinned version with checksum verification)
ACTIONLINT_VERSION="1.7.9"
ACTIONLINT_URL="https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
EXPECTED_SHA256="233b280d05e100837f4af1433c7b40a5dcb306e3aa68fb4f17f8a7f45a7df7b4"

curl -sL "$ACTIONLINT_URL" -o actionlint.tar.gz
echo "$EXPECTED_SHA256 actionlint.tar.gz" | sha256sum -c -
tar xzf actionlint.tar.gz
sudo mv ./actionlint /usr/local/bin/
rm actionlint.tar.gz
actionlint --version

- name: Run actionlint
run: |
echo "Running actionlint to validate workflow syntax and best practices..."
actionlint -color
continue-on-error: false

detect-outdated-actions:
name: Detect Outdated Actions
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Extract actions from workflows
id: extract-actions
run: |
echo "Extracting actions from workflow files..."
mkdir -p /tmp/workflow-analysis

# Extract all 'uses:' lines from workflow files
find .github/workflows -name "*.yml" -o -name "*.yaml" | while IFS= read -r workflow; do
echo "Analyzing $workflow"
grep -E "^\s*uses:" "$workflow" | sed 's/.*uses:\s*//' | sed 's/#.*//' | sed 's/\s*$//' >> /tmp/workflow-analysis/actions.txt || true
done

# Remove duplicates and sort
if [ -f /tmp/workflow-analysis/actions.txt ]; then
sort -u /tmp/workflow-analysis/actions.txt > /tmp/workflow-analysis/unique_actions.txt
echo "Found actions:"
cat /tmp/workflow-analysis/unique_actions.txt

# Count actions
ACTION_COUNT=$(wc -l < /tmp/workflow-analysis/unique_actions.txt)
echo "Total unique actions: $ACTION_COUNT"
else
echo "No actions found in workflows"
fi

- name: Install jq for JSON parsing
run: sudo apt-get update && sudo apt-get install -y jq

- name: Check action availability and versions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Checking if actions are available on GitHub..."

if [ ! -f /tmp/workflow-analysis/unique_actions.txt ]; then
echo "No actions to check"
exit 0
fi

UNAVAILABLE_ACTIONS=""

while IFS= read -r action; do
# Skip local actions (starting with ./)
if [[ "$action" == ./* ]]; then
echo "✓ Local action: $action (skipped)"
continue
fi

# Check if action has a version specified
if [[ "$action" != *"@"* ]]; then
echo "⚠️ Warning: Action without version: $action"
continue
fi

# Extract owner/repo and version
ACTION_PATH=$(echo "$action" | cut -d'@' -f1)
ACTION_VERSION=$(echo "$action" | cut -d'@' -f2)

# Skip if no valid path
if [[ "$ACTION_PATH" != *"/"* ]]; then
continue
fi

echo "Checking $ACTION_PATH@$ACTION_VERSION..."

# Use GitHub API with authentication for better rate limits
API_URL="https://api.github.com/repos/$ACTION_PATH"
RESPONSE=$(curl -s -w "\n%{http_code}" \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"$API_URL")

HTTP_CODE=$(echo "$RESPONSE" | tail -n1)

if [ "$HTTP_CODE" -eq 200 ]; then
echo "✓ Action available: $action"

# Try to fetch latest release for comparison
RELEASE_RESPONSE=$(curl -s \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"$API_URL/releases/latest")

LATEST_RELEASE=$(echo "$RELEASE_RESPONSE" | jq -r '.tag_name // empty')

if [ -n "$LATEST_RELEASE" ] && [ "$ACTION_VERSION" != "$LATEST_RELEASE" ]; then
echo " ℹ️ Latest version available: $LATEST_RELEASE (current: $ACTION_VERSION)"
fi
else
echo "✗ Action not found or inaccessible: $action (HTTP $HTTP_CODE)"
UNAVAILABLE_ACTIONS="${UNAVAILABLE_ACTIONS}${action}"$'\n'
fi
done < /tmp/workflow-analysis/unique_actions.txt

if [ -n "$UNAVAILABLE_ACTIONS" ]; then
echo ""
echo "⚠️ Warning: Some actions are unavailable:"
echo "$UNAVAILABLE_ACTIONS"
fi

- name: Generate action version report
run: |
{
echo "## Action Version Report"
echo ""
echo "This report lists all GitHub Actions used in workflows:"
echo ""
} > /tmp/workflow-analysis/report.md

if [ -f /tmp/workflow-analysis/unique_actions.txt ]; then
{
echo "| Action | Version | Status |"
echo "|--------|---------|--------|"
} >> /tmp/workflow-analysis/report.md

while IFS= read -r action; do
ACTION_PATH=$(echo "$action" | cut -d'@' -f1)
ACTION_VERSION=$(echo "$action" | cut -d'@' -f2)
echo "| \`$ACTION_PATH\` | \`$ACTION_VERSION\` | ✓ In use |" >> /tmp/workflow-analysis/report.md
done < /tmp/workflow-analysis/unique_actions.txt
else
echo "No actions found in workflows." >> /tmp/workflow-analysis/report.md
fi

{
echo ""
echo "---"
echo "Generated on: $(date -u)"
} >> /tmp/workflow-analysis/report.md

cat /tmp/workflow-analysis/report.md

- name: Upload report
uses: actions/upload-artifact@v4
if: always()
with:
name: workflow-validation-report
path: /tmp/workflow-analysis/report.md
retention-days: 30

summary:
name: Validation Summary
runs-on: ubuntu-latest
needs: [validate-workflows, detect-outdated-actions]
if: always()
permissions:
contents: read

steps:
- name: Create summary
run: |
{
echo "# Workflow Validation Summary"
echo ""
echo "✅ All workflow validation jobs completed"
echo ""
echo "## Jobs Status:"
echo "- Validate Workflows: ${{ needs.validate-workflows.result }}"
echo "- Detect Outdated Actions: ${{ needs.detect-outdated-actions.result }}"
} >> "$GITHUB_STEP_SUMMARY"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,6 @@ build/
# Bicep compiled ARM templates
infra/**/*.json
!infra/**/*.parameters.json

# actionlint binary (downloaded for local testing)
actionlint
Loading