#!/usr/bin/env bash

# The packslip backend installs a release from its vendor's signed manifest.
# jdx/packslip publishes one for its own releases, signed keylessly by its
# release workflow, which is the identity the project name pins.

# Every release carrying a packslip is recent; do not let the default
# minimum release age hide them all.
export MISE_MINIMUM_RELEASE_AGE=0

# The backend needs no setting turned on to be used.
assert_contains "env -u MISE_EXPERIMENTAL mise ls-remote packslip:github.com/jdx/packslip" "0.2.0"

# The registry supplies the canonical project and pins each publishing workflow
# separately so CI signing jobs cannot authorize either bundles or the index.
mkdir canonical
pushd canonical >/dev/null
cat >mise.toml <<'EOF'
[tools]
packslip = "latest"
EOF
# Latest resolves and verifies the vendor recommendation without installing it.
assert_contains "MISE_DEBUG=1 mise latest packslip 2>&1" "verifying for resolution"
latest=$(mise latest packslip) || exit 1
[[ -n $latest ]] || exit 1
assert_contains "mise ls-remote packslip" "$latest"
# What resolution verified is kept, so resolving again asks only for the
# vendor's list, while installing what it picked verifies the release again.
assert_not_contains "MISE_DEBUG=1 mise latest packslip 2>&1" "verifying for resolution"
# The quickstart works with no explicit signer options in the user's config.
assert_contains "MISE_DEBUG=1 MISE_GLOBAL_CONFIG_FILE=$PWD/global.toml mise use -g packslip 2>&1" "packslip signed by"
assert_contains "cat global.toml" 'packslip ='
assert_contains "mise exec -- packslip version" "packslip $latest"
canonical_install_path="$(mise where packslip)"
assert_contains "cat $canonical_install_path/.mise-packslip.json" '"project": "packslip.dev"'
# Changing a list policy must not reuse the accepted versions from the warm cache.
assert_fail_contains "mise ls-remote 'packslip[list_identity_prefix=https://github.com/jdx/packslip/.github/workflows/ci.yml@]'" "verifying the release list"
# A trusted index does not authorize its signer (or CI) to sign release bundles.
assert_fail_contains "mise latest 'packslip[identity_prefix=https://github.com/jdx/packslip/.github/workflows/packslip-releases.yml@]'" "expected an identity starting with"
assert_fail_contains "mise latest 'packslip[identity_prefix=https://github.com/jdx/packslip/.github/workflows/ci.yml@]'" "expected an identity starting with"
mise packslip forget packslip.dev
popd >/dev/null

# A warm accepted-version cache must not hide changed stamper policy.
mkdir stamp-policy
pushd stamp-policy >/dev/null
cat >mise.toml <<'EOF'
[settings.packslip]
stampers = ["invalid"]
EOF
assert_fail_contains "mise ls-remote packslip:github.com/jdx/packslip" "has no pin"
popd >/dev/null

mise use packslip:github.com/jdx/packslip@0.2.0
assert_contains "$MISE_DATA_DIR/shims/packslip version" "packslip 0.2.0"

# github.com is implied for owner/repo.
assert_contains "mise x packslip:jdx/packslip@0.2.0 -- packslip version" "packslip 0.2.0"

# The verified statement is kept beside the install, and the lockfile
# entry carries the URL and digest the statement signed.
install_path="$(mise where packslip:github.com/jdx/packslip@0.2.0)"
assert_contains "cat $install_path/.mise-packslip.json" '"project": "github.com/jdx/packslip"'
assert_contains "mise tool packslip:github.com/jdx/packslip" "packslip"

# The signer is pinned, the way SSH remembers a host, and can be forgotten.
assert_contains "mise packslip pins" "https://github.com/jdx/packslip/.github/workflows/release.yml"
assert_contains "mise packslip forget jdx/packslip" "forgot the pinned signer"
assert_contains "mise packslip pins" "no packslip signers pinned"

# This release's packslip lists no completion, and mise says so rather
# than guessing at one; a tool mise does not know has no packslip at all.
assert_fail_contains "mise completion zsh --tool packslip" "declares no zsh completion"
assert_fail_contains "mise completion zsh --tool nope" "not an active, installed tool"

# This release declares no skill either, and sync links nothing.
assert_contains "mise skills ls" "no skills declared"
assert "mise skills ls --json" "[]"
assert_contains "mise skills sync --dir skills" "nothing to link"
assert_directory_not_exists skills
assert_contains "env MISE_SKILLS_DIR=agents/skills mise skills sync" "nothing to link"
assert_directory_not_exists agents

# A lockfile records who signed, so the project commits to that signer.
export MISE_LOCKFILE=1
mkdir -p locked && cd locked
touch mise.lock
cat <<EOF >mise.toml
[tools]
"packslip:github.com/jdx/packslip" = "0.2.0"
EOF
mise uninstall packslip:github.com/jdx/packslip@0.2.0
mise install
assert_contains "cat mise.lock" 'signer = "sigstore-oidc:https://github.com/jdx/packslip/.github/workflows/release.yml"'
# The commitment carries the repository's forge ID, so it follows a rename
# and refuses a different repository that takes the name.
assert_contains "cat mise.lock" 'repository_ids = { repository = "1356006409" }'
# A lockfile is an already-reviewed selection. A later release-age policy must
# not make that committed install unreproducible.
mise uninstall packslip:github.com/jdx/packslip@0.2.0
MISE_MINIMUM_RELEASE_AGE=2000-01-01 mise install
cd ..
unset MISE_LOCKFILE

# Naming one release is itself the selection release age governs, so a config
# that pins an exact version installs during the cooling window with no
# lockfile, and locking records the same selection.
mkdir -p pinned && cd pinned
cat <<EOF >mise.toml
[tools]
"packslip:github.com/jdx/packslip" = "0.2.0"
EOF
mise uninstall packslip:github.com/jdx/packslip@0.2.0
MISE_MINIMUM_RELEASE_AGE=2000-01-01 mise install
assert_contains "mise x -- packslip version" "packslip 0.2.0"
MISE_MINIMUM_RELEASE_AGE=2000-01-01 mise lock
assert_contains "cat mise.lock" 'version = "0.2.0"'
cd ..

# A prefix resolves like latest: each newest match is verified, and one this
# host cannot install is skipped rather than resolved and left for install to
# refuse. Here every match is.
mise packslip forget github.com/jdx/packslip
assert_fail_contains "MISE_DEBUG=1 mise latest 'packslip:jdx/packslip[variant=nope]@0'" "verifying for resolution"
assert_fail_contains "mise latest 'packslip:jdx/packslip[variant=nope]@0'" "skipping 0.3.1: no artifact"
assert_fail_contains "mise install 'packslip:jdx/packslip[variant=nope]@0'" "no release of packslip:github.com/jdx/packslip matching 0 can be installed"
# The verifications that walk kept serve a prefix with another variant, which
# only changes the artifact chosen, and that choice is made again on reading.
assert_not_contains "MISE_DEBUG=1 mise latest packslip:jdx/packslip@0 2>&1" "verifying for resolution"

# A release that carries no packslip is refused rather than guessed at.
assert_fail_contains "mise install packslip:jdx/mise-test-fixtures@1.0.0" "no release"
