#!/bin/sh
# @(#) aishell-gate 0.4.0

# aishell-gate — AIShellGate session entry point
#
# "AIShell-Gate" Copyright (c) 2026 AIShell Labs LLC Winston-Salem NC USA.
# All Rights Reserved. Author: Sean T. Gilley
# Do not remove this notice.
# Use of this Software requires a valid license.
#
# THIS SOFTWARE IS PROVIDED BY AISHELL LABS LLC "AS IS" AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL AISHELL LABS LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# For full license terms see the LICENSE file or: www.aishellgate.com
#
# This script is the single named entry point for all AIShellGate sessions.
# It performs pre-flight environment validation, then transfers control to
# aishell-gate-exec via exec(). This process does not remain in the process
# tree after handoff.
#
# INTERNAL NOTE:
#   In v1, this script is a thin launcher. The aishell-gate binary slot is
#   reserved for the v2 broker, which will assume session coordination,
#   multi-agent routing, and multi-operator confirmation responsibilities.
#   When the broker is introduced, aishell-gate-exec becomes a child worker
#   spawned by the broker rather than the user-facing entry point. The
#   authorized_keys forced command and all user-facing invocations already
#   point here, so the transition requires no changes to deployed SSH
#   configuration on target hosts.
#
# ENVIRONMENT OVERRIDES (for non-standard installations or testing):
#   AISHELL_EXEC_BIN    Path to aishell-gate-exec  (default: same directory as this script)
#   AISHELL_POLICY_BIN  Path to aishell-gate-policy (default: same directory as this script)
#
# VERSION: 0.4.0
#
# CHANGES FROM 0.3.0
# ------------------
# Version bump to 0.4.0. Stale "Evaluation copies expire 30 days from
#   download" line removed from the license header — the evaluation
#   edition was retired project-wide; this file predated that cleanup and
#   was missed since it wasn't part of the C source pass that caught it.
#   License URL corrected: www.aishell.org/aishellgate -> www.aishellgate.com.
#   No functional changes — this script is a pure passthrough to
#   aishell-gate-exec with no hardcoded flags or preset names, so nothing
#   here was affected by the Standard/Enterprise feature split.
#
# CHANGES FROM 0.2.0
# ------------------
# Version bump to 0.3.0. Fix co-located binary discovery: the script now
#   resolves EXEC_BIN and POLICY_BIN relative to its own directory rather
#   than defaulting to /usr/local/bin unconditionally. Works whether the
#   script is invoked as ./aishell-gate, as a full path, or via $PATH with
#   no directory prefix. No env vars required when all three files live in
#   the same directory.
#
# SYNOPSIS:
#   aishell-gate [exec-flags] [policy-flags] [-- other-policy-flags]
#   aishell-gate --policy-preset ops_safe --audit-log /var/log/aishell.log
#   echo '<json-plan>' | aishell-gate --policy-preset dev_sandbox
#
# All flags are passed through unchanged to aishell-gate-exec.
# See aishell-gate-exec(1) for the full flag reference.

set -eu

# ── Binary locations ─────────────────────────────────────────────────────────
# Resolve the directory containing this script so that co-located binaries
# are found automatically — no env vars required. Works whether invoked as
# ./aishell-gate, /full/path/aishell-gate, or plain aishell-gate via $PATH.

case "$0" in
    */*)  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ;;
    *)    SCRIPT_DIR="$(cd "$(dirname "$(command -v "$0")")" && pwd)" ;;
esac

EXEC_BIN="${AISHELL_EXEC_BIN:-${SCRIPT_DIR}/aishell-gate-exec}"
POLICY_BIN="${AISHELL_POLICY_BIN:-${SCRIPT_DIR}/aishell-gate-policy}"

# ── Pre-flight checks ────────────────────────────────────────────────────────

# Refuse to run as root. aishell-gate-exec enforces this too, but catching it
# here produces a cleaner error before exec is ever involved.
if [ "$(id -u)" -eq 0 ]; then
    echo "aishell-gate: error: must not be run as root" >&2
    exit 1
fi

# Verify exec binary is present and executable.
if [ ! -x "$EXEC_BIN" ]; then
    echo "aishell-gate: error: aishell-gate-exec not found or not executable: $EXEC_BIN" >&2
    exit 1
fi

# Verify policy binary is present and executable.
if [ ! -x "$POLICY_BIN" ]; then
    echo "aishell-gate: error: aishell-gate-policy not found or not executable: $POLICY_BIN" >&2
    exit 1
fi

# Verify neither binary is setuid or setgid. aishell-gate-exec performs its
# own check at startup, but verifying here provides an early, unambiguous
# failure before any exec binary code runs.
if [ "$(find "$EXEC_BIN" -perm /6000 2>/dev/null | wc -l)" -gt 0 ]; then
    echo "aishell-gate: error: aishell-gate-exec must not be setuid or setgid" >&2
    exit 1
fi

if [ "$(find "$POLICY_BIN" -perm /6000 2>/dev/null | wc -l)" -gt 0 ]; then
    echo "aishell-gate: error: aishell-gate-policy must not be setuid or setgid" >&2
    exit 1
fi

# ── Handoff ──────────────────────────────────────────────────────────────────
#
# exec() replaces this process entirely. aishell-gate does not remain in the
# process tree. --policy-binary is injected here so callers (including
# authorized_keys forced commands) do not need to supply it explicitly.
#
# All remaining arguments ($@) pass through unchanged to aishell-gate-exec.

exec "$EXEC_BIN" --policy-binary "$POLICY_BIN" "$@"
