#!/usr/bin/env bash # AUTH.3A PHASE 11 — Test-Sensitivity: Beweise ROT bei gebrochener Auth-Semantik. # # Mutiert rq_c5c.py temporaer (A-H) und prueft, dass die AUTH.3A-Testsuite # ROT wird. Keine hardcodierten PASS-Werte. Keine Produktion. # # A. fehlendes Token sendet Request trotzdem # B. Authorization Header entfernt # C. SAVE Caller laedt DELETE Token # D. DeleteExecutor laedt SAVE Token # E. Delete ohne Human Approval erlaubt # F. Token wird geloggt # G. Retry verliert Authorization # H. Replay faellt auf unauthenticated zurueck set -u cd "$(dirname "$0")" TARGET="rq_c5c.py" TARGET2="rq_c5_delete.py" TEST="test_c5_auth3a.py" PY="python3 -m unittest ${TEST%.py}" fail=0 run_mutation() { local name="$1"; shift local expect_red="$1"; shift # Mutation anwenden "$@" || { echo "MUTATION-APPLY-FAIL: $name"; fail=1; return; } # Tests ausfuehren local out out=$($PY 2>&1) local rc=$? # Mutation zurueckrollen (aus .bak, NICHT git checkout — AUTH.3A-Aenderungen sind uncommitted) cp "$TARGET.bak" "$TARGET" cp "$TARGET2.bak" "$TARGET2" if [ "$expect_red" = "RED" ]; then if [ $rc -ne 0 ]; then echo "OK [$name] -> ROT (rc=$rc)" else echo "FAIL[$name] -> GRUEN (sollte ROT sein)" fail=1 fi else if [ $rc -eq 0 ]; then echo "OK [$name] -> GRUEN" else echo "FAIL[$name] -> ROT (sollte GRUEN sein)" fail=1 fi fi } cp "$TARGET" "$TARGET.bak" cp "$TARGET2" "$TARGET2.bak" # A. fehlendes Token sendet Request trotzdem (entferne _require_token in write) run_mutation "A-fehlendes-token-sendet-trotzdem" RED \ python3 - <<'EOF' import re p="rq_c5c.py" s=open(p).read() # write(): _require_token entfernen -> sendet ohne Token s=s.replace("token = self._require_token(self.save_token, \"SAVE\")","token = self.save_token") open(p,"w").write(s) EOF # B. Authorization Header entfernt (kein auth_token an _post) run_mutation "B-auth-header-entfernt" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() s=s.replace("if auth_token is not None:\n headers[\"Authorization\"] = f\"Bearer {auth_token}\"","pass") open(p,"w").write(s) EOF # C. SAVE Caller laedt DELETE Token (write nutzt delete_token) run_mutation "C-save-laedt-delete-token" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() s=s.replace("token = self._require_token(self.save_token, \"SAVE\")","token = self._require_token(self.delete_token, \"SAVE\")") open(p,"w").write(s) EOF # D. DeleteExecutor laedt SAVE Token (delete nutzt save_token) run_mutation "D-delete-laedt-save-token" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() s=s.replace("token = self._require_token(self.delete_token, \"DELETE\")","token = self._require_token(self.save_token, \"DELETE\")") open(p,"w").write(s) EOF # E. Delete ohne Human Approval erlaubt (entferne _validate_approval in execute) run_mutation "E-delete-ohne-approval-erlaubt" RED \ python3 - <<'EOF' p="rq_c5_delete.py" s=open(p).read() s=s.replace("approval = self._validate_approval(commit_sha, change)","approval = {'approval_id': 'x', 'workflow_commit': commit_sha, 'object_id': change.get('object_id'), 'path': change.get('path_before') or change.get('path_after')}") open(p,"w").write(s) EOF # F. Token wird geloggt (repr enthaelt Token) run_mutation "F-token-geloggt" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() # Fuege eine __repr__ ein, die den save_token exponiert (nach self.delete_token = delete_token) s=s.replace(" self.save_token = save_token\n self.delete_token = delete_token", " self.save_token = save_token\n self.delete_token = delete_token\n\n def __repr__(self):\n return f\"TolariaClient(save_token={self.save_token})\"") open(p,"w").write(s) EOF # G. Retry verliert Authorization (write sendet kein Token beim 2. Aufruf) run_mutation "G-retry-verliert-auth" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() s=s.replace("token = self._require_token(self.save_token, \"SAVE\")","token = self._require_token(self.save_token, \"SAVE\") if not hasattr(self,'_retried') else None\n self._retried = True") open(p,"w").write(s) EOF # H. Replay faellt auf unauthenticated zurueck (delete ohne Token) run_mutation "H-replay-unauthenticated" RED \ python3 - <<'EOF' p="rq_c5c.py" s=open(p).read() s=s.replace("token = self._require_token(self.delete_token, \"DELETE\")","token = None") open(p,"w").write(s) EOF rm -f "$TARGET.bak" "$TARGET2.bak" echo "=== SENSITIVITY RESULT: $([ $fail -eq 0 ] && echo ALL-RED || echo FAILURES) ===" exit $fail