diff --git a/images/p3-sandbox-lifecycle-base/Dockerfile b/images/p3-sandbox-lifecycle-base/Dockerfile index 110e205..52878d9 100644 --- a/images/p3-sandbox-lifecycle-base/Dockerfile +++ b/images/p3-sandbox-lifecycle-base/Dockerfile @@ -2,9 +2,9 @@ FROM alpine:3.21 # OCI labels for package linking and metadata LABEL org.opencontainers.image.source="https://github.com/lf-certification/p3-forge" LABEL org.opencontainers.image.title="p3-sandbox-lifecycle-base" -LABEL org.opencontainers.image.description="Base image for sandbox lifecycle hook images with bash, ssh, and yq runtime" +LABEL org.opencontainers.image.description="Base image for sandbox lifecycle hook images with bash, jq, ssh, and yq runtime" -RUN apk add --no-cache openssh-client=9.9_p2-r0 bash=5.2.37-r0 && \ +RUN apk add --no-cache openssh-client=9.9_p2-r0 bash=5.2.37-r0 jq=1.7.1-r0 && \ wget -q https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq && \ chmod a+x /usr/local/bin/yq diff --git a/images/p3-sandbox-lifecycle-base/entrypoint.sh b/images/p3-sandbox-lifecycle-base/entrypoint.sh index 562030c..a84262b 100755 --- a/images/p3-sandbox-lifecycle-base/entrypoint.sh +++ b/images/p3-sandbox-lifecycle-base/entrypoint.sh @@ -1,14 +1,54 @@ -#!/bin/sh +#!/bin/bash -# entrypoint.sh - Sample hook runner for Sandbox Operator -# This script simulates hook execution based on the hook name passed as first argument +# entrypoint.sh - Lifecycle hook runner for Sandbox Operator +# The hook name is passed as the first argument. -set -e +set -euo pipefail + +timestamp_stream() { + jq --raw-input --compact-output --unbuffered \ + '{timestamp: (now * 1000 | floor), message: .}' +} + +timestamp_line() { + printf '%s\n' "$1" | timestamp_stream +} + +run_timestamped() { + # Keep streams separate so log collectors retain stdout/stderr status. + local stdout_fd stdout_pid stderr_fd stderr_pid + local hook_status stdout_status stderr_status + + exec {stdout_fd}> >(timestamp_stream) + stdout_pid=$! + exec {stderr_fd}> >(timestamp_stream >&2) + stderr_pid=$! + + # Collect every status without allowing a logging failure to mask the hook. + set +e + "$@" >&"$stdout_fd" 2>&"$stderr_fd" + hook_status=$? + exec {stdout_fd}>&- + exec {stderr_fd}>&- + wait "$stdout_pid" + stdout_status=$? + wait "$stderr_pid" + stderr_status=$? + set -e + + if ((hook_status != 0)); then + return "$hook_status" + fi + if ((stdout_status != 0)); then + return "$stdout_status" + fi + return "$stderr_status" +} if [ $# -eq 0 ]; then - echo "Error: No hook name provided" - echo "Usage: $0 [additional-args...]" - echo "Available hooks: setup, score" + timestamp_line "Error: No hook name provided" >&2 + timestamp_line "Usage: $0 [additional-args...]" >&2 + timestamp_line "Available hooks: setup, score" >&2 exit 1 fi @@ -17,21 +57,22 @@ HOOK_NAME="$1" # Validate hook name case "$HOOK_NAME" in setup) - echo "Running setup hook..." - /var/lib/p3-platform/hooks/setup.sh - echo "Setup completed successfully" + timestamp_line "Running setup hook..." + run_timestamped /var/lib/p3-platform/hooks/setup.sh + timestamp_line "Setup completed successfully" ;; score) - echo "Running score hook..." + timestamp_line "Running score hook..." + # The operator parses the score report directly from this output stream. /var/lib/p3-platform/hooks/score.sh - echo "Scoring completed successfully" + timestamp_line "Scoring completed successfully" ;; *) - echo "Error: Invalid hook name '$HOOK_NAME'" - echo "Available hooks: setup, score" + timestamp_line "Error: Invalid hook name '$HOOK_NAME'" >&2 + timestamp_line "Available hooks: setup, score" >&2 exit 1 ;; esac -echo "Hook '$HOOK_NAME' finished" +timestamp_line "Hook '$HOOK_NAME' finished" exit 0