~bigbes/sr-ht-ecore

353a7f19f00b0413558eaffb8e1fd658ccccb1f3 — Eugene Blikh 9 days ago 34cf83d
follow cover.sr.ht's rename to cov.sr.ht

The section in ecoretest's synthetic config.ini, and the grant vocabulary the
grants package uses for its examples — cover:upload was the stock example of a
well-formed grant, and the service that defines it now spells it cov:upload.
M README.md => README.md +2 -2
@@ 1,7 1,7 @@
# sr-ht-ecore

Extended core for the custom services of a self-hosted SourceHut instance
(diff, spec, dolt, cover, bench, ...). Everything these services share that
(diff, spec, dolt, cov, bench, ...). Everything these services share that
is *ours* — not upstream's — lives here, so the sr-ht-core fork can stay a
clean mirror of upstream core-go, and so the services stop carrying drifting
copies of the same code.


@@ 164,7 164,7 @@ both live in that package's globals.
Two of those arms are the ones to get right. `ErrNotOurs` is deliberately not
decided by the validator: SPEC ch. 6 step 2 leaves it to each service whether a
foreign bearer token is a meta PAT to accept (dolt) or something to refuse
(bench, cover). And `ErrUnavailable` is **503, never 401** — reading an
(bench, cov). And `ErrUnavailable` is **503, never 401** — reading an
unreachable daemon as "revoked" would refuse live tokens across the instance
for the length of a tokens.sr.ht restart.


M chrome/chrome.go => chrome/chrome.go +2 -2
@@ 1,5 1,5 @@
// Package chrome is the shared page chrome for the custom services of a
// self-hosted SourceHut instance (diff, spec, dolt, cover, bench, ...).
// self-hosted SourceHut instance (diff, spec, dolt, cov, bench, ...).
//
// Every one of those services renders the same top strip: the brand (circle
// icon + site name + red service label), the service switcher derived from the


@@ 172,7 172,7 @@ type Page struct {
//
// Updated and Meta are optional, and deliberately so. Four services wanted a
// listing here and disagreed about its shape: bench and spec needed a
// modification time, dolt has no timestamp in its schema at all, and cover's
// modification time, dolt has no timestamp in its schema at all, and cov's
// index is a table of percentages and sparklines that no shared partial will
// ever render. A required column would have pushed dolt back onto a local
// copy; a zero Updated and a nil Meta render nothing, which is what keeps all

M ecoretest/ecoretest.go => ecoretest/ecoretest.go +2 -2
@@ 1,5 1,5 @@
// Package ecoretest is the test bootstrap shared by the custom services of a
// self-hosted SourceHut instance (diff, spec, dolt, cover, bench, tokens).
// self-hosted SourceHut instance (diff, spec, dolt, cov, bench, tokens).
//
// Every one of those services opens its web tests with the same two things: a
// hand-built ini.File standing in for the instance's config.ini, and a TestMain


@@ 115,7 115,7 @@ var customSections = []string{
	"spec.sr.ht",
	"dolt.sr.ht",
	"bench.sr.ht",
	"cover.sr.ht",
	"cov.sr.ht",
	"tokens.sr.ht",
}


M ecoretest/ecoretest_test.go => ecoretest/ecoretest_test.go +1 -1
@@ 27,7 27,7 @@ func TestConfigHasTheSectionsTheNavRulesNeed(t *testing.T) {
	}
	assert.Equal(t, []string{
		"git", "lists", "todo", "builds", "man", "meta",
		"bench", "cover", "diff", "dolt", "spec", "tokens",
		"bench", "cov", "diff", "dolt", "spec", "tokens",
	}, names)

	for _, item := range nav {

M grants/grants.go => grants/grants.go +4 -4
@@ 14,7 14,7 @@
// This package parses that string and answers questions about it. It does not
// know which services exist or which actions they define, and it must not learn:
// SPEC ch. 3 gives the vocabulary to the services and keeps the daemon out of
// it, so that adding cover:download to cover.sr.ht is a change to cover.sr.ht.
// it, so that adding cov:download to cov.sr.ht is a change to cov.sr.ht.
// An unknown grant is therefore not an error — it is a grant that happens to
// admit nobody anywhere, which is the safe direction for a string the daemon
// only ever passes through.


@@ 160,7 160,7 @@ func parse(s string, allowID bool) (Grants, error) {
		g.members[m] = struct{}{}
	}

	// "* cover:upload" is the universal set with a redundant member spelled out;
	// "* cov:upload" is the universal set with a redundant member spelled out;
	// keeping the member would make String round-trip to something longer than
	// what it means, and Has already answers true for everything.
	if g.all {


@@ 233,8 233,8 @@ func (g Grants) Empty() bool { return !g.all && len(g.members) == 0 }

// Has reports whether the set admits one named action, e.g. "bench:upload".
//
// There is no wildcard below the universal one: "cover:*" is a member like any
// other and matches only a validator asking for exactly "cover:*". SPEC ch. 3
// There is no wildcard below the universal one: "cov:*" is a member like any
// other and matches only a validator asking for exactly "cov:*". SPEC ch. 3
// defines "*" and nothing else, and a per-service wildcard invented here would
// be a permission the services do not know they are honouring.
func (g Grants) Has(grant string) bool {

M grants/grants_test.go => grants/grants_test.go +16 -16
@@ 21,14 21,14 @@ import (
var nbsp = string(rune(0x00a0))

func TestParseReadsTheVocabularyOfTheSpec(t *testing.T) {
	g, err := Parse("cover:upload bench:upload spec:propose")
	g, err := Parse("cov:upload bench:upload spec:propose")
	require.NoError(t, err)

	assert.False(t, g.All())
	assert.True(t, g.Has("cover:upload"))
	assert.True(t, g.Has("cov:upload"))
	assert.True(t, g.Has("bench:upload"))
	assert.True(t, g.Has("spec:propose"))
	assert.False(t, g.Has("cover:read"), "a grant not named is not held")
	assert.False(t, g.Has("cov:read"), "a grant not named is not held")
	assert.Equal(t, 0, g.TokenID(), "no id: member, so no row id")
}



@@ 61,20 61,20 @@ func TestZeroGrantsAdmitNothing(t *testing.T) {
	assert.Equal(t, "", g.String())
}

// "* cover:upload" is the universal set with one member spelled out redundantly.
// "* cov:upload" is the universal set with one member spelled out redundantly.
// Keeping the member would make String render something longer than what it
// means.
func TestUniversalAbsorbsNamedMembers(t *testing.T) {
	g, err := Parse("cover:upload * bench:read")
	g, err := Parse("cov:upload * bench:read")
	require.NoError(t, err)
	assert.True(t, g.All())
	assert.Equal(t, "*", g.String())
}

func TestStringIsSortedAndDeduplicated(t *testing.T) {
	g, err := Parse("spec:propose  cover:upload   bench:upload cover:upload")
	g, err := Parse("spec:propose  cov:upload   bench:upload cov:upload")
	require.NoError(t, err)
	assert.Equal(t, "bench:upload cover:upload spec:propose", g.String(),
	assert.Equal(t, "bench:upload cov:upload spec:propose", g.String(),
		"one permission set must have one spelling: the string is both a column and a token payload")
}



@@ 92,13 92,13 @@ func TestMalformedGrantsAreRefused(t *testing.T) {
	for name, s := range map[string]string{
		"no colon":        "coverupload",
		"leading colon":   ":upload",
		"trailing colon":  "cover:",
		"empty segment":   "cover::upload",
		"trailing colon":  "cov:",
		"empty segment":   "cov::upload",
		"upper case":      "Cover:upload",
		"non-ascii":       "cover:upload" + nbsp,
		"non-ascii":       "cov:upload" + nbsp,
		"lone nbsp":       nbsp,
		"control byte":    "cover:up\x01load",
		"bare wildcard 2": "cover:upload **",
		"control byte":    "cov:up\x01load",
		"bare wildcard 2": "cov:upload **",
	} {
		t.Run(name, func(t *testing.T) {
			_, err := Parse(s)


@@ 130,7 130,7 @@ func TestOverlongGrantsAreRefused(t *testing.T) {
// caller who could choose it could point their token's revocation check at
// somebody else's live row and make their own revoke a no-op.
func TestRequestedGrantsRefuseTheReservedIDMember(t *testing.T) {
	for _, s := range []string{"id:7", "cover:upload id:7", "id:0", "id:nope"} {
	for _, s := range []string{"id:7", "cov:upload id:7", "id:0", "id:nope"} {
		_, err := ParseRequested(s)
		require.Error(t, err, "should refuse %q", s)
		assert.True(t, errors.Is(err, ErrInvalid), "%q: %v", s, err)


@@ 183,10 183,10 @@ func TestIsSubsetOfIsTheNarrowingRule(t *testing.T) {
		return g
	}

	parent := parse("cover:upload bench:upload")
	parent := parse("cov:upload bench:upload")

	assert.True(t, parse("bench:upload").IsSubsetOf(parent), "dropping a grant narrows")
	assert.True(t, parse("cover:upload bench:upload").IsSubsetOf(parent), "asking for all of them")
	assert.True(t, parse("cov:upload bench:upload").IsSubsetOf(parent), "asking for all of them")
	assert.True(t, Grants{}.IsSubsetOf(parent), "the empty set is a subset of anything")

	assert.False(t, parse("spec:propose").IsSubsetOf(parent), "a grant the parent lacks")


@@ 201,7 201,7 @@ func TestIsSubsetOfIsTheNarrowingRule(t *testing.T) {
// A stamped child is still a narrowing of its parent: the id: is not a
// permission and must take no part in the comparison.
func TestSubsetIgnoresTheIDMember(t *testing.T) {
	parent, err := Parse("cover:upload bench:upload")
	parent, err := Parse("cov:upload bench:upload")
	require.NoError(t, err)
	child, err := Parse("bench:upload id:42")
	require.NoError(t, err)