CAT-G2: the packages token is renewed on the forge's refusal, said as a finding, never on a timer

The Go bundle raises packages-token-refused in the module's findings state when the forge
answers 401 to a write; the watcher mints afresh on that key's event and clears it (lead's
ruling on A3n, map-onto-how-the-mesh-is-built: nothing waits on a timer).

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 14:47:26 +01:00
parent 929b1ce13e
commit 4492bc3013
7 changed files with 103 additions and 20 deletions
+30 -2
View File
@@ -27,6 +27,32 @@ type Forge struct {
Owner string // the package registry's owner, as the seat serves it
// Type is the registry's package type retention reads: TypeNpm when empty, or TypeGo.
Type string
// Refused says whether the forge refused the write side's token (401), as the finding PackagesTokenRefused in the
// module's findings state: the TypeScript bundle mints a new token on that key's event and clears it (no timer
// looks at the token). Nil says nothing.
Refused func(raised bool)
}
// PackagesTokenRefused is the finding this bundle raises when the forge refuses the packages account's token, and its
// key in the module's findings state (packages-account.ts PACKAGES_TOKEN_REFUSED watches that key).
const (
PackagesTokenRefused = "packages-token-refused"
PackagesTokenRefusedKey = "seat.gitea.packages-token-refused_write"
)
// wrote is a write's answer, said on Refused: a 401 raises the finding, a write the forge took clears it.
func (f *Forge) wrote(err error) error {
if f.Refused == nil {
return err
}
var status *forgehttp.StatusError
switch {
case errors.As(err, &status) && status.Status == http.StatusUnauthorized:
f.Refused(true)
case err == nil:
f.Refused(false)
}
return err
}
// The package types the retention reads: npm packages (the npm seat) and Go modules (the Go seat).
@@ -59,7 +85,9 @@ func ForgeFromEnv() (*Forge, error) {
missing = append(missing, m)
}
}
f := &Forge{Client: c, Writer: &w, Owner: os.Getenv("MESH_NPM_OWNER")}
f := &Forge{Client: c, Writer: &w, Owner: os.Getenv("MESH_NPM_OWNER"), Refused: func(raised bool) {
finding(PackagesTokenRefused, "write", "the forge refused the package seats' write token; the module mints it afresh", raised)
}}
if f.Owner == "" {
missing = append(missing, "MESH_NPM_OWNER")
}
@@ -152,7 +180,7 @@ func (f *Forge) Delete(ctx context.Context, name, version string) error {
return err
}
_, err = w.Do(ctx, http.MethodDelete, f.versionPath(name, version), nil, maxBody)
return err
return f.wrote(err)
}
// Repository is one repository on the forge, as far as reading its manifests needs.
+2 -2
View File
@@ -90,14 +90,14 @@ func (s seatStore) Put(seat string, p packageseats.Publish, file []byte) (string
return "", err
}
_, err = w.Send(ctx, http.MethodPut, fmt.Sprintf("/api/packages/%s/go/upload", url.PathEscape(f.Owner)), file, "application/zip", maxBody)
return module, err
return module, f.wrote(err)
}
doc, err := npmDocument(f.URL, f.Owner, p, file)
if err != nil {
return "", err
}
_, err = w.Do(ctx, http.MethodPut, fmt.Sprintf("/api/packages/%s/npm/%s", url.PathEscape(f.Owner), url.PathEscape(p.Name)), doc, maxBody)
return "", err
return "", f.wrote(err)
}
func (s seatStore) Versions(seat, name string) ([]packageseats.Version, error) {
@@ -19,6 +19,7 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/health"
"gitea/internal/forgehttp"
"gitea/internal/packageseats"
)
@@ -63,7 +64,10 @@ func (g *registry) handle(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
want = "token writer"
}
if got := r.Header.Get("Authorization"); got != want {
if got := r.Header.Get("Authorization"); got == "token stale" {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
} else if got != want {
http.Error(w, r.Method+" "+p+" came as "+got+", not "+want, http.StatusForbidden)
return
}
@@ -125,6 +129,19 @@ func TestThePackageSeatsStoreIntoTheForge(t *testing.T) {
t.Errorf("a forge handed no write side wrote: %v", err)
}
s := seatStore{forge: func() (*Forge, error) { return forge, nil }}
// The forge refuses the write side's token: the finding the TypeScript bundle renews on is raised under its key,
// and the next write the forge takes clears it (no timer looks at the token).
var refused []bool
forge.Refused = func(raised bool) { refused = append(refused, raised) }
if k := health.FindingKey(health.ScopeSeat, packageseats.Self, PackagesTokenRefused+".write"); k != PackagesTokenRefusedKey {
t.Errorf("the refusal's key is %s, the watcher watches %s", k, PackagesTokenRefusedKey)
}
_ = os.WriteFile(writer.TokenFile, []byte("stale\n"), 0o600)
if _, err := s.Put(packageseats.GoSeat, packageseats.Publish{Version: "0.1.15"}, moduleZip(t, "git.example/acme/sdk@v0.1.15")); err == nil ||
len(refused) != 1 || !refused[0] {
t.Errorf("a write the forge refused with 401 raised no finding: %v %v", err, refused)
}
_ = os.WriteFile(writer.TokenFile, []byte("writer\n"), 0o600)
tgz := tarball(t, `{"name":"@acme/contracts","version":"0.1.15-feat-x.2","main":"index.js"}`)
p := packageseats.Publish{Name: "@acme/contracts", Version: "0.1.15-feat-x.2", Tag: "feat-x", Kind: packageseats.KindPackage, Digest: "sha256:" + sha(tgz)}
@@ -174,4 +191,7 @@ func TestThePackageSeatsStoreIntoTheForge(t *testing.T) {
g.deleted[0] != "go/git.example%2Facme%2Fsdk/v0.1.15-feat.1" {
t.Errorf("remove: %v %v", err, g.deleted)
}
if len(refused) < 2 || refused[len(refused)-1] {
t.Errorf("a write the forge took after the refusal did not clear it: %v", refused)
}
}