Skip to content
quarry Artifact [e6b8a39c87]
Login

Artifact [e6b8a39c87]

Artifact e6b8a39c87be3ebaa2dc4c65654e674ad92a4c7e250732cde40ca485b8a75d8f:


package api

import (
	"strings"
	"testing"
)

// recordingForum captures modlog lines; every other ForumStore method
// is unreachable from logModeration and stays unimplemented on purpose,
// so a future call from this path fails loudly rather than silently.
type recordingForum struct {
	ForumStore
	lines [][6]string
	fail  error
}

func (f *recordingForum) AppendModLog(repo, actor, action, target, reason, about string) error {
	f.lines = append(f.lines, [6]string{repo, actor, action, target, reason, about})
	return f.fail
}

// An attachment decision is recorded on the same public log the forum's
// decisions go to.
//
// Nothing recorded them before. Rejection cleared the hold and removed
// the file; the removal wrote a sourceless A card carrying the actor,
// so the DAG knew who and when, but there was no reason anywhere and no
// surface a person would find (01a3b35f4055).
func TestAnAttachmentDecisionReachesTheModLog(t *testing.T) {
	for _, c := range []struct {
		action, name, artifact, reason, about string
	}{
		{"attach-vouch", "crash.png", "4f9a1b2c3d4e5f60718293a4b5c6d7e8", "looks fine", "jan"},
		{"attach-reject", "spam.gif", "0011223344556677889900aabbccddee", "unsolicited advertising", "jan"},
	} {
		f := &recordingForum{}
		d := Deps{Forum: f}
		d.logModeration("alpha", "jva", c.action, c.name, c.artifact, c.reason, c.about)
		if len(f.lines) != 1 {
			t.Fatalf("FAIL: %s wrote %d log lines, want 1", c.action, len(f.lines))
		}
		got := f.lines[0]
		if got[0] != "alpha" || got[1] != "jva" || got[2] != c.action || got[4] != c.reason {
			t.Errorf("FAIL: %s logged %v", c.action, got)
		}
		// The line must name WHO it is about, not only who wrote it: the
		// author is the one person the log now has to be filterable by.
		if got[5] != c.about {
			t.Errorf("FAIL: %s logged about %q, want %q — the actor is not the subject",
				c.action, got[5], c.about)
		}
		// The target has to name the FILE. A line naming only a hash is
		// a line nobody reads, and the whole point is that a person can
		// find out what happened to something they uploaded.
		if !strings.Contains(got[3], c.name) {
			t.Errorf("FAIL: target %q does not name the file", got[3])
		}
		if !strings.Contains(got[3], c.artifact[:12]) {
			t.Errorf("FAIL: target %q does not identify which artifact", got[3])
		}
		t.Logf("ok: %s -> %q (%s)", c.action, got[3], got[4])
	}
}

// A decision that happened must not be undone because its log line
// could not be written. The forum's own call sites take the same view:
// the alternative is refusing to moderate when the audit trail is down.
func TestAFailedModLogDoesNotBreakTheDecision(t *testing.T) {
	f := &recordingForum{fail: errWriteFailed}
	d := Deps{Forum: f}
	d.logModeration("alpha", "jva", "attach-reject", "spam.gif", "0011223344556677", "spam", "jan")
	if len(f.lines) != 1 {
		t.Fatal("FAIL: the line was not attempted")
	}
	t.Log("ok: a failing log is reported and swallowed, the decision stands")
}

// No forum plane at all — a forge with moderation unconfigured — must
// not panic the attachment path.
func TestModerationLogIsSilentWithoutAForumPlane(t *testing.T) {
	d := Deps{}
	d.logModeration("alpha", "jva", "attach-vouch", "x.png", "00112233445566", "", "jan")
	t.Log("ok: no forum plane, no panic, nothing recorded")
}

var errWriteFailed = errStr("the log is unavailable")

type errStr string

func (e errStr) Error() string { return string(e) }