feat: Payment Compliance Pack — Semgrep + CodeQL + State Machine + Schema
Ausfuehrbares Pruefpaket fuer Payment-Terminal-Systeme: 1. Semgrep-Regeln (25 Regeln in 5 Dateien): - Logging: Sensitive Daten, Tokens, Debug-Flags - Crypto: MD5/SHA1/DES/ECB, Hardcoded Secrets, Weak Random, TLS - API: Debug-Routes, Exception Leaks, IDOR, Input Validation - Config: Test-Endpoints, CORS, Cookies, Retry - Data: Telemetrie, Cache, Export, Queue, Testdaten 2. CodeQL Query-Specs (5 Briefings): - Sensitive Data → Logs - Sensitive Data → HTTP Response - Tenant Context Loss - Sensitive Data → Telemetry - Cache/Export Leak 3. State-Machine-Tests (10 Testfaelle): - 11 Zustaende, 15 Events, 8 Invarianten - Duplicate Response, Timeout+Late Success, Decline - Invalid Reversal, Cancel, Backend Timeout - Parallel Reversal, Unknown Response, Reconnect - Late Response after Cancel 4. Finding Schema (JSON Schema): - Einheitliches Format fuer alle Engines - control_id, engine, status, confidence, evidence, verdict_text Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
65
ai-compliance-sdk/payment-compliance-pack/README.md
Normal file
65
ai-compliance-sdk/payment-compliance-pack/README.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Payment Compliance Pack
|
||||||
|
|
||||||
|
Ausfuehrbares Pruefpaket fuer Payment-Terminal-Systeme.
|
||||||
|
|
||||||
|
## Inhalt
|
||||||
|
|
||||||
|
### Semgrep-Regeln (25 Regeln)
|
||||||
|
|
||||||
|
| Datei | Regeln | Controls |
|
||||||
|
|-------|--------|----------|
|
||||||
|
| `payment_logging.yml` | 5 | LOG-001, LOG-002, LOG-014 |
|
||||||
|
| `payment_crypto.yml` | 6 | CRYPTO-001, CRYPTO-008, CRYPTO-009, KEYMGMT-001 |
|
||||||
|
| `payment_api.yml` | 5 | API-004, API-005, API-014, API-017 |
|
||||||
|
| `payment_config.yml` | 5 | CONFIG-001 bis CONFIG-004 |
|
||||||
|
| `payment_data.yml` | 5 | DATA-004, DATA-005, DATA-013, TELEMETRY-001 |
|
||||||
|
|
||||||
|
### CodeQL-Specs (5 Queries)
|
||||||
|
|
||||||
|
| Datei | Ziel | Controls |
|
||||||
|
|-------|------|----------|
|
||||||
|
| `sensitive-data-to-logs.md` | Datenfluss zu Loggern | LOG-001, LOG-002, DATA-013 |
|
||||||
|
| `sensitive-data-to-response.md` | Datenfluss in HTTP-Responses | API-009, ERROR-005 |
|
||||||
|
| `tenant-context-loss.md` | Mandantenkontext-Verlust | TENANT-001, TENANT-002 |
|
||||||
|
| `sensitive-data-to-telemetry.md` | Datenfluss in Telemetrie | TELEMETRY-001, TELEMETRY-002 |
|
||||||
|
| `cache-export-leak.md` | Leaks in Cache/Export | DATA-004, DATA-011 |
|
||||||
|
|
||||||
|
### State-Machine-Tests (10 Testfaelle)
|
||||||
|
|
||||||
|
| Datei | Inhalt |
|
||||||
|
|-------|--------|
|
||||||
|
| `terminal_states.md` | 11 Zustaende, 15 Events, Transitions |
|
||||||
|
| `terminal_invariants.md` | 8 Invarianten |
|
||||||
|
| `terminal_testcases.json` | 10 ausfuehrbare Testfaelle |
|
||||||
|
|
||||||
|
### Finding-Schema
|
||||||
|
|
||||||
|
| Datei | Beschreibung |
|
||||||
|
|-------|-------------|
|
||||||
|
| `finding.schema.json` | JSON Schema fuer Pruefergebnisse |
|
||||||
|
|
||||||
|
## Ausfuehrung
|
||||||
|
|
||||||
|
### Semgrep
|
||||||
|
|
||||||
|
```bash
|
||||||
|
semgrep --config payment-compliance-pack/semgrep/ /path/to/source
|
||||||
|
```
|
||||||
|
|
||||||
|
### State-Machine-Tests
|
||||||
|
|
||||||
|
Die Testfaelle in `terminal_testcases.json` definieren:
|
||||||
|
- Ausgangszustand
|
||||||
|
- Event-Sequenz
|
||||||
|
- Erwarteten Endzustand
|
||||||
|
- Zu pruefende Invarianten
|
||||||
|
- Gemappte Controls
|
||||||
|
|
||||||
|
Diese koennen gegen einen Terminal-Adapter oder Simulator ausgefuehrt werden.
|
||||||
|
|
||||||
|
## Priorisierte Umsetzung
|
||||||
|
|
||||||
|
1. **Welle 1:** 25 Semgrep-Regeln sofort produktiv
|
||||||
|
2. **Welle 2:** 5 CodeQL-Queries fuer Datenfluesse
|
||||||
|
3. **Welle 3:** 10 State-Machine-Tests gegen Terminal-Simulator
|
||||||
|
4. **Welle 4:** Tender-Mapping (Requirement → Control → Finding → Verdict)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# CodeQL Query: Cache and Export Leak
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Finde Leaks sensibler Daten in Caches, Files, Reports und Exportpfaden.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- Sensitive payment attributes (pan, cvv, track2)
|
||||||
|
- Full transaction objects with sensitive fields
|
||||||
|
|
||||||
|
## Sinks
|
||||||
|
- Redis/Memcache writes
|
||||||
|
- Temp file writes
|
||||||
|
- CSV/PDF/Excel exports
|
||||||
|
- Report builders
|
||||||
|
|
||||||
|
## Mapped Controls
|
||||||
|
- `DATA-004`: Temporaere Speicher ohne sensitive Daten
|
||||||
|
- `DATA-005`: Sensitive Daten in Telemetrie nicht offengelegt
|
||||||
|
- `DATA-011`: Batch/Queue ohne unnoetige sensitive Felder
|
||||||
|
- `REPORT-005`: Berichte beruecksichtigen Zeitzonen konsistent
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# CodeQL Query: Sensitive Data to Logs
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Finde Fluesse von sensitiven Zahlungsdaten zu Loggern.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
Variablen, Felder, Parameter oder JSON-Felder mit Namen:
|
||||||
|
- `pan`, `cardNumber`, `card_number`
|
||||||
|
- `cvv`, `cvc`
|
||||||
|
- `track2`, `track_2`
|
||||||
|
- `pin`
|
||||||
|
- `expiry`, `ablauf`
|
||||||
|
|
||||||
|
## Sinks
|
||||||
|
- Logger-Aufrufe (`logging.*`, `logger.*`, `console.*`, `log.*`)
|
||||||
|
- Telemetrie-/Tracing-Emitter (`span.set_attribute`, `tracer.*)
|
||||||
|
- Audit-Logger (wenn nicht maskiert)
|
||||||
|
|
||||||
|
## Expected Result
|
||||||
|
| Field | Type |
|
||||||
|
|-------|------|
|
||||||
|
| file | string |
|
||||||
|
| line | int |
|
||||||
|
| source_name | string |
|
||||||
|
| sink_call | string |
|
||||||
|
| path | string[] |
|
||||||
|
|
||||||
|
## Mapped Controls
|
||||||
|
- `LOG-001`: Keine sensitiven Zahlungsdaten im Log
|
||||||
|
- `LOG-002`: PAN maskiert in Logs
|
||||||
|
- `DATA-013`: Sensitive Daten in Telemetrie nicht offengelegt
|
||||||
|
- `TELEMETRY-001`: Telemetriedaten ohne sensitive Zahlungsdaten
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# CodeQL Query: Sensitive Data to HTTP Response
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Finde Fluesse sensibler Daten in HTTP-/API-Responses oder Exception-Bodies.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- Sensible Payment-Felder: pan, cvv, track2, cardNumber, pin, expiry
|
||||||
|
- Interne Payment DTOs mit sensitiven Attributen
|
||||||
|
|
||||||
|
## Sinks
|
||||||
|
- JSON serializer / response builder
|
||||||
|
- Exception payload / error handler response
|
||||||
|
- Template rendering output
|
||||||
|
|
||||||
|
## Mapped Controls
|
||||||
|
- `API-009`: API-Antworten minimieren sensible Daten
|
||||||
|
- `API-015`: Interne Fehler ohne sensitive Daten an Client
|
||||||
|
- `ERROR-005`: Ausnahmebehandlung gibt keine sensitiven Rohdaten zurueck
|
||||||
|
- `REPORT-006`: Reports offenbaren nur rollenerforderliche Daten
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# CodeQL Query: Sensitive Data to Telemetry
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Finde Fluesse sensibler Daten in Metriken, Traces und Telemetrie-Events.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- Payment DTO fields (pan, cvv, track2, cardNumber)
|
||||||
|
- Token/Session related fields
|
||||||
|
|
||||||
|
## Sinks
|
||||||
|
- Span attributes / trace tags
|
||||||
|
- Metric labels
|
||||||
|
- Telemetry events / exporters
|
||||||
|
|
||||||
|
## Mapped Controls
|
||||||
|
- `TELEMETRY-001`: Telemetriedaten ohne sensitive Zahlungsdaten
|
||||||
|
- `TELEMETRY-002`: Tracing maskiert identifizierende Felder
|
||||||
|
- `TELEMETRY-003`: Metriken ohne hochkartesische sensitive Labels
|
||||||
|
- `DATA-013`: Sensitive Daten in Telemetrie nicht offengelegt
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# CodeQL Query: Tenant Context Loss
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
Finde Datenbank-, Cache- oder Exportpfade ohne durchgehenden Tenant-Kontext.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- Request tenant (header, token, session)
|
||||||
|
- Device tenant
|
||||||
|
- User tenant
|
||||||
|
|
||||||
|
## Danger Patterns
|
||||||
|
- DB Query ohne tenant filter / WHERE clause
|
||||||
|
- Cache key ohne tenant prefix
|
||||||
|
- Export job ohne tenant binding
|
||||||
|
- Report query ohne Mandanteneinschraenkung
|
||||||
|
|
||||||
|
## Mapped Controls
|
||||||
|
- `TENANT-001`: Mandantenkontext serverseitig validiert
|
||||||
|
- `TENANT-002`: Datenabfragen mandantenbeschraenkt
|
||||||
|
- `TENANT-006`: Caching beruecksichtigt Mandantenkontext
|
||||||
|
- `TENANT-008`: Datenexporte erzwingen Mandantenisolation
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"title": "Payment Compliance Finding",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["control_id", "engine", "status", "confidence", "evidence", "verdict_text"],
|
||||||
|
"properties": {
|
||||||
|
"control_id": { "type": "string" },
|
||||||
|
"engine": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["semgrep", "codeql", "contract_test", "state_machine_test", "integration_test", "manual"]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["passed", "failed", "warning", "not_tested", "needs_manual_review"]
|
||||||
|
},
|
||||||
|
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
|
||||||
|
"severity": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["low", "medium", "high", "critical"]
|
||||||
|
},
|
||||||
|
"evidence": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"file": { "type": "string" },
|
||||||
|
"line": { "type": "integer" },
|
||||||
|
"snippet_type": { "type": "string" },
|
||||||
|
"scenario": { "type": "string" },
|
||||||
|
"observed_state": { "type": "string" },
|
||||||
|
"expected_state": { "type": "string" },
|
||||||
|
"notes": { "type": "string" }
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mapped_requirements": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" }
|
||||||
|
},
|
||||||
|
"verdict_text": { "type": "string" },
|
||||||
|
"next_action": { "type": "string" }
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
rules:
|
||||||
|
- id: payment-debug-route
|
||||||
|
message: Debug- oder Diagnosepfad im produktiven API-Code pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(/debug|/internal|/test|/actuator|/swagger|/openapi)
|
||||||
|
|
||||||
|
- id: payment-admin-route-without-auth
|
||||||
|
message: Administrative Route ohne offensichtlichen Auth-Schutz pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python]
|
||||||
|
patterns:
|
||||||
|
- pattern: |
|
||||||
|
@app.$METHOD($ROUTE)
|
||||||
|
def $FUNC(...):
|
||||||
|
...
|
||||||
|
- metavariable-pattern:
|
||||||
|
metavariable: $ROUTE
|
||||||
|
pattern-regex: (?i).*(admin|config|terminal|maintenance|device|key).*
|
||||||
|
|
||||||
|
- id: payment-raw-exception-response
|
||||||
|
message: Roh-Exceptions duerfen nicht direkt an Clients zurueckgegeben werden.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript]
|
||||||
|
pattern-regex: (?i)(return .*str\(e\)|res\.status\(500\)\.send\(e|json\(.*error.*e)
|
||||||
|
|
||||||
|
- id: payment-missing-input-validation
|
||||||
|
message: Zahlungsrelevanter Endpunkt ohne offensichtliche Validierung pruefen.
|
||||||
|
severity: INFO
|
||||||
|
languages: [python, javascript, typescript]
|
||||||
|
pattern-regex: (?i)(amount|currency|terminalId|transactionId)
|
||||||
|
|
||||||
|
- id: payment-idor-risk
|
||||||
|
message: Direkter Zugriff ueber terminalId/transactionId ohne Pruefung.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(get.*terminalId|find.*terminalId|get.*transactionId|find.*transactionId)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
rules:
|
||||||
|
- id: payment-prod-config-test-endpoint
|
||||||
|
message: Test- oder Sandbox-Endpunkt in produktionsnaher Konfiguration erkannt.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [yaml, json]
|
||||||
|
pattern-regex: (?i)(sandbox|test-endpoint|mock-terminal|dummy-acquirer)
|
||||||
|
|
||||||
|
- id: payment-prod-debug-flag
|
||||||
|
message: Unsicherer Debug-Flag in Konfiguration erkannt.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [yaml, json]
|
||||||
|
pattern-regex: (?i)(debug:\s*true|"debug"\s*:\s*true)
|
||||||
|
|
||||||
|
- id: payment-open-cors
|
||||||
|
message: Offene CORS-Freigabe pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [yaml, json, javascript, typescript]
|
||||||
|
pattern-regex: (?i)(Access-Control-Allow-Origin.*\*|origin:\s*["']\*["'])
|
||||||
|
|
||||||
|
- id: payment-insecure-session-cookie
|
||||||
|
message: Unsicher gesetzte Session-Cookies pruefen.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [javascript, typescript, python]
|
||||||
|
pattern-regex: (?i)(httpOnly\s*:\s*false|secure\s*:\s*false|sameSite\s*:\s*["']none["'])
|
||||||
|
|
||||||
|
- id: payment-unbounded-retry
|
||||||
|
message: Retry-Konfiguration scheint unbegrenzt oder zu hoch.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [yaml, json]
|
||||||
|
pattern-regex: (?i)(retry.*(9999|infinite|unbounded))
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
rules:
|
||||||
|
- id: payment-no-md5-sha1
|
||||||
|
message: Unsichere Hash-Algorithmen erkannt.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)\b(md5|sha1)\b
|
||||||
|
|
||||||
|
- id: payment-no-des-3des
|
||||||
|
message: Veraltete symmetrische Verfahren erkannt.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)\b(des|3des|tripledes)\b
|
||||||
|
|
||||||
|
- id: payment-no-ecb
|
||||||
|
message: ECB-Modus ist fuer sensible Daten ungeeignet.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)\becb\b
|
||||||
|
|
||||||
|
- id: payment-hardcoded-secret
|
||||||
|
message: Moeglicherweise hartkodiertes Secret erkannt.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
patterns:
|
||||||
|
- pattern-either:
|
||||||
|
- pattern: $KEY = "..."
|
||||||
|
- pattern: const $KEY = "..."
|
||||||
|
- pattern: final String $KEY = "..."
|
||||||
|
- metavariable-pattern:
|
||||||
|
metavariable: $KEY
|
||||||
|
pattern-regex: (?i).*(secret|apikey|api_key|password|passwd|privatekey|private_key|terminalkey|zvtkey|opiKey).*
|
||||||
|
|
||||||
|
- id: payment-weak-random
|
||||||
|
message: Nicht-kryptographischer Zufall in Sicherheitskontext erkannt.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java]
|
||||||
|
pattern-regex: (?i)(Math\.random|random\.random|new Random\()
|
||||||
|
|
||||||
|
- id: payment-disable-tls-verify
|
||||||
|
message: TLS-Zertifikatspruefung scheint deaktiviert zu sein.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(verify\s*=\s*False|rejectUnauthorized\s*:\s*false|InsecureSkipVerify\s*:\s*true|trustAll)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
rules:
|
||||||
|
- id: payment-sensitive-in-telemetry
|
||||||
|
message: Sensitive Zahlungsdaten in Telemetrie oder Tracing pruefen.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(trace|span|metric|telemetry).*(pan|cvv|track2|cardnumber|pin|expiry)
|
||||||
|
|
||||||
|
- id: payment-sensitive-in-cache
|
||||||
|
message: Sensitiver Wert in Cache-Key oder Cache-Payload pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(cache|redis|memcache).*(pan|cvv|track2|cardnumber|pin)
|
||||||
|
|
||||||
|
- id: payment-sensitive-export
|
||||||
|
message: Export oder Report mit sensitiven Feldern pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(export|report|csv|xlsx|pdf).*(pan|cvv|track2|cardnumber|pin)
|
||||||
|
|
||||||
|
- id: payment-test-fixture-real-data
|
||||||
|
message: Testdaten mit moeglichen echten Kartendaten pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [json, yaml, python, javascript, typescript]
|
||||||
|
pattern-regex: (?i)(4111111111111111|5555555555554444|track2|cvv)
|
||||||
|
|
||||||
|
- id: payment-queue-sensitive-payload
|
||||||
|
message: Queue-Nachricht mit sensitiven Zahlungsfeldern pruefen.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(publish|send|enqueue).*(pan|cvv|track2|cardnumber|pin)
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
rules:
|
||||||
|
- id: payment-no-sensitive-logging-python
|
||||||
|
message: Sensitive Zahlungsdaten duerfen nicht geloggt werden.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python]
|
||||||
|
patterns:
|
||||||
|
- pattern-either:
|
||||||
|
- pattern: logging.$METHOD(..., $X, ...)
|
||||||
|
- pattern: logger.$METHOD(..., $X, ...)
|
||||||
|
- metavariable-pattern:
|
||||||
|
metavariable: $X
|
||||||
|
pattern-regex: (?i).*(pan|cvv|cvc|track2|track_2|cardnumber|card_number|karten|pin|expiry|ablauf).*
|
||||||
|
|
||||||
|
- id: payment-no-sensitive-logging-js
|
||||||
|
message: Sensitive Zahlungsdaten duerfen nicht geloggt werden.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [javascript, typescript]
|
||||||
|
patterns:
|
||||||
|
- pattern-either:
|
||||||
|
- pattern: console.$METHOD(..., $X, ...)
|
||||||
|
- pattern: logger.$METHOD(..., $X, ...)
|
||||||
|
- metavariable-pattern:
|
||||||
|
metavariable: $X
|
||||||
|
pattern-regex: (?i).*(pan|cvv|cvc|track2|cardnumber|pin|expiry).*
|
||||||
|
|
||||||
|
- id: payment-no-token-logging
|
||||||
|
message: Tokens oder Session-IDs duerfen nicht geloggt werden.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(log|logger|logging|console)\.(debug|info|warn|error).*?(token|sessionid|session_id|authheader|authorization)
|
||||||
|
|
||||||
|
- id: payment-no-debug-logging-prod-flag
|
||||||
|
message: Debug-Logging darf in produktiven Pfaden nicht fest aktiviert sein.
|
||||||
|
severity: WARNING
|
||||||
|
languages: [python, javascript, typescript, java, go]
|
||||||
|
pattern-regex: (?i)(DEBUG\s*=\s*true|debug\s*:\s*true|setLevel\(.*DEBUG.*\))
|
||||||
|
|
||||||
|
- id: payment-audit-log-admin-action
|
||||||
|
message: Administrative sicherheitsrelevante Aktion ohne Audit-Hinweis pruefen.
|
||||||
|
severity: INFO
|
||||||
|
languages: [python, javascript, typescript]
|
||||||
|
pattern-regex: (?i)(deleteTerminal|rotateKey|updateConfig|disableDevice|enableMaintenance)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Terminal State Machine Invariants
|
||||||
|
|
||||||
|
## Invariant 1
|
||||||
|
APPROVED darf ohne expliziten Reversal-Pfad nicht in WAITING_FOR_TERMINAL zurueckgehen.
|
||||||
|
|
||||||
|
## Invariant 2
|
||||||
|
DECLINED darf keinen Buchungserfolg oder Success-Report erzeugen.
|
||||||
|
|
||||||
|
## Invariant 3
|
||||||
|
duplicate_response darf keinen zweiten Commit und keine zweite Success-Bestaetigung erzeugen.
|
||||||
|
|
||||||
|
## Invariant 4
|
||||||
|
DESYNC muss Audit-Logging und Klaerungsstatus ausloesen.
|
||||||
|
|
||||||
|
## Invariant 5
|
||||||
|
REVERSAL_PENDING darf nicht mehrfach parallel ausgeloest werden.
|
||||||
|
|
||||||
|
## Invariant 6
|
||||||
|
invalid_command darf nie zu APPROVED fuehren.
|
||||||
|
|
||||||
|
## Invariant 7
|
||||||
|
terminal_timeout darf nie stillschweigend als Erfolg interpretiert werden.
|
||||||
|
|
||||||
|
## Invariant 8
|
||||||
|
Late responses nach finalem Zustand muessen kontrolliert behandelt werden.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Terminal Payment State Machine
|
||||||
|
|
||||||
|
## States
|
||||||
|
- IDLE
|
||||||
|
- SESSION_OPEN
|
||||||
|
- PAYMENT_REQUESTED
|
||||||
|
- WAITING_FOR_TERMINAL
|
||||||
|
- APPROVED
|
||||||
|
- DECLINED
|
||||||
|
- CANCELLED
|
||||||
|
- REVERSAL_PENDING
|
||||||
|
- REVERSED
|
||||||
|
- ERROR
|
||||||
|
- DESYNC
|
||||||
|
|
||||||
|
## Events
|
||||||
|
- open_session
|
||||||
|
- close_session
|
||||||
|
- send_payment
|
||||||
|
- terminal_ack
|
||||||
|
- terminal_approve
|
||||||
|
- terminal_decline
|
||||||
|
- terminal_timeout
|
||||||
|
- backend_timeout
|
||||||
|
- reconnect
|
||||||
|
- cancel_request
|
||||||
|
- reversal_request
|
||||||
|
- reversal_success
|
||||||
|
- reversal_fail
|
||||||
|
- duplicate_response
|
||||||
|
- invalid_command
|
||||||
|
|
||||||
|
## Transitions
|
||||||
|
| From | Event | To |
|
||||||
|
|------|-------|----|
|
||||||
|
| IDLE | open_session | SESSION_OPEN |
|
||||||
|
| SESSION_OPEN | send_payment | PAYMENT_REQUESTED |
|
||||||
|
| PAYMENT_REQUESTED | terminal_ack | WAITING_FOR_TERMINAL |
|
||||||
|
| WAITING_FOR_TERMINAL | terminal_approve | APPROVED |
|
||||||
|
| WAITING_FOR_TERMINAL | terminal_decline | DECLINED |
|
||||||
|
| WAITING_FOR_TERMINAL | terminal_timeout | DESYNC |
|
||||||
|
| WAITING_FOR_TERMINAL | cancel_request | CANCELLED |
|
||||||
|
| APPROVED | reversal_request | REVERSAL_PENDING |
|
||||||
|
| REVERSAL_PENDING | reversal_success | REVERSED |
|
||||||
|
| REVERSAL_PENDING | reversal_fail | ERROR |
|
||||||
|
| * | invalid_command | ERROR |
|
||||||
|
| * | backend_timeout | DESYNC |
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-001",
|
||||||
|
"name": "Duplicate approved response",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["terminal_approve", "duplicate_response"],
|
||||||
|
"expected_final_state": "APPROVED",
|
||||||
|
"invariants": ["Invariant 3"],
|
||||||
|
"mapped_controls": ["TRANS-004", "TRANS-009", "ZVT-RESP-005"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-002",
|
||||||
|
"name": "Timeout then late success",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["terminal_timeout", "terminal_approve"],
|
||||||
|
"expected_final_state": "DESYNC",
|
||||||
|
"invariants": ["Invariant 4", "Invariant 7", "Invariant 8"],
|
||||||
|
"mapped_controls": ["TRANS-005", "TRANS-007", "TERMSYNC-009", "TERMSYNC-010"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-003",
|
||||||
|
"name": "Decline must not produce booking",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["terminal_decline"],
|
||||||
|
"expected_final_state": "DECLINED",
|
||||||
|
"invariants": ["Invariant 2"],
|
||||||
|
"mapped_controls": ["TRANS-011", "TRANS-025", "ZVT-RESP-002"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-004",
|
||||||
|
"name": "Invalid reversal before approval",
|
||||||
|
"initial_state": "PAYMENT_REQUESTED",
|
||||||
|
"events": ["reversal_request"],
|
||||||
|
"expected_final_state": "ERROR",
|
||||||
|
"invariants": ["Invariant 6"],
|
||||||
|
"mapped_controls": ["ZVT-REV-001", "ZVT-STATE-002", "ZVT-CMD-001"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-005",
|
||||||
|
"name": "Cancel during waiting",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["cancel_request"],
|
||||||
|
"expected_final_state": "CANCELLED",
|
||||||
|
"invariants": ["Invariant 7"],
|
||||||
|
"mapped_controls": ["TRANS-006", "ZVT-CMD-001", "ZVT-STATE-003"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-006",
|
||||||
|
"name": "Backend timeout after terminal ack",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["terminal_ack", "backend_timeout"],
|
||||||
|
"expected_final_state": "DESYNC",
|
||||||
|
"invariants": ["Invariant 4", "Invariant 7"],
|
||||||
|
"mapped_controls": ["TERMSYNC-010", "TRANS-012", "ZVT-SESSION-003"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-007",
|
||||||
|
"name": "Parallel reversal requests",
|
||||||
|
"initial_state": "APPROVED",
|
||||||
|
"events": ["reversal_request", "reversal_request"],
|
||||||
|
"expected_final_state": "REVERSAL_PENDING",
|
||||||
|
"invariants": ["Invariant 5"],
|
||||||
|
"mapped_controls": ["ZVT-REV-003", "TRANS-016", "TRANS-019"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-008",
|
||||||
|
"name": "Unknown response code",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["terminal_ack", "invalid_command"],
|
||||||
|
"expected_final_state": "ERROR",
|
||||||
|
"invariants": ["Invariant 6"],
|
||||||
|
"mapped_controls": ["ZVT-RESP-003", "ZVT-COM-005", "ZVT-STATE-005"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-009",
|
||||||
|
"name": "Reconnect and resume controlled",
|
||||||
|
"initial_state": "SESSION_OPEN",
|
||||||
|
"events": ["send_payment", "terminal_timeout", "reconnect"],
|
||||||
|
"expected_final_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"invariants": ["Invariant 7"],
|
||||||
|
"mapped_controls": ["ZVT-SESSION-004", "TRANS-007", "ZVT-RT-004"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "ZVT-SM-010",
|
||||||
|
"name": "Late response after cancel",
|
||||||
|
"initial_state": "WAITING_FOR_TERMINAL",
|
||||||
|
"events": ["cancel_request", "terminal_approve"],
|
||||||
|
"expected_final_state": "DESYNC",
|
||||||
|
"invariants": ["Invariant 4", "Invariant 8"],
|
||||||
|
"mapped_controls": ["TERMSYNC-008", "TERMSYNC-009", "TRANS-018"]
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user