diff --git a/modules/cloudflare-dns/module.json b/modules/cloudflare-dns/module.json index 49292e9..294ddd1 100644 --- a/modules/cloudflare-dns/module.json +++ b/modules/cloudflare-dns/module.json @@ -52,23 +52,26 @@ "mode": "0600" }, { - "id": "provisioner", + "id": "runtime", "type": "container", - "name": "mesh-provision-cloudflare-dns", - "image": "mesh-provision-cloudflare-dns@sha256:0000000000000000000000000000000000000000000000000000000000000000", + "name": "mesh-cloudflare-dns", + "image": "mesh-runtime-cloudflare-dns@sha256:0000000000000000000000000000000000000000000000000000000000000000", "network": "host", - "env": { - "GRANTS": "/grants", - "MESH_CLOUDFLARE_TOKEN_FILE": "/run/secrets/token", - "MESH_BROKER_FILE": "/run/secrets/broker", - "MESH_CLOUDFLARE_CONFIG_FILE": "/run/config/config.json" - }, "volumes": [ "/var/lib/cloudflare-dns/config.json:/run/config/config.json:ro", "/var/lib/cloudflare-dns/grants:/grants", "/var/lib/cloudflare-dns/token:/run/secrets/token:ro", "/var/lib/mesh/cloudflare-dns/broker:/run/secrets/broker:ro" - ] + ], + "env": { + "MESH_CLOUDFLARE_TOKEN_FILE": "/run/secrets/token", + "MESH_BROKER_FILE": "/run/secrets/broker", + "MESH_CLOUDFLARE_CONFIG_FILE": "/run/config/config.json", + "MESH_RECEIVES": "/var/lib/cloudflare-dns/grants/mesh.json" + } } + ], + "capabilities": [ + "container-runtime" ] } diff --git a/modules/cloudflare-dns/provisioner/index.ts b/modules/cloudflare-dns/provisioner/index.ts index c9cfac3..d214dab 100644 --- a/modules/cloudflare-dns/provisioner/index.ts +++ b/modules/cloudflare-dns/provisioner/index.ts @@ -1,35 +1,36 @@ // cloudflare-dns's provisioner — the adapter making it a provider of the mesh `public-dns` interface -// (novox/hq ADR 0049). The reconcile loop, sealing and grant-file handling are the sdk harness's; -// this writes only the per-registrar half: register a consumer's public name at Cloudflare, pointing -// it at the mesh's ingress, and remove it when the grant is withdrawn. +// (novox/hq ADR 0049). The reconcile loop and the contributions file are the sdk harness's; this +// writes only the per-registrar half: register a consumer's public name at Cloudflare, pointing it +// at the mesh's ingress, and remove it when the consumer is withdrawn (ADR 0053). // // The `public-dns` interface hands a consumer { fqdn, target, ttl } — a name that resolves publicly -// and what it resolves to. It is not a secret (a DNS record is public), so nothing is sealed beyond -// what the harness seals; the only secret is this module's own Cloudflare token, which never leaves. +// and what it resolves to. Like umami's analytics it is a *data* provision, not a credential one: +// nothing the mesh mints is set here (a DNS record is public, and the only secret is this module's +// own Cloudflare token, which never leaves). So the password the harness carries is unused; the name +// is derived from the login the mesh gave the consumer, which the consumer can derive too. Delivering +// the record back to the consumer is the data-provision return path ADR 0053 leaves out of scope. -import { runProvisioner, type Grant, type Credential } from "@novox/mesh-sdk/provisioner"; +import { runProvisioner, type Provision } from "@novox/mesh-sdk/provisioner"; import { emit } from "@novox/mesh-sdk/events"; import { CloudflareClient } from "../client.js"; const cloudflare = CloudflareClient.fromEnv(); runProvisioner("public-dns", { - async create(grant: Grant): Promise { - const fqdn = cloudflare.nameFor(grant.consumer); + async create(p: Provision): Promise { + const fqdn = cloudflare.nameFor(p.as); await cloudflare.upsert(fqdn); await announce("module.cloudflare-dns.record.created", { name: fqdn, target: cloudflare.ingress, - consumer: grant.consumer, - node: grant.node, + consumer: p.consumer ?? "", }); - return { fields: { fqdn, target: cloudflare.ingress, ttl: "300" } }; }, - async remove(grant: Grant): Promise { - const fqdn = cloudflare.nameFor(grant.consumer); + async remove(p: { as: string }): Promise { + const fqdn = cloudflare.nameFor(p.as); await cloudflare.remove(fqdn); - await announce("module.cloudflare-dns.record.removed", { name: fqdn, consumer: grant.consumer, node: grant.node }); + await announce("module.cloudflare-dns.record.removed", { name: fqdn, consumer: p.as }); }, }); diff --git a/modules/minio/module.json b/modules/minio/module.json index 7794739..2b11d43 100644 --- a/modules/minio/module.json +++ b/modules/minio/module.json @@ -98,21 +98,23 @@ ] }, { - "id": "provisioner", + "id": "runtime", "type": "container", - "name": "mesh-provision-objectstore", - "image": "mesh-provision-objectstore@sha256:0000000000000000000000000000000000000000000000000000000000000000", + "name": "mesh-minio", + "image": "mesh-runtime-minio@sha256:0000000000000000000000000000000000000000000000000000000000000000", "network": "minio", - "env": { - "GRANTS": "/var/lib/minio/grants", - "MESH_MINIO_ENDPOINT": "http://minio:9000", - "MESH_MINIO_ROOT_USER": "meshroot", - "MESH_MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root" - }, "volumes": [ + "/var/lib/mesh/minio/broker:/run/secrets/broker:ro", "/var/lib/minio/grants:/var/lib/minio/grants:ro", "/var/lib/minio/root.secret:/run/secrets/root:ro" - ] + ], + "env": { + "MESH_MINIO_ENDPOINT": "http://minio:9000", + "MESH_MINIO_ROOT_USER": "meshroot", + "MESH_MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root", + "MESH_BROKER_FILE": "/run/secrets/broker", + "MESH_RECEIVES": "/var/lib/minio/grants/mesh.json" + } } ] } diff --git a/modules/postgres/module.json b/modules/postgres/module.json index 5fe0d69..3818a2f 100644 --- a/modules/postgres/module.json +++ b/modules/postgres/module.json @@ -97,20 +97,22 @@ ] }, { - "id": "provisioner", + "id": "runtime", "type": "container", - "name": "mesh-provision-postgres", - "image": "mesh-provision-postgres@sha256:0000000000000000000000000000000000000000000000000000000000000000", + "name": "mesh-postgres", + "image": "mesh-runtime-postgres@sha256:0000000000000000000000000000000000000000000000000000000000000000", "network": "postgres", - "env": { - "GRANTS": "/var/lib/postgres/grants", - "MESH_PROVISION_POSTGRES": "postgres://postgres@postgres:5432/postgres?sslmode=disable", - "MESH_PROVISION_PASSWORD_FILE": "/run/secrets/superuser" - }, "volumes": [ + "/var/lib/mesh/postgres/broker:/run/secrets/broker:ro", "/var/lib/postgres/grants:/var/lib/postgres/grants:ro", "/var/lib/postgres/superuser.secret:/run/secrets/superuser:ro" - ] + ], + "env": { + "MESH_PROVISION_POSTGRES": "postgres://postgres@postgres:5432/postgres?sslmode=disable", + "MESH_PROVISION_PASSWORD_FILE": "/run/secrets/superuser", + "MESH_BROKER_FILE": "/run/secrets/broker", + "MESH_RECEIVES": "/var/lib/postgres/grants/mesh.json" + } } ] } diff --git a/modules/redis/module.json b/modules/redis/module.json index 77b648d..5150f69 100644 --- a/modules/redis/module.json +++ b/modules/redis/module.json @@ -96,20 +96,22 @@ ] }, { - "id": "provisioner", + "id": "runtime", "type": "container", - "name": "mesh-provision-redis", - "image": "mesh-provision-redis@sha256:0000000000000000000000000000000000000000000000000000000000000000", + "name": "mesh-redis", + "image": "mesh-runtime-redis@sha256:0000000000000000000000000000000000000000000000000000000000000000", "network": "redis", - "env": { - "GRANTS": "/var/lib/redis-module/grants", - "MESH_PROVISION_REDIS": "redis:6379", - "MESH_PROVISION_PASSWORD_FILE": "/run/secrets/default" - }, "volumes": [ + "/var/lib/mesh/redis/broker:/run/secrets/broker:ro", "/var/lib/redis-module/grants:/var/lib/redis-module/grants:ro", "/var/lib/redis-module/default.secret:/run/secrets/default:ro" - ] + ], + "env": { + "MESH_BROKER_FILE": "/run/secrets/broker", + "MESH_RECEIVES": "/var/lib/redis-module/grants/mesh.json", + "MESH_PROVISION_REDIS": "redis:6379", + "MESH_PROVISION_PASSWORD_FILE": "/run/secrets/default" + } } ] } diff --git a/modules/umami/module.json b/modules/umami/module.json index b4b5d19..022da13 100644 --- a/modules/umami/module.json +++ b/modules/umami/module.json @@ -4,7 +4,6 @@ "capabilities": [ "container-runtime" ], - "requires": [ "postgres-database" ], @@ -19,7 +18,6 @@ "secrets": { "postgres-database": "/var/lib/umami/database.secret" }, - "provides": [ { "name": "analytics", @@ -35,12 +33,11 @@ "grants": { "analytics": "/var/lib/umami/grants" }, - "own-secrets": { "app-secret": "/var/lib/umami/app.secret", - "admin": "/var/lib/umami/admin.secret" + "admin": "/var/lib/umami/admin.secret", + "broker": "/var/lib/mesh/umami/broker" }, - "listens": [ { "port": 3000, @@ -49,8 +46,13 @@ "why": "one port serves two surfaces: the dashboard (the proxy gates it to the mesh) and the public collection endpoint that the browsers of every tracked site POST to — so the port itself must be reachable from anywhere" } ], - "resources": [ + { + "id": "mesh-state", + "type": "directory", + "path": "/var/lib/mesh/umami", + "mode": "0700" + }, { "id": "state", "type": "directory", @@ -96,17 +98,22 @@ ] }, { - "id": "provisioner", + "id": "runtime", "type": "container", - "name": "mesh-provision-umami-analytics", - "image": "mesh-provision-umami-analytics@sha256:0000000000000000000000000000000000000000000000000000000000000000", + "name": "mesh-umami", + "image": "mesh-runtime-umami@sha256:0000000000000000000000000000000000000000000000000000000000000000", "network": "umami", - "env-file": [ - "/var/lib/umami/provisioner.env" - ], "volumes": [ + "/var/lib/mesh/umami/broker:/run/secrets/broker:ro", "/var/lib/umami/grants:/var/lib/umami/grants", "/var/lib/umami/admin.secret:/run/secrets/admin:ro" + ], + "env": { + "MESH_BROKER_FILE": "/run/secrets/broker", + "MESH_RECEIVES": "/var/lib/umami/grants/mesh.json" + }, + "env-file": [ + "/var/lib/umami/provisioner.env" ] } ]