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
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:
1 parent
c6cd632c85
commit
cca4f54a1f
2 files changed
+182
No files matched your search
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user