The npm registry is a seat gitea holds, and gitea holds the git seat a build's source can live on #69

Merged
jschoubben merged 2 commits from feat/seats-are-a-closed-set into main 2026-09-26 12:31:11 +00:00
4 changed files with 43 additions and 15 deletions
+3 -3
View File
@@ -12,13 +12,13 @@
], ],
"requires": [ "requires": [
"artifact-store", "artifact-store",
"package-registry" "npm-package-registry"
], ],
"binds": { "binds": {
"package-registry": "/var/lib/mesh/builder/package-registry.json" "npm-package-registry": "/var/lib/mesh/builder/package-registry.json"
}, },
"secrets": { "secrets": {
"package-registry": "/var/lib/mesh/builder/package-registry.secret" "npm-package-registry": "/var/lib/mesh/builder/package-registry.secret"
}, },
"emits": [ "emits": [
"module.builder.built" "module.builder.built"
+23 -5
View File
@@ -57,18 +57,32 @@
} }
], ],
"serves": { "serves": {
"package-registry": { "npm-package-registry": {
"scheme": "http", "scheme": "http",
"port": 3000, "port": 3000,
"npm-path": "/api/packages/novox/npm/" "npm-path": "/api/packages/novox/npm/"
},
"git": {
"scheme": "http",
"port": 3000
} }
}, },
"receives": { "receives": {
"package-registry": "/var/lib/gitea/grants/mesh.json" "npm-package-registry": "/var/lib/gitea/grants/npm.json"
}, },
"grants": { "grants": {
"package-registry": "/var/lib/gitea/grants" "npm-package-registry": "/var/lib/gitea/grants"
}, },
"claims": [
{
"name": "npm-package-registry",
"scope": "mesh"
},
{
"name": "git",
"scope": "mesh"
}
],
"own-secrets": { "own-secrets": {
"broker": "/var/lib/mesh/gitea/broker" "broker": "/var/lib/mesh/gitea/broker"
}, },
@@ -185,7 +199,7 @@
"MESH_GITEA_ADMIN_USER": "mesh-admin", "MESH_GITEA_ADMIN_USER": "mesh-admin",
"MESH_GITEA_ADMIN_PASSWORD_FILE": "/run/secrets/admin", "MESH_GITEA_ADMIN_PASSWORD_FILE": "/run/secrets/admin",
"MESH_GITEA_STATE_DIR": "/run/state", "MESH_GITEA_STATE_DIR": "/run/state",
"MESH_RECEIVES": "/var/lib/gitea/grants/mesh.json" "MESH_RECEIVES": "/var/lib/gitea/grants/npm.json"
}, },
"artifact": "runtime", "artifact": "runtime",
"restart-on": [ "restart-on": [
@@ -195,7 +209,11 @@
], ],
"provides": [ "provides": [
{ {
"name": "package-registry", "name": "npm-package-registry",
"scope": "mesh"
},
{
"name": "git",
"scope": "mesh" "scope": "mesh"
} }
], ],
+16 -6
View File
@@ -1,9 +1,15 @@
// gitea's provisioner — the adapter that makes gitea a provider of the mesh `package-registry` // gitea's provisioner — the adapter that makes gitea a provider of the mesh
// interface. The reconcile loop, the contributions file, and reading the mesh's minted password are // `npm-package-registry` interface. The reconcile loop, the contributions file, and reading the
// the sdk harness's; this writes only the per-service half: how gitea creates and removes a // mesh's minted password are the sdk harness's; this writes only the per-service half: how gitea
// consumer's npm credential (novox/hq ADR 0048/0076). // creates and removes a consumer's npm credential (novox/hq ADR 0048/0076).
// //
// The `package-registry` interface: a consumer authenticates to the npm registry at // **A package registry seat is one per ecosystem (novox/hq ADR 0109).** gitea holds the npm seat
// (ADR 0110). Adding cargo or PyPI is adding a provision — another `provides` entry, another
// `receives` path and another registration below — not widening this one. `git`, which gitea also
// provides, mints nothing and so registers nothing here: the mesh's own repositories are public,
// and a clone credential is not yet decided (ADR 0111).
//
// The `npm-package-registry` interface: a consumer authenticates to the npm registry at
// `/api/packages/novox/npm/` with basic auth, as `as` with the password the mesh minted, and can // `/api/packages/novox/npm/` with basic auth, as `as` with the password the mesh minted, and can
// read and write packages under the `@novox` scope. The registry's npm owner is the gitea org // read and write packages under the `@novox` scope. The registry's npm owner is the gitea org
// `novox`; a consumer is a gitea *user* placed on that org's package team. // `novox`; a consumer is a gitea *user* placed on that org's package team.
@@ -26,7 +32,11 @@ const PACKAGE_TEAM = "packages";
const gitea = GiteaAdmin.fromEnv(); const gitea = GiteaAdmin.fromEnv();
runProvisioner("package-registry", { // Where this registration's contributions land comes from $MESH_RECEIVES, never a path written
// here: the mesh writes the file where the manifest's `receives` says, and a second copy of that
// path in code would drift from it. One variable carries one path, so a second registration in this
// module needs the mesh to say where each provision's file is — not yet possible, and not faked.
runProvisioner("npm-package-registry", {
async create(p: Provision): Promise<void> { async create(p: Provision): Promise<void> {
// The org and its package team are the same for every consumer; ensuring them per-create is // The org and its package team are the same for every consumer; ensuring them per-create is
// idempotent and needs no separate bootstrap step. // idempotent and needs no separate bootstrap step.
+1 -1
View File
@@ -102,7 +102,7 @@
}, },
"provides": [ "provides": [
{ {
"name": "package-registry", "name": "npm-package-registry",
"scope": "mesh" "scope": "mesh"
} }
], ],