diff --git a/.github/scripts/package-artifacts.sh b/.github/scripts/package-artifacts.sh index e9771517..9e88fa87 100755 --- a/.github/scripts/package-artifacts.sh +++ b/.github/scripts/package-artifacts.sh @@ -21,10 +21,16 @@ echo "==> app.tar.gz from source (git archive HEAD)" git archive --format=tar.gz -o app.tar.gz HEAD \ agent deploy langgraph.json pyproject.toml uv.lock README.md +# List the archive ONCE into a variable. (`tar -tzf ... | grep -q ...` is unsafe +# under `set -o pipefail`: grep -q exits on first match, SIGPIPEs tar -> "write +# error" -> the pipeline reports non-zero even though grep succeeded, a false +# failure. Listing once avoids the pipe entirely.) +APP_LIST="$(tar -tzf app.tar.gz)" + # Sanity: the box's `uv sync --frozen` needs pyproject.toml + uv.lock at the root, # and the package itself (agent/). Fail loudly here rather than on the box. for required in pyproject.toml uv.lock agent/server.py langgraph.json; do - tar -tzf app.tar.gz | grep -qx "${required}" || { + printf '%s\n' "${APP_LIST}" | grep -qx "${required}" || { echo "ERROR: app.tar.gz is missing ${required}" >&2 exit 1 } @@ -36,9 +42,9 @@ done # extensions so credential-handling *source* (e.g. team_credentials.py) is not a # false positive. SECRET_RE='(^|/)(\.env(\..+)?|id_rsa|.*\.(pem|key|p12|pfx)|.*(secret|credential|password|token)s?\.(json|ya?ml|txt|env|ini|cfg))$' -if tar -tzf app.tar.gz | grep -qiE "${SECRET_RE}"; then +if printf '%s\n' "${APP_LIST}" | grep -qiE "${SECRET_RE}"; then echo "ERROR: app.tar.gz contains a secret-shaped file — refusing to publish:" >&2 - tar -tzf app.tar.gz | grep -iE "${SECRET_RE}" >&2 + printf '%s\n' "${APP_LIST}" | grep -iE "${SECRET_RE}" >&2 exit 1 fi