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
8 changes: 6 additions & 2 deletions .github/actions/configure-redis/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,15 @@ runs:
- name: 🗄️ Configure Redis Settings
id: redis-config
shell: bash
env:
# Route env-json through env: (matches parse-env). A single-quote-wrapped ${{ }}
# in the run: body can be broken out of by any value containing a single quote,
# so keep it as data the shell never parses.
ENV_JSON: ${{ inputs.env-json }}
run: |
echo "🗄️ Configuring Redis service settings..."

# Parse environment JSON for Redis settings
ENV_JSON='${{ inputs.env-json }}'
# Redis settings are parsed from ENV_JSON (provided via env:)

# Validate JSON format
if ! echo "$ENV_JSON" | jq empty 2>/dev/null; then
Expand Down
22 changes: 12 additions & 10 deletions .github/actions/download-artifact-resilient/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,15 @@ runs:
# Fetch artifacts list (best-effort). In some workflow contexts GitHub will
# block listing artifacts via API even though direct downloads work.
# So: if listing fails, we fall back to attempting the download directly.
ARTIFACTS_JSON=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts --paginate 2>&1) || {
ARTIFACTS_JSON=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts" --paginate 2>&1) || {
API_ERROR=$?
echo "⚠️ Failed to fetch artifacts list (exit code: $API_ERROR)"
echo " Response: $ARTIFACTS_JSON"
echo "↪ Falling back to direct download attempt (skipping preflight list)"

DOWNLOAD_CMD="gh run download ${{ github.run_id }} --pattern \"$ARTIFACT_PATTERN\" --dir \"$ARTIFACT_PATH\""
if timeout "$DOWNLOAD_TIMEOUT" bash -c "$DOWNLOAD_CMD"; then
# Run gh directly (no bash -c on a built-up string) so env-routed values can
# never be re-parsed as shell. run_id/repo come from built-in env vars.
if timeout "$DOWNLOAD_TIMEOUT" gh run download "$GITHUB_RUN_ID" --pattern "$ARTIFACT_PATTERN" --dir "$ARTIFACT_PATH"; then
echo "✅ Successfully downloaded artifacts via fallback"
DOWNLOAD_SUCCESS=true
ARTIFACTS_FOUND=1
Expand All @@ -134,8 +135,9 @@ runs:
echo " Response: $ARTIFACTS_JSON"
echo "↪ Falling back to direct download attempt (skipping preflight list)"

DOWNLOAD_CMD="gh run download ${{ github.run_id }} --pattern \"$ARTIFACT_PATTERN\" --dir \"$ARTIFACT_PATH\""
if timeout "$DOWNLOAD_TIMEOUT" bash -c "$DOWNLOAD_CMD"; then
# Run gh directly (no bash -c on a built-up string) so env-routed values can
# never be re-parsed as shell. run_id/repo come from built-in env vars.
if timeout "$DOWNLOAD_TIMEOUT" gh run download "$GITHUB_RUN_ID" --pattern "$ARTIFACT_PATTERN" --dir "$ARTIFACT_PATH"; then
echo "✅ Successfully downloaded artifacts via fallback"
DOWNLOAD_SUCCESS=true
ARTIFACTS_FOUND=1
Expand All @@ -152,7 +154,7 @@ runs:
fi
fi

if ! echo "$ARTIFACTS_JSON" | jq -e ".artifacts[] | select(.name | test(\"$REGEX_PATTERN\"))" > /dev/null 2>&1; then
if ! echo "$ARTIFACTS_JSON" | jq -e --arg re "$REGEX_PATTERN" '.artifacts[] | select(.name | test($re))' > /dev/null 2>&1; then
echo "⚠️ No artifacts found matching pattern '$ARTIFACT_PATTERN'"
echo "📋 Available artifacts:"
echo "$ARTIFACTS_JSON" | jq -r '.artifacts[].name' 2>/dev/null | sed 's/^/ • /' || echo " No artifacts available"
Expand All @@ -168,17 +170,17 @@ runs:
fi

# Count available artifacts
AVAILABLE_ARTIFACTS=$(echo "$ARTIFACTS_JSON" | jq "[.artifacts[] | select(.name | test(\"$REGEX_PATTERN\"))] | length")
AVAILABLE_ARTIFACTS=$(echo "$ARTIFACTS_JSON" | jq --arg re "$REGEX_PATTERN" '[.artifacts[] | select(.name | test($re))] | length')
echo "📊 Found $AVAILABLE_ARTIFACTS artifact(s) matching pattern"

# Attempt download with timeout
echo "⏳ Downloading with ${DOWNLOAD_TIMEOUT}s timeout..."

# Always use --pattern flag since "coverage-data" is treated as a pattern
# Using --name with patterns causes gh CLI to download all artifacts when no exact match found
DOWNLOAD_CMD="gh run download ${{ github.run_id }} --pattern \"$ARTIFACT_PATTERN\" --dir \"$ARTIFACT_PATH\""

if timeout "$DOWNLOAD_TIMEOUT" bash -c "$DOWNLOAD_CMD"; then
# Run gh directly (no bash -c on a built-up string) so env-routed values can
# never be re-parsed as shell. run_id/repo come from built-in env vars.
if timeout "$DOWNLOAD_TIMEOUT" gh run download "$GITHUB_RUN_ID" --pattern "$ARTIFACT_PATTERN" --dir "$ARTIFACT_PATH"; then
echo "✅ Successfully downloaded artifacts on attempt $ATTEMPT_NUM"
DOWNLOAD_SUCCESS=true
ARTIFACTS_FOUND=$AVAILABLE_ARTIFACTS
Expand Down
4 changes: 3 additions & 1 deletion .github/actions/extract-module-dir/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ runs:
- name: 🔧 Extract Go module directory
id: extract
shell: bash
env:
# Route the input through env: (never string-spliced into the shell)
GO_SUM_FILE: ${{ inputs.go-sum-file }}
run: |
GO_SUM_FILE="${{ inputs.go-sum-file }}"
GO_MODULE_DIR=$(dirname "$GO_SUM_FILE")

# Handle root directory case (dirname returns ".")
Expand Down
30 changes: 22 additions & 8 deletions .github/actions/parse-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
#
# Maintainer: @mrz1836
#
# SECURITY INVARIANT: only invoke this action (and its siblings under `.github/actions/`)
# from `push` / `pull_request` runs with a powerless (read-only on forks) token. Values
# that could be influenced by a PR are routed through `env:` and referenced as quoted
# "$VAR". Do NOT wire these actions to `pull_request_target` / `workflow_run` (privileged
# token on an untrusted ref) without first auditing every `${{ }}`→shell/jq sink.
#
# ------------------------------------------------------------------------------------

name: "Parse Environment Variables"
Expand Down Expand Up @@ -55,16 +61,24 @@ runs:
exit 1
fi

# Parse and set each variable (exact pattern from existing workflows)
echo "$ENV_JSON" | jq -r 'to_entries | .[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
# Validate key name (basic safety check)
if [[ -z "$key" ]]; then
echo "⚠️ WARNING: Skipping empty variable name" >&2
# Parse and set each variable. Harden $GITHUB_ENV writes (defense-in-depth):
# base64-encode values so newlines/special chars can't corrupt the read loop,
# accept only valid env-var names, and reject newline-bearing values (which could
# otherwise inject arbitrary extra env vars). base64's decode flag differs by
# platform (GNU: -d, BSD/macOS: -D) — detect it.
if printf '' | base64 -d >/dev/null 2>&1; then B64D=-d; else B64D=-D; fi
echo "$ENV_JSON" | jq -r 'to_entries[] | .key, (.value | tostring | @base64)' | while IFS= read -r key; do
IFS= read -r value_b64
if [[ ! "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
echo "⚠️ WARNING: Skipping invalid variable name: $key" >&2
continue
fi

# Set the environment variable
echo "$key=$value" >> $GITHUB_ENV
value=$(printf '%s' "$value_b64" | base64 "$B64D")
if [[ "$value" == *$'\n'* ]]; then
echo "⚠️ WARNING: Skipping $key: value contains a newline" >&2
continue
fi
printf '%s=%s\n' "$key" "$value" >> "$GITHUB_ENV"
done

# Count and report variables set
Expand Down
16 changes: 12 additions & 4 deletions .github/actions/setup-benchstat/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,20 @@ runs:
- name: ⬇️ Install benchstat (cache miss)
if: steps.version-check.outputs.skip != 'true' && steps.benchstat-cache.outputs.cache-hit != 'true'
shell: bash
env:
# Route the version through env: so it can never break out of the go install
# command via ${{ }} interpolation (completes the safe pattern; version is config).
BENCHSTAT_VERSION: ${{ inputs.benchstat-version }}
run: |
echo "⬇️ Cache miss – installing benchstat via go install..."
echo "📋 Installing benchstat version: ${{ inputs.benchstat-version }}"

# Install benchstat
go install "golang.org/x/perf/cmd/benchstat@${{ inputs.benchstat-version }}"
echo "📋 Installing benchstat version: $BENCHSTAT_VERSION"

# Install benchstat. Version is pinned in config and verified by Go's checksum DB
# (sum.golang.org), so SonarCloud S8545 is a known false positive here. Inline
# NOSONAR is NOT honored by Sonar's GitHub Actions analyzer — suppress it via
# SonarCloud config (Quality Profile, or an Analysis-Scope / properties exclusion
# for rule githubactions:S8545 on .github/actions/**).
go install "golang.org/x/perf/cmd/benchstat@${BENCHSTAT_VERSION}"

# Cache the binary for future runs
mkdir -p ~/.cache/benchstat-bin
Expand Down
7 changes: 6 additions & 1 deletion .github/actions/setup-go-with-cache/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,12 @@ runs:
echo "🔐 Configuring git authentication for private Go modules..."
echo "📋 GOPRIVATE=$GOPRIVATE"

# Configure git to use the token for HTTPS URLs
# Configure git to use the token for HTTPS URLs.
# SECURITY: this writes the token into the job's global git config (~/.gitconfig).
# It is deliberately job-lifetime — subsequent `go mod download` steps in the SAME
# job need it — and the GitHub-hosted runner is ephemeral and single-tenant, so the
# config is destroyed when the job ends. Do not persist this beyond the job (e.g. into
# a cache) and keep this step gated to private-module runs only.
git config --global url."https://x-access-token:${PRIVATE_MODULE_TOKEN}@github.com/".insteadOf "https://github.com/"

# Set GONOSUMDB to match GOPRIVATE if not explicitly set
Expand Down
16 changes: 12 additions & 4 deletions .github/actions/setup-mage/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,20 @@ runs:
- name: ⬇️ Install mage (cache miss)
if: steps.mage-cache.outputs.cache-hit != 'true'
shell: bash
env:
# Route the version through env: so it can never break out of the go install
# command via ${{ }} interpolation (completes the safe pattern; version is config).
MAGE_VERSION: ${{ inputs.mage-version }}
run: |
echo "⬇️ Cache miss – installing mage via go install..."
echo "📋 Installing mage version: ${{ inputs.mage-version }}"

# Install mage
go install "github.com/magefile/mage@${{ inputs.mage-version }}"
echo "📋 Installing mage version: $MAGE_VERSION"

# Install mage. Version is pinned in config and verified by Go's checksum DB
# (sum.golang.org), so SonarCloud S8545 is a known false positive here. Inline
# NOSONAR is NOT honored by Sonar's GitHub Actions analyzer — suppress it via
# SonarCloud config (Quality Profile, or an Analysis-Scope / properties exclusion
# for rule githubactions:S8545 on .github/actions/**).
go install "github.com/magefile/mage@${MAGE_VERSION}"

# Cache the binary for future runs
mkdir -p ~/.cache/mage-bin
Expand Down
71 changes: 48 additions & 23 deletions .github/actions/validate-test-results/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ runs:
echo "🔍 Validating test results from CI mode output..."
source .github/scripts/parse-test-label.sh

# Guard against bash arithmetic-eval injection: artifact-derived counts flow into
# $(( )) and [[ -gt ]]. Coerce each to a bare non-negative integer so a crafted
# JSONL value like "a[$(cmd)]" becomes 0 instead of being evaluated as code.
to_int() {
local v="${1//[[:space:]]/}"
if [[ "$v" =~ ^[0-9]+$ ]]; then printf '%s' "$v"; else printf '0'; fi
}

VALIDATION_FAILED=false
TOTAL_FAILURES=0
TOTAL_UNIQUE=0
Expand Down Expand Up @@ -95,11 +103,11 @@ runs:

if [[ -n "$SUMMARY" ]]; then
STATUS=$(echo "$SUMMARY" | jq -r '.summary.status // "unknown"')
PASSED=$(echo "$SUMMARY" | jq -r '.summary.passed // 0')
FAILED=$(echo "$SUMMARY" | jq -r '.summary.failed // 0')
SKIPPED=$(echo "$SUMMARY" | jq -r '.summary.skipped // 0')
UNIQUE=$(echo "$SUMMARY" | jq -r '.summary.unique_total // 0')
TOTAL=$(echo "$SUMMARY" | jq -r '.summary.total // 0')
PASSED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.passed // 0')")
FAILED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.failed // 0')")
SKIPPED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.skipped // 0')")
UNIQUE=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.unique_total // 0')")
TOTAL=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.total // 0')")
DURATION=$(echo "$SUMMARY" | jq -r '.summary.duration // "unknown"')

echo " • Status: $STATUS"
Expand Down Expand Up @@ -143,7 +151,9 @@ runs:
else
echo " ⚠️ No summary found in JSONL file"

FAILURE_COUNT=$(grep -c '"type":"failure"' "$jsonl_file" 2>/dev/null || echo "0")
# grep -c exits 1 on zero matches; ignore its status (it still prints 0) so
# the step can't hard-fail under bash -e/pipefail when there are no failures.
FAILURE_COUNT=$(to_int "$(grep -c '"type":"failure"' "$jsonl_file" 2>/dev/null || true)")
if [[ "$FAILURE_COUNT" -gt 0 ]]; then
echo " • Found $FAILURE_COUNT failure entries"
VALIDATION_FAILED=true
Expand All @@ -161,7 +171,9 @@ runs:
if grep -q "^FAIL" "$log_file" 2>/dev/null || grep -q "--- FAIL:" "$log_file" 2>/dev/null; then
echo " ❌ Found test failures in log file"
VALIDATION_FAILED=true
FAIL_COUNT=$(grep -c "^--- FAIL:" "$log_file" 2>/dev/null || echo "1")
# grep -c exits 1 on zero matches; ignore its status (it still prints 0).
FAIL_COUNT=$(to_int "$(grep -c "^--- FAIL:" "$log_file" 2>/dev/null || true)")
[[ "$FAIL_COUNT" -gt 0 ]] || FAIL_COUNT=1 # we already matched a FAIL above
TOTAL_FAILURES=$((TOTAL_FAILURES + FAIL_COUNT))
fi
done < <(find ci-results/ -name "test-output.log" -print0 2>/dev/null)
Expand Down Expand Up @@ -199,11 +211,22 @@ runs:
set -uo pipefail
source .github/scripts/parse-test-label.sh

# Coerce artifact-derived counts to integers (arithmetic-eval injection guard) and
# strip backticks from artifact-derived text before it is written into the job
# summary (prevents markdown code-span / fenced-block breakout & content spoofing).
to_int() {
local v="${1//[[:space:]]/}"
if [[ "$v" =~ ^[0-9]+$ ]]; then printf '%s' "$v"; else printf '0'; fi
}
# Strip backticks AND control chars (except tab/newline) from artifact-derived text:
# prevents code-span/fenced-block breakout and control-character (ANSI/NUL) spoofing.
strip_bt() { printf '%s' "$1" | LC_ALL=C tr -d '\000-\010\013-\037\140\177'; }
Comment thread
mrz1836 marked this conversation as resolved.

echo "## 🔍 Test Validation Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# Count artifacts
MATRIX_JOBS=$(find ci-results/ -name "*.jsonl" 2>/dev/null | wc -l || echo "0")
MATRIX_JOBS=$(to_int "$(find ci-results/ -name "*.jsonl" 2>/dev/null | wc -l)")
echo "- **Matrix Jobs Validated**: $MATRIX_JOBS" >> $GITHUB_STEP_SUMMARY

# Aggregate results from JSONL files
Expand All @@ -216,11 +239,11 @@ runs:
while IFS= read -r -d '' jsonl_file; do
SUMMARY=$(grep '"type":"summary"' "$jsonl_file" 2>/dev/null | head -1 || echo "")
if [[ -n "$SUMMARY" ]]; then
PASSED=$(echo "$SUMMARY" | jq -r '.summary.passed // 0')
FAILED=$(echo "$SUMMARY" | jq -r '.summary.failed // 0')
SKIPPED=$(echo "$SUMMARY" | jq -r '.summary.skipped // 0')
UNIQUE=$(echo "$SUMMARY" | jq -r '.summary.unique_total // 0')
TOTAL=$(echo "$SUMMARY" | jq -r '.summary.total // 0')
PASSED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.passed // 0')")
FAILED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.failed // 0')")
SKIPPED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.skipped // 0')")
UNIQUE=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.unique_total // 0')")
TOTAL=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.total // 0')")
TOTAL_PASSED=$((TOTAL_PASSED + PASSED))
TOTAL_FAILED=$((TOTAL_FAILED + FAILED))
TOTAL_SKIPPED=$((TOTAL_SKIPPED + SKIPPED))
Expand Down Expand Up @@ -256,14 +279,14 @@ runs:
ARTIFACT_DIR=$(basename "$(dirname "$jsonl_file")")
fi

TEST_LABEL=$(parse_test_label "$ARTIFACT_DIR" "$JSONL_NAME")
TEST_LABEL=$(strip_bt "$(parse_test_label "$ARTIFACT_DIR" "$JSONL_NAME")")

SUMMARY=$(grep '"type":"summary"' "$jsonl_file" 2>/dev/null | head -1 || echo "")

if [[ -n "$SUMMARY" ]]; then
STATUS=$(echo "$SUMMARY" | jq -r '.summary.status // "unknown"')
PASSED=$(echo "$SUMMARY" | jq -r '.summary.passed // 0')
FAILED=$(echo "$SUMMARY" | jq -r '.summary.failed // 0')
PASSED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.passed // 0')")
FAILED=$(to_int "$(echo "$SUMMARY" | jq -r '.summary.failed // 0')")

if [[ "$STATUS" == "passed" ]]; then
echo "- ✅ **$TEST_LABEL**: $PASSED tests passed" >> $GITHUB_STEP_SUMMARY
Expand Down Expand Up @@ -292,12 +315,14 @@ runs:
break 2
fi

TEST=$(echo "$line" | jq -r '.failure.test // "unknown"')
PKG=$(echo "$line" | jq -r '.failure.package // "unknown"' | sed 's|.*/||')
FAIL_TYPE=$(echo "$line" | jq -r '.failure.type // "test"')
ERROR_MSG=$(echo "$line" | jq -r '.failure.error // ""')
OUTPUT=$(echo "$line" | jq -r '.failure.output // ""')
STACK=$(echo "$line" | jq -r '.failure.stack // ""')
# Strip backticks from artifact-derived text so it cannot break out of the
# markdown code spans / fenced blocks it is written into below.
TEST=$(strip_bt "$(echo "$line" | jq -r '.failure.test // "unknown"')")
PKG=$(strip_bt "$(echo "$line" | jq -r '.failure.package // "unknown"' | sed 's|.*/||')")
FAIL_TYPE=$(strip_bt "$(echo "$line" | jq -r '.failure.type // "test"')")
ERROR_MSG=$(strip_bt "$(echo "$line" | jq -r '.failure.error // ""')")
OUTPUT=$(strip_bt "$(echo "$line" | jq -r '.failure.output // ""')")
STACK=$(strip_bt "$(echo "$line" | jq -r '.failure.stack // ""')")

echo "<details>" >> $GITHUB_STEP_SUMMARY
echo "<summary>❌ <code>$TEST</code> ($PKG) - $FAIL_TYPE</summary>" >> $GITHUB_STEP_SUMMARY
Expand Down Expand Up @@ -332,7 +357,7 @@ runs:
# For fuzz tests, show fuzz-specific info
FUZZ_INFO=$(echo "$line" | jq -r '.failure.fuzz_info // null')
if [[ "$FUZZ_INFO" != "null" && -n "$FUZZ_INFO" ]]; then
CORPUS=$(echo "$FUZZ_INFO" | jq -r '.corpus_path // ""')
CORPUS=$(strip_bt "$(echo "$FUZZ_INFO" | jq -r '.corpus_path // ""')")
if [[ -n "$CORPUS" && "$CORPUS" != "null" ]]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Fuzz Corpus:** \`$CORPUS\`" >> $GITHUB_STEP_SUMMARY
Expand Down
Loading