#!/usr/bin/env bash # ©AngelaMos | 2026 # package-gate.sh set -uo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BUILD_IMAGE="ruby:4.0-slim" FLOOR_IMAGE="ruby:3.4-slim" BELOW_FLOOR_IMAGE="ruby:3.3-slim" DECLARED_FLOOR=">= 3.4" WORK="${HERE}/tmp/package" OBSERVED="${WORK}/observed" OWNER="$(id -u):$(id -g)" GIVEN="${1:-}" INVALID_SIGN_STREAM='"\x04\x08l!\x06\x01\x00".b' run() { docker run --rm --network none --user "${OWNER}" -e HOME=/tmp "$@" } record() { tee -a "${OBSERVED}" | sed 's/^/ /' } echo "packaging gate" echo rm -rf "${WORK}" mkdir -p "${WORK}/build" "${WORK}/ships-target" "${WORK}/drifted" : >"${OBSERVED}" echo "=== 1 build ===" if [[ -n "${GIVEN}" ]]; then GEM_DIR="$(cd "$(dirname "${GIVEN}")" && pwd)" GEM_FILE="$(basename "${GIVEN}")" echo " auditing a pre-built artifact, no build performed" echo " ${GEM_DIR}/${GEM_FILE}" echo "gem_built=true" | record else GEM_DIR="${WORK}/build" GEM_FILE="marshalsea-$(run -v "${HERE}:/src:ro" -w /src "${BUILD_IMAGE}" \ ruby -e 'require "./lib/marshalsea/version"; print Marshalsea::VERSION').gem" run -v "${HERE}:/src:ro" -v "${WORK}/build:/out" -w /out "${BUILD_IMAGE}" sh -c ' set -e cd /src && ruby -e "puts Gem::Specification.load(%q{marshalsea.gemspec}).files" >/out/declared.txt cd /out && tar -C /src -T declared.txt -cf - | tar -xf - cp /src/marshalsea.gemspec /out/ gem build --strict marshalsea.gemspec ' 2>&1 | sed 's/^/ /' if [[ -f "${GEM_DIR}/${GEM_FILE}" ]]; then echo "gem_built=true" | record else echo "gem_built=false" | record fi fi echo echo "=== 2 manifest audit ===" run -v "${HERE}:/src:ro" -v "${GEM_DIR}:/gem:ro" "${BUILD_IMAGE}" \ ruby /src/scripts/audit_gem.rb "/gem/${GEM_FILE}" /src "${DECLARED_FLOOR}" /tmp/extract 2>&1 | record echo echo "=== 3 install path ===" install_and_use() { local image="$1" local label="$2" docker run --rm --network none -v "${GEM_DIR}:/gem:ro" -w / "${image}" sh -c " set -e gem install --local --no-document /gem/${GEM_FILE} >/dev/null ruby -e ' require \"marshalsea\" raise \"loaded from the worktree\" unless Gem.loaded_specs[\"marshalsea\"] blob = Marshal.dump(Gem::Requirement.new(\">= 0\")) result = Marshalsea::Marshal::Parser.new(blob).parse sinks = result.sinks.map { |s| \"#{s.class_name}##{s.sink_method}\" } decision = Marshalsea::Marshal::BoundaryDetector.new.inspect_stream(blob) ok = result.class_names.include?(\"Gem::Requirement\") && sinks.include?(\"Gem::Requirement#marshal_load\") && decision.blocked? && !defined?(Marshalsea::Marshal::FloatBody).nil? puts \"installed_gem_works_on_${label}=#{ok}\" ' " 2>&1 | tail -1 } install_and_use "${FLOOR_IMAGE}" floor | record install_and_use "${BUILD_IMAGE}" current | record echo echo "=== 4 release identity ===" release_tag="$(run -v "${HERE}:/app:ro" -w /app "${BUILD_IMAGE}" \ ruby -e 'require "rake"; load "Rakefile"; print Bundler::GemHelper.instance.send(:version_tag)' 2>/dev/null)" gem_version="$(run -v "${HERE}:/app:ro" -w /app "${BUILD_IMAGE}" \ ruby -e 'require "./lib/marshalsea/version"; print Marshalsea::VERSION' 2>/dev/null)" echo " rake release would tag: ${release_tag}" echo "release_tag_is_namespaced=$([[ ${release_tag} == "marshalsea-v${gem_version}" ]] && echo true || echo false)" | record bare_tag="$(run -v "${HERE}:/app:ro" -w /tmp "${BUILD_IMAGE}" sh -c ' cp -r /app/lib /app/marshalsea.gemspec /app/README.md /app/LICENSE /tmp/ 2>/dev/null printf "require \"rake\"\nrequire \"bundler/gem_tasks\"\n" >/tmp/Rakefile ruby -e "require \"rake\"; load \"Rakefile\"; print Bundler::GemHelper.instance.send(:version_tag)" ' 2>/dev/null)" echo "control_bare_rakefile_tags_the_whole_monorepo=$([[ ${bare_tag} == "v${gem_version}" ]] && echo true || echo false)" | record echo echo "=== 5 the floor is measured, not asserted ===" suite_status=0 for suite in marshal/parser_test scanner_test chains_test marshal/boundary_detector_test \ marshal/load_guard_test psych/inspector_test corpus_test; do if ! docker run --rm --network none -v "${HERE}:/app:ro" -w /app "${FLOOR_IMAGE}" \ ruby -Ilib -Itest "test/${suite}.rb" >/dev/null 2>&1; then echo " ${suite} is RED on the floor image" suite_status=1 fi done if [[ ${suite_status} -eq 0 ]]; then echo "suite_green_on_floor=true" | record else echo "suite_green_on_floor=false" | record fi differential() { local image="$1" local label="$2" docker run --rm --network none -v "${HERE}:/app:ro" -w /app "${image}" ruby -Ilib -e " require \"marshalsea\" bytes = ${INVALID_SIGN_STREAM} ruby_accepts = begin Marshal.load(bytes) true rescue StandardError false end parser_accepts = begin Marshalsea::Marshal::Parser.new(bytes).parse true rescue Marshalsea::Marshal::StreamError false end puts \"${label}_ruby_accepts_invalid_sign=#{ruby_accepts}\" puts \"${label}_parser_accepts_invalid_sign=#{parser_accepts}\" " 2>&1 | tail -2 } differential "${FLOOR_IMAGE}" floor | record differential "${BELOW_FLOOR_IMAGE}" below_floor | record echo echo "=== 6 negative controls ===" cat >"${WORK}/ships-target/marshalsea.gemspec" <<'SPEC' require_relative "lib/marshalsea/version" Gem::Specification.new do |spec| spec.name = "marshalsea" spec.version = Marshalsea::VERSION spec.authors = ["Carter Perez"] spec.email = ["carterperez2222@gmail.com"] spec.summary = "control fixture that deliberately ships the vulnerable target" spec.description = "control fixture for package-gate.sh, never published" spec.homepage = "https://github.com/CarterPerez-dev/Cybersecurity-Projects" spec.license = "AGPL-3.0-or-later" spec.required_ruby_version = ">= 3.4" spec.files = Dir["lib/**/*.rb", "target/**/*", "README.md", "LICENSE"] spec.require_paths = ["lib"] end SPEC run -v "${HERE}:/src:ro" -v "${WORK}/ships-target:/out" -w /out "${BUILD_IMAGE}" sh -c ' set -e tar -C /src -cf - lib target README.md LICENSE | tar -xf - gem build marshalsea.gemspec ' >/dev/null 2>&1 control_target="$(run -v "${HERE}:/src:ro" -v "${WORK}/ships-target:/gem:ro" "${BUILD_IMAGE}" \ ruby /src/scripts/audit_gem.rb "/gem/${GEM_FILE}" /src "${DECLARED_FLOOR}" /tmp/extract 2>/dev/null | grep -c '^target_absent=false$')" echo "control_auditor_rejects_a_gem_shipping_the_target=$([[ ${control_target} == 1 ]] && echo true || echo false)" | record run -v "${HERE}:/src:ro" -v "${WORK}/drifted:/out" -w /out "${BUILD_IMAGE}" sh -c ' set -e cd /src && ruby -e "puts Gem::Specification.load(%q{marshalsea.gemspec}).files" >/out/declared.txt cd /out && tar -C /src -T declared.txt -cf - | tar -xf - cp /src/marshalsea.gemspec /out/ ruby -e "File.write(%q{lib/marshalsea/version.rb}, File.read(%q{lib/marshalsea/version.rb}) + %q{ })" gem build marshalsea.gemspec ' >/dev/null 2>&1 control_drift="$(run -v "${HERE}:/src:ro" -v "${WORK}/drifted:/gem:ro" "${BUILD_IMAGE}" \ ruby /src/scripts/audit_gem.rb "/gem/${GEM_FILE}" /src "${DECLARED_FLOOR}" /tmp/extract 2>/dev/null | grep -c '^lib_matches_worktree=false$')" echo "control_auditor_rejects_a_drifted_lib_file=$([[ ${control_drift} == 1 ]] && echo true || echo false)" | record if docker run --rm --network none -v "${GEM_DIR}:/gem:ro" -w / "${BELOW_FLOOR_IMAGE}" \ gem install --local --no-document "/gem/${GEM_FILE}" >/dev/null 2>&1; then echo "control_floor_blocks_install_below_it=false" | record else echo "control_floor_blocks_install_below_it=true" | record fi echo failures=0 expect() { if grep -qx "$1=true" "${OBSERVED}"; then echo " PASS $2" else echo " FAIL $2" failures=$((failures + 1)) fi } reject() { if grep -qx "$1=false" "${OBSERVED}"; then echo " PASS $2" else echo " FAIL $2" failures=$((failures + 1)) fi } echo "=== verdict ===" expect gem_built "the gem builds with --strict from its declared manifest alone" expect every_declared_file_shipped "every file the gemspec declares is in the artifact" expect nothing_undeclared_shipped "the artifact carries nothing the gemspec did not declare" expect lib_is_non_empty "the artifact ships a non-empty lib, so the audit is not vacuous" expect lib_matches_worktree "every shipped lib file is byte-identical to the worktree" expect floor_is_declared "the artifact declares the floor this gate proves" expect target_absent "the vulnerable target is absent" expect tests_absent "the test suite, corpus and fixtures are absent" expect scripts_absent "the gate scripts are absent" expect dev_docs_absent "research, plans and agent briefing are absent" expect build_tooling_absent "justfile, Gemfile, Rakefile and lint config are absent" expect container_files_absent "Dockerfile and rack config are absent" expect lab_artifacts_absent "no canary, payload or nested gem artifact shipped" expect installed_gem_works_on_floor "the installed gem parses, classifies and blocks on the floor" expect installed_gem_works_on_current "the installed gem parses, classifies and blocks on current" expect release_tag_is_namespaced "rake release tags marshalsea-vX, not a bare vX the monorepo shares" expect control_bare_rakefile_tags_the_whole_monorepo "without the tag_prefix line the tag really is bare, so that check is live" expect suite_green_on_floor "every suite is green on the floor image" reject floor_ruby_accepts_invalid_sign "on the floor, real Marshal rejects an invalid bignum sign" reject floor_parser_accepts_invalid_sign "on the floor, the parser rejects it too, so they agree" expect below_floor_ruby_accepts_invalid_sign "one version below the floor, real Marshal accepts it" reject below_floor_parser_accepts_invalid_sign "the parser still rejects it, so below the floor they disagree" expect control_auditor_rejects_a_gem_shipping_the_target "the auditor rejects a gem that ships the target" expect control_auditor_rejects_a_drifted_lib_file "the auditor rejects a gem whose lib drifted from source" expect control_floor_blocks_install_below_it "RubyGems refuses to install below the declared floor" echo if [[ ${failures} -eq 0 ]]; then echo "GATE PASSED" exit 0 fi echo "GATE FAILED (${failures})" exit 1