Update guardrails.yml

This commit is contained in:
2025-12-26 23:28:09 -06:00
parent b2839c10a5
commit e5ae493aaa

View File

@@ -51,21 +51,16 @@ permissions:
contents: read contents: read
jobs: jobs:
guardrails: release_config:
name: Setting Guardrails name: Release configuration
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- name: Checkout - name: Guardrails: release secrets and vars
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate required repository secrets and variables
env: env:
PROFILE: ${{ github.event.inputs.profile || 'all' }} PROFILE: ${{ github.event.inputs.profile || 'all' }}
# Release pipeline SFTP configuration (secrets + vars)
FTP_HOST: ${{ secrets.FTP_HOST }} FTP_HOST: ${{ secrets.FTP_HOST }}
FTP_USER: ${{ secrets.FTP_USER }} FTP_USER: ${{ secrets.FTP_USER }}
FTP_KEY: ${{ secrets.FTP_KEY }} FTP_KEY: ${{ secrets.FTP_KEY }}
@@ -74,28 +69,169 @@ jobs:
FTP_PROTOCOL: ${{ secrets.FTP_PROTOCOL }} FTP_PROTOCOL: ${{ secrets.FTP_PROTOCOL }}
FTP_PORT: ${{ secrets.FTP_PORT }} FTP_PORT: ${{ secrets.FTP_PORT }}
FTP_PATH_SUFFIX: ${{ vars.FTP_PATH_SUFFIX }} FTP_PATH_SUFFIX: ${{ vars.FTP_PATH_SUFFIX }}
run: | run: |
set -euxo pipefail set -euxo pipefail
profile="${PROFILE}" profile="${PROFILE}"
if [ "${profile}" != "all" ] && [ "${profile}" != "release" ] && [ "${profile}" != "scripts" ]; then
echo "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
# Centralized checklist. if [ "${profile}" = "scripts" ]; then
required_release_secrets=( echo "Profile scripts selected. Skipping release configuration checks." >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
required=(
"FTP_HOST" "FTP_HOST"
"FTP_USER" "FTP_USER"
"FTP_KEY" "FTP_KEY"
"FTP_PATH" "FTP_PATH"
) )
optional_release=( optional=(
"FTP_PASSWORD" # Only needed for encrypted PPK conversion "FTP_PASSWORD"
"FTP_PROTOCOL" # Defaults to sftp in pipelines "FTP_PROTOCOL"
"FTP_PORT" # Defaults to provider default "FTP_PORT"
"FTP_PATH_SUFFIX" # Variable, optional "FTP_PATH_SUFFIX"
) )
missing=()
missing_optional=()
for k in "${required[@]}"; do
v="${!k:-}"
if [ -z "${v}" ]; then
missing+=("${k}")
fi
done
for k in "${optional[@]}"; do
v="${!k:-}"
if [ -z "${v}" ]; then
missing_optional+=("${k}")
fi
done
proto="${FTP_PROTOCOL:-sftp}"
if [ -n "${FTP_PROTOCOL:-}" ] && [ "${proto}" != "sftp" ]; then
missing+=("FTP_PROTOCOL_INVALID")
fi
# Key format guardrail (do not print key material).
if [ -n "${FTP_KEY:-}" ]; then
first_line="$(printf '%s' "${FTP_KEY}" | head -n 1 || true)"
if printf '%s' "${first_line}" | grep -q '^PuTTY-User-Key-File-'; then
key_format="ppk"
elif printf '%s' "${first_line}" | grep -q '^-----BEGIN '; then
key_format="openssh"
else
key_format="unknown"
missing+=("FTP_KEY_FORMAT")
fi
else
key_format="missing"
fi
{
echo "### Guardrails: release configuration"
echo "KEY_FORMAT=${key_format}"
echo ""
echo "### Guardrails report (JSON)"
echo "```json"
printf '{"profile":"%s","checked":{"required":[' "${profile}"
sep=""
for c in "${required[@]}"; do
printf '%s"%s"' "${sep}" "${c}"
sep=",";
done
printf '],"optional":['
sep=""
for c in "${optional[@]}"; do
printf '%s"%s"' "${sep}" "${c}"
sep=",";
done
printf ']},"missing_required":['
sep=""
for m in "${missing[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=",";
done
printf '],"missing_optional":['
sep=""
for m in "${missing_optional[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=",";
done
printf ']}
'
echo "```"
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${#missing[@]}" -gt 0 ]; then
echo "### Missing required release configuration" >> "${GITHUB_STEP_SUMMARY}"
for m in "${missing[@]}"; do
echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}"
done
fi
if [ "${#missing_optional[@]}" -gt 0 ]; then
echo "### Missing optional release configuration" >> "${GITHUB_STEP_SUMMARY}"
for m in "${missing_optional[@]}"; do
echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}"
done
fi
if [ "${#missing[@]}" -gt 0 ]; then
echo "MISSING_REQUIRED: ${missing[*]}" >&2
echo "ERROR: Guardrails failed. Missing required release configuration." >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
scripts_config:
name: Scripts and tooling
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Guardrails: script files and toolchain
env:
PROFILE: ${{ github.event.inputs.profile || 'all' }}
run: |
set -euxo pipefail
profile="${PROFILE}"
if [ "${profile}" != "all" ] && [ "${profile}" != "release" ] && [ "${profile}" != "scripts" ]; then
echo "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
if [ "${profile}" = "release" ]; then
echo "Profile release selected. Skipping scripts checks." >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
required_script_files=( required_script_files=(
"scripts/validate/manifest.sh"
"scripts/validate/xml_wellformed.sh"
"scripts/validate/changelog.sh"
"scripts/validate/tabs.sh"
"scripts/validate/paths.sh"
"scripts/validate/version_alignment.sh"
"scripts/validate/language_structure.sh"
"scripts/validate/php_syntax.sh"
"scripts/validate/no_secrets.sh"
"scripts/validate/license_headers.sh"
)
legacy_script_files=(
"scripts/validate_manifest.sh" "scripts/validate_manifest.sh"
"scripts/validate_xml_wellformed.sh" "scripts/validate_xml_wellformed.sh"
"scripts/validate_changelog.sh" "scripts/validate_changelog.sh"
@@ -108,163 +244,49 @@ jobs:
"scripts/validate_license_headers.sh" "scripts/validate_license_headers.sh"
) )
missing=() fi
missing_optional=() done
missing_files=()
check_release() { # Report legacy scripts if present so teams can clean up.
for k in "${required_release_secrets[@]}"; do for f in "${legacy_script_files[@]}"; do
v="${!k:-}" if [ -f "${f}" ]; then
if [ -z "${v}" ]; then legacy_present+=("${f}")
missing+=("${k}")
fi
done
# Optional configuration.
for k in "${optional_release[@]}"; do
v="${!k:-}"
if [ -z "${v}" ]; then
missing_optional+=("${k}")
fi
done
# Protocol sanity if provided.
proto="${FTP_PROTOCOL:-sftp}"
if [ -n "${FTP_PROTOCOL:-}" ] && [ "${proto}" != "sftp" ]; then
missing+=("FTP_PROTOCOL_INVALID")
fi fi
done
# Key format guardrail (do not print key). tools_to_install=()
if [ -n "${FTP_KEY:-}" ]; then command -v php >/dev/null 2>&1 || tools_to_install+=("php-cli")
first_line="$(printf '%s' "${FTP_KEY}" | head -n 1 || true)" command -v xmllint >/dev/null 2>&1 || tools_to_install+=("libxml2-utils")
if printf '%s' "${first_line}" | grep -q '^PuTTY-User-Key-File-'; then
key_format="ppk"
elif printf '%s' "${first_line}" | grep -q '^-----BEGIN '; then
key_format="openssh"
else
key_format="unknown"
missing+=("FTP_KEY_FORMAT")
fi
else
key_format="missing"
fi
echo "KEY_FORMAT=${key_format}" >> "${GITHUB_STEP_SUMMARY}" if [ "${#tools_to_install[@]}" -gt 0 ]; then
} echo "Installing missing tools: ${tools_to_install[*]}" >> "${GITHUB_STEP_SUMMARY}"
sudo apt-get update -y
check_scripts() { ntf '%s"%s"' "${sep}" "${c}"
for f in "${required_script_files[@]}"; do
if [ ! -f "${f}" ]; then
missing_files+=("${f}")
fi
done
# Tooling expectations: scripts may rely on php and xmllint.
# Do not fail on tooling here; CI runners can install dependencies.
# Still report as guardrail visibility.
tool_missing=()
command -v php >/dev/null 2>&1 || tool_missing+=("php")
command -v xmllint >/dev/null 2>&1 || tool_missing+=("xmllint")
if [ "${#tool_missing[@]}" -gt 0 ]; then
echo "WARN: Missing tools on runner (install in workflow when required): ${tool_missing[*]}" >> "${GITHUB_STEP_SUMMARY}"
fi
}
case "${profile}" in
release)
check_release
;;
scripts)
check_scripts
;;
all)
check_release
check_scripts
;;
*)
echo "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
# Emit report.
{
echo "### Guardrails report (JSON)"
echo "```json"
printf '{"repository":"%s","profile":"%s","checked":{' "${GITHUB_REPOSITORY}" "${profile}"
printf '"release_required":['
sep=""
for c in "${required_release_secrets[@]}"; do
printf '%s"%s"' "${sep}" "${c}"
sep=","; sep=",";
done done
printf ']},"missing_script_files":['
printf '],"release_optional":['
sep=""
for c in "${optional_release[@]}"; do
printf '%s"%s"' "${sep}" "${c}"
sep=",";
done
printf '],"script_files":['
sep=""
for c in "${required_script_files[@]}"; do
printf '%s"%s"' "${sep}" "${c}"
sep=",";
done
printf ']},'
printf '"missing_required":['
sep=""
for m in "${missing[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=",";
done
printf '],"missing_optional":['
sep=""
for m in "${missing_optional[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=",";
done
printf '],"missing_script_files":['
sep="" sep=""
for m in "${missing_files[@]}"; do for m in "${missing_files[@]}"; do
printf '%s"%s"' "${sep}" "${m}" printf '%s"%s"' "${sep}" "${m}"
sep=","; sep=",";
done done
printf '],"legacy_present":['
sep=""
for m in "${legacy_present[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=",";
done
printf ']}' printf ']}'
echo echo
echo "```" echo "```"
} >> "${GITHUB_STEP_SUMMARY}" } >> "${GITHUB_STEP_SUMMARY}"
# Human-readable missing items (in addition to JSON)
if [ "${#missing[@]}" -gt 0 ]; then
echo "### Missing required configuration" >> "${GITHUB_STEP_SUMMARY}"
for m in "${missing[@]}"; do
echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}"
done
fi
if [ "${#missing_optional[@]}" -gt 0 ]; then
echo "### Missing optional configuration" >> "${GITHUB_STEP_SUMMARY}"
for m in "${missing_optional[@]}"; do
echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}"
done
fi
if [ "${#missing_files[@]}" -gt 0 ]; then if [ "${#missing_files[@]}" -gt 0 ]; then
echo "### Missing script files" >> "${GITHUB_STEP_SUMMARY}" echo "### Missing script files" >> "${GITHUB_STEP_SUMMARY}"
for m in "${missing_files[@]}"; do for m in "${missing_files[@]}"; do
echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}" echo "- ${m}" >> "${GITHUB_STEP_SUMMARY}"
done done
fi echo "MISSING_SCRIPT_FILES: ${missing_files[*]}" >&2
echo "ERROR: Guardrails failed. Missing required script files." >> "${GITHUB_STEP_SUMMARY}"
# Fail the workflow if required items are missing.
if [ "${#missing[@]}" -gt 0 ] || [ "${#missing_files[@]}" -gt 0 ]; then
echo "ERROR: Guardrails failed. Missing required configuration or script files." >> "${GITHUB_STEP_SUMMARY}"
exit 1 exit 1
fi fi