API-21: Nachweistest fuer den Scanner selbst (injizierte Verstoesse + Ausnahme)
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-09-22 11:15:38 +02:00
1 parent c6cd632c85
commit cca4f54a1f
2 files changed
+182

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
package archtest
import (
"os"
"path/filepath"
"strings"
"testing"
)
// TestScanDetectsInjectedViolations ist der geforderte Nachweis (Prüfung 1):
// ein absichtlich eingefügter Verstoß muss den Scanner nachweislich zum
// Fund bringen - für beide Regeln, plus den Beleg, dass eine begründete
// archtest:allow-Ausnahme direkt über der Fundstelle den Fund unterdrückt.
func TestScanDetectsInjectedViolations(t *testing.T) {
dir := t.TempDir()
src := `package fixture
import (
"encoding/json"
"fmt"
"net/http"
)
func leak(w http.ResponseWriter, err error) {
w.Write([]byte(err.Error()))
}
func leakFprintf(w http.ResponseWriter, err error) {
fmt.Fprintf(w, "%v", err.Error())
}
func leakEncode(w http.ResponseWriter, err error) {
_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
}
func allowedLeak(w http.ResponseWriter, err error) {
// archtest:allow Testfixtur - Nachweis, dass eine direkt darueberstehende, begruendete Ausnahme greift
w.Write([]byte(err.Error()))
}
func rawServer() {
http.ListenAndServe(":8080", nil)
}
`
if err := os.WriteFile(filepath.Join(dir, "fixture.go"), []byte(src), 0o644); err != nil {
t.Fatalf("Testfixtur schreiben: %v", err)
}
allowedCallLine := lineNumberOf(src, "w.Write([]byte(err.Error()))", 2) // die zweite (zulässige) Vorkommnis
findings, err := Scan(dir, nil)
if err != nil {
t.Fatalf("Scan: %v", err)
}
var leakLines, rawLines []int
for _, f := range findings {
switch f.Rule {
case "err-in-response":
leakLines = append(leakLines, f.Line)
case "raw-listen-and-serve":
rawLines = append(rawLines, f.Line)
}
}
if len(leakLines) != 3 {
t.Errorf("erwarte 3 err-in-response-Funde (Write, Fprintf, Encode), habe %d: %v", len(leakLines), leakLines)
}
if len(rawLines) != 1 {
t.Errorf("erwarte 1 raw-listen-and-serve-Fund, habe %d: %v", len(rawLines), rawLines)
}
for _, l := range leakLines {
if l == allowedCallLine {
t.Errorf("Zeile %d mit direkt darueberstehender, begruendeter archtest:allow-Ausnahme haette nicht gefunden werden duerfen", l)
}
}
}
// lineNumberOf gibt die 1-basierte Zeilennummer des n-ten Vorkommens von
// needle in src zurueck (n=1 fuer das erste), oder 0 wenn nicht gefunden.
func lineNumberOf(src, needle string, n int) int {
count := 0
for i, line := range strings.Split(src, "\n") {
if strings.Contains(line, needle) {
count++
if count == n {
return i + 1
}
}
}
return 0
}
+91
View File
@@ -0,0 +1,91 @@
package archtest
import (
"os"
"path/filepath"
"strings"
"testing"
)
// TestScanDetectsInjectedViolations ist der geforderte Nachweis (Prüfung 1):
// ein absichtlich eingefügter Verstoß muss den Scanner nachweislich zum
// Fund bringen - für beide Regeln, plus den Beleg, dass eine begründete
// archtest:allow-Ausnahme direkt über der Fundstelle den Fund unterdrückt.
func TestScanDetectsInjectedViolations(t *testing.T) {
dir := t.TempDir()
src := `package fixture
import (
"encoding/json"
"fmt"
"net/http"
)
func leak(w http.ResponseWriter, err error) {
w.Write([]byte(err.Error()))
}
func leakFprintf(w http.ResponseWriter, err error) {
fmt.Fprintf(w, "%v", err.Error())
}
func leakEncode(w http.ResponseWriter, err error) {
_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
}
func allowedLeak(w http.ResponseWriter, err error) {
// archtest:allow Testfixtur - Nachweis, dass eine direkt darueberstehende, begruendete Ausnahme greift
w.Write([]byte(err.Error()))
}
func rawServer() {
http.ListenAndServe(":8080", nil)
}
`
if err := os.WriteFile(filepath.Join(dir, "fixture.go"), []byte(src), 0o644); err != nil {
t.Fatalf("Testfixtur schreiben: %v", err)
}
allowedCallLine := lineNumberOf(src, "w.Write([]byte(err.Error()))", 2) // die zweite (zulässige) Vorkommnis
findings, err := Scan(dir, nil)
if err != nil {
t.Fatalf("Scan: %v", err)
}
var leakLines, rawLines []int
for _, f := range findings {
switch f.Rule {
case "err-in-response":
leakLines = append(leakLines, f.Line)
case "raw-listen-and-serve":
rawLines = append(rawLines, f.Line)
}
}
if len(leakLines) != 3 {
t.Errorf("erwarte 3 err-in-response-Funde (Write, Fprintf, Encode), habe %d: %v", len(leakLines), leakLines)
}
if len(rawLines) != 1 {
t.Errorf("erwarte 1 raw-listen-and-serve-Fund, habe %d: %v", len(rawLines), rawLines)
}
for _, l := range leakLines {
if l == allowedCallLine {
t.Errorf("Zeile %d mit direkt darueberstehender, begruendeter archtest:allow-Ausnahme haette nicht gefunden werden duerfen", l)
}
}
}
// lineNumberOf gibt die 1-basierte Zeilennummer des n-ten Vorkommens von
// needle in src zurueck (n=1 fuer das erste), oder 0 wenn nicht gefunden.
func lineNumberOf(src, needle string, n int) int {
count := 0
for i, line := range strings.Split(src, "\n") {
if strings.Contains(line, needle) {
count++
if count == n {
return i + 1
}
}
}
return 0
}