Create config_guardrails.yml

This commit is contained in:
2025-12-26 23:07:22 -06:00
parent c25f2a5d9c
commit 8f626e1378

222
.github/workflows/config_guardrails.yml vendored Normal file
View File

@@ -0,0 +1,222 @@
# ============================================================================
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Validation
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/config_guardrails.yml
# VERSION: 03.05.00
# BRIEF: Validate that required repository secrets and variables exist for workflows and scripts.
# NOTE: Secrets are never printed. This workflow only verifies presence and emits an audit JSON report.
# ============================================================================
name: Config Guardrails (secrets and vars)
on:
workflow_dispatch:
inputs:
profile:
description: "Which configuration profile to validate. release checks SFTP variables used by release_pipeline. scripts checks baseline script prerequisites. all runs both."
required: true
default: all
type: choice
options:
- all
- release
- scripts
pull_request:
paths:
- ".github/workflows/**"
- "scripts/**"
permissions:
contents: read
jobs:
guardrails:
name: Guardrails
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate required repository secrets and variables
env:
PROFILE: ${{ github.event.inputs.profile || 'all' }}
# Release pipeline SFTP configuration (secrets + vars)
FTP_HOST: ${{ secrets.FTP_HOST }}
FTP_USER: ${{ secrets.FTP_USER }}
FTP_KEY: ${{ secrets.FTP_KEY }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
FTP_PATH: ${{ secrets.FTP_PATH }}
FTP_PROTOCOL: ${{ secrets.FTP_PROTOCOL }}
FTP_PORT: ${{ secrets.FTP_PORT }}
FTP_PATH_SUFFIX: ${{ vars.FTP_PATH_SUFFIX }}
run: |
set -euxo pipefail
profile="${PROFILE}"
# Centralized checklist.
required_release_secrets=(
"FTP_HOST"
"FTP_USER"
"FTP_KEY"
"FTP_PATH"
)
optional_release=(
"FTP_PASSWORD" # Only needed for encrypted PPK conversion
"FTP_PROTOCOL" # Defaults to sftp in pipelines
"FTP_PORT" # Defaults to provider default
"FTP_PATH_SUFFIX" # Variable, optional
)
required_script_files=(
"scripts/verify_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"
)
missing=()
missing_optional=()
missing_files=()
check_release() {
for k in "${required_release_secrets[@]}"; do
v="${!k:-}"
if [ -z "${v}" ]; then
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
# Key format guardrail (do not print key).
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 "KEY_FORMAT=${key_format}" >> "${GITHUB_STEP_SUMMARY}"
}
check_scripts() {
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 "### Config guardrails report (JSON)"
echo "```json"
printf '{"repository":"%s","profile":"%s","missing_required":[' "${GITHUB_REPOSITORY}" "${profile}"
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=""
for m in "${missing_files[@]}"; do
printf '%s"%s"' "${sep}" "${m}"
sep=","
done
printf ']}'
echo
echo "```"
} >> "${GITHUB_STEP_SUMMARY}"
# Fail the workflow if required items are missing.
if [ "${#missing[@]}" -gt 0 ] || [ "${#missing_files[@]}" -gt 0 ]; then
echo "ERROR: Config guardrails failed. Missing required configuration or script files." >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi