Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s

This commit is contained in:
李建琦
2026-08-21 18:30:13 +08:00
commit 6d655c9903
3584 changed files with 1270640 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
#!/bin/bash
set -euo pipefail
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_DIR="$(cd "${TEST_DIR}/.." && pwd)"
SCRIPT="${DEPLOY_DIR}/apple-container.sh"
TEST_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/sub2api-apple-test.XXXXXX")"
STATE_DIR="${TEST_ROOT}/state"
ENV_FILE="${TEST_ROOT}/sub2api.env"
cleanup() {
rm -rf "${TEST_ROOT}"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$*" >&2
exit 1
}
assert_exists() {
[[ -e "$1" ]] || fail "Expected path to exist: $1"
}
assert_missing() {
[[ ! -e "$1" ]] || fail "Expected path to be absent: $1"
}
export FAKE_CONTAINER_STATE="${STATE_DIR}"
export PATH="${TEST_DIR}/fixtures/bin:${PATH}"
export SUB2API_ENV_FILE="${ENV_FILE}"
mkdir -p "${STATE_DIR}"
"${SCRIPT}" init
[[ "$(stat -f '%Lp' "${ENV_FILE}")" == "600" ]] || fail "init did not create a mode-600 env file"
grep -q '^POSTGRES_PASSWORD=change_this_secure_password$' "${ENV_FILE}" && fail "init retained the placeholder password"
chmod 644 "${ENV_FILE}"
if "${SCRIPT}" up >/dev/null 2>&1; then
fail "up accepted an insecure env file"
fi
chmod 600 "${ENV_FILE}"
"${SCRIPT}" up
assert_exists "${STATE_DIR}/containers/sub2api-apple"
assert_exists "${STATE_DIR}/containers/sub2api-apple-postgres"
assert_exists "${STATE_DIR}/containers/sub2api-apple-redis"
assert_exists "${STATE_DIR}/running/sub2api-apple"
"${SCRIPT}" status >/dev/null
"${SCRIPT}" up --recreate
assert_exists "${STATE_DIR}/running/sub2api-apple"
"${SCRIPT}" down
assert_missing "${STATE_DIR}/running/sub2api-apple"
assert_missing "${STATE_DIR}/running/sub2api-apple-postgres"
assert_missing "${STATE_DIR}/running/sub2api-apple-redis"
"${SCRIPT}" destroy --yes
assert_missing "${STATE_DIR}/containers/sub2api-apple"
assert_missing "${STATE_DIR}/networks/sub2api-apple"
assert_exists "${STATE_DIR}/volumes/sub2api-apple-data"
"${SCRIPT}" up
"${SCRIPT}" destroy --volumes --yes
assert_missing "${STATE_DIR}/volumes/sub2api-apple-data"
assert_missing "${STATE_DIR}/volumes/sub2api-apple-postgres-data"
assert_missing "${STATE_DIR}/volumes/sub2api-apple-redis-data"
touch "${STATE_DIR}/system-running"
touch "${STATE_DIR}/containers/sub2api-apple"
touch "${STATE_DIR}/unowned/container/sub2api-apple"
if "${SCRIPT}" status >/dev/null 2>&1; then
fail "status accepted an unowned same-name container"
fi
printf 'Apple container lifecycle tests passed.\n'
+44
View File
@@ -0,0 +1,44 @@
#!/bin/sh
set -eu
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
cd "$repo_root"
check_application_security_opt() {
file=$1
count=$(
awk '
$0 == " sub2api:" {
in_application = 1
next
}
in_application && $0 ~ /^ [A-Za-z0-9_-]+:$/ {
in_application = 0
}
in_application && $0 == " security_opt:" {
in_security_opt = 1
next
}
in_application && in_security_opt && $0 == " - no-new-privileges:true" {
count++
}
END { print count + 0 }
' "$file"
)
if [ "$count" -ne 1 ]; then
printf '%s must enable no-new-privileges exactly once for the sub2api service\n' "$file" >&2
exit 1
fi
}
for compose_file in \
deploy/docker-compose.yml \
deploy/docker-compose.local.yml \
deploy/docker-compose.standalone.yml \
deploy/docker-compose.dev.yml
do
check_application_security_opt "$compose_file"
done
printf 'docker compose security test passed\n'
+34
View File
@@ -0,0 +1,34 @@
#!/bin/sh
set -eu
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
cd "$repo_root"
fail() {
printf 'docker runtime resources test failed: %s\n' "$1" >&2
exit 1
}
assert_line() {
file=$1
line=$2
grep -Fqx "$line" "$file" || fail "$file is missing: $line"
}
assert_count() {
file=$1
line=$2
expected=$3
actual=$(grep -Fxc "$line" "$file" || true)
[ "$actual" -eq "$expected" ] || fail "$file has $actual occurrences of '$line', expected $expected"
}
test -s backend/resources/model-pricing/model_prices_and_context_window.json || \
fail 'fallback pricing data is missing or empty'
assert_line Dockerfile.goreleaser 'COPY --chown=sub2api:sub2api backend/resources /app/resources'
assert_line deploy/Dockerfile 'COPY --from=backend-builder --chown=sub2api:sub2api /app/backend/resources /app/resources'
assert_count .goreleaser.yaml ' - backend/resources' 4
assert_count .goreleaser.simple.yaml ' - backend/resources' 1
printf 'docker runtime resources test passed\n'
+164
View File
@@ -0,0 +1,164 @@
#!/bin/bash
set -eu
STATE_DIR="${FAKE_CONTAINER_STATE:?FAKE_CONTAINER_STATE is required}"
mkdir -p \
"${STATE_DIR}/containers" \
"${STATE_DIR}/running" \
"${STATE_DIR}/networks" \
"${STATE_DIR}/volumes" \
"${STATE_DIR}/unowned/container" \
"${STATE_DIR}/unowned/network" \
"${STATE_DIR}/unowned/volume"
list_names() {
local directory=$1
local path
for path in "${directory}"/*; do
[[ -e "${path}" ]] || continue
basename "${path}"
done
}
last_argument() {
local value=""
for value in "$@"; do :; done
printf '%s\n' "${value}"
}
inspect_resource() {
local resource_type=$1
local resource_name=$2
local label_value="apple-container"
local address="192.168.65.4/24"
if [[ -e "${STATE_DIR}/unowned/${resource_type}/${resource_name}" ]]; then
label_value="other"
fi
case "${resource_name}" in
sub2api-apple-postgres) address="192.168.65.2/24" ;;
sub2api-apple-redis) address="192.168.65.3/24" ;;
esac
printf '[{"configuration":{"labels":{"org.sub2api.stack":"%s"}},"status":{"networks":[{"ipv4Address":"%s"}]}}]\n' \
"${label_value}" "${address}"
}
command=${1-}
if [[ $# -gt 0 ]]; then shift; fi
case "${command}" in
--version)
echo "container CLI version 1.1.0 (build: release, commit: fake)"
;;
system)
subcommand=${1-}
case "${subcommand}" in
status) [[ -e "${STATE_DIR}/system-running" ]] ;;
start) touch "${STATE_DIR}/system-running" ;;
stop) rm -f "${STATE_DIR}/system-running" "${STATE_DIR}/running"/* ;;
*) exit 1 ;;
esac
;;
list)
include_all=false
for argument in "$@"; do
[[ "${argument}" == "--all" || "${argument}" == "-a" ]] && include_all=true
done
if [[ "${include_all}" == true ]]; then
list_names "${STATE_DIR}/containers"
else
list_names "${STATE_DIR}/running"
fi
;;
network)
subcommand=${1-}
shift || true
case "${subcommand}" in
list)
echo default
list_names "${STATE_DIR}/networks"
;;
create) touch "${STATE_DIR}/networks/$(last_argument "$@")" ;;
inspect) inspect_resource network "${1}" ;;
delete) rm -f "${STATE_DIR}/networks/${1}" ;;
*) exit 1 ;;
esac
;;
volume)
subcommand=${1-}
shift || true
case "${subcommand}" in
list) list_names "${STATE_DIR}/volumes" ;;
create) touch "${STATE_DIR}/volumes/$(last_argument "$@")" ;;
inspect) inspect_resource volume "${1}" ;;
delete) rm -f "${STATE_DIR}/volumes/${1}" ;;
*) exit 1 ;;
esac
;;
image)
subcommand=${1-}
case "${subcommand}" in
inspect|pull) exit 0 ;;
*) exit 1 ;;
esac
;;
create)
name=""
while [[ $# -gt 0 ]]; do
case "$1" in
--name)
name=$2
shift 2
;;
--label|--network|--platform|--ulimit|--env-file|--volume|--entrypoint|--publish)
shift 2
;;
*)
shift
;;
esac
done
[[ -n "${name}" ]]
touch "${STATE_DIR}/containers/${name}"
;;
inspect)
inspect_resource container "${1}"
;;
start)
touch "${STATE_DIR}/running/${1}"
;;
stop)
for argument in "$@"; do
case "${argument}" in
--time|--signal) skip_next=true ;;
[0-9]*|SIG*) ;;
*) rm -f "${STATE_DIR}/running/${argument}" ;;
esac
done
;;
delete)
for argument in "$@"; do
case "${argument}" in
--force|-f) ;;
*)
rm -f "${STATE_DIR}/running/${argument}"
rm -f "${STATE_DIR}/containers/${argument}"
;;
esac
done
;;
exec)
echo 1
;;
logs|copy)
exit 0
;;
*)
echo "Unsupported fake container command: ${command} $*" >&2
exit 1
;;
esac
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
set -eu
printf '{"status":"ok"}\n'
+103
View File
@@ -0,0 +1,103 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT
cat > "$TEMP_DIR/curl" <<'EOF'
#!/bin/bash
printf '%s\n' "$@" > "$CURL_ARGS_LOG"
env > "${CURL_ARGS_LOG}.env"
cat > "${CURL_ARGS_LOG}.stdin"
EOF
chmod +x "$TEMP_DIR/curl"
mkdir "$TEMP_DIR/home"
cat > "$TEMP_DIR/home/.curlrc" <<'EOF'
url = "https://example.com/collect"
header = "X-Leaked-From-Curlrc: yes"
EOF
run_api_curl() {
CURL_ARGS_LOG="$1" HOME="$TEMP_DIR/home" PATH="$TEMP_DIR:$PATH" UPDATE_GITHUB_TOKEN="${2:-}" \
GITHUB_TOKEN="github-fallback" GH_TOKEN="gh-fallback" \
bash -c 'source <(head -n -1 "$1"); github_api_curl -s "$2"' bash \
"$ROOT_DIR/deploy/install.sh" "https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest"
}
run_api_curl "$TEMP_DIR/authenticated" "update-secret"
test "$(head -n 1 "$TEMP_DIR/authenticated")" = '-q'
grep -Fxq -- '--config' "$TEMP_DIR/authenticated"
grep -Fxq -- '-' "$TEMP_DIR/authenticated"
grep -Fxq -- '--globoff' "$TEMP_DIR/authenticated"
grep -Fxq 'header = "Authorization: Bearer update-secret"' "$TEMP_DIR/authenticated.stdin"
if grep -Fq 'update-secret' "$TEMP_DIR/authenticated"; then
echo "installer exposed the update token in curl argv" >&2
exit 1
fi
if grep -Eq 'update-secret|github-fallback|gh-fallback' "$TEMP_DIR/authenticated.env"; then
echo "installer exposed a token in curl environment" >&2
exit 1
fi
test "$(grep -Fxc 'https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest' "$TEMP_DIR/authenticated")" -eq 1
if grep -Fq 'example.com/collect' "$TEMP_DIR/authenticated" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/authenticated" ||
grep -Fq 'example.com/collect' "$TEMP_DIR/authenticated.stdin" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/authenticated.stdin"; then
echo "installer allowed hostile curl config into authenticated invocation" >&2
exit 1
fi
run_api_curl "$TEMP_DIR/anonymous"
test "$(head -n 1 "$TEMP_DIR/anonymous")" = '-q'
if grep -Eq 'github-fallback|gh-fallback' "$TEMP_DIR/anonymous.env"; then
echo "installer exposed a fallback token in anonymous curl environment" >&2
exit 1
fi
if grep -Fq 'Authorization:' "$TEMP_DIR/anonymous"; then
echo "installer unexpectedly used a fallback token" >&2
exit 1
fi
test ! -s "$TEMP_DIR/anonymous.stdin"
test "$(grep -Fxc 'https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest' "$TEMP_DIR/anonymous")" -eq 1
if grep -Fq 'example.com/collect' "$TEMP_DIR/anonymous" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/anonymous"; then
echo "installer allowed hostile curl config into anonymous invocation" >&2
exit 1
fi
assert_unsafe_invocation_rejected() {
local name=$1
shift
rm -f "$TEMP_DIR/$name" "$TEMP_DIR/$name.stdin"
if CURL_ARGS_LOG="$TEMP_DIR/$name" PATH="$TEMP_DIR:$PATH" UPDATE_GITHUB_TOKEN="update-secret" \
bash -c 'source <(head -n -1 "$1"); shift; github_api_curl "$@"' bash \
"$ROOT_DIR/deploy/install.sh" "$@" 2>/dev/null; then
echo "installer accepted unsafe curl invocation: $name" >&2
exit 1
fi
if [ -e "$TEMP_DIR/$name" ]; then
echo "installer invoked curl for unsafe request: $name" >&2
exit 1
fi
}
assert_unsafe_invocation_rejected non-api -s \
"https://github.com/Wei-Shaw/sub2api/releases/download/v1/asset"
assert_unsafe_invocation_rejected mixed-host -s \
"https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest" \
"https://example.com/collect"
assert_unsafe_invocation_rejected multiple-api -s \
"https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest" \
"https://api.github.com/repos/Wei-Shaw/sub2api/releases"
assert_unsafe_invocation_rejected url-option -s --url \
"https://example.com/collect" \
"https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest"
# Every installer release API request must use the scoped helper.
test "$(grep -c 'github_api_curl .*https://api.github.com/' "$ROOT_DIR/deploy/install.sh")" -eq 3
# Asset and checksum downloads must continue to call curl directly.
grep -Fq 'curl -sL "$download_url"' "$ROOT_DIR/deploy/install.sh"
grep -Fq 'curl -sL "$checksum_url"' "$ROOT_DIR/deploy/install.sh"
echo "install GitHub token checks passed"