Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot]
b3eaa4f227 Upgrade dotnet sdk to v8.0.414 2025-09-15 08:02:44 +00:00
21 changed files with 25 additions and 788 deletions

View File

@@ -4,7 +4,7 @@
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
"ghcr.io/devcontainers/features/dotnet": {
"version": "8.0.413"
"version": "8.0.414"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
close-issue-message: "This issue does not seem to be a problem with the runner application, it concerns the GitHub actions platform more generally. Could you please post your feedback on the [GitHub Community Support Forum](https://github.com/orgs/community/discussions/categories/actions) which is actively monitored. Using the forum ensures that we route your problem to the correct team. 😃"
exempt-issue-labels: "keep"

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
close-issue-message: "Thank you for your interest in the runner application and taking the time to provide your valuable feedback. We kindly ask you to redirect this feedback to the [GitHub Community Support Forum](https://github.com/orgs/community/discussions/categories/actions-and-packages) which our team actively monitors and would be a better place to start a discussion for new feature requests in GitHub Actions. For more information on this policy please [read our contribution guidelines](https://github.com/actions/runner#contribute). 😃"
exempt-issue-labels: "keep"

View File

@@ -1,211 +0,0 @@
name: Dependency Status Check
on:
workflow_dispatch:
inputs:
check_type:
description: "Type of dependency check"
required: false
default: "all"
type: choice
options:
- all
- node
- dotnet
- docker
- npm
schedule:
- cron: "0 11 * * 1" # Weekly on Monday at 11 AM
jobs:
dependency-status:
runs-on: ubuntu-latest
outputs:
node20-status: ${{ steps.check-versions.outputs.node20-status }}
node24-status: ${{ steps.check-versions.outputs.node24-status }}
dotnet-status: ${{ steps.check-versions.outputs.dotnet-status }}
docker-status: ${{ steps.check-versions.outputs.docker-status }}
buildx-status: ${{ steps.check-versions.outputs.buildx-status }}
npm-vulnerabilities: ${{ steps.check-versions.outputs.npm-vulnerabilities }}
open-dependency-prs: ${{ steps.check-prs.outputs.open-dependency-prs }}
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Check dependency versions
id: check-versions
run: |
echo "## Dependency Status Report" >> $GITHUB_STEP_SUMMARY
echo "Generated on: $(date)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Check Node versions
if [[ "${{ github.event.inputs.check_type }}" == "all" || "${{ github.event.inputs.check_type }}" == "node" ]]; then
echo "### Node.js Versions" >> $GITHUB_STEP_SUMMARY
VERSIONS_JSON=$(curl -s https://raw.githubusercontent.com/actions/node-versions/main/versions-manifest.json)
LATEST_NODE20=$(echo "$VERSIONS_JSON" | jq -r '.[] | select(.version | startswith("20.")) | .version' | head -1)
LATEST_NODE24=$(echo "$VERSIONS_JSON" | jq -r '.[] | select(.version | startswith("24.")) | .version' | head -1)
CURRENT_NODE20=$(grep "NODE20_VERSION=" src/Misc/externals.sh | cut -d'"' -f2)
CURRENT_NODE24=$(grep "NODE24_VERSION=" src/Misc/externals.sh | cut -d'"' -f2)
NODE20_STATUS="✅ up-to-date"
NODE24_STATUS="✅ up-to-date"
if [ "$CURRENT_NODE20" != "$LATEST_NODE20" ]; then
NODE20_STATUS="⚠️ outdated"
fi
if [ "$CURRENT_NODE24" != "$LATEST_NODE24" ]; then
NODE24_STATUS="⚠️ outdated"
fi
echo "| Version | Current | Latest | Status |" >> $GITHUB_STEP_SUMMARY
echo "|---------|---------|--------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Node 20 | $CURRENT_NODE20 | $LATEST_NODE20 | $NODE20_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "| Node 24 | $CURRENT_NODE24 | $LATEST_NODE24 | $NODE24_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "node20-status=$NODE20_STATUS" >> $GITHUB_OUTPUT
echo "node24-status=$NODE24_STATUS" >> $GITHUB_OUTPUT
fi
# Check .NET version
if [[ "${{ github.event.inputs.check_type }}" == "all" || "${{ github.event.inputs.check_type }}" == "dotnet" ]]; then
echo "### .NET SDK Version" >> $GITHUB_STEP_SUMMARY
current_dotnet_version=$(jq -r .sdk.version ./src/global.json)
current_major_minor=$(echo "$current_dotnet_version" | cut -d '.' -f 1,2)
latest_dotnet_version=$(curl -sb -H "Accept: application/json" "https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$current_major_minor/latest.version")
DOTNET_STATUS="✅ up-to-date"
if [ "$current_dotnet_version" != "$latest_dotnet_version" ]; then
DOTNET_STATUS="⚠️ outdated"
fi
echo "| Component | Current | Latest | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|---------|--------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| .NET SDK | $current_dotnet_version | $latest_dotnet_version | $DOTNET_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "dotnet-status=$DOTNET_STATUS" >> $GITHUB_OUTPUT
fi
# Check Docker versions
if [[ "${{ github.event.inputs.check_type }}" == "all" || "${{ github.event.inputs.check_type }}" == "docker" ]]; then
echo "### Docker Versions" >> $GITHUB_STEP_SUMMARY
current_docker=$(grep "ARG DOCKER_VERSION=" ./images/Dockerfile | cut -d'=' -f2)
current_buildx=$(grep "ARG BUILDX_VERSION=" ./images/Dockerfile | cut -d'=' -f2)
latest_docker=$(curl -s https://download.docker.com/linux/static/stable/x86_64/ | grep -o 'docker-[0-9]*\.[0-9]*\.[0-9]*\.tgz' | sort -V | tail -n 1 | sed 's/docker-\(.*\)\.tgz/\1/')
latest_buildx=$(curl -s https://api.github.com/repos/docker/buildx/releases/latest | jq -r '.tag_name' | sed 's/^v//')
DOCKER_STATUS="✅ up-to-date"
BUILDX_STATUS="✅ up-to-date"
if [ "$current_docker" != "$latest_docker" ]; then
DOCKER_STATUS="⚠️ outdated"
fi
if [ "$current_buildx" != "$latest_buildx" ]; then
BUILDX_STATUS="⚠️ outdated"
fi
echo "| Component | Current | Latest | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|---------|--------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Docker | $current_docker | $latest_docker | $DOCKER_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "| Docker Buildx | $current_buildx | $latest_buildx | $BUILDX_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "docker-status=$DOCKER_STATUS" >> $GITHUB_OUTPUT
echo "buildx-status=$BUILDX_STATUS" >> $GITHUB_OUTPUT
fi
# Check npm vulnerabilities
if [[ "${{ github.event.inputs.check_type }}" == "all" || "${{ github.event.inputs.check_type }}" == "npm" ]]; then
echo "### NPM Security Audit" >> $GITHUB_STEP_SUMMARY
cd src/Misc/expressionFunc/hashFiles
npm install --silent
AUDIT_OUTPUT=""
AUDIT_EXIT_CODE=0
# Run npm audit and capture output and exit code
if ! AUDIT_OUTPUT=$(npm audit --json 2>&1); then
AUDIT_EXIT_CODE=$?
fi
# Check if output is valid JSON
if echo "$AUDIT_OUTPUT" | jq . >/dev/null 2>&1; then
VULN_COUNT=$(echo "$AUDIT_OUTPUT" | jq '.metadata.vulnerabilities.total // 0')
# Ensure VULN_COUNT is a number
VULN_COUNT=$(echo "$VULN_COUNT" | grep -o '[0-9]*' | head -1)
VULN_COUNT=${VULN_COUNT:-0}
NPM_STATUS="✅ no vulnerabilities"
if [ "$VULN_COUNT" -gt 0 ] 2>/dev/null; then
NPM_STATUS="⚠️ $VULN_COUNT vulnerabilities found"
# Get vulnerability details
HIGH_VULNS=$(echo "$AUDIT_OUTPUT" | jq '.metadata.vulnerabilities.high // 0')
CRITICAL_VULNS=$(echo "$AUDIT_OUTPUT" | jq '.metadata.vulnerabilities.critical // 0')
echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Critical | $CRITICAL_VULNS |" >> $GITHUB_STEP_SUMMARY
echo "| High | $HIGH_VULNS |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
else
echo "No npm vulnerabilities found ✅" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
else
NPM_STATUS="❌ npm audit failed"
echo "npm audit failed to run or returned invalid JSON ❌" >> $GITHUB_STEP_SUMMARY
echo "Exit code: $AUDIT_EXIT_CODE" >> $GITHUB_STEP_SUMMARY
echo "Output: $AUDIT_OUTPUT" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
echo "npm-vulnerabilities=$NPM_STATUS" >> $GITHUB_OUTPUT
fi
- name: Check for open dependency PRs
id: check-prs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "### Open Dependency PRs" >> $GITHUB_STEP_SUMMARY
# Get open PRs with dependency label
OPEN_PRS=$(gh pr list --label "dependencies" --state open --json number,title,url)
PR_COUNT=$(echo "$OPEN_PRS" | jq '. | length')
if [ "$PR_COUNT" -gt 0 ]; then
echo "Found $PR_COUNT open dependency PR(s):" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "$OPEN_PRS" | jq -r '.[] | "- [#\(.number)](\(.url)) \(.title)"' >> $GITHUB_STEP_SUMMARY
else
echo "No open dependency PRs found ✅" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "open-dependency-prs=$PR_COUNT" >> $GITHUB_OUTPUT
- name: Summary
run: |
echo "### Summary" >> $GITHUB_STEP_SUMMARY
echo "- Check for open PRs with the \`dependency\` label before releases" >> $GITHUB_STEP_SUMMARY
echo "- Review and merge dependency updates regularly" >> $GITHUB_STEP_SUMMARY
echo "- Critical vulnerabilities should be addressed immediately" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Automated workflows run weekly to check for updates:**" >> $GITHUB_STEP_SUMMARY
echo "- Node.js versions (Mondays at 6 AM)" >> $GITHUB_STEP_SUMMARY
echo "- NPM audit fix (Mondays at 7 AM)" >> $GITHUB_STEP_SUMMARY
echo "- .NET SDK updates (Mondays at midnight)" >> $GITHUB_STEP_SUMMARY
echo "- Docker/Buildx updates (Mondays at midnight)" >> $GITHUB_STEP_SUMMARY

View File

@@ -2,7 +2,7 @@ name: "Docker/Buildx Version Upgrade"
on:
schedule:
- cron: "0 0 * * 1" # Run every Monday at midnight
- cron: "0 9 * * 1" # Weekly on Monday at 9 AM UTC (independent of other dependencies)
workflow_dispatch: # Allow manual triggering
jobs:
@@ -159,8 +159,5 @@ jobs:
# Create PR
gh pr create -B main -H "$branch_name" \
--title "$pr_title" \
--label "dependencies" \
--label "dependencies-weekly-check" \
--label "dependencies-not-dependabot" \
--label "docker" \
--label "dependency" \
--body-file pr_body.txt

View File

@@ -96,7 +96,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr create -B main -H feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }} --title "Update dotnet sdk to latest version @${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}" --label "dependencies" --label "dependencies-weekly-check" --label "dependencies-not-dependabot" --label "dotnet" --body "
gh pr create -B main -H feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }} --title "Update dotnet sdk to latest version @${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}" --label "dependency" --body "
https://dotnetcli.blob.core.windows.net/dotnet/Sdk/${{ needs.dotnet-update.outputs.DOTNET_CURRENT_MAJOR_MINOR_VERSION }}/latest.version

View File

@@ -120,11 +120,7 @@ jobs:
# Create PR
gh pr create -B main -H "$branch_name" \
--title "chore: update Node versions" \
--label "dependencies" \
--label "dependencies-weekly-check" \
--label "dependencies-not-dependabot" \
--label "node" \
--label "javascript" \
--label "dependency" \
--body-file pr_body.txt
echo "::notice title=PR Created::Successfully created Node.js version update PR on branch $branch_name"

View File

@@ -220,9 +220,9 @@ jobs:
fi
# Create PR with appropriate labels
labels="dependencies,dependencies-not-dependabot,typescript,npm,security"
labels="dependency,typescript"
if [[ "$build_status" == *"fails"* ]]; then
labels="dependencies,dependencies-not-dependabot,typescript,npm,security,needs-manual-review"
labels="dependency,typescript,needs-manual-review"
fi
# Create PR

View File

@@ -125,12 +125,7 @@ jobs:
# Create PR
gh pr create -B main -H "$branch_name" \
--title "chore: npm audit fix for hashFiles dependencies" \
--label "dependencies" \
--label "dependencies-weekly-check" \
--label "dependencies-not-dependabot" \
--label "npm" \
--label "typescript" \
--label "security" \
--label "dependency" \
--body-file pr_body.txt
else
echo "✅ No changes to commit - npm audit fix did not modify any files"

View File

@@ -16,7 +16,7 @@ jobs:
# Make sure ./releaseVersion match ./src/runnerversion
# Query GitHub release ensure version is not used
- name: Check version
uses: actions/github-script@v8.0.0
uses: actions/github-script@v7.0.1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
@@ -171,7 +171,7 @@ jobs:
# Create ReleaseNote file
- name: Create ReleaseNote
id: releaseNote
uses: actions/github-script@v8.0.0
uses: actions/github-script@v7.0.1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
@@ -300,7 +300,7 @@ jobs:
- name: Compute image version
id: image
uses: actions/github-script@v8.0.0
uses: actions/github-script@v7.0.1
with:
script: |
const fs = require('fs');

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
stale-issue-message: "This issue is stale because it has been open 365 days with no activity. Remove stale label or comment or this will be closed in 15 days."
close-issue-message: "This issue was closed because it has been stalled for 15 days with no activity."

View File

@@ -1,217 +0,0 @@
# Runner Dependency Management Process
## Overview
This document outlines the automated dependency management process for the GitHub Actions Runner, designed to ensure we maintain up-to-date and secure dependencies while providing predictable release cycles.
## Release Schedule
- **Monthly Runner Releases**: New runner versions are released monthly
- **Weekly Dependency Checks**: Automated workflows check for dependency updates every Monday
- **Security Patches**: Critical security vulnerabilities are addressed immediately outside the regular schedule
## Automated Workflows
**Note**: These workflows are implemented across separate PRs for easier review and independent deployment. Each workflow includes comprehensive error handling and security-focused vulnerability detection.
### 1. Foundation Labels
- **Workflow**: `.github/workflows/setup-labels.yml` (PR #4024)
- **Purpose**: Creates consistent dependency labels for all automation workflows
- **Labels**: `dependencies`, `security`, `typescript`, `needs-manual-review`
- **Prerequisite**: Must be merged before other workflows for proper labeling
### 2. Node.js Version Updates
- **Workflow**: `.github/workflows/node-upgrade.yml`
- **Schedule**: Mondays at 6:00 AM UTC
- **Purpose**: Updates Node.js 20 and 24 versions in `src/Misc/externals.sh`
- **Source**: [nodejs.org](https://nodejs.org) and [actions/alpine_nodejs](https://github.com/actions/alpine_nodejs)
- **Priority**: First (NPM depends on current Node.js versions)
### 3. NPM Security Audit
- **Primary Workflow**: `.github/workflows/npm-audit.yml` ("NPM Audit Fix")
- **Schedule**: Mondays at 7:00 AM UTC
- **Purpose**: Automated security vulnerability detection and basic fixes
- **Location**: `src/Misc/expressionFunc/hashFiles/`
- **Features**: npm audit, security patch application, PR creation
- **Dependency**: Runs after Node.js updates for optimal compatibility
- **Fallback Workflow**: `.github/workflows/npm-audit-typescript.yml` ("NPM Audit Fix with TypeScript Auto-Fix")
- **Trigger**: Manual dispatch only
- **Purpose**: Manual security audit with TypeScript compatibility fixes
- **Use Case**: When scheduled workflow fails or needs custom intervention
- **Features**: Enhanced TypeScript auto-repair, graduated security response
- **How to Use**:
1. If the scheduled "NPM Audit Fix" workflow fails, go to Actions tab
2. Select "NPM Audit Fix with TypeScript Auto-Fix" workflow
3. Click "Run workflow" and optionally specify fix level (auto/manual)
4. Review the generated PR for TypeScript compatibility issues
### 4. .NET SDK Updates
- **Workflow**: `.github/workflows/dotnet-upgrade.yml`
- **Schedule**: Mondays at midnight UTC
- **Purpose**: Updates .NET SDK and package versions with build validation
- **Features**: Global.json updates, NuGet package management, compatibility checking
- **Independence**: Runs independently of Node.js/NPM updates
### 5. Docker/Buildx Updates
- **Workflow**: `.github/workflows/docker-buildx-upgrade.yml` ("Docker/Buildx Version Upgrade")
- **Schedule**: Mondays at midnight UTC
- **Purpose**: Updates Docker and Docker Buildx versions with multi-platform validation
- **Features**: Container security scanning, multi-architecture build testing
- **Independence**: Runs independently of other dependency updates
### 6. Dependency Monitoring
- **Workflow**: `.github/workflows/dependency-check.yml` ("Dependency Status Check")
- **Schedule**: Mondays at 11:00 AM UTC
- **Purpose**: Comprehensive status report of all dependencies with security audit
- **Features**: Multi-dependency checking, npm audit status, build validation, choice of specific component checks
- **Summary**: Runs last to capture results from all morning dependency updates
## Release Process Integration
### Pre-Release Checklist
Before each monthly runner release:
1. **Check Dependency PRs**:
```bash
# List all open dependency PRs
gh pr list --label "dependencies" --state open
# List only automated weekly dependency updates
gh pr list --label "dependencies-weekly-check" --state open
# List only custom dependency automation (not dependabot)
gh pr list --label "dependencies-not-dependabot" --state open
```
2. **Run Manual Dependency Check**:
- Go to Actions tab → "Dependency Status Check" → "Run workflow"
- Review the summary for any outdated dependencies
3. **Review and Merge Updates**:
- Prioritize security-related updates
- Test dependency updates in development environment
- Merge approved dependency PRs
### Vulnerability Response
#### Critical Security Vulnerabilities
- **Response Time**: Within 24 hours
- **Process**:
1. Assess impact on runner security
2. Create hotfix branch if runner data security is affected
3. Expedite patch release if necessary
4. Document in security advisory if applicable
#### Non-Critical Vulnerabilities
- **Response Time**: Next monthly release
- **Process**:
1. Evaluate if vulnerability affects runner functionality
2. Include fix in regular dependency update cycle
3. Document in release notes
## Monitoring and Alerts
### GitHub Actions Workflow Status
- All dependency workflows create PRs with the `dependencies` label
- Failed workflows should be investigated immediately
- Weekly dependency status reports are generated automatically
### Manual Checks
You can manually trigger dependency checks:
- **Full Status**: Run "Dependency Status Check" workflow
- **Specific Component**: Use the dropdown to check individual dependencies
## Dependency Labels
All automated dependency PRs are tagged with labels for easy filtering and management:
### Primary Labels
- **`dependencies`**: All automated dependency-related PRs
- **`dependencies-weekly-check`**: Automated weekly dependency updates from scheduled workflows
- **`dependencies-not-dependabot`**: Custom dependency automation (not created by dependabot)
- **`security`**: Security vulnerability fixes and patches
- **`typescript`**: TypeScript compatibility and type definition updates
- **`needs-manual-review`**: Complex updates requiring human verification
### Technology-Specific Labels
- **`node`**: Node.js version updates
- **`javascript`**: JavaScript runtime and tooling updates
- **`npm`**: NPM package and security updates
- **`dotnet`**: .NET SDK and NuGet package updates
- **`docker`**: Docker and container tooling updates
### Workflow-Specific Branches
- **Node.js updates**: `chore/update-node` branch
- **NPM security fixes**: `chore/npm-audit-fix-YYYYMMDD` and `chore/npm-audit-fix-with-ts-repair` branches
- **NuGet/.NET updates**: `feature/dotnetsdk-upgrade/{version}` branches
- **Docker updates**: `feature/docker-buildx-upgrade` branch
## Special Considerations
### Node.js Updates
When updating Node.js versions, remember to:
1. Create a corresponding release in [actions/alpine_nodejs](https://github.com/actions/alpine_nodejs)
2. Follow the alpine_nodejs getting started guide
3. Test container builds with new Node versions
### .NET SDK Updates
- Only patch versions are auto-updated within the same major.minor version
- Major/minor version updates require manual review and testing
### Docker Updates
- Updates include both Docker Engine and Docker Buildx
- Verify compatibility with runner container workflows
## Troubleshooting
### Common Issues
1. **NPM Audit Workflow Fails**:
- Check if `package.json` exists in `src/Misc/expressionFunc/hashFiles/`
- Verify Node.js setup step succeeded
2. **Version Detection Fails**:
- Check if upstream APIs are available
- Verify parsing logic for version extraction
3. **PR Creation Fails**:
- Ensure `GITHUB_TOKEN` has sufficient permissions
- Check if branch already exists
### Contact
For questions about the dependency management process:
- Create an issue with the `dependencies` label
- Review existing dependency management workflows
- Consult the runner team for security-related concerns
## Metrics and KPIs
Track these metrics to measure dependency management effectiveness:
- Number of open dependency PRs at release time
- Time to merge dependency updates
- Number of security vulnerabilities by severity
- Release cycle adherence (monthly target)

View File

@@ -334,7 +334,6 @@ namespace GitHub.Runner.Listener.Configuration
{
var runner = await _dotcomServer.AddRunnerAsync(runnerSettings.PoolId, agent, runnerSettings.GitHubUrl, registerToken, publicKeyXML);
runnerSettings.ServerUrlV2 = runner.RunnerAuthorization.ServerUrl;
runnerSettings.UseV2Flow = true; // if we are using runner admin, we also need to hit broker
agent.Id = runner.Id;
agent.Authorization = new TaskAgentAuthorization()

View File

@@ -111,19 +111,19 @@ namespace GitHub.Runner.Worker.Container
{
IList<string> dockerOptions = new List<string>();
// OPTIONS
dockerOptions.Add(DockerUtil.CreateEscapedOption("--name", container.ContainerDisplayName));
dockerOptions.Add($"--name {container.ContainerDisplayName}");
dockerOptions.Add($"--label {DockerInstanceLabel}");
if (!string.IsNullOrEmpty(container.ContainerWorkDirectory))
{
dockerOptions.Add(DockerUtil.CreateEscapedOption("--workdir", container.ContainerWorkDirectory));
dockerOptions.Add($"--workdir {container.ContainerWorkDirectory}");
}
if (!string.IsNullOrEmpty(container.ContainerNetwork))
{
dockerOptions.Add(DockerUtil.CreateEscapedOption("--network", container.ContainerNetwork));
dockerOptions.Add($"--network {container.ContainerNetwork}");
}
if (!string.IsNullOrEmpty(container.ContainerNetworkAlias))
{
dockerOptions.Add(DockerUtil.CreateEscapedOption("--network-alias", container.ContainerNetworkAlias));
dockerOptions.Add($"--network-alias {container.ContainerNetworkAlias}");
}
foreach (var port in container.UserPortMappings)
{
@@ -195,10 +195,10 @@ namespace GitHub.Runner.Worker.Container
{
IList<string> dockerOptions = new List<string>();
// OPTIONS
dockerOptions.Add(DockerUtil.CreateEscapedOption("--name", container.ContainerDisplayName));
dockerOptions.Add($"--name {container.ContainerDisplayName}");
dockerOptions.Add($"--label {DockerInstanceLabel}");
dockerOptions.Add(DockerUtil.CreateEscapedOption("--workdir", container.ContainerWorkDirectory));
dockerOptions.Add($"--workdir {container.ContainerWorkDirectory}");
dockerOptions.Add($"--rm");
foreach (var env in container.ContainerEnvironmentVariables)

View File

@@ -249,7 +249,7 @@ namespace GitHub.Runner.Worker.Handlers
{
// We do not not the full path until we know what shell is being used, so that we can determine the file extension
scriptFilePath = Path.Combine(tempDirectory, $"{Guid.NewGuid()}{ScriptHandlerHelpers.GetScriptFileExtension(shellCommand)}");
resolvedScriptPath = $"\"{StepHost.ResolvePathForStepHost(ExecutionContext, scriptFilePath).Replace("\"", "\\\"")}\"";
resolvedScriptPath = StepHost.ResolvePathForStepHost(ExecutionContext, scriptFilePath).Replace("\"", "\\\"");
}
else
{
@@ -260,7 +260,7 @@ namespace GitHub.Runner.Worker.Handlers
}
scriptFilePath = Inputs["path"];
ArgUtil.NotNullOrEmpty(scriptFilePath, "path");
resolvedScriptPath = $"\"{Inputs["path"].Replace("\"", "\\\"")}\"";
resolvedScriptPath = Inputs["path"].Replace("\"", "\\\"");
}
// Format arg string with script path

View File

@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using GitHub.Runner.Sdk;
using GitHub.Runner.Common;
using GitHub.Runner.Common.Util;
@@ -64,47 +63,10 @@ namespace GitHub.Runner.Worker.Handlers
var append = @"if ((Test-Path -LiteralPath variable:\LASTEXITCODE)) { exit $LASTEXITCODE }";
contents = $"{prepend}{Environment.NewLine}{contents}{Environment.NewLine}{append}";
break;
case "bash":
case "sh":
contents = FixBashEnvironmentVariables(contents);
break;
}
return contents;
}
/// <summary>
/// Fixes unquoted environment variables in bash/sh scripts to prevent issues with paths containing spaces.
/// This method quotes environment variables used in shell redirects and command substitutions.
/// </summary>
/// <param name="contents">The shell script content to fix</param>
/// <returns>Fixed shell script content with properly quoted environment variables</returns>
private static string FixBashEnvironmentVariables(string contents)
{
if (string.IsNullOrEmpty(contents))
{
return contents;
}
// Pattern to match environment variables in shell redirects that aren't already quoted
// This targets patterns like: >> $GITHUB_STEP_SUMMARY, > $GITHUB_OUTPUT, etc.
// but avoids already quoted ones like: >> "$GITHUB_STEP_SUMMARY" or >> '$GITHUB_OUTPUT'
var redirectPattern = new Regex(
@"(\s+(?:>>|>|<|2>>|2>)\s+)(\$[A-Za-z_][A-Za-z0-9_]*)\b(?!\s*['""])",
RegexOptions.Compiled | RegexOptions.Multiline
);
// Replace unquoted environment variables in redirects with quoted versions
contents = redirectPattern.Replace(contents, match =>
{
var redirectOperator = match.Groups[1].Value; // e.g., " >> "
var envVar = match.Groups[2].Value; // e.g., "$GITHUB_STEP_SUMMARY"
return $"{redirectOperator}\"{envVar}\"";
});
return contents;
}
internal static (string shellCommand, string shellArgs) ParseShellOptionString(string shellOption)
{
var shellStringParts = shellOption.Split(" ", 2);

View File

@@ -220,7 +220,7 @@ namespace GitHub.Runner.Worker.Handlers
// [OPTIONS]
dockerCommandArgs.Add($"-i");
dockerCommandArgs.Add(DockerUtil.CreateEscapedOption("--workdir", workingDirectory));
dockerCommandArgs.Add($"--workdir {workingDirectory}");
foreach (var env in environment)
{
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing

View File

@@ -12,12 +12,6 @@
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Sdk\Sdk.csproj" />
<ProjectReference Include="..\Runner.Common\Runner.Common.csproj" />

View File

@@ -1,278 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using GitHub.DistributedTask.Pipelines.ContextData;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Common;
using GitHub.Runner.Worker;
using GitHub.Runner.Worker.Handlers;
using Moq;
using Xunit;
namespace GitHub.Runner.Common.Tests.Worker.Handlers
{
public sealed class ScriptHandlerL0
{
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void ScriptPath_WithSpaces_ShouldBeQuoted()
{
// Arrange - Test the path quoting logic that our fix addresses
var tempPathWithSpaces = "/path with spaces/_temp";
var scriptPathWithSpaces = Path.Combine(tempPathWithSpaces, "test-script.sh");
// Test the original (broken) behavior
var originalPath = scriptPathWithSpaces.Replace("\"", "\\\"");
// Test our fix - properly quoted path
var quotedPath = $"\"{scriptPathWithSpaces.Replace("\"", "\\\"")}\"";
// Assert
Assert.False(originalPath.StartsWith("\""), "Original path should not be quoted");
Assert.True(quotedPath.StartsWith("\"") && quotedPath.EndsWith("\""), "Fixed path should be properly quoted");
Assert.Contains("path with spaces", quotedPath, StringComparison.Ordinal);
// Verify the path is properly quoted (platform-agnostic check)
Assert.True(quotedPath.StartsWith("\"/path with spaces/_temp"), "Path should start with quoted temp directory");
Assert.True(quotedPath.EndsWith("test-script.sh\""), "Path should end with quoted script name");
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void ScriptPath_WithQuotes_ShouldEscapeQuotes()
{
// Arrange - Test paths that contain quotes
var pathWithQuotes = "/path/\"quoted folder\"/script.sh";
// Test our fix - properly escape quotes and wrap in quotes
var quotedPath = $"\"{pathWithQuotes.Replace("\"", "\\\"")}\"";
// Assert
Assert.True(quotedPath.StartsWith("\"") && quotedPath.EndsWith("\""), "Path should be wrapped in quotes");
Assert.Contains("\\\"", quotedPath, StringComparison.Ordinal);
Assert.Contains("quoted folder", quotedPath, StringComparison.Ordinal);
// Verify quotes are properly escaped
Assert.Contains("\\\"quoted folder\\\"", quotedPath, StringComparison.Ordinal);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void ScriptPath_ActionsRunnerWithSpaces_ShouldBeQuoted()
{
// Arrange - Test the specific real-world scenario that was failing
var runnerPathWithSpaces = "/Users/user/Downloads/actions-runner-osx-arm64-2.328.0 2";
var tempPath = Path.Combine(runnerPathWithSpaces, "_work", "_temp");
var scriptPath = Path.Combine(tempPath, "script-guid.sh");
// Test our fix
var quotedPath = $"\"{scriptPath.Replace("\"", "\\\"")}\"";
// Assert
Assert.True(quotedPath.StartsWith("\"") && quotedPath.EndsWith("\""), "Path should be wrapped in quotes");
Assert.Contains("actions-runner-osx-arm64-2.328.0 2", quotedPath, StringComparison.Ordinal);
Assert.Contains("_work", quotedPath, StringComparison.Ordinal);
Assert.Contains("_temp", quotedPath, StringComparison.Ordinal);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void ScriptPath_MultipleSpaces_ShouldBeQuoted()
{
// Arrange - Test paths with multiple spaces
var pathWithMultipleSpaces = "/path/with multiple spaces/script.sh";
// Test our fix
var quotedPath = $"\"{pathWithMultipleSpaces.Replace("\"", "\\\"")}\"";
// Assert
Assert.True(quotedPath.StartsWith("\"") && quotedPath.EndsWith("\""), "Path should be wrapped in quotes");
Assert.Contains("multiple spaces", quotedPath, StringComparison.Ordinal);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void ScriptPath_WithoutSpaces_ShouldStillBeQuoted()
{
// Arrange - Test normal paths without spaces (regression test)
var normalPath = "/home/user/runner/_work/_temp/script.sh";
// Test our fix
var quotedPath = $"\"{normalPath.Replace("\"", "\\\"")}\"";
// Assert
Assert.True(quotedPath.StartsWith("\"") && quotedPath.EndsWith("\""), "Path should be wrapped in quotes");
Assert.Equal($"\"{normalPath}\"", quotedPath);
}
[Theory]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
[InlineData("/path with spaces/script.sh")]
[InlineData("/Users/user/Downloads/actions-runner-osx-arm64-2.328.0 2/_work/_temp/guid.sh")]
[InlineData("C:\\Program Files\\GitHub Runner\\script.cmd")]
[InlineData("/path/\"with quotes\"/script.sh")]
[InlineData("/path/with'single'quotes/script.sh")]
public void ScriptPath_VariousScenarios_ShouldBeProperlyQuoted(string inputPath)
{
// Arrange & Act
var quotedPath = $"\"{inputPath.Replace("\"", "\\\"")}\"";
// Assert
Assert.True(quotedPath.StartsWith("\""), "Path should start with quote");
Assert.True(quotedPath.EndsWith("\""), "Path should end with quote");
// Ensure the original path content is preserved
var unquotedContent = quotedPath.Substring(1, quotedPath.Length - 2);
if (inputPath.Contains("\""))
{
// If original had quotes, they should be escaped in the result
Assert.Contains("\\\"", unquotedContent);
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_BashEnvironmentVariables_ShouldQuoteRedirects()
{
// Arrange
var scriptContent = @"echo ""## Dependency Status Report"" >> $GITHUB_STEP_SUMMARY
echo ""Generated on: $(date)"" >> $GITHUB_STEP_SUMMARY
echo ""| Component | Status |"" > $GITHUB_OUTPUT
echo ""npm-status=ok"" >> $GITHUB_OUTPUT";
// Act
var fixedContent = ScriptHandlerHelpers.FixUpScriptContents("bash", scriptContent);
// Assert
Assert.Contains(">> \"$GITHUB_STEP_SUMMARY\"", fixedContent);
Assert.Contains("> \"$GITHUB_OUTPUT\"", fixedContent);
Assert.DoesNotContain(">> $GITHUB_STEP_SUMMARY", fixedContent);
Assert.DoesNotContain("> $GITHUB_OUTPUT", fixedContent);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_AlreadyQuotedVariables_ShouldNotDoubleQuote()
{
// Arrange
var scriptContent = @"echo ""test"" >> ""$GITHUB_STEP_SUMMARY""
echo ""test"" > '$GITHUB_OUTPUT'
echo ""test"" 2>> ""$GITHUB_ENV""";
// Act
var fixedContent = ScriptHandlerHelpers.FixUpScriptContents("bash", scriptContent);
// Assert - Should remain unchanged
Assert.Equal(scriptContent, fixedContent);
Assert.Contains(">> \"$GITHUB_STEP_SUMMARY\"", fixedContent);
Assert.Contains("> '$GITHUB_OUTPUT'", fixedContent);
Assert.Contains("2>> \"$GITHUB_ENV\"", fixedContent);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_ShellRedirectOperators_ShouldHandleAllTypes()
{
// Arrange
var scriptContent = @"echo ""test"" >> $VAR1
echo ""test"" > $VAR2
cat < $VAR3
echo ""test"" 2>> $VAR4
echo ""test"" 2> $VAR5";
// Act
var fixedContent = ScriptHandlerHelpers.FixUpScriptContents("sh", scriptContent);
// Assert
Assert.Contains(">> \"$VAR1\"", fixedContent);
Assert.Contains("> \"$VAR2\"", fixedContent);
Assert.Contains("< \"$VAR3\"", fixedContent);
Assert.Contains("2>> \"$VAR4\"", fixedContent);
Assert.Contains("2> \"$VAR5\"", fixedContent);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_NonShellTypes_ShouldNotModifyEnvironmentVariables()
{
// Arrange
var scriptContent = @"echo ""test"" >> $GITHUB_STEP_SUMMARY";
// Act
var powershellFixed = ScriptHandlerHelpers.FixUpScriptContents("powershell", scriptContent);
var cmdFixed = ScriptHandlerHelpers.FixUpScriptContents("cmd", scriptContent);
var pythonFixed = ScriptHandlerHelpers.FixUpScriptContents("python", scriptContent);
// Assert - Should not modify environment variables for non-shell types
Assert.Contains(">> $GITHUB_STEP_SUMMARY", powershellFixed);
Assert.Contains(">> $GITHUB_STEP_SUMMARY", cmdFixed);
Assert.Contains(">> $GITHUB_STEP_SUMMARY", pythonFixed);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_ComplexScript_ShouldQuoteOnlyUnquotedRedirects()
{
// Arrange
var scriptContent = @"#!/bin/bash
# This is a test script
echo ""Starting workflow"" >> $GITHUB_STEP_SUMMARY
echo ""Already quoted"" >> ""$GITHUB_OUTPUT""
export MY_VAR=""$HOME/path with spaces""
curl -s https://api.github.com/rate_limit > $TEMP_FILE
echo ""Final status"" 2>> $ERROR_LOG
if [ -f ""$GITHUB_ENV"" ]; then
echo ""MY_VAR=test"" >> $GITHUB_ENV
fi";
// Act
var fixedContent = ScriptHandlerHelpers.FixUpScriptContents("bash", scriptContent);
// Assert
Assert.Contains(">> \"$GITHUB_STEP_SUMMARY\"", fixedContent);
Assert.Contains(">> \"$GITHUB_OUTPUT\"", fixedContent); // Should remain quoted
Assert.Contains("> \"$TEMP_FILE\"", fixedContent);
Assert.Contains("2>> \"$ERROR_LOG\"", fixedContent);
Assert.Contains(">> \"$GITHUB_ENV\"", fixedContent);
// Other parts should remain unchanged
Assert.Contains("#!/bin/bash", fixedContent);
Assert.Contains("# This is a test script", fixedContent);
Assert.Contains("export MY_VAR=\"$HOME/path with spaces\"", fixedContent);
Assert.Contains("if [ -f \"$GITHUB_ENV\" ]; then", fixedContent);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void FixUpScriptContents_EnvironmentVariablesInCommands_ShouldNotQuote()
{
// Arrange - Environment variables not in redirects should not be touched
var scriptContent = @"echo $GITHUB_STEP_SUMMARY
cd $HOME
ls -la $TEMP_DIR
if [ ""$MY_VAR"" == ""test"" ]; then
echo ""match""
fi";
// Act
var fixedContent = ScriptHandlerHelpers.FixUpScriptContents("bash", scriptContent);
// Assert - Should remain unchanged as these are not redirects
Assert.Equal(scriptContent, fixedContent);
}
}
}

View File

@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
PACKAGE_DIR="$SCRIPT_DIR/../_package"
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
DOTNETSDK_VERSION="8.0.413"
DOTNETSDK_VERSION="8.0.414"
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
RUNNER_VERSION=$(cat runnerversion)

View File

@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.413"
"version": "8.0.414"
}
}