Narrow Gitea Actions deploy guardrail
Homelab Main / validate-and-deploy (push) Failing after 5s
Details
Homelab Main / validate-and-deploy (push) Failing after 5s
Details
This commit is contained in:
parent
c470e64070
commit
e59e3258fc
|
|
@ -147,7 +147,7 @@ jobs:
|
|||
tofu -chdir="${stack}" validate
|
||||
done
|
||||
|
||||
- name: Block automatic deploy for high-impact changes
|
||||
- name: Block automatic deploy for Raspberry Pi Gitea changes
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
|
|
@ -156,14 +156,92 @@ jobs:
|
|||
)"
|
||||
|
||||
if [[ -n "${event_before}" && ! "${event_before}" =~ ^0+$ ]]; then
|
||||
changed_files="$(git diff --name-only "${event_before}" HEAD)"
|
||||
base_ref="${event_before}"
|
||||
else
|
||||
changed_files="$(git diff-tree --no-commit-id --name-only -r HEAD)"
|
||||
base_ref="$(git rev-parse HEAD^ 2>/dev/null || git hash-object -t tree /dev/null)"
|
||||
fi
|
||||
changed_files="$(git diff --name-only "${base_ref}" HEAD)"
|
||||
printf '%s\n' "${changed_files}"
|
||||
|
||||
if printf '%s\n' "${changed_files}" | grep -Eq '^(bootstrap/(provisioning|cluster|platform|edge)/|infra/gitea/|lab[.]sh|[.]gitea/workflows/)'; then
|
||||
echo "High-impact bootstrap, runner, or workflow changes require a manual Debian run."
|
||||
blocked_files="$(printf '%s\n' "${changed_files}" | grep -E '^infra/gitea/' || true)"
|
||||
if printf '%s\n' "${changed_files}" | grep -qx 'lab.sh' &&
|
||||
python3 - "${base_ref}" <<'PY'
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
base_ref = sys.argv[1]
|
||||
path = "lab.sh"
|
||||
target_functions = {
|
||||
"deploy_gitea",
|
||||
"install_gitea_backup_timer",
|
||||
"backup_gitea",
|
||||
"drill_gitea_restore",
|
||||
}
|
||||
|
||||
|
||||
def function_ranges(content):
|
||||
starts = []
|
||||
for index, line in enumerate(content.splitlines(), 1):
|
||||
match = re.match(r"^([A-Za-z_][A-Za-z0-9_]*)\(\) \{", line)
|
||||
if match:
|
||||
starts.append((index, match.group(1)))
|
||||
|
||||
ranges = []
|
||||
for offset, (start, name) in enumerate(starts):
|
||||
end = starts[offset + 1][0] - 1 if offset + 1 < len(starts) else len(content.splitlines())
|
||||
if name in target_functions:
|
||||
ranges.append((start, end))
|
||||
return ranges
|
||||
|
||||
|
||||
current_ranges = function_ranges(open(path, encoding="utf-8").read())
|
||||
try:
|
||||
base_content = subprocess.check_output(
|
||||
["git", "show", f"{base_ref}:{path}"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True,
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
base_ranges = []
|
||||
else:
|
||||
base_ranges = function_ranges(base_content)
|
||||
|
||||
diff = subprocess.check_output(
|
||||
["git", "diff", "--unified=0", base_ref, "HEAD", "--", path],
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def overlaps(start, length, ranges):
|
||||
if length == 0:
|
||||
end = start
|
||||
else:
|
||||
end = start + length - 1
|
||||
return any(start <= range_end and end >= range_start for range_start, range_end in ranges)
|
||||
|
||||
|
||||
for line in diff.splitlines():
|
||||
match = re.match(r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@", line)
|
||||
if not match:
|
||||
continue
|
||||
old_start = int(match.group(1))
|
||||
old_length = int(match.group(2) or "1")
|
||||
new_start = int(match.group(3))
|
||||
new_length = int(match.group(4) or "1")
|
||||
if overlaps(old_start, old_length, base_ranges) or overlaps(new_start, new_length, current_ranges):
|
||||
sys.exit(0)
|
||||
|
||||
sys.exit(1)
|
||||
PY
|
||||
then
|
||||
blocked_files="${blocked_files}"$'\n'"lab.sh"
|
||||
fi
|
||||
blocked_files="$(printf '%s\n' "${blocked_files}" | sed '/^$/d' | sort -u)"
|
||||
|
||||
if [[ -n "${blocked_files}" ]]; then
|
||||
printf '%s\n' "${blocked_files}"
|
||||
echo "Raspberry Pi Gitea service changes require a manual Debian run."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -407,12 +407,11 @@ This repo includes a Gitea Actions workflow at
|
|||
a repository-scoped Debian host runner with the label `homelab-debian`.
|
||||
|
||||
The workflow validates shell syntax, Kubernetes manifests, and all OpenTofu
|
||||
stacks before deployment. It automatically stops when high-impact files under
|
||||
`bootstrap/provisioning`, `bootstrap/cluster`, `bootstrap/platform`,
|
||||
`bootstrap/edge`, `infra/gitea`, `lab.sh`, or `.gitea/workflows` change; those
|
||||
changes still require a manual Debian run. Lower-risk app changes proceed to
|
||||
`./lab.sh apps` after validation passes, which skips Gitea, Pimox, cluster,
|
||||
platform, and edge changes.
|
||||
stacks before deployment. Automatic deploy is blocked only for Raspberry Pi
|
||||
Gitea service changes: files under `infra/gitea/`, or edits inside the
|
||||
`deploy_gitea`, `install_gitea_backup_timer`, `backup_gitea`, or
|
||||
`drill_gitea_restore` functions in `lab.sh`. Other changes proceed to
|
||||
`./lab.sh apps` after validation passes.
|
||||
|
||||
`./lab.sh bootstrap-gitea-repo` also registers the Debian host SSH public key
|
||||
with the Gitea repository and switches the Debian working copy's `gitea` remote
|
||||
|
|
|
|||
Loading…
Reference in New Issue