Skip to content
quarry Artifact [1bdc5d3d65]
Login

Artifact [1bdc5d3d65]

Artifact 1bdc5d3d659f757fb27d7d60cb9bebe369141fab8ee27ec8cd479c47ddb4d950:


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)
	}
}