Skip to content
quarry Artifact [8674c664ec]
Login

Artifact [8674c664ec]

Artifact 8674c664ec553aa91e62597e6feee013c775ffc58e4f1e5a45ba8a9e2d1f9790:


package api

import (
	"errors"
	"os"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/ops"
)

// A repository's uploads do not go to the forge's own bucket.
//
// bucketOf falls back to the forge binding when a repository has none,
// so uploads landed in the operator's storage without anybody being
// told: dmestas attached files to an announcement on quarry and found
// them in his personal R2 (9b8b8fb6). The disclosure half — a repo
// admin handed the endpoint, bucket name and key id — was fixed by
// forgeAnswer. This is the half that decided where the BYTES went.
//
// The refusal names the remedy, because a refusal that does not is the
// other bug this forge keeps finding.
func TestUploadsRefuseTheForgeBucketAndSayWhatToDo(t *testing.T) {
	var d Deps
	// A forge with no bucket store at all still refuses, and says so
	// in its own words rather than falling through to a nil map.
	_, _, _, err := d.boundBucket("alpha")
	if err == nil {
		t.Fatal("FAIL: a forge with no bucket store accepted an upload")
	}
	if !strings.Contains(err.Error(), "binds no buckets") {
		t.Errorf("FAIL: the refusal does not say the forge binds none: %v", err)
	}
}

// The refusal for the forge-fallback case is ErrInvalid and names the
// settings page, so the caller learns what to do rather than that
// something is wrong.
func TestTheForgeBucketRefusalIsActionable(t *testing.T) {
	// Asserted on the message the code produces, because the whole
	// point of this refusal is its words: the previous behaviour was
	// silent success into the wrong account.
	b, rerr := os.ReadFile("attachwrite.go")
	if rerr != nil {
		t.Fatal(rerr)
	}
	src := string(b)
	for _, want := range []string{
		"has no bucket of its own",
		"do not go to the",
		"bind a bucket under Settings > Attachments",
		"ops.ErrInvalid",
	} {
		if !strings.Contains(src, want) {
			t.Errorf("FAIL: the forge-bucket refusal is missing %q; a refusal that does not "+
				"name the remedy is the other half of this class of bug", want)
		}
	}
	if !strings.Contains(src, "if info.Forge {") {
		t.Error("FAIL: boundBucket no longer refuses the forge binding, so a repository's " +
			"uploads go to the operator's storage again")
	}
	// And marks are deliberately left alone.
	if !strings.Contains(src, "Marks are untouched") {
		t.Error("FAIL: the note explaining why avatars still use the forge bucket is gone; " +
			"somebody will remove forgeBucketForAvatar next")
	}
	_ = errors.Is
	_ = ops.ErrInvalid
}