Files
copilotkit__copilotkit/showcase/bin/spec/test_ghcr_token.rb
Jordan Ritter c03270135e fix(showcase): promote resolves staging tag to GHCR digest before pinning prod
The showcase deploy model is STAGING = mutable :latest tag, PROD = immutable
@sha256: digest (P6 enforces both shapes). SnapshotCommand#build_snapshot
stored the raw serviceInstance.source.image, so for staging svc["image"] was
the :latest TAG. execute_promotion was pinning THAT mutable tag to prod via
serviceInstanceUpdate, defeating the immutable-prod invariant before
pin_and_verify raised on the nil expected_digest.

Fix: add PromoteCommand#resolved_prod_image — returns the staging svc as
@sha256:-pinned (pass-through if already pinned; resolves the tag via the
shared GHCR client otherwise; returns nil if the tag cannot be resolved).
execute_promotion now refuses (P0) rather than pin a mutable tag, and
check_p1_ghcr_digests verifies the resolved digest (it previously SKIPPED
tag-form images entirely, so :latest was never P1-checked).

Also:
- P2 race-check guards latest["meta"] when Railway returns a JSON String
  (deserialized as Ruby String, not Hash) — .dig used to crash with
  NoMethodError. SUCCESS status remains the real gate.
- Remove dead --include-startcommand flag (never read; doubly inert because
  P6 REFUSEs on any startCommand divergence).
- Spec hygiene: P3 skip-test raises if probe runs under --no-require-staging-
  green; P6 warn-proceed stubs execute_promotion to isolate the gate and
  asserts rc==0; test_ghcr_token teardown unconditionally deletes
  GITHUB_TOKEN/GHCR_TOKEN/RAILWAY_TOKEN before restoring priors.

70 runs, 204 assertions, 0 failures (up from 66/188 baseline).
2026-05-29 11:45:13 -07:00

46 lines
1.4 KiB
Ruby

# frozen_string_literal: true
require_relative "spec_helper"
class GHCRTokenTest < Minitest::Test
def setup
@prior_github = ENV.delete("GITHUB_TOKEN")
@prior_ghcr = ENV.delete("GHCR_TOKEN")
@prior_railway = ENV.delete("RAILWAY_TOKEN")
end
def teardown
# Unconditionally delete any test-set values so they don't leak across
# tests, THEN re-set the saved priors if those were present.
ENV.delete("GITHUB_TOKEN")
ENV.delete("GHCR_TOKEN")
ENV.delete("RAILWAY_TOKEN")
ENV["GITHUB_TOKEN"] = @prior_github if @prior_github
ENV["GHCR_TOKEN"] = @prior_ghcr if @prior_ghcr
ENV["RAILWAY_TOKEN"] = @prior_railway if @prior_railway
end
def test_prefers_explicit_ghcr_token
ENV["GITHUB_TOKEN"] = "ci-token"
ENV["GHCR_TOKEN"] = "explicit-pat"
assert_equal "explicit-pat", Railway::Auth.ghcr_token
end
def test_falls_back_to_github_token_in_ci
ENV["GITHUB_TOKEN"] = "ci-token"
assert_equal "ci-token", Railway::Auth.ghcr_token
end
def test_returns_nil_when_no_token_available
# No GH_AUTH_TOKEN shim, no env vars: nil (caller decides to refuse).
assert_nil Railway::Auth.ghcr_token
end
def test_does_not_return_railway_token
ENV["RAILWAY_TOKEN"] = "railway-bearer"
assert_nil Railway::Auth.ghcr_token
ensure
ENV.delete("RAILWAY_TOKEN")
end
end