#!/usr/bin/env bash
# v1.7.2 AC6 腿 —— `deny` 四类【严格化】之判据(绿侧 + 红侧 · 阳性对照接入出口码)
#
# 判据面: `deny.toml`(本仓)∧ `Cargo.lock`(本仓)∧ `cargo deny` 实跑读数
# 器: `cargo-deny`(CI 由 `taiki-e/install-action` 装; 本机 `cargo deny`)
#
# 承路标 §四.2「新增腿件须伴红侧(阳性对照)」⇒ 本腿之红侧【接入出口码】:
#   仅当【绿侧全过 ∧ 红侧咬合】时 exit 0; 否则 exit 1。
#
# 用法: bash scripts/tests/ac6_supply_chain_leg.sh [仓根]
# 退出码: 0 = 绿侧全过 ∧ 红侧咬合 / 1 = 任一不符
set -uo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="${1:-$(cd "$HERE/../.." && pwd)}"
cd "$ROOT" || { echo "仓根不可达: $ROOT" >&2; exit 1; }

PASS=0
FAIL=0
ok() { printf '  ✓ %s\n' "$1"; PASS=$((PASS + 1)); }
no() { printf '  ✗ %s\n' "$1"; FAIL=$((FAIL + 1)); }

command -v cargo >/dev/null 2>&1 || { echo "缺 cargo" >&2; exit 1; }
cargo deny --help >/dev/null 2>&1 || { echo "缺 cargo-deny" >&2; exit 1; }

# ══ ★★★ v1.9.17 后补(承流水线 `release #6` `supply-chain` **假红** · `test` 修)══════════
# ★ 病(一手 · 容器日志**原始字节**): 调用方置 `CARGO_TERM_COLOR=always`
#   (`.xuanwu/release/Dockerfile.supply-chain:20`)⇒ `cargo deny` 之【结论行】被上色:
#     `advisories ESC[32mok ESC[0m, bans ESC[32mok ESC[0m, licenses …`
#   ⇒ ★ `G1` 之**纯文本**谓词(`grep -q 'advisories ok, bans ok, licenses ok, sources ok'`)
#     与 `G2` 之正则(`^(.+?)\s*\(\d+\):` —— 需 `(` **直跟数字**,而实形为 `(ESC[1;37m1ESC[0m`)
#     **皆不中**; ★★ 而【屏面渲染**剥 ESC** ⇒ 看着与期望串**逐字一样**】⇒ **静默假红**
#     (`R3′` 之 `deny_r3p_leg.sh` 同族 · 其 `^bug\[`/`^error\[` 兼有假红 ∨ **假绿**)。
# ★★ 一手实证(**同面同命令 · 唯一变量该 env**):
#     `CARGO_TERM_COLOR=always` ⇒ `deny list` 实见名集 = **`0`**(= 容器之读数 `实见名集=0`)
#     `CARGO_TERM_COLOR=never`  ⇒ 同面同名集 = **`15`**(⊇ `deny.toml` `allow` 之 `14`)
# ★ 正形(承 [[fixture-run-inherits-caller-env]]): 本腿之判据取【**文本形**】⇒ 于腿内
#   **显式归一** —— `export` 只及本腿**子树** · **不改调用方** ⇒ 读数与调用方环境**解耦**。
export CARGO_TERM_COLOR=never

TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

echo "== AC6 腿 · 面 = $ROOT =="

# ── 绿侧 G1: cargo deny 四类全绿 ────────────────────────────────────────────
echo "-- G1 cargo deny check(advisories ∧ bans ∧ licenses ∧ sources)"
DENY_OUT="$TMP/deny_all.txt"
cargo deny check >"$DENY_OUT" 2>&1
RC=$?
TAIL="$(tail -1 "$DENY_OUT")"
# ★ 色面归一【自证】(**去静默** · 承「对照须能翻转」): 上 `export` 若失效(或他源上色)⇒
#   下列纯文本谓词复归**假红** ∧ 屏面**看不出** ⇒ ★ 本臂即其**探针**: 捕获面有 ESC 即**显名致红**。
if grep -q $'\x1b' "$DENY_OUT"; then
  no "G0 ★ 捕获面含 ANSI 转义 ⇒ 纯文本谓词将假红(色面未归一 · 禁静默)"
else
  ok "G0 捕获面无 ANSI 转义(谓词与实形同形)"
fi
if [ "$RC" -eq 0 ] && printf '%s' "$TAIL" | grep -q 'advisories ok, bans ok, licenses ok, sources ok'; then
  ok "G1 rc=0 ∧ 四类皆 ok(${TAIL})"
else
  no "G1 rc=$RC ∧ 末行 = ${TAIL}"
fi

# ── 绿侧 G2: licenses 零僵尸(`allow` ⊆ `cargo deny list` 实见许可名集)─────────
# ★ 谓词取【子集】而非【等集】—— 由(现取实证): `cargo deny list` 列【表达式中出现过的
#   全部】许可(含【未被选中之支】: `r-efi` 之 `MIT OR Apache-2.0 OR LGPL-2.1-or-later`
#   ⇒ 列出 `LGPL-2.1-or-later`)⇒ 等集谓词会【错求】`allow` 收 `LGPL`(收之反触
#   `unused-allowed-license`)⇒ 本腿首跑即以 FAIL=1 自捕此误(阳性对照之效)。
# ★ 故: 本项判【`allow` 中无一【不在实见集】者】= 零僵尸;
#   而【allow 中有【在用但非必需】者】之严格面由 G1 之 `unused-allowed-license = "deny"`
#   承之(器自判 · 非本腿自证)。
echo "-- G2 licenses 零僵尸(allow ⊆ cargo deny list 实见许可名集)"
cargo deny list >"$TMP/deny_list.txt" 2>/dev/null
G2_OUT="$(python3 - "$TMP/deny_list.txt" <<'PY'
import re, sys
names = set()
for ln in open(sys.argv[1], encoding='utf-8'):
    m = re.match(r'^(.+?)\s*\(\d+\):', ln)
    if m:
        names.add(m.group(1).strip())
t = open('deny.toml', encoding='utf-8').read()
blk = re.search(r'^allow = \[(.*?)^\]', t, re.M | re.S).group(1)
allow = [s.strip() for s in re.findall(r'"([^"]+)"', blk)]
missing = [a for a in allow if a not in names]
print(f'{len(allow)} {len(names)} {len(missing)} {",".join(missing)}')
PY
)"
read -r N_ALLOW N_USED N_MISSING MISSING <<<"$G2_OUT"
if [ "$N_ALLOW" -gt 0 ] && [ "$N_MISSING" -eq 0 ]; then
  ok "G2 allow=$N_ALLOW ⊆ 实见名集=$N_USED ∧ 僵尸=$N_MISSING(零僵尸)"
else
  no "G2 allow=$N_ALLOW ⇄ 实见名集=$N_USED ∧ 僵尸=$N_MISSING($MISSING)"
fi

# ── 绿侧 G3: sources 【集合】谓词(`allow-git` ⊆ `Cargo.lock` git 仓键集)──────
# ★★ v1.8.0 `M0`(承审计 `F-2`): 旧谓词系【计数对表】(`N_ALLOWGIT == N_LOCKGIT`)——
#   计数相等【不承】成员相等之证 ⇒ 成员错而计数仍等则报绿(且旧报文并书「差集空」,
#   而全函数无差集计算)。今改【集合】谓词: 判 `allow ⊆ lock`(零未用),
#   并【报】`lock \ allow`(该侧即 `unknown-git = "deny"` 所实际强制者)。
# ★ 键之【归一形】(本席阳性对照实证 · `cargo-deny 0.20.2`): 仅 scheme 变
#   (`ssh://git@…` ⇄ `https://git@…`)⇒ `cargo deny check sources` `rc=0`; 而改 host /
#   改 path ⇒ `rc=8` `source-not-allowed` ⇒ 匹配键 = **host + path**,**scheme 不参与**。
#   故键 = 去 `git+` 前缀 ∧ 去 scheme ∧ 去 userinfo ∧ 去 `?`/`#` 查询 ∧ 去尾 `.git` ∧ 去尾 `/`。
# ★ 谓词书其正则原文(承在册: 报谓词须书正则,禁描述式名)。
g3_predicate() { # $1 = deny.toml 路径(默认 deny.toml)⇒ 5 行: 计数 ∧ 未用数 ∧ lock\allow 数 ∧ 二明细
  python3 - "$1" <<'PY'
import re, sys
def key(u):
    u = re.sub(r'^git\+', '', u)
    u = re.sub(r'[?#].*$', '', u)
    u = u.rstrip('/')
    u = re.sub(r'\.git$', '', u)
    m = re.match(r'^[A-Za-z][A-Za-z0-9+.\-]*://(?:[^@/]*@)?(.*)$', u)
    return m.group(1) if m else u
t = open(sys.argv[1], encoding='utf-8').read()
m = re.search(r'^allow-git = \[(.*?)^\]', t, re.M | re.S)
allow = {key(s) for s in re.findall(r'"([^"]+)"', m.group(1))} if m else set()
lk = open('Cargo.lock', encoding='utf-8').read()
blocks = re.findall(r'^\[\[(?:package|patch\.unused)\]\]\n(.*?)(?=^\[\[|\Z)', lk, re.M | re.S)
lock = set()
for b in blocks:
    mm = re.search(r'^source = "(git\+.*)"$', b, re.M)
    if mm:
        lock.add(key(mm.group(1)))
print(len(allow), len(lock), len(allow - lock), len(lock - allow))
print(','.join(sorted(allow - lock)) or '-')
print(','.join(sorted(lock - allow)) or '-')
PY
}
echo "-- G3 sources 集合谓词(allow-git ⊆ Cargo.lock git 仓键集 · 键 = host+path)"
G3_OUT="$(g3_predicate deny.toml)"
{ read -r N_A N_L N_UNUSED N_UNCOV; read -r UNUSED; read -r UNCOV; } <<<"$G3_OUT"
if [ "$N_A" -gt 0 ] && [ "$N_UNUSED" -eq 0 ]; then
  ok "G3 allow($N_A) ⊆ lock($N_L) ⇒ 未用=$N_UNUSED(零未用)· lock\\allow=$N_UNCOV($UNCOV)"
else
  no "G3 allow($N_A) ⊄ lock($N_L) ⇒ 未用=$N_UNUSED($UNUSED)"
fi

# ── 绿侧 G4: 收紧键在位(未用许可清零之硬门)────────────────────────────────
echo "-- G4 收紧键在位(unused-allowed-license = \"deny\")"
if grep -qE '^unused-allowed-license = "deny"' deny.toml; then
  ok 'G4 unused-allowed-license = "deny" 在位'
else
  no 'G4 unused-allowed-license = "deny" 缺席 ⇒ 清零无门'
fi

# ── 红侧 R1(阳性对照): 注入一条【未用】许可 ⇒ 硬门必咬 ──────────────────────
echo "-- R1 阳性对照: allow 注入未用之 \"AGPL-3.0\" ⇒ licenses 必红"
python3 - "$TMP/deny_red.toml" <<'PY'
import re, sys
t = open('deny.toml', encoding='utf-8').read()
t2, n = re.subn(r'(^allow = \[\n)', r'\1  "AGPL-3.0",\n', t, count=1, flags=re.M)
assert n == 1, 'inject failed'
open(sys.argv[1], 'w', encoding='utf-8').write(t2)
PY
RED_OUT="$TMP/deny_red_out.txt"
cargo deny --config "$TMP/deny_red.toml" check licenses >"$RED_OUT" 2>&1
RRC=$?
# ★★ 显名支(承裁19 §2 同律 · `test` 域修): 照实 —— 本腿**零** `timeout`(`cargo deny`
#   直调)⇒ `124` 支为**防御**(不可达)。真伪由 = 原 `else` 以任意 `rc≠0` 径判
#   「谓词不承证力」—— 器/环境之失(config 解析、取源失败)亦落此 ⇒ **伪由**。
if [ "$RRC" -eq 124 ]; then
  no "R1 ★ 逾时被杀 rc=124(**本腿未判**)—— 承裁19 §2: 超时 ≠ 未咬合 · 禁混(候复跑)"
elif [ ! -s "$RED_OUT" ]; then
  no "R1 ★ 器无输出 rc=$RRC(**未判**)—— 无从判咬合(显名 · 非判「未咬合」)"
elif [ "$RRC" -ne 0 ] && grep -q 'unmatched license allowance' "$RED_OUT"; then
  ok "R1 咬合 rc=$RRC ∧ 命中 'unmatched license allowance'"
else
  no "R1 未咬合 rc=$RRC ∧ 有输出 ∧ 未中(阳性对照失败 ⇒ 谓词不承证力)"
  tail -3 "$RED_OUT" | sed 's/^/      /'
fi

# ── 红侧 R2(阳性对照 · 接入出口码): `allow` 一条 path 改错 ⇒ 集合谓词必咬 ────
# ★ 判别力之证(**专打旧计数谓词之盲**): 注入后**条数不变**(`allow` 仍 29 ∧ lock 仍 29)
#   ⇒ 旧【计数】谓词报绿(= 盲); 新【集合】谓词 ⇒ `allow ⊄ lock`(未用 ≥ 1)⇒ 必红。
#   二者之差即本项之判别力(承在册: 阳性对照须接入出口码 ∧ 零命中可有独立因)。
# ★ 注入形【scheme 无关 ∧ org 无关】(`…/xwcore` ⇒ `…/xwcore-typo`)⇒ 对 `S1` 翻转前后同效。
#   ★★ 订正(`v1.9.6` `M1` 源切批 · 2026-10-17): 原锚逐字钉 `kemeng1/xwcore"` ⇒ 源切(`kemeng1` ⇒
#   `xuanwu-code`)后**注入失败**(`AssertionError: inject failed` ⇒ R2 阳性对照 FAIL ⇒ 本腿 rc=1)。
#   改为 org 无关形(唯仓名)⇒ 对后续换 org **恒稳**(承在册「报谓词须书正则原文 ∧ 可取结构面者恒稳」)。
#   ★ 唯一性核(一手): `/xwcore"` 于 `deny.toml` 命中 **1** 处 ⇒ 无歧义。
echo "-- R2 阳性对照: allow 一条 path 改错 ⇒ 集合谓词必咬(而条数不变 ⇒ 旧计数谓词不咬)"
python3 - "$TMP/deny_g3red.toml" <<'PY'
import re, sys
t = open('deny.toml', encoding='utf-8').read()
t2, n = re.subn(r'(/xwcore)"', r'\1-typo"', t, count=1)
assert n == 1, 'inject failed'
open(sys.argv[1], 'w', encoding='utf-8').write(t2)
PY
REDG3_OUT="$(g3_predicate "$TMP/deny_g3red.toml")"
{ read -r RA RL RU RC2; read -r _RU; read -r _RC; } <<<"$REDG3_OUT"
DENY_G3RC=0
cargo deny --config "$TMP/deny_g3red.toml" check sources >"$TMP/deny_g3red_out.txt" 2>&1 || DENY_G3RC=$?
# ★★ 显名支(承裁19 §2 同律 · 同 R1)
if [ "$DENY_G3RC" -eq 124 ]; then
  no "R2 ★ 逾时被杀 rc=124(**本腿未判**)—— 超时 ≠ 未咬合 · 禁混(候复跑)"
elif [ ! -s "$TMP/deny_g3red_out.txt" ]; then
  no "R2 ★ 器无输出 rc=$DENY_G3RC(**未判**)—— 无从判咬合(显名 · 非判「未咬合」)"
elif [ "$RU" -ge 1 ] && [ "$RA" -eq "$RL" ] && [ "$DENY_G3RC" -ne 0 ]; then
  ok "R2 咬合: 集合谓词 未用=$RU(必红)∧ 条数 $RA==$RL 不变(旧计数谓词报绿 = 盲)∧ 器 rc=$DENY_G3RC"
else
  no "R2 未咬合: 未用=$RU ∧ 条数 $RA⇄$RL ∧ 器 rc=$DENY_G3RC(有输出 ∧ 未中 ⇒ 阳性对照失败)"
fi

echo "== 结果: PASS=$PASS FAIL=$FAIL =="
[ "$FAIL" -eq 0 ] || exit 1
exit 0