#!/usr/bin/env bash

# The gem `source` option, exercised through version listing only. With a
# source configured, listing is a plain HTTP request against that registry and
# never shells out to `gem`, so this needs no Ruby and stays fast.
#
# Two properties, both of which regressed or would have:
#
#   1. The source is read from the CONFIG, even when the backend is built from a
#      bare CLI argument. Reading it off the argument instead sent listing to
#      rubygems.org while the cache key still said "private registry", so a
#      later install took a version from one registry and asked the other for it.
#   2. A credential in the source never reaches output. RubyGems authenticates a
#      private registry with basic-auth userinfo, so a token genuinely lives in
#      this URL.

TOKEN="ghp_e2eSECRET"

# A fake registry. It records each request's path and whether it carried basic
# auth, one per line, so the assertions below can stay in bash.
cat >registry.py <<'PYTHON'
import json
import os
import threading
import time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path

versions = json.dumps([
    {"number": "1.0.0", "created_at": "2026-01-01T00:00:00.000Z"},
    {"number": "2.2.0", "created_at": "2026-02-01T00:00:00.000Z"},
]).encode()


class Handler(BaseHTTPRequestHandler):
    def log_message(self, *args):
        pass

    def do_GET(self):
        auth = (self.headers.get("Authorization") or "").split(" ")[0] or "none"
        with open("requests.log", "a") as log:
            log.write(f"{self.path} {auth}\n")
        if self.path != "/acme/api/v1/versions/internal-cli.json":
            self.send_error(404)
            return
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(versions)))
        self.end_headers()
        self.wfile.write(versions)


def exit_with_test():
    # Stop once the test script that started us is gone, so the fixture needs
    # no cleanup trap and never outlives the test.
    parent = os.getppid()
    while os.getppid() == parent:
        time.sleep(0.5)
    os._exit(0)


threading.Thread(target=exit_with_test, daemon=True).start()
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
Path("registry.port").write_text(str(server.server_port))
server.serve_forever()
PYTHON

python3 registry.py &
registry_pid=$!
wait_for_file registry.port "gem registry port" 30 "$registry_pid"
port="$(cat registry.port)"

# Declared in config, with a credential in the URL. The command below names the
# tool as a bare argument and passes no options.
cat >mise.toml <<EOF
[tools]
"gem:internal-cli" = { version = "latest", source = "http://${TOKEN}@127.0.0.1:${port}/acme" }
EOF

output="$(MISE_DEBUG=1 mise ls-remote gem:internal-cli 2>&1)"
echo "$output"

# Versions came from the fixture, not from rubygems.org, which only happens if
# the source was resolved from config.
assert_contains_text "$output" "2.2.0"

# Exactly one request, under the source's path, with the credential sent as
# basic auth rather than dropped.
assert "cat requests.log" "/acme/api/v1/versions/internal-cli.json Basic"

# And the token appears nowhere, at debug verbosity, in stdout or stderr.
assert_not_contains_text "$output" "$TOKEN"
# The credential travels as a header, so the logged URL has no userinfo at all.
assert_contains_text "$output" "GET http://127.0.0.1:${port}/acme/api/v1/versions/internal-cli.json"
