#!/usr/bin/env bash # Verify phase-1/2 minimum security gem/package versions in lockfiles. set -euo pipefail semver_ge() { printf '%s\n%s\n' "$2" "$1" | sort -V | head -1 | grep -qx "$2" } check_gemfile_lock() { local file=$1 name min echo "Checking ${file}..." while read -r name min; do [[ -z "$name" ]] && continue local ver ver=$(grep -E "^ ${name} \(" "$file" | head -1 | sed -E 's/.*\(([0-9][0-9.a-z-]*).*/\1/' || true) if [[ -z "$ver" ]]; then echo "FAIL: ${name} not found in ${file}" exit 1 fi if ! semver_ge "$ver" "$min"; then echo "FAIL: ${name} ${ver} < required ${min} in ${file}" exit 1 fi echo " OK ${name} ${ver} (>= ${min})" done <<'GEMS' rack 2.2.13 nokogiri 1.13.10 rexml 3.3.9 tzinfo 1.2.10 rails-html-sanitizer 1.4.4 GEMS if grep -qE '^ sidekiq \(' "$file"; then local sidekiq_ver sidekiq_ver=$(grep -E '^ sidekiq \(' "$file" | head -1 | sed -E 's/.*\(([0-9][0-9.a-z-]*).*/\1/') if ! semver_ge "$sidekiq_ver" "6.4.0"; then echo "FAIL: sidekiq ${sidekiq_ver} < required 6.4.0 in ${file}" exit 1 fi echo " OK sidekiq ${sidekiq_ver} (>= 6.4.0)" fi } check_yarn_lock() { local file=$1 echo "Checking ${file}..." local axios ws axios=$(grep -A1 '^axios@\^0\.32' "$file" | grep 'version "' | head -1 | sed -E 's/.*version "([^"]+)".*/\1/') ws=$(grep -A1 '^ws@\^7\.5' "$file" | grep 'version "' | head -1 | sed -E 's/.*version "([^"]+)".*/\1/') if [[ -z "$axios" ]] || ! semver_ge "$axios" "0.32.0"; then echo "FAIL: axios ${axios:-missing} < 0.32.0" exit 1 fi echo " OK axios ${axios} (>= 0.32.0)" if [[ -z "$ws" ]] || ! semver_ge "$ws" "7.5.10"; then echo "FAIL: ws ${ws:-missing} < 7.5.10" exit 1 fi echo " OK ws ${ws} (>= 7.5.10)" } case "${1:-}" in ruby) check_gemfile_lock "${2:-Gemfile.lock}" ;; yarn) check_yarn_lock "${2:-yarn.lock}" ;; *) echo "Usage: $0 ruby [Gemfile.lock] | yarn [yarn.lock]" exit 1 ;; esac echo "Security pin verification passed."