#!/usr/bin/env bash

# A mise.lock is read along with a mise.toml that only lists plain tool keys,
# which loads without trust. Until the project is trusted, a lock entry may pin
# a version of the backend the tool key or the registry selects, but not choose
# the backend or add options: an untrusted project must not be able to point a
# github: tool's api_url at a host of its choosing and receive the user's
# GITHUB_TOKEN, nor swap a registry tool for an http: download with a
# postinstall command.

export MISE_TRUSTED_CONFIG_PATHS=""
unset CI GITHUB_ACTIONS GITHUB_ACTION 2>/dev/null || true

cat <<'PY' >sink.py
import http.server, os

class H(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        with open("sink.log", "a") as f:
            f.write("%s Authorization: %s\n" % (self.path, self.headers.get("Authorization")))
        body = b"[]"
        self.send_response(200)
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, *a):
        pass

server = http.server.HTTPServer(("127.0.0.1", 0), H)
with open("sink.port.tmp", "w") as f:
    f.write(str(server.server_port))
os.rename("sink.port.tmp", "sink.port")
server.serve_forever()
PY
python3 sink.py &
sink_pid=$!
trap 'kill $sink_pid 2>/dev/null' EXIT
for _ in $(seq 100); do
  [ -s sink.port ] && break
  sleep 0.1
done
[ -s sink.port ] || fail "sink server did not become ready"
sink_port=$(cat sink.port)
touch sink.log

mkdir -p proj
cat <<'EOF' >proj/mise.toml
[tools]
"github:jdx/mise-test-fixtures" = "latest"
shfmt = "3.10.0"
EOF
cat <<EOF >proj/mise.lock
lockfile_version = 3

[[tools."github:jdx/mise-test-fixtures"]]
version = "1.0.0"
backend = "github:jdx/mise-test-fixtures[api_url=http://127.0.0.1:${sink_port}/api/v3]"
specifiers = ["latest"]

[[tools.shfmt]]
version = "3.10.0"
backend = "http:shfmt[url=http://127.0.0.1:${sink_port}/shfmt.tar.gz,postinstall=touch \$HOME/postinstall-ran]"
specifiers = ["3.10.0"]
EOF

export GITHUB_TOKEN=ghp_lockfile_backend_secret
assert_contains "MISE_YES=0 mise -C proj trust --show" "untrusted"
(cd proj && MISE_YES=0 mise ls >../ls.log 2>&1) || true
assert_not_contains "cat sink.log" "Authorization"
assert_contains "cat ls.log" "which needs its config to be trusted"

# the lock may not move shfmt off the registry's backend before trust
assert_contains "cd proj && MISE_YES=0 mise tool shfmt --backend 2>/dev/null" "aqua:mvdan/sh"
assert_contains "MISE_YES=0 mise -C proj trust --show" "untrusted"

# a backend that names no tool is ignored too, instead of crashing every prompt
cat <<'EOF' >proj/mise.lock
[[tools.shfmt]]
version = "3.10.0"
backend = ""
EOF
assert_succeed "cd proj && MISE_YES=0 mise hook-env -s bash >/dev/null 2>&1"

# once trusted, the lock entries apply as written
cat <<EOF >proj/mise.lock
[[tools.shfmt]]
version = "3.10.0"
backend = "http:shfmt[url=http://127.0.0.1:${sink_port}/shfmt.tar.gz]"
EOF
mise trust proj/mise.toml
assert_contains "cd proj && mise tool shfmt --backend" "http:shfmt[url=http://127.0.0.1:${sink_port}/shfmt.tar.gz]"
