#!/usr/bin/env sh
set -eu

if ! grep -q '^#!\[deny(unsafe_code)\]' src/lib.rs; then
    echo "unsafe boundary: src/lib.rs must keep #![deny(unsafe_code)]"
    exit 1
fi

simd_allow_files='src/simd/mod.rs src/simd/neon.rs src/simd/neon/direct.rs src/simd/wasm/direct.rs src/simd/x86/cleanup.rs src/simd/x86/decode.rs src/simd/x86/decode_direct.rs src/simd/x86/mod.rs'
simd_boundary_files='src/simd/mod.rs src/simd/neon.rs src/simd/neon/direct.rs src/simd/rvv.rs src/simd/rvv/asm.rs src/simd/static_token.rs src/simd/sve.rs src/simd/wasm.rs src/simd/wasm/direct.rs src/simd/x86/cleanup.rs src/simd/x86/decode.rs src/simd/x86/decode_direct.rs src/simd/x86/mod.rs'
simd_tests_allowed='src/simd/tests.rs src/simd/x86_encode_tests.rs'
root_allowed='src/lib.rs'
cleanup_allowed='src/cleanup.rs'
ct_allowed_files='src/ct/decode.rs src/ct/equality.rs'
assurance_allowed_files='src/v2/assurance/context.rs src/v2/assurance/default_provider.rs src/v2/assurance/protected.rs src/v2/assurance/provider.rs'
matches="$(grep -RIl 'allow(unsafe_code)' src | sort || true)"
allowed="$(printf '%s\n' "$cleanup_allowed" src/ct/decode.rs src/ct/equality.rs $simd_allow_files $assurance_allowed_files | sort)"

if [ "$matches" != "$allowed" ]; then
    echo "unsafe boundary: allow(unsafe_code) may appear only in reviewed cleanup, CT, SIMD, and v2 assurance boundaries"
    if [ -n "$matches" ]; then
        echo "$matches"
    fi
    exit 1
fi

assurance_allow_count="$(grep -h -c '^[[:space:]]*#\[allow(unsafe_code)\]$' $assurance_allowed_files | awk '{ total += $1 } END { print total + 0 }')"
if [ "$assurance_allow_count" -ne 5 ]; then
    echo "unsafe boundary: v2 assurance must have exactly five reviewed allow(unsafe_code) sites"
    exit 1
fi

if ! awk '
    /^[[:space:]]*#\[allow\(unsafe_code\)\]$/ {
        allow_line = NR
    }
    /pub const unsafe fn new\(/ || /pub unsafe trait PlatformAttestation/ || /pub unsafe trait ProtectedMemoryProvider/ || /unsafe impl<const SLOTS: usize> ProtectedMemoryProvider/ || /unsafe impl<P, State, Level> Send/ {
        if (allow_line != NR - 1) {
            failed = 1
        }
        seen += 1
    }
    END { exit failed || seen != 5 }
' $assurance_allowed_files; then
    echo "unsafe boundary: v2 assurance allows unsafe only for evidence construction, provider protocols, the default provider, and conditional Send"
    exit 1
fi

root_allow_count="$(grep -c '^#\[allow(unsafe_code)\]$' "$root_allowed" || true)"
if [ "$root_allow_count" -ne 0 ]; then
    echo "unsafe boundary: src/lib.rs must not carry module-local allow(unsafe_code) helpers"
    exit 1
fi

cleanup_allow_count="$(grep -c '^#\[allow(unsafe_code)\]$' "$cleanup_allowed" || true)"
if [ "$cleanup_allow_count" -ne 3 ]; then
    echo "unsafe boundary: src/cleanup.rs must have exactly three reviewed allow(unsafe_code) helpers"
    exit 1
fi

ct_allow_count="$(grep -h -c '^#\[allow(unsafe_code)\]$' $ct_allowed_files | awk '{ total += $1 } END { print total + 0 }')"
if [ "$ct_allow_count" -ne 4 ]; then
    echo "unsafe boundary: src/ct/ must have exactly four reviewed allow(unsafe_code) helpers"
    exit 1
fi

if ! awk '
    /^#\[allow\(unsafe_code\)\]$/ {
        allow_line = NR
    }
    /^(pub\((crate|super)\) )?fn wipe_bytes\(/ || /^fn wipe_barrier\(/ || /^(pub\((crate|super)\) )?fn wipe_vec_spare_capacity\(/ || /^(pub\((crate|super)\) )?fn ct_error_gate_barrier\(/ || /^fn constant_time_eq_same_len\(/ || /^(pub\((crate|super)\) )?fn ct_accumulate_u8\(/ || /^(pub\((crate|super)\) )?fn ct_decode_alphabet_byte/ {
        if (allow_line != NR - 1) {
            failed = 1
        }
        seen += 1
    }
    END { exit failed || seen != 7 }
' "$cleanup_allowed" $ct_allowed_files; then
    echo "unsafe boundary: allow(unsafe_code) must apply only to reviewed cleanup, comparison, CT accumulator, CT scan, and CT gate helpers"
    exit 1
fi

arch_matches="$(grep -RIl -e 'core::arch' -e 'std::arch' -e 'is_x86_feature_detected!' -e 'target_feature' src | sort || true)"
arch_allowed="$(printf '%s\n' src/ct/equality.rs "$cleanup_allowed" $simd_boundary_files $simd_tests_allowed | sort)"

if [ "$arch_matches" != "$arch_allowed" ]; then
    echo "unsafe boundary: architecture intrinsics may appear only in src/ct/equality.rs CT barriers, $cleanup_allowed cleanup barriers, and src/simd/"
    if [ -n "$arch_matches" ]; then
        echo "$arch_matches"
    fi
    exit 1
fi

if ! grep -q 'core::arch::asm!' "$cleanup_allowed"; then
    echo "unsafe boundary: src/cleanup.rs cleanup barrier must use the reviewed inline assembly barrier"
    exit 1
fi

if [ ! -s docs/UNSAFE.md ]; then
    echo "unsafe boundary: docs/UNSAFE.md must document unsafe sites"
    exit 1
fi

# Parse declaration tokens with POSIX awk. BSD sed does not support the GNU
# basic-regex `\|` extension previously used here, which made the macOS
# inventory appear empty even though the reviewed unsafe functions were present.
unsafe_functions="$(awk '
    {
        for (field = 1; field + 2 <= NF; field += 1) {
            if ($field == "unsafe" && $(field + 1) == "fn") {
                symbol = $(field + 2)
                sub(/[<(].*$/, "", symbol)
                if (symbol ~ /^[A-Za-z_][A-Za-z0-9_]*$/) {
                    print symbol
                }
            }
        }
    }
' $simd_boundary_files)"

if [ -z "$unsafe_functions" ]; then
    echo "unsafe boundary: expected documented prototype unsafe functions in src/simd/"
    exit 1
fi

for symbol in $unsafe_functions; do
    if ! grep -q "$symbol" docs/UNSAFE.md; then
        echo "unsafe boundary: docs/UNSAFE.md must document $symbol"
        exit 1
    fi
done

bare_unsafe_wrappers='decode_slice_ssse3_sse41 decode_slice_avx2 decode_slice_avx512 decode_slice_neon'
for symbol in $bare_unsafe_wrappers; do
    if ! grep -q "$symbol" docs/UNSAFE.md; then
        echo "unsafe boundary: docs/UNSAFE.md must document $symbol"
        exit 1
    fi
done

if ! awk '
    /^[[:space:]]*unsafe[[:space:]]*\{/ {
        if (prev1 !~ /SAFETY:/ && prev2 !~ /SAFETY:/ && prev3 !~ /SAFETY:/ && prev4 !~ /SAFETY:/) {
            print FILENAME ":" FNR ": unsafe block is missing a nearby SAFETY explanation"
            failed = 1
        }
    }
    {
        prev4 = prev3
        prev3 = prev2
        prev2 = prev1
        prev1 = $0
    }
    END { exit failed }
' $ct_allowed_files "$cleanup_allowed" $simd_boundary_files $assurance_allowed_files; then
    echo "unsafe boundary: every unsafe block must have a nearby SAFETY explanation"
    exit 1
fi

echo "unsafe boundary: ok"
