#!/bin/sh
# Box-side git deny gate. Keep this file the sole shim implementation: the
# sandbox and harness-seat images each install this exact source file.

SPEC=2026-08-16-remote-deny-gate-design.md
RAW_GIT=/usr/bin/git
WORKSPACE_ROOT=/sandbox/workspaces

record_denial() {
  file=${SANDBOX_TOOLGAP_FILE:-/sandbox/toolgap/gaps.jsonl}
  mkdir -p "$(dirname "$file")" 2>/dev/null || return 0
  /usr/bin/jq -cn \
    --arg kind git-deny --arg cwd "$(pwd -P)" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
    --argjson argv "$ORIGINAL_ARGV_JSON" \
    '{kind:$kind,argv:$argv,cwd:$cwd,ts:$ts}' \
    >>"$file" 2>/dev/null || true
}

deny() {
  verb=$1
  target=$2
  record_denial
  printf '%s\n' "sandbox-git-shim: denied $verb target $target by $SPEC" >&2
  exit 86
}

is_allowed_push_target() {
  case "$1" in
    refs/cdx/*|refs/harness-seat/*|refs/heads/factory-result/*|refs/heads/wip/*) return 0 ;;
    *) return 1 ;;
  esac
}

push_target() {
  case "$1" in
    *:*) printf '%s\n' "${1#*:}" ;;
    *) printf '%s\n' "$1" ;;
  esac
}

git_dir_is_outside_workspace() {
  if [ -n "${GITDIR_OVERRIDE:-}" ]; then
    resolved="$(readlink -f "$GITDIR_OVERRIDE" 2>/dev/null)" || return 0
  else
    git_dir="$($RAW_GIT rev-parse --absolute-git-dir 2>/dev/null)" || return 1
    resolved="$(readlink -f "$git_dir" 2>/dev/null)" || return 1
  fi
  case "$resolved" in "$WORKSPACE_ROOT"|"$WORKSPACE_ROOT"/*) return 1 ;; esac
  return 0
}

destructive_verb() {
  verb=$1
  shift
  case "$verb" in
    reset)
      for arg in "$@"; do [ "$arg" = --hard ] && return 0; done ;;
    clean)
      for arg in "$@"; do case "$arg" in -f*|--force) return 0 ;; esac; done ;;
    checkout)
      [ "${1:-}" = -- ] || [ "${1:-}" = . ] && return 0 ;;
    restore) return 0 ;;
    stash) [ "${1:-}" = drop ] || [ "${1:-}" = clear ] && return 0 ;;
    gc)
      for arg in "$@"; do [ "$arg" = --prune=now ] && return 0; done ;;
    update-ref) [ "${1:-}" = -d ] && return 0 ;;
    branch) [ "${1:-}" = -D ] && return 0 ;;
  esac
  return 1
}

selftest() {
  is_allowed_push_target "$(push_target 'HEAD:refs/cdx/selftest/out')" || return 1
  is_allowed_push_target "$(push_target 'HEAD:refs/heads/main')" && return 1
  return 0
}

[ "${1:-}" = --deny-gate-selftest ] && { selftest; exit $?; }
ORIGINAL_ARGV_JSON="$(/usr/bin/jq -cn --args '$ARGS.positional' -- "$@")"

dispatch() {
  # Git accepts global options BEFORE the verb; a shim that only looks at $1
  # is bypassed by `git --git-dir=X push ...`. Consume every leading option so
  # the verb the checks see is the verb git will run, while the outer exec
  # preserves all original arguments unchanged. A --git-dir/--work-tree
  # override makes the repo location explicit, so the workspace decision uses
  # it instead of the cwd.
  GITDIR_OVERRIDE=""
  while [ $# -gt 0 ]; do
    case "$1" in
      -C) [ $# -ge 2 ] || return 0; cd "$2" 2>/dev/null || return 0; shift 2 ;;
      --git-dir|--work-tree) [ $# -ge 2 ] || return 0; GITDIR_OVERRIDE=$2; shift 2 ;;
      --git-dir=*|--work-tree=*) GITDIR_OVERRIDE=${1#*=}; shift ;;
      -c|--exec-path|--namespace|--super-prefix|--config-env) [ $# -ge 2 ] || return 0; shift 2 ;;
      --exec-path=*|--namespace=*|--config-env=*) shift ;;
      -*) shift ;;
      *) break ;;
    esac
  done
  verb=${1:-}
  [ -n "$verb" ] || return 0
  shift

  for arg in "$@"; do
    [ "$arg" = --no-verify ] && deny "$verb" "$arg"
  done

  if [ "$verb" = push ]; then
    target=unknown
    saw_remote=0
    for arg in "$@"; do
      case "$arg" in
        --force|-f) deny push "$arg" ;;
        --no-verify) deny push "$arg" ;;
        --*) continue ;;
      esac
      if [ "$saw_remote" = 0 ]; then
        saw_remote=1
        continue
      fi
      target="$(push_target "$arg")"
      case "$target" in refs/heads/main|refs/heads/master) deny push "$target" ;; esac
      is_allowed_push_target "$target" || deny push "$target"
    done
    [ "$saw_remote" = 1 ] && [ "$target" != unknown ] || deny push "$target"
  fi

  if destructive_verb "$verb" "$@" && git_dir_is_outside_workspace; then
    deny "$verb" "$(pwd -P)"
  fi
}

(dispatch "$@")
rc=$?
[ "$rc" -eq 86 ] && exit 86
exec "$RAW_GIT" "$@"
