#!/bin/bash # control-negativ.sh - IN WSL: controlul negativ al probelor clientului .NET (Aere.Cloud). Fiecare paznic se strica intr-o COPIE a sursei # (depozitul nu se atinge), probele ruleaza pe copie si proba tinta TREBUIE sa pice. O plantare a carei ancora nu apare exact o data, sau # care nu compileaza (TreatWarningsAsErrors), e STRICAT, nu rosu. La urma, sursa neatinsa trebuie sa treaca intreaga. # bash csharp/control-negativ.sh (Linux sau WSL, cu un SDK .NET 8+ in PATH; `dotnet` gasit altundeva: DOTNET_ROOT + PATH) # 2026-09-29: caile sunt derivate (dosarul scriptului, un dosar temporar), nu scrise fix, ca scriptul sa mearga si din depozitul public. set -u export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 command -v dotnet >/dev/null || { echo "STRICAT: dotnet nu e in PATH"; exit 2; } S=$(cd "$(dirname "$0")" && pwd) W=$(mktemp -d "${TMPDIR:-/tmp}/sdk-csharp-control-XXXX") cp -r "$S/Aere.Cloud" "$S/Aere.Cloud.Tests" "$W/"; rm -rf "$W"/*/bin "$W"/*/obj SRC="$W/Aere.Cloud/AereCloudClient.cs"; tr -d '\r' < "$S/Aere.Cloud/AereCloudClient.cs" > "$W/original.cs" cat > "$W/plantari.py" <<'PY' import sys P = [ ("exportul jsonl declarat verificat fara hash", 'format == "jsonl" ? !string.IsNullOrEmpty(digest) && digest == Sha256Hex(r.Body) : null', 'format == "jsonl" ? true : null', "ExportulZilei"), ("ziua tinuta acceptata fara comparatie", 'new KeptCheck(day, "held", held, local, local == held, null)', 'new KeptCheck(day, "held", held, local, true, null)', "ExportulPastrat"), ("piatra zilei sterse acceptata fara comparatie", 'new KeptCheck(day, "expired", digest, local, local == digest, del)', 'new KeptCheck(day, "expired", digest, local, true, del)', "ExportulPastrat"), # inaintea throw-ului pentru non-2xx (prima forma a plantarii statea dupa el, deci nu se executa niciodata si "a ramas verde") ("un 429 intors ca nepotrivire", ' if (r.Status < 200 || r.Status >= 300) throw new AereCloudException(r.Status, Encoding.UTF8.GetString(r.Body), "/account/audit");\n var held', ' if (r.Status == 429) return new KeptCheck(day, "held", "", local, false, null);\n if (r.Status < 200 || r.Status >= 300) throw new AereCloudException(r.Status, Encoding.UTF8.GetString(r.Body), "/account/audit");\n var held', "ExportulPastrat"), ("cheia trimisa si fara attest", 'return JsonAsync(HttpMethod.Post, "/pq/readiness", b, attest, ct);', 'return JsonAsync(HttpMethod.Post, "/pq/readiness", b, true, ct);', "ReadinessCheiaNumaiLaAttest"), ("redirectarile urmate (cheia ar pleca spre alta gazda)", 'new HttpClientHandler { AllowAutoRedirect = false }', 'new HttpClientHandler { AllowAutoRedirect = true }', "RedirectareaNuEUrmata"), ("webhook acceptat fara semnatura", 'return CryptographicOperations.FixedTimeEquals(want, got);', 'return got.Length >= 0 || CryptographicOperations.FixedTimeEquals(want, got);', "VerifyWebhook"), ("cheia goala acceptata", 'if (string.IsNullOrEmpty(apiKey)) throw', 'if (apiKey == "niciodata-" + "asa") throw', "CheiaEObligatorie"), ("lantul cerut scapat din Trust API", '(chain > 0 ? "?chain=" + chain : "")', '(chain > 0 ? "" : "")', "TrustApiVerify"), ("un rezultat RPC fara forma citit ca zero", ' throw new AereCloudException(200, e.GetRawText(), "/rpc");', ' return 0;', "EroriSiBlockNumber"), ] if sys.argv[1] == "n": print(len(P)); sys.exit(0) i = int(sys.argv[1]); nume, vechi, nou, tinta = P[i] t = open(sys.argv[2]).read() if t.count(vechi) != 1: print("ANCORA %d" % t.count(vechi)); sys.exit(3) open(sys.argv[3], "w").write(t.replace(vechi, nou)); print(nume + "|" + tinta) PY ruleaza() { # -> iesirea probelor in $W/iesire.txt; cod: 0 rulat, 2 nu compileaza ( cd "$W" && dotnet build Aere.Cloud.Tests -c Release -p:NuGetAudit=false -nodeReuse:false -p:UseSharedCompilation=false > build.log 2>&1 < /dev/null ) || return 2 # exact UN dll de probe in iesirea acestei constructii (un `| head -1` peste mai multe ar alege la intamplare) local dll; dll=$(ls "$W"/Aere.Cloud.Tests/bin/Release/net*/Aere.Cloud.Tests.dll 2>/dev/null); [ "$(printf '%s\n' "$dll" | grep -c .)" = 1 ] || return 2 dotnet "$dll" > "$W/iesire.txt" 2>&1 < /dev/null; return 0 } N=$(python3 "$W/plantari.py" n); RAU=0 for i in $(seq 0 $((N - 1))); do L=$(python3 "$W/plantari.py" "$i" "$W/original.cs" "$SRC"); c=$? [ "$c" = 0 ] || { echo " STRICAT plantarea $i: $L"; RAU=$((RAU+1)); continue; } nume=${L%|*}; tinta=${L#*|} if ! ruleaza; then echo " STRICAT $nume: nu compileaza ($(grep -m1 -oE 'error [A-Z]+[0-9]+[^[]*' "$W/build.log"))"; RAU=$((RAU+1)); continue; fi if grep -q "^--- FAIL: $tinta" "$W/iesire.txt"; then echo " ROSU cum trebuia $nume (pica $(grep -c '^--- FAIL' "$W/iesire.txt"): $(grep '^--- FAIL' "$W/iesire.txt" | cut -d: -f2 | tr '\n' ' '))" else echo " CONTROL CAZUT $nume: $tinta a ramas verde"; RAU=$((RAU+1)); fi done cp "$W/original.cs" "$SRC" if ruleaza && ! grep -q '^--- FAIL' "$W/iesire.txt" && grep -q '^--- PASS' "$W/iesire.txt"; then echo " martor: sursa neatinsa, $(grep -c '^--- PASS' "$W/iesire.txt") probe verzi" else echo " MARTORUL nu e verde"; RAU=$((RAU+1)); fi [ "$RAU" = 0 ] && echo "CONTROL NEGATIV TRECUT ($N din $N rosii, martorul verde)" || echo "CONTROL NEGATIV: $RAU probleme" rm -rf "$W" exit $([ "$RAU" = 0 ] && echo 0 || echo 1)