#!/usr/bin/env bash
set -uo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SEAT="$(dirname "$HERE")"
WRAPPERS="$(dirname "$SEAT")/wrappers"
WORK="$(mktemp -d)"
PASS=0
FAIL=0

ok()  { PASS=$((PASS + 1)); printf '  ok   %s\n' "$1"; }
bad() { FAIL=$((FAIL + 1)); printf '  FAIL %s\n     %s\n' "$1" "$2"; }
trap 'rm -rf "$WORK"' EXIT

# ---------------------------------------------------------------- manifest is the single source
manifest_ids="$(jq -r '.items[].id' "$SEAT/credentials.json" | sort | tr '\n' ' ')"
[[ "$manifest_ids" == "claude codex-auth codex-config cursor " ]] \
  && ok "manifest declares the seat credential set" \
  || bad "manifest declares the seat credential set" "got: $manifest_ids"

# Neither launcher may carry a hard-coded credential path — that is the duplication the
# manifest exists to remove, and a drifting copy is how a credential silently stops shipping.
strays="$(grep -nE '/seed/(claude|codex|cursor)/' "$SEAT/seat-run.sh" "$SEAT/seat-entrypoint.sh" | grep -v CREDENTIALS_MANIFEST || true)"
[[ -z "$strays" ]] \
  && ok "no launcher hard-codes a credential path" \
  || bad "no launcher hard-codes a credential path" "$strays"

for wrapper in ca.sh codex.sh; do
  required="$(jq -r --arg w "$wrapper" '[.items[] | select((.required_by // []) | index($w))] | length' "$SEAT/credentials.json")"
  [[ "$required" == 1 ]] \
    && ok "$wrapper has exactly one required credential" \
    || bad "$wrapper has exactly one required credential" "got $required"
done

# ---------------------------------------------------------------- convergence unit behaviour
node --input-type=module -e '
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, writeFileSync, symlinkSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { loadManifest, localCredentials, parseRemoteDigests, stampSatisfied, convergeHost } from "'"$SEAT"'/seat-creds.mjs";

const manifest = loadManifest("'"$SEAT"'/credentials.json");

// A live credential path is a symlink into the systray account store; the source must be what
// the link points AT, so the active account is what reaches the fleet.
const home = mkdtempSync(join(tmpdir(), "seatcreds-"));
const store = join(home, "store");
mkdirSync(store, { recursive: true });
writeFileSync(join(store, "auth.json"), "active-account-token");
mkdirSync(join(home, ".codex"), { recursive: true });
symlinkSync(join(store, "auth.json"), join(home, ".codex", "auth.json"));
const creds = localCredentials(manifest, home);
assert.equal(creds.length, 1, "only the present credential is collected");
assert.equal(creds[0].id, "codex-auth");
assert.equal(creds[0].content.toString(), "active-account-token", "source follows the systray link");

// digest parsing tolerates the absent-file case (no line emitted for it)
const parsed = parseRemoteDigests(`${"a".repeat(64)}  .codex/auth.json\n`, [creds[0], { id: "ghost", home: "nope" }]);
assert.equal(parsed["codex-auth"], "a".repeat(64));
assert.equal(parsed.ghost, null);

assert.equal(stampSatisfied({ items: { "codex-auth": creds[0].sha } }, creds), true);
assert.equal(stampSatisfied({ items: { "codex-auth": "stale" } }, creds), false);
assert.equal(stampSatisfied(null, creds), false);

// a host whose digest already matches is never written to
let pushes = 0;
const matching = {
  loadRemoteConfig: () => ({ hosts: ["h1"] }),
  ssh: (_cfg, command, opts) => {
    if (opts?.input) { pushes += 1; return { status: 0, stdout: "" }; }
    return { status: 0, stdout: `${creds[0].sha}  .codex/auth.json\n` };
  },
};
const state = mkdtempSync(join(tmpdir(), "seatstate-"));
const converged = convergeHost(matching, {}, "h1", creds, state, () => {});
assert.equal(pushes, 0, "no push when the box already holds the current digest");
assert.deepEqual(converged.pushed, []);

// the second call short-circuits on the stamp without opening a connection
let dialled = 0;
convergeHost({ ...matching, ssh: () => { dialled += 1; return { status: 0, stdout: "" }; } }, {}, "h1", creds, state, () => {});
assert.equal(dialled, 0, "a satisfied stamp opens no connection");

// drift is pushed and verified; an unreachable host is reported, never guessed at
let pushed = null;
const drifting = {
  ssh: (_cfg, command, opts) => {
    if (opts?.input) { pushed = opts.input.toString(); return { status: 0, stdout: `${creds[0].sha}  .codex/auth.json\n` }; }
    return { status: 0, stdout: "" };
  },
};
const driftState = mkdtempSync(join(tmpdir(), "seatstate-"));
const result = convergeHost(drifting, {}, "h2", creds, driftState, () => {});
assert.deepEqual(result.pushed, ["codex-auth"]);
assert.equal(pushed, "active-account-token");

const downState = mkdtempSync(join(tmpdir(), "seatstate-"));
const down = convergeHost({ ssh: () => ({ status: 255, stdout: "" }) }, {}, "h3", creds, downState, () => {});
assert.equal(down.unreachable, true);
assert.deepEqual(down.pushed, []);

// a post-push digest mismatch must NOT be recorded as converged
const liarState = mkdtempSync(join(tmpdir(), "seatstate-"));
const liar = convergeHost({
  ssh: (_cfg, command, opts) => opts?.input
    ? { status: 0, stdout: `${"b".repeat(64)}  .codex/auth.json\n` }
    : { status: 0, stdout: "" },
}, {}, "h4", creds, liarState, () => {});
assert.deepEqual(liar.pushed, [], "a mismatching post-push digest is not converged");
' 2>&1 | sed 's/^/     /' >"$WORK/node.log"
node_rc=${PIPESTATUS[0]}
if [[ "$node_rc" -eq 0 ]]; then
  ok "convergence derives from the active account, pushes only on drift, verifies every write"
else
  bad "convergence derives from the active account, pushes only on drift, verifies every write" "$(cat "$WORK/node.log")"
fi

if grep -Fq 'HARNESS_SEAT_CREDENTIALS_MANIFEST=/w/$BUNDLE_REL/seat/credentials.json' "$SEAT/seat-run.sh" \
  && grep -Fq 'HARNESS_SEAT_CREDENTIALS_MANIFEST:-' "$SEAT/seat-entrypoint.sh" \
  && ! grep -Fq '/w/modules/harness/seat/credentials.json' "$SEAT/seat-entrypoint.sh"; then
  ok "the container reads credentials from the transported runtime bundle"
else
  bad "the container reads credentials from the transported runtime bundle" "runner and entrypoint manifest paths diverge"
fi

# ---------------------------------------------------------------- the box-side refusal
REPO="$WORK/repo"
RUNTIME="$REPO/.harness-seat/t/runtime"
mkdir -p "$RUNTIME"
cp -a "$SEAT" "$RUNTIME/seat"
cp -a "$WRAPPERS" "$RUNTIME/wrappers"
FAKE_HOME="$WORK/home"
mkdir -p "$FAKE_HOME"
PRIVATE_PROMPT="$WORK/private-prompt"
PROMPT_SECRET="prompt-$RANDOM-$$"
printf '%s\n' "$PROMPT_SECRET" > "$PRIVATE_PROMPT"
out="$(BUILD_REMOTE_INPUT_FILE="$PRIVATE_PROMPT" HOME="$FAKE_HOME" bash "$RUNTIME/seat/seat-run.sh" \
  --run-id t1 --wrapper ca.sh --repo-root "$REPO" --prompt-file p.txt \
  --log-rel logs --task-slug t --image none 2>&1)"
rc=$?
if [[ "$rc" -eq 3 && "$out" == *".config/cursor/auth.json"* ]]; then
  ok "a box without the cursor credential refuses the dispatch as exit 3"
else
  bad "a box without the cursor credential refuses the dispatch as exit 3" "rc=$rc out=$out"
fi
if [[ ! -e "$PRIVATE_PROMPT" ]] && ! grep -R -Fq "$PROMPT_SECRET" "$FAKE_HOME" "$REPO"; then
  ok "a refused dispatch removes its private prompt input"
else
  bad "a refused dispatch removes its private prompt input" "secret input remained after refusal"
fi

echo
echo "PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]]
