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
1 change: 1 addition & 0 deletions POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Typical gates for incremental development:
- Informational diagnostics should be bounded; avoid repeating non-actionable messages across stages.
- Timeouts and pull retry/backoff are configurable to bound long-running operations (`SUPRAGOFLOW_TIMEOUT_*`, `SUPRAGOFLOW_PULL_RETRIES`, `SUPRAGOFLOW_PULL_BACKOFF_SEC`).
- Long-running operations provide liveness/progress feedback with configurable heartbeat interval (`SUPRAGOFLOW_HEARTBEAT_SEC`).
- Heartbeat logs should include bounded resource telemetry (process CPU/memory and host memory/load/disk) and remain configurable (`SUPRAGOFLOW_HEARTBEAT_RESOURCE=1|0`).
- Cache strategy is configurable (`SUPRAGOFLOW_CACHE_STRATEGY=volume|host`); CI should prefer `host` to enable cache restore/save across runs.
- Host cache should be size-bounded in automation (`SUPRAGOFLOW_HOST_CACHE_MAX_MB`) and pruned with `gg cache-prune`.
- `gg diagnose` should produce bounded diagnostics bundles suitable for corrective maintenance and CI triage.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Optional strict compatibility checks are supported with:
Runtime bounds are configurable with env vars, including:
`SUPRAGOFLOW_TIMEOUT_STAGE_SEC`, `SUPRAGOFLOW_TIMEOUT_PULL_SEC`, `SUPRAGOFLOW_TIMEOUT_IMAGE_BUILD_SEC`, `SUPRAGOFLOW_TIMEOUT_SMOKE_SEC`, `SUPRAGOFLOW_PULL_RETRIES`, `SUPRAGOFLOW_PULL_BACKOFF_SEC`.
Liveness heartbeat interval for long operations is configurable via `SUPRAGOFLOW_HEARTBEAT_SEC` (set `0` to disable periodic in-progress logs).
Resource telemetry in heartbeat logs is enabled by default via `SUPRAGOFLOW_HEARTBEAT_RESOURCE=1` and includes process CPU/memory plus host memory/load/disk usage; set `SUPRAGOFLOW_HEARTBEAT_RESOURCE=0` to disable resource fields.
Cache behavior is configurable via `SUPRAGOFLOW_CACHE_STRATEGY`:
- `volume` (default): Docker named volumes for local iterative runs
- `host`: bind mounts under `SUPRAGOFLOW_HOST_CACHE_ROOT` (default `.cache/supragoflow`) for CI cache restore/save compatibility
Expand Down
1 change: 1 addition & 0 deletions scripts/check-policy-conformance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fi
grep -q "All GitHub Actions must be pinned to immutable commit SHAs" POLICY.md || fail "POLICY.md missing action pinning policy statement"
grep -q "Release workflows publish explicit release tags only" POLICY.md || fail "POLICY.md missing explicit release tag policy statement"
grep -q "Release GHCR tags are immutable by default" POLICY.md || fail "POLICY.md missing release tag immutability policy statement"
grep -q "Heartbeat logs should include bounded resource telemetry" POLICY.md || fail "POLICY.md missing heartbeat resource telemetry policy statement"
grep -q "Container images must default to non-root execution identity" POLICY.md || fail "POLICY.md missing non-root container execution identity policy statement"
grep -Eq 'scripts/gg.*invoker UID:GID mapping' POLICY.md || fail "POLICY.md missing invoker UID:GID mapping policy statement"

Expand Down
44 changes: 43 additions & 1 deletion scripts/gg
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ TIMEOUT_PULL_SEC="${SUPRAGOFLOW_TIMEOUT_PULL_SEC:-300}"
TIMEOUT_IMAGE_BUILD_SEC="${SUPRAGOFLOW_TIMEOUT_IMAGE_BUILD_SEC:-1800}"
TIMEOUT_SMOKE_SEC="${SUPRAGOFLOW_TIMEOUT_SMOKE_SEC:-600}"
HEARTBEAT_SEC="${SUPRAGOFLOW_HEARTBEAT_SEC:-30}"
HEARTBEAT_RESOURCE="${SUPRAGOFLOW_HEARTBEAT_RESOURCE:-1}"
TEST_PARALLEL="${SUPRAGOFLOW_TEST_PARALLEL:-}"
BUILD_PARALLEL="${SUPRAGOFLOW_BUILD_PARALLEL:-}"
DOCKER_QUIET=0
Expand Down Expand Up @@ -54,6 +55,47 @@ CACHE_STRATEGY="${SUPRAGOFLOW_CACHE_STRATEGY:-volume}"
HOST_CACHE_ROOT="${SUPRAGOFLOW_HOST_CACHE_ROOT:-${ROOT}/.cache/supragoflow}"
CONTRACT_FILE="${ROOT}/contracts/gg-interface.json"

emit_resource_heartbeat() {
local pid="$1"
local desc="$2"
local elapsed="$3"
local proc_metrics=""
local mem_metrics=""
local disk_metrics=""
local load_metrics=""

if [[ "${HEARTBEAT_RESOURCE}" != "1" ]]; then
log_msg info "in-progress: ${desc} elapsed=${elapsed}s"
return
fi

if command -v ps >/dev/null 2>&1; then
proc_metrics="$(ps -p "${pid}" -o %cpu=,%mem=,rss=,vsz=,etime=,stat= 2>/dev/null | awk '{printf "proc_cpu_pct=%s proc_mem_pct=%s proc_rss_kb=%s proc_vsz_kb=%s proc_etime=%s proc_state=%s", $1,$2,$3,$4,$5,$6}')"
fi

if [[ -r /proc/meminfo ]]; then
mem_metrics="$(awk '
/MemTotal:/ {total=$2}
/MemAvailable:/ {avail=$2}
END {
if (total > 0) {
used=total-avail
printf "host_mem_used_mb=%.0f host_mem_avail_mb=%.0f", used/1024, avail/1024
}
}' /proc/meminfo)"
fi

if [[ -r /proc/loadavg ]]; then
load_metrics="$(awk '{printf "host_load_1m=%s host_load_5m=%s host_load_15m=%s", $1,$2,$3}' /proc/loadavg)"
fi

if command -v df >/dev/null 2>&1; then
disk_metrics="$(df -Pm "${ROOT}" 2>/dev/null | awk 'NR==2 {printf "disk_used_mb=%s disk_avail_mb=%s disk_use_pct=%s", $3,$4,$5}')"
fi

log_msg info "in-progress: ${desc} elapsed=${elapsed}s ${proc_metrics} ${mem_metrics} ${load_metrics} ${disk_metrics}"
}

run_with_timeout() {
local timeout_sec="$1"; shift
local desc="$1"; shift
Expand All @@ -73,7 +115,7 @@ run_with_timeout() {
elapsed=$((now_ts - start_ts))

if [[ "$HEARTBEAT_SEC" =~ ^[0-9]+$ ]] && [[ "$HEARTBEAT_SEC" -gt 0 ]] && (( elapsed > 0 )) && (( elapsed % HEARTBEAT_SEC == 0 )); then
log_msg info "in-progress: ${desc} elapsed=${elapsed}s"
emit_resource_heartbeat "$pid" "$desc" "$elapsed"
fi

if [[ "$timeout_sec" =~ ^[0-9]+$ ]] && [[ "$timeout_sec" -gt 0 ]] && (( elapsed >= timeout_sec )); then
Expand Down