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
549 changes: 0 additions & 549 deletions .github/.env.base

This file was deleted.

3 changes: 2 additions & 1 deletion .github/.yamlfmt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ exclude:
- "**/*.swo"
- "**/*~"

# Build configs
# Environment files
- "**/env/**"
- "**/.env.base"
- "**/.env.custom"
17 changes: 16 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
* @mrz1836

# GitHub Actions workflows
.github/actions/* @mrz1836
.github/scripts/* @mrz1836
.github/workflows/* @mrz1836
.github/env/* @mrz1836
.github/.env.base @mrz1836
.github/.env.custom @mrz1836

Expand Down Expand Up @@ -37,7 +40,6 @@ codecov.yml @mrz1836
.github/AGENTS.md @mrz1836
.cursorrules @mrz1836
.github/CLAUDE.md @mrz1836
sweep.yml @mrz1836

# Security and configuration files
.github/SECURITY.md @mrz1836
Expand All @@ -46,3 +48,16 @@ sweep.yml @mrz1836
# Repository configuration
.github/labels.yml @mrz1836
.github/dependabot.yml @mrz1836

# Tech Conventions
.github/tech-conventions/* @mrz1836

# Cursor Rules
.cursorrules @mrz1836

# Devcontainer configuration
.devcontainer/* @mrz1836
.devcontainer.json @mrz1836

# Gitpod configuration
.gitpod.yml @mrz1836
28 changes: 24 additions & 4 deletions .github/actions/download-artifact-resilient/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,29 @@ runs:
# Check if artifacts exist first (avoid unnecessary retries)
echo "🔍 Checking artifact availability..."

# Fetch artifacts list, handling API errors gracefully
ARTIFACTS_JSON=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts 2>&1) || {
# 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) || {
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
echo "✅ Successfully downloaded artifacts via fallback"
DOWNLOAD_SUCCESS=true
ARTIFACTS_FOUND=1
break
fi

if [ "$CONTINUE_ON_ERROR" = "true" ]; then
echo "::warning title=Artifact API Error::Failed to fetch artifacts list - API may be unavailable or credentials invalid"
echo "::warning title=Artifact API Error::Failed to list/download artifacts - API may be unavailable or credentials invalid"
DOWNLOAD_SUCCESS=false
break
else
echo "::error title=Artifact API Error::Failed to fetch artifacts list - API may be unavailable or credentials invalid"
echo "::error title=Artifact API Error::Failed to list/download artifacts - API may be unavailable or credentials invalid"
exit 1
fi
}
Expand All @@ -121,6 +132,15 @@ runs:
if ! echo "$ARTIFACTS_JSON" | jq -e '.artifacts' > /dev/null 2>&1; then
echo "⚠️ Invalid API response (not valid artifacts JSON)"
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
echo "✅ Successfully downloaded artifacts via fallback"
DOWNLOAD_SUCCESS=true
ARTIFACTS_FOUND=1
break
fi

if [ "$CONTINUE_ON_ERROR" = "true" ]; then
echo "::warning title=Invalid API Response::Artifacts API returned invalid response"
Expand Down
190 changes: 39 additions & 151 deletions .github/actions/load-env/action.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
# ------------------------------------------------------------------------------------
# Load Environment Variables Composite Action
#
# Purpose: Loads and parses environment configuration from .env.base and .env.custom
# Purpose: Loads and parses environment configuration from modular .github/env/
# files into JSON format for use across all GitHub Actions workflows.
#
# Loading Strategy:
# 1. Load .env.base (required) - contains default configuration
# 2. Load .env.custom (optional) - project-specific overrides
# 3. Merge with custom values taking precedence
# 1. Run .github/env/load-env.sh to load all modular env files
# 2. Extract exported variables to JSON for workflow compatibility
#
# Outputs:
# env-json: JSON object containing all merged environment variables
# env-json: JSON object containing all environment variables
#
# Usage:
# - uses: ./.github/actions/load-env
Expand All @@ -21,7 +20,7 @@
# ------------------------------------------------------------------------------------

name: "Load Environment Variables"
description: "Loads and merges environment variables from .env.base and .env.custom files"
description: "Loads environment variables from modular .github/env/ files"

outputs:
env-json:
Expand All @@ -30,154 +29,70 @@ outputs:
primary-runner:
description: "Primary runner OS extracted from environment variables"
value: ${{ steps.load-env.outputs.primary-runner }}
base-file-found:
description: "Whether .env.base file was found"
value: ${{ steps.load-env.outputs.base-file-found }}
custom-file-found:
description: "Whether .env.custom file was found"
value: ${{ steps.load-env.outputs.custom-file-found }}
base-var-count:
description: "Number of variables loaded from .env.base"
value: ${{ steps.load-env.outputs.base-var-count }}
custom-var-count:
description: "Number of variables loaded from .env.custom"
value: ${{ steps.load-env.outputs.custom-var-count }}
config-mode:
description: "Configuration mode: new (base+custom) or base-only"
value: ${{ steps.load-env.outputs.config-mode }}
env-file-count:
description: "Number of env files loaded"
value: ${{ steps.load-env.outputs.env-file-count }}
var-count:
description: "Total number of variables loaded"
value: ${{ steps.load-env.outputs.var-count }}

runs:
using: "composite"
steps:
# --------------------------------------------------------------------
# Load and merge environment configuration files
# Load environment configuration from modular env files
# --------------------------------------------------------------------
- name: 🔧 Load environment variables
- name: 🌍 Load environment variables
id: load-env
shell: bash
run: |
echo "📋 Loading environment configuration..."

# Function to parse .env file to JSON
parse_env_file() {
local file="$1"
if [[ -f "$file" ]]; then
cat "$file" | \
grep -v '^#' | \
grep -v '^$' | \
sed 's/#.*$//' | \
sed 's/[[:space:]]*$//' | \
jq -Rs 'split("\n") | map(select(length > 0) | split("=") | select(length == 2) | {(.[0]): .[1]}) | add // {}'
else
echo "{}"
fi
}
LOADER_SCRIPT=".github/env/load-env.sh"

# Function to validate environment variable names and values
validate_env_vars() {
local json="$1"
local source="$2"

echo "🔒 Validating environment variables from $source..."

# Extract all keys and values
local keys=$(echo "$json" | jq -r 'keys[]')

while IFS= read -r key; do
# Skip empty keys
[[ -z "$key" ]] && continue

# Validate key name: must match ^[A-Z_][A-Z0-9_]*$
if ! echo "$key" | grep -qE '^[A-Z_][A-Z0-9_]*$'; then
echo "❌ ERROR: Invalid environment variable name in $source: '$key'" >&2
echo " Variable names must start with uppercase letter or underscore" >&2
echo " and contain only uppercase letters, numbers, and underscores" >&2
exit 1
fi

# Get the value for this key
local value=$(echo "$json" | jq -r --arg k "$key" '.[$k]')

# Validate value length (max 10000 chars to prevent DoS)
if [[ ${#value} -gt 10000 ]]; then
echo "❌ ERROR: Environment variable value too long in $source: '$key'" >&2
echo " Maximum length is 10000 characters, got ${#value}" >&2
exit 1
fi

# Check for suspicious command injection patterns
if echo "$value" | grep -qE '`|\$\(|\$\{|;|&|\||<\(|>|<|\\|'"'"'|"|\x00|[[:cntrl:]]'; then
echo "⚠️ WARNING: Potentially unsafe characters in $source variable '$key'" >&2
echo " Value contains backticks, command substitution, or shell metacharacters" >&2
echo " Value will be treated as a literal string during extraction" >&2
fi

done <<< "$keys"

echo "✅ All variables in $source passed validation"
}

# Load configuration files in order of precedence
BASE_JSON="{}"
CUSTOM_JSON="{}"

# 1. Load base configuration (required)
if [[ -f ".github/.env.base" ]]; then
echo "📂 Loading base configuration from .env.base..."
BASE_JSON=$(parse_env_file ".github/.env.base")
BASE_COUNT=$(echo "$BASE_JSON" | jq 'keys | length')
echo "✅ Loaded $BASE_COUNT base configuration variables"
if [[ ! -f "$LOADER_SCRIPT" ]]; then
echo "❌ ERROR: Environment loader not found at $LOADER_SCRIPT" >&2
exit 1
fi

# Validate base configuration
validate_env_vars "$BASE_JSON" ".env.base"
else
echo "❌ ERROR: Required .env.base file not found!" >&2
# Source the loader script with verbose output
echo "🔄 Loading modular environment files..."
if ! source "$LOADER_SCRIPT" --verbose; then
echo "❌ ERROR: Failed to load environment configuration" >&2
exit 1
fi

# 2. Load custom overrides (optional)
if [[ -f ".github/.env.custom" ]]; then
echo "🎨 Loading custom configuration from .env.custom..."
CUSTOM_JSON=$(parse_env_file ".github/.env.custom")
CUSTOM_COUNT=$(echo "$CUSTOM_JSON" | jq 'keys | length')
echo "✅ Loaded $CUSTOM_COUNT custom override variables"
# Extract all exported variables to JSON for workflow compatibility
echo "📦 Extracting environment variables to JSON..."
ENV_JSON=$(env | grep -E '^[A-Z_][A-Z0-9_]*=' | while IFS='=' read -r key value; do
# Escape special characters in value for JSON
escaped_value=$(printf '%s' "$value" | jq -Rs '.')
echo "{\"$key\": $escaped_value}"
done | jq -s 'add // {}')

# Validate custom configuration
validate_env_vars "$CUSTOM_JSON" ".env.custom"
else
echo "ℹ️ No custom configuration file found (this is optional)"
fi
TOTAL_COUNT=$(echo "$ENV_JSON" | jq 'keys | length')
echo "✅ Extracted $TOTAL_COUNT variables"

# 3. Merge configurations with precedence: custom > base
echo "🔀 Merging configuration files..."
ENV_JSON=$(echo "$BASE_JSON $CUSTOM_JSON" | jq -s 'add')
# Count env files loaded
ENV_FILE_COUNT=$(ls -1 .github/env/*.env 2>/dev/null | wc -l | tr -d ' ')

# Validate merged configuration
if [[ -z "$ENV_JSON" ]] || [[ "$ENV_JSON" == "null" ]] || [[ "$ENV_JSON" == "{}" ]]; then
echo "❌ ERROR: No valid environment variables found!" >&2
echo " Please ensure .env.base exists with valid configuration." >&2
exit 1
fi

# Output final merged configuration
# Output final configuration
echo "env-json<<EOF" >> $GITHUB_OUTPUT
echo "$ENV_JSON" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

# Log summary
TOTAL_COUNT=$(echo "$ENV_JSON" | jq 'keys | length')
echo "✅ Environment configuration loaded successfully"
echo "📊 Total variables: $TOTAL_COUNT"
echo "📁 Env files loaded: $ENV_FILE_COUNT"

# Show merge summary if both files were used
if [[ -f ".github/.env.custom" ]] && [[ "$CUSTOM_COUNT" -gt 0 ]]; then
echo "📊 Configuration sources:"
echo " - Base (.env.base): $BASE_COUNT variables"
echo " - Custom (.env.custom): $CUSTOM_COUNT overrides"
echo " - Total merged: $TOTAL_COUNT variables"
fi

# Extract and validate PRIMARY_RUNNER for backward compatibility
# Extract and validate PRIMARY_RUNNER
PRIMARY_RUNNER=$(echo "$ENV_JSON" | jq -r '.PRIMARY_RUNNER')
if [[ -z "$PRIMARY_RUNNER" ]] || [[ "$PRIMARY_RUNNER" == "null" ]]; then
echo "❌ ERROR: PRIMARY_RUNNER is not set in the configuration!" >&2
Expand All @@ -186,33 +101,6 @@ runs:
echo "primary-runner=$PRIMARY_RUNNER" >> $GITHUB_OUTPUT
echo "🖥️ Primary runner: $PRIMARY_RUNNER"

# Output configuration file discovery information
BASE_FOUND="false"
CUSTOM_FOUND="false"
CONFIG_MODE="new"

if [[ -f ".github/.env.base" ]]; then
BASE_FOUND="true"
fi

if [[ -f ".github/.env.custom" ]]; then
CUSTOM_FOUND="true"
fi

# Determine configuration mode
if [[ "$CUSTOM_FOUND" == "true" ]]; then
CONFIG_MODE="new"
else
CONFIG_MODE="base-only"
fi

# Set default counts for missing variables
BASE_COUNT=${BASE_COUNT:-0}
CUSTOM_COUNT=${CUSTOM_COUNT:-0}

# Output all the discovery information
echo "base-file-found=$BASE_FOUND" >> $GITHUB_OUTPUT
echo "custom-file-found=$CUSTOM_FOUND" >> $GITHUB_OUTPUT
echo "base-var-count=$BASE_COUNT" >> $GITHUB_OUTPUT
echo "custom-var-count=$CUSTOM_COUNT" >> $GITHUB_OUTPUT
echo "config-mode=$CONFIG_MODE" >> $GITHUB_OUTPUT
# Output counts
echo "env-file-count=$ENV_FILE_COUNT" >> $GITHUB_OUTPUT
echo "var-count=$TOTAL_COUNT" >> $GITHUB_OUTPUT
40 changes: 40 additions & 0 deletions .github/docs/repository-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Repository Features

A comprehensive list of built-in features that ship with this repository.

<br>

---

<br>

* **Continuous Integration on Autopilot** with [GitHub Actions](https://github.com/features/actions) – every push is built, tested, and reported in minutes.
* **Pull‑Request Flow That Merges Itself** thanks to [auto‑merge](../workflows/auto-merge-on-approval.yml) and hands‑free [Dependabot auto‑merge](../workflows/dependabot-auto-merge.yml).
* **One‑Command Builds** powered by battle‑tested [MAGE-X](https://github.com/mrz1836/mage-x) targets for linting, testing, releases, and more.
* **First‑Class Dependency Management** using native [Go Modules](https://github.com/golang/go/wiki/Modules).
* **Uniform Code Style** via [gofumpt](https://github.com/mvdan/gofumpt) plus zero‑noise linting with [golangci‑lint](https://github.com/golangci/golangci-lint).
* **Confidence‑Boosting Tests** with [testify](https://github.com/stretchr/testify), the Go [race detector](https://blog.golang.org/race-detector), crystal‑clear [HTML coverage](https://blog.golang.org/cover) snapshots, and automatic reporting via internal coverage system.
* **Hands‑Free Releases** delivered by [GoReleaser](https://github.com/goreleaser/goreleaser) whenever you create a [new Tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging).
* **Relentless Dependency & Vulnerability Scans** via [Dependabot](https://dependabot.com) (runs daily at 8am to ensure broadcast dependencies are always current), [Nancy](https://github.com/sonatype-nexus-community/nancy), and [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck).
* **Security Posture by Default** with [CodeQL](https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/about-code-scanning), [OpenSSF Scorecard](https://openssf.org), and secret‑leak detection via [gitleaks](https://github.com/gitleaks/gitleaks).
* **Automatic Syndication** to [pkg.go.dev](https://pkg.go.dev/) on every release for instant godoc visibility.
* **Polished Community Experience** using rich templates for [Issues & PRs](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-go-broadcastsitory).
* **All the Right Meta Files** (`LICENSE`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SUPPORT.md`, `SECURITY.md`) pre‑filled and ready.
* **Code Ownership** clarified through a [CODEOWNERS](../CODEOWNERS) file, keeping reviews fast and focused.
* **Zero‑Noise Dev Environments** with tuned editor settings ([`.editorconfig`](../../.editorconfig)) plus curated *ignore* files for [VS Code](../../.editorconfig), [Docker](../../.dockerignore), and [Git](../../.gitignore).
* **Label Sync Magic**: your repo labels stay in lock‑step with [.github/labels.yml](../labels.yml).
* **Friendly First PR Workflow** – newcomers get a warm welcome thanks to a dedicated [workflow](../workflows/pull-request-management.yml).
* **Standards‑Compliant Docs** adhering to the [standard‑readme](https://github.com/RichardLitt/standard-readme/blob/master/spec.md) spec.
* **Instant Cloud Workspaces** via [Gitpod](https://gitpod.io/) – spin up a fully configured dev environment with automatic linting and tests.
* **Out‑of‑the‑Box VS Code Happiness** with a preconfigured [Go](https://code.visualstudio.com/docs/languages/go) workspace and [`.vscode`](../../.vscode) folder with all the right settings.
* **Optional Release Broadcasts** to your community via [Slack](https://slack.com), [Discord](https://discord.com), or [Twitter](https://twitter.com) – plug in your webhook.
* **AI Playbook** – machine‑readable guidelines in [tech conventions](../tech-conventions/ai-compliance.md)
* **Go-Pre-commit System** - [High-performance Go-native pre-commit hooks](https://github.com/mrz1836/go-pre-commit) with 17x faster execution—run the same formatting, linting, and tests before every commit, just like CI.
* **Zero Python Dependencies** - Pure Go implementation with [modular environment-based configuration](../env/README.md).
* **DevContainers for Instant Onboarding** – Launch a ready-to-code environment in seconds with [VS Code DevContainers](https://containers.dev/) and the included [.devcontainer.json](../../.devcontainer.json) config.

<br>

---

[← Back to README](../../README.md)
Loading
Loading