package fault
import (
"errors"
"strings"
"testing"
)
// A field that describes the FORGE reaches the log and not the client.
//
// A store fault used to carry the repository's absolute path in the
// string a caller receives, so a 404 body read
// "command=zit ls store=/srv/quarry/repos/quarry version=-trunk" to
// anyone who could provoke it, anonymously. That leaked command line is
// how the argument injection was found in the first place — it showed a
// URL segment sitting in argv.
func TestAPrivateFieldStaysOutOfTheClientsError(t *testing.T) {
f := Wrap(errors.New("exit status 2"), "a store command failed").
With("command", "zit ls").
WithPrivate("store", "/srv/quarry/repos/quarry").
With("version", "trunk")
msg := f.Error()
if strings.Contains(msg, "/srv/quarry") {
t.Errorf("FAIL: the client's error names the forge's filesystem: %s", msg)
}
for _, want := range []string{"command=zit ls", "version=trunk"} {
if !strings.Contains(msg, want) {
t.Errorf("FAIL: the client lost %q, which is theirs to see: %s", want, msg)
}
}
// The operator keeps everything: two audiences, two renderers.
var found bool
for _, fld := range FieldsOf(f) {
if fld.Key == "store" && fld.Value == "/srv/quarry/repos/quarry" {
found = true
}
}
if !found {
t.Error("FAIL: the log lost the store path — an operator cannot diagnose without it")
}
t.Logf("ok: client sees %q", msg)
}
// The brackets are driven by what is WRITTEN, not by index, or a
// private field in the first or last slot leaves the message looking
// truncated.
func TestBracketsSurviveAPrivateFieldAtEitherEnd(t *testing.T) {
for _, c := range []struct {
what string
f *Fault
}{
{"private first", New("x").WithPrivate("store", "/p").With("a", "1").With("b", "2")},
{"private last", New("x").With("a", "1").With("b", "2").WithPrivate("store", "/p")},
{"private only", New("x").WithPrivate("store", "/p")},
} {
msg := c.f.Error()
if strings.Contains(msg, "/p") {
t.Errorf("FAIL [%s]: leaked: %s", c.what, msg)
continue
}
open, close := strings.Count(msg, "["), strings.Count(msg, "]")
if open != close {
t.Errorf("FAIL [%s]: unbalanced brackets: %s", c.what, msg)
continue
}
t.Logf("ok [%s]: %q", c.what, msg)
}
}