@wildo-ai/platform-infra-providers 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/aws-s3/aws-s3.infra.module.d.ts +5 -3
- package/dist/esm/aws-s3/aws-s3.infra.module.d.ts.map +1 -1
- package/dist/esm/aws-s3/aws-s3.infra.module.js +12 -3
- package/dist/esm/aws-s3/aws-s3.infra.module.js.map +1 -1
- package/dist/esm/clamav-self/clamav-self.infra.module.d.ts.map +1 -1
- package/dist/esm/immudb-self/immudb-self.infra.module.d.ts +75 -0
- package/dist/esm/immudb-self/immudb-self.infra.module.d.ts.map +1 -0
- package/dist/esm/immudb-self/immudb-self.infra.module.js +186 -0
- package/dist/esm/immudb-self/immudb-self.infra.module.js.map +1 -0
- package/dist/esm/index.d.ts +35 -5
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +45 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/minio-self/minio-self.infra.module.d.ts.map +1 -1
- package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.d.ts +38 -16
- package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.d.ts.map +1 -1
- package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.js +174 -39
- package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.js.map +1 -1
- package/dist/esm/mongodb-self/mongodb-self.infra.module.d.ts +25 -9
- package/dist/esm/mongodb-self/mongodb-self.infra.module.d.ts.map +1 -1
- package/dist/esm/mongodb-self/mongodb-self.infra.module.js +29 -18
- package/dist/esm/mongodb-self/mongodb-self.infra.module.js.map +1 -1
- package/dist/esm/postgres-self/postgres-self.infra.module.d.ts +5 -2
- package/dist/esm/postgres-self/postgres-self.infra.module.d.ts.map +1 -1
- package/dist/esm/postgres-self/postgres-self.infra.module.js +25 -11
- package/dist/esm/postgres-self/postgres-self.infra.module.js.map +1 -1
- package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.d.ts +4 -2
- package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.d.ts.map +1 -1
- package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.js +7 -4
- package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.js.map +1 -1
- package/dist/esm/redis-self/redis-self.infra.module.d.ts +4 -2
- package/dist/esm/redis-self/redis-self.infra.module.d.ts.map +1 -1
- package/dist/esm/redis-self/redis-self.infra.module.js +7 -4
- package/dist/esm/redis-self/redis-self.infra.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/__tests__/servable-infra-providers.test.ts +137 -0
- package/src/aws-s3/aws-s3.infra.module.ts +14 -3
- package/src/immudb-self/__tests__/immudb-self.infra.module.test.ts +117 -0
- package/src/immudb-self/immudb-self.infra.module.ts +221 -0
- package/src/index.ts +47 -5
- package/src/mongodb-atlas/__tests__/mongodb-atlas.infra.module.test.ts +105 -0
- package/src/mongodb-atlas/mongodb-atlas.infra.module.ts +198 -39
- package/src/mongodb-self/mongodb-self.infra.module.ts +29 -18
- package/src/postgres-self/__tests__/postgres-self.infra.module.test.ts +24 -7
- package/src/postgres-self/postgres-self.infra.module.ts +26 -12
- package/src/rabbitmq-self/rabbitmq-self.infra.module.ts +7 -4
- package/src/redis-self/redis-self.infra.module.ts +7 -4
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
*
|
|
25
25
|
* No environment selects this provider today (every example uses
|
|
26
26
|
* `BackingServiceSource.SELF` → MinIO), which is why this is recorded as
|
|
27
|
-
* a gap rather than an outage.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* a gap rather than an outage. `s3: { source: MANAGED }` and
|
|
28
|
+
* `provider: 'aws'` still RESOLVE here, but since #1693 such a
|
|
29
|
+
* declaration is refused at authoring time: `unservableReason` below
|
|
30
|
+
* takes this provider out of the servable set until the AWS STS path
|
|
31
|
+
* exists. Tracked in
|
|
30
32
|
* `.claude/plans/object-storage-root-credential-distribution.md`.
|
|
31
33
|
*
|
|
32
34
|
* The module still reuses the `STORAGE_*` env contract for the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-s3.infra.module.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"aws-s3.infra.module.d.ts","sourceRoot":"","sources":["../../../src/aws-s3/aws-s3.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,OAAO,EAIL,mBAAmB,EAEpB,MAAM,+BAA+B,CAAC;AAEvC,eAAO,MAAM,wBAAwB,EAAE,mBA2DtC,CAAC"}
|
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
*
|
|
25
25
|
* No environment selects this provider today (every example uses
|
|
26
26
|
* `BackingServiceSource.SELF` → MinIO), which is why this is recorded as
|
|
27
|
-
* a gap rather than an outage.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* a gap rather than an outage. `s3: { source: MANAGED }` and
|
|
28
|
+
* `provider: 'aws'` still RESOLVE here, but since #1693 such a
|
|
29
|
+
* declaration is refused at authoring time: `unservableReason` below
|
|
30
|
+
* takes this provider out of the servable set until the AWS STS path
|
|
31
|
+
* exists. Tracked in
|
|
30
32
|
* `.claude/plans/object-storage-root-credential-distribution.md`.
|
|
31
33
|
*
|
|
32
34
|
* The module still reuses the `STORAGE_*` env contract for the
|
|
@@ -62,6 +64,13 @@ import { InfraCapability, InfraPlatformAdminConsumer, InfraProvider, } from '@wi
|
|
|
62
64
|
export const AwsS3InfraProviderModule = {
|
|
63
65
|
provider: InfraProvider.AWS_S3,
|
|
64
66
|
supportedCapabilities: [InfraCapability.OBJECT_STORAGE],
|
|
67
|
+
/**
|
|
68
|
+
* What the ⚠️ block above says, made mechanical: a declaration resolving here (`s3: { source:
|
|
69
|
+
* MANAGED }`, or `provider: 'aws'`) is refused by `wildo config validate` / `config sync` /
|
|
70
|
+
* `lock check` until this field is deleted — in the change that teaches the broker AWS STS (#14).
|
|
71
|
+
*/
|
|
72
|
+
unservableReason: 'The object-storage credential broker speaks only MinIO AssumeRole, so an application on AWS S3 '
|
|
73
|
+
+ 'would receive no storage credential (#14).',
|
|
65
74
|
/**
|
|
66
75
|
* Shared bucket, shared access key — no per-app credential is minted, so there is nothing
|
|
67
76
|
* per-principal to confine. Confinement for object storage is done by STS session policy at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-s3.infra.module.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"aws-s3.infra.module.js","sourceRoot":"","sources":["../../../src/aws-s3/aws-s3.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,aAAa,GAGd,MAAM,+BAA+B,CAAC;AAEvC,MAAM,CAAC,MAAM,wBAAwB,GAAwB;IAC3D,QAAQ,EAAE,aAAa,CAAC,MAAM;IAC9B,qBAAqB,EAAE,CAAC,eAAe,CAAC,cAAc,CAAC;IAEvD;;;;OAIG;IACH,gBAAgB,EACd,iGAAiG;UAC/F,4CAA4C;IAEhD;;;;OAIG;IACH,2BAA2B,EAAE,EAAE;IAE/B,IAAI;QACF,OAAO;YACL,4CAA4C;YAC5C,iCAAiC;YACjC,aAAa,EAAE;gBACb,OAAO,EAAE;oBACP,gBAAgB,EAAE,IAAI;oBACtB,6DAA6D;oBAC7D,yDAAyD;oBACzD,8CAA8C;oBAC9C,eAAe,EAAE,MAAM;iBACxB;gBACD,aAAa,EAAE;oBACb,oBAAoB;oBACpB,oBAAoB;oBACpB,uDAAuD;oBACvD,yDAAyD;oBACzD,yDAAyD;oBACzD,2DAA2D;oBAC3D,qDAAqD;oBACrD,iCAAiC;oBACjC,gBAAgB;iBACjB;gBACD,SAAS,EAAE;oBACT,0BAA0B,CAAC,YAAY;oBACvC,0BAA0B,CAAC,SAAS;iBACrC;aACF;YACD,gEAAgE;YAChE,oEAAoE;YACpE,mEAAmE;YACnE,oEAAoE;SACrE,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,oEAAoE;IACpE,8EAA8E;IAC9E,0DAA0D;CAC3D,CAAC","sourcesContent":["/**\n * `AwsS3InfraProviderModule` — seventh concrete `InfraProviderModule`\n * (Slice 5.1 of `infra-provider-planner.md`).\n *\n * Implements the `AWS_S3` `InfraProvider`. Shares the one-bucket,\n * prefix-namespaced object layout of `MinioSelfInfraProviderModule` —\n * the only differences are (a) no compose / K8s contribution (S3 is\n * managed), and (b) the bucket endpoint is the regional AWS hostname\n * instead of the in-cluster `minio` service.\n *\n * ## ⚠️ NOT USABLE TODAY — selecting this provider leaves apps with no\n * storage credential (2026-08-10)\n *\n * The application-tier `STORAGE_ACCESS_KEY` / `STORAGE_SECRET_KEY` env\n * vars were removed **for every provider**: they were the object store's\n * ROOT pair, handed to every app, minion and worker. Applications now\n * obtain short-lived, prefix-confined credentials from apps-manager.\n *\n * That replacement is implemented for **MinIO only**. apps-manager's\n * `ObjectStorageStsBrokerService` speaks MinIO's STS `AssumeRole` with an\n * inline session policy; AWS STS requires a role ARN the broker does not\n * supply, so an `AWS_S3` deployment would fail at storage initialisation\n * with no credential and no path to one.\n *\n * No environment selects this provider today (every example uses\n * `BackingServiceSource.SELF` → MinIO), which is why this is recorded as\n * a gap rather than an outage. `s3: { source: MANAGED }` and\n * `provider: 'aws'` still RESOLVE here, but since #1693 such a\n * declaration is refused at authoring time: `unservableReason` below\n * takes this provider out of the servable set until the AWS STS path\n * exists. Tracked in\n * `.claude/plans/object-storage-root-credential-distribution.md`.\n *\n * The module still reuses the `STORAGE_*` env contract for the\n * NON-secret values (endpoint, region, bucket, provider); it is only the\n * credential half that is gone.\n *\n * **Why this module exists despite \"no compose / no mint\"**: it\n * gives the lockfile a stable digest entry (so a switch from\n * `minio-self` to `aws-s3` shows up as a `wildo lock check` drift)\n * AND it formalizes which env vars the operator must set for AWS\n * (`STORAGE_REGION` is mandatory; `STORAGE_ENDPOINT` is optional —\n * defaults to the AWS regional endpoint when unset).\n *\n * **No mint methods here** — and the reason is no longer the one this\n * block used to give. It said per-app credentials were out of scope\n * \"because the engine adapter uses a single shared SDK client\", which\n * stopped being true when the adapter moved to a credential provider that\n * rebuilds its client whenever the credential changes. Per-application\n * isolation exists; what is missing for AWS is only the broker's ability\n * to speak AWS STS.\n *\n * Nor should the missing piece be per-app IAM users or roles, which is\n * what this block previously anticipated. The MinIO path deliberately\n * rejected long-lived per-principal accounts in favour of `AssumeRole`\n * with an inline session policy — nothing long-lived exists to leak, and\n * credential-rotation safety dissolves instead of needing a design. The\n * AWS equivalent is the same shape: `AssumeRole` against a role ARN the\n * operator supplies, with a session policy confining the principal to\n * `applications/<applicationId>/`. That role ARN is the one input the\n * broker does not have today, and is the whole of the gap.\n */\n\nimport {\n InfraCapability,\n InfraPlatformAdminConsumer,\n InfraProvider,\n InfraProviderModule,\n InfraProviderPlanContribution,\n} from '@wildo-ai/platform-config-lib';\n\nexport const AwsS3InfraProviderModule: InfraProviderModule = {\n provider: InfraProvider.AWS_S3,\n supportedCapabilities: [InfraCapability.OBJECT_STORAGE],\n\n /**\n * What the ⚠️ block above says, made mechanical: a declaration resolving here (`s3: { source:\n * MANAGED }`, or `provider: 'aws'`) is refused by `wildo config validate` / `config sync` /\n * `lock check` until this field is deleted — in the change that teaches the broker AWS STS (#14).\n */\n unservableReason:\n 'The object-storage credential broker speaks only MinIO AssumeRole, so an application on AWS S3 '\n + 'would receive no storage credential (#14).',\n\n /**\n * Shared bucket, shared access key — no per-app credential is minted, so there is nothing\n * per-principal to confine. Confinement for object storage is done by STS session policy at\n * request time, not by a secret in the application blob.\n */\n perPrincipalSecretBlobPaths: [],\n\n plan(): InfraProviderPlanContribution {\n return {\n // No compose service — S3 is fully managed.\n // No K8s manifest — same reason.\n platformAdmin: {\n envVars: {\n STORAGE_PROVIDER: 's3',\n // Endpoint and port have AWS defaults; operator may override\n // for region-specific or VPC-endpoint topologies via the\n // env's authored `backingServices.s3` config.\n STORAGE_USE_SSL: 'true',\n },\n secretEnvVars: [\n 'STORAGE_ACCESS_KEY',\n 'STORAGE_SECRET_KEY',\n // Region is sensitive-ish (deployment topology) and is\n // delivered via the secret env channel for symmetry with\n // the access keys, even though it's not strictly secret.\n // The legacy treatment was env-var, not secret-env-var; if\n // operators object, this can flip to `envVars` later\n // without breaking the contract.\n 'STORAGE_REGION',\n ],\n consumers: [\n InfraPlatformAdminConsumer.APPS_MANAGER,\n InfraPlatformAdminConsumer.COMPANION,\n ],\n },\n // Same shared bucket as MinIO_Self. Apps receive the NON-secret\n // `STORAGE_*` values via the bootstrap env contract; the credential\n // half is no longer emitted for any provider — see the ⚠️ block in\n // this module's JSDoc for why that makes AWS_S3 currently unusable.\n };\n },\n\n // No `mintAppCredentials` / `revokeAppCredentials` — not because the model\n // is shared-bucket (it is, but that is not the reason), but because\n // per-application isolation is delivered by BROKERED STS SESSIONS rather than\n // by minted long-lived accounts. See this module's JSDoc.\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clamav-self.infra.module.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"clamav-self.infra.module.d.ts","sourceRoot":"","sources":["../../../src/clamav-self/clamav-self.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAIL,mBAAmB,EAEpB,MAAM,+BAA+B,CAAC;AAIvC,eAAO,MAAM,6BAA6B,EAAE,mBAiC3C,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ImmudbSelfInfraProviderModule` — the self-hosted tamper-evident audit store (#1696).
|
|
3
|
+
*
|
|
4
|
+
* ## What it replaces
|
|
5
|
+
*
|
|
6
|
+
* Until #1696 the platform ran ONE immudb and every application's audit sink logged into it as the server's
|
|
7
|
+
* built-in `immudb` SYSADMIN, into the same `defaultdb`: any application's backend held a superuser credential over
|
|
8
|
+
* every application's tamper-evident audit data, and the server's admin password was copied from the OWNING
|
|
9
|
+
* application's provider secret, so every hosted application had to be handed the owner's sysadmin password to write
|
|
10
|
+
* at all. `IMMUDB_SELF` was servable only as an operator-credentialed exemption because nothing could mint anything
|
|
11
|
+
* narrower.
|
|
12
|
+
*
|
|
13
|
+
* ## What it mints
|
|
14
|
+
*
|
|
15
|
+
* Per application: ONE immudb database and ONE user holding `READ_WRITE` on that database only — the permission an
|
|
16
|
+
* audit sink needs to append and verify, and nothing that administers users, databases or the server. The values
|
|
17
|
+
* reach the application in its platform secrets at `database.immudb.{username,password,database}`, the same paths the
|
|
18
|
+
* engine's immudb provider reads first (`platformMintedSecretPath`), so the operator-authored `IMMUDB_USER` /
|
|
19
|
+
* `IMMUDB_PASSWORD` / `IMMUDB_DATABASE` no longer decide anything on a self-hosted platform.
|
|
20
|
+
*
|
|
21
|
+
* The admin credential apps-manager mints with is a framework-managed PLATFORM secret (`immudb.adminPassword`),
|
|
22
|
+
* delivered to apps-manager only (`IMMUDB_ADMIN_*`), and never to an application.
|
|
23
|
+
*
|
|
24
|
+
* ## Naming, and why it is this narrow
|
|
25
|
+
*
|
|
26
|
+
* immudb accepts only letters and digits in a database name ("punctuation marks and symbols are not allowed in
|
|
27
|
+
* database name", immudb issue #1770) and `^[a-zA-Z0-9_]+$` up to 63 characters for a username. The application
|
|
28
|
+
* namespace (`<slug>-<environment>`) carries hyphens, so the database name is its lowercased letters and digits plus
|
|
29
|
+
* a short digest of the namespace itself: stripping punctuation alone would give `wonder-todos` and `wondertodos` the
|
|
30
|
+
* SAME database, which is exactly the sharing this module exists to remove.
|
|
31
|
+
* spec-cite: immudb v1.11.1 `pkg/auth/user.go` — `usernameRegex = ^[a-zA-Z0-9_]+$`, `maxUsernameLen = 63`
|
|
32
|
+
* (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/user.go, fetched 2026-09-29); the database
|
|
33
|
+
* name rule is the server's error text quoted in https://github.com/codenotary/immudb/issues/1770.
|
|
34
|
+
*
|
|
35
|
+
* ## Runtime principals
|
|
36
|
+
*
|
|
37
|
+
* The APPLICATION BACKEND only. A minion's audit events go through the same application's audit trail, so it
|
|
38
|
+
* receives the application's credential through the ordinary delivery (`perPrincipalSecretBlobPaths` is empty, so
|
|
39
|
+
* nothing is stripped for it). A named principal passed here is refused rather than given a second database.
|
|
40
|
+
*
|
|
41
|
+
* ## Revocation
|
|
42
|
+
*
|
|
43
|
+
* `revokeAppCredentials` DEACTIVATES the user and revokes its permission — immudb has no user deletion, and the
|
|
44
|
+
* database and its events are kept, because an append-only audit history must outlive the credential that wrote it
|
|
45
|
+
* (#1307, #1562). `mintAppCredentials` re-activates and re-grants, which is what a restore runs.
|
|
46
|
+
*/
|
|
47
|
+
import { InfraProviderModule } from '@wildo-ai/platform-config-lib';
|
|
48
|
+
/**
|
|
49
|
+
* The `Wildo_Application_Secrets` paths this module writes — the SAME strings the engine's immudb provider names as
|
|
50
|
+
* `platformMintedSecretPath` (`IMMUDB_MINTED_SECRET_PATHS` in external-connectors-private). Each side is pinned to the
|
|
51
|
+
* engine's `AppConfigurationSecrets.database.immudb` schema, which is where the two ends meet: these constants by
|
|
52
|
+
* apps-manager's `immudb-minted-secret-paths` test, the engine's by saas-backend-lib's
|
|
53
|
+
* `app-config-secrets.boundaries` test. The lifecycle imports these, never literals.
|
|
54
|
+
*/
|
|
55
|
+
export declare const IMMUDB_USERNAME_PATH = "database.immudb.username";
|
|
56
|
+
export declare const IMMUDB_PASSWORD_PATH = "database.immudb.password";
|
|
57
|
+
export declare const IMMUDB_DATABASE_PATH = "database.immudb.database";
|
|
58
|
+
/**
|
|
59
|
+
* immudb's password rule, checked here so a non-compliant value fails naming the application rather than as a bare
|
|
60
|
+
* gRPC error from the server.
|
|
61
|
+
* spec-cite: immudb v1.11.1 `pkg/auth/passwords.go` — "password must have between 8 and 32 letters, digits and
|
|
62
|
+
* special characters of which at least 1 uppercase letter, 1 digit and 1 special character"
|
|
63
|
+
* (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/passwords.go, fetched 2026-09-29).
|
|
64
|
+
*/
|
|
65
|
+
export declare function isImmudbCompliantPassword(password: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The per-application database name: the namespace's lowercased letters and digits (capped) plus the first 8 hex of
|
|
68
|
+
* its SHA-256, so two namespaces differing only in punctuation still get two databases. Deterministic, so a revoke,
|
|
69
|
+
* a restore and a re-registration all address the database the first mint created.
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildImmudbDatabaseName(applicationNamespace: string): string;
|
|
72
|
+
/** The per-application audit user: the database name plus a role suffix, inside immudb's username rule. */
|
|
73
|
+
export declare function buildImmudbUsername(databaseName: string): string;
|
|
74
|
+
export declare const ImmudbSelfInfraProviderModule: InfraProviderModule;
|
|
75
|
+
//# sourceMappingURL=immudb-self.infra.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"immudb-self.infra.module.d.ts","sourceRoot":"","sources":["../../../src/immudb-self/immudb-self.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAIH,OAAO,EASL,mBAAmB,EAEpB,MAAM,+BAA+B,CAAC;AAKvC;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAiB/D;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMnE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,2GAA2G;AAC3G,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhE;AA0BD,eAAO,MAAM,6BAA6B,EAAE,mBA0E3C,CAAC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ImmudbSelfInfraProviderModule` — the self-hosted tamper-evident audit store (#1696).
|
|
3
|
+
*
|
|
4
|
+
* ## What it replaces
|
|
5
|
+
*
|
|
6
|
+
* Until #1696 the platform ran ONE immudb and every application's audit sink logged into it as the server's
|
|
7
|
+
* built-in `immudb` SYSADMIN, into the same `defaultdb`: any application's backend held a superuser credential over
|
|
8
|
+
* every application's tamper-evident audit data, and the server's admin password was copied from the OWNING
|
|
9
|
+
* application's provider secret, so every hosted application had to be handed the owner's sysadmin password to write
|
|
10
|
+
* at all. `IMMUDB_SELF` was servable only as an operator-credentialed exemption because nothing could mint anything
|
|
11
|
+
* narrower.
|
|
12
|
+
*
|
|
13
|
+
* ## What it mints
|
|
14
|
+
*
|
|
15
|
+
* Per application: ONE immudb database and ONE user holding `READ_WRITE` on that database only — the permission an
|
|
16
|
+
* audit sink needs to append and verify, and nothing that administers users, databases or the server. The values
|
|
17
|
+
* reach the application in its platform secrets at `database.immudb.{username,password,database}`, the same paths the
|
|
18
|
+
* engine's immudb provider reads first (`platformMintedSecretPath`), so the operator-authored `IMMUDB_USER` /
|
|
19
|
+
* `IMMUDB_PASSWORD` / `IMMUDB_DATABASE` no longer decide anything on a self-hosted platform.
|
|
20
|
+
*
|
|
21
|
+
* The admin credential apps-manager mints with is a framework-managed PLATFORM secret (`immudb.adminPassword`),
|
|
22
|
+
* delivered to apps-manager only (`IMMUDB_ADMIN_*`), and never to an application.
|
|
23
|
+
*
|
|
24
|
+
* ## Naming, and why it is this narrow
|
|
25
|
+
*
|
|
26
|
+
* immudb accepts only letters and digits in a database name ("punctuation marks and symbols are not allowed in
|
|
27
|
+
* database name", immudb issue #1770) and `^[a-zA-Z0-9_]+$` up to 63 characters for a username. The application
|
|
28
|
+
* namespace (`<slug>-<environment>`) carries hyphens, so the database name is its lowercased letters and digits plus
|
|
29
|
+
* a short digest of the namespace itself: stripping punctuation alone would give `wonder-todos` and `wondertodos` the
|
|
30
|
+
* SAME database, which is exactly the sharing this module exists to remove.
|
|
31
|
+
* spec-cite: immudb v1.11.1 `pkg/auth/user.go` — `usernameRegex = ^[a-zA-Z0-9_]+$`, `maxUsernameLen = 63`
|
|
32
|
+
* (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/user.go, fetched 2026-09-29); the database
|
|
33
|
+
* name rule is the server's error text quoted in https://github.com/codenotary/immudb/issues/1770.
|
|
34
|
+
*
|
|
35
|
+
* ## Runtime principals
|
|
36
|
+
*
|
|
37
|
+
* The APPLICATION BACKEND only. A minion's audit events go through the same application's audit trail, so it
|
|
38
|
+
* receives the application's credential through the ordinary delivery (`perPrincipalSecretBlobPaths` is empty, so
|
|
39
|
+
* nothing is stripped for it). A named principal passed here is refused rather than given a second database.
|
|
40
|
+
*
|
|
41
|
+
* ## Revocation
|
|
42
|
+
*
|
|
43
|
+
* `revokeAppCredentials` DEACTIVATES the user and revokes its permission — immudb has no user deletion, and the
|
|
44
|
+
* database and its events are kept, because an append-only audit history must outlive the credential that wrote it
|
|
45
|
+
* (#1307, #1562). `mintAppCredentials` re-activates and re-grants, which is what a restore runs.
|
|
46
|
+
*/
|
|
47
|
+
import { createHash } from 'node:crypto';
|
|
48
|
+
import { ApplicationRuntimePrincipalKind, ImmudbDatabasePermission, InfraCapability, InfraPlatformAdminConsumer, InfraProvider, } from '@wildo-ai/platform-config-lib';
|
|
49
|
+
/** immudb's gRPC port (matches `INFRA_DEFAULT_PORTS.IMMUDB`). */
|
|
50
|
+
const DEFAULT_IMMUDB_PORT = 3322;
|
|
51
|
+
/**
|
|
52
|
+
* The `Wildo_Application_Secrets` paths this module writes — the SAME strings the engine's immudb provider names as
|
|
53
|
+
* `platformMintedSecretPath` (`IMMUDB_MINTED_SECRET_PATHS` in external-connectors-private). Each side is pinned to the
|
|
54
|
+
* engine's `AppConfigurationSecrets.database.immudb` schema, which is where the two ends meet: these constants by
|
|
55
|
+
* apps-manager's `immudb-minted-secret-paths` test, the engine's by saas-backend-lib's
|
|
56
|
+
* `app-config-secrets.boundaries` test. The lifecycle imports these, never literals.
|
|
57
|
+
*/
|
|
58
|
+
export const IMMUDB_USERNAME_PATH = 'database.immudb.username';
|
|
59
|
+
export const IMMUDB_PASSWORD_PATH = 'database.immudb.password';
|
|
60
|
+
export const IMMUDB_DATABASE_PATH = 'database.immudb.database';
|
|
61
|
+
/**
|
|
62
|
+
* `applicationConfigInputs` key for the database name RECORDED at the first mint (apps-manager passes the stored
|
|
63
|
+
* `database.immudb.database` back, so a revoke, a restore and a re-registration address the database the first mint
|
|
64
|
+
* created even if the derivation ever changes). Not an authored value: `backingServices.immudb.database` is not read
|
|
65
|
+
* for a self-hosted store.
|
|
66
|
+
*/
|
|
67
|
+
const DATABASE_NAME_INPUT_KEY = 'databaseName';
|
|
68
|
+
/**
|
|
69
|
+
* The longest database name whose `<name>_audit` user still fits immudb's 63-character username limit, and the
|
|
70
|
+
* database name's own character rule (letters and digits). A recorded name outside either is refused rather than sent.
|
|
71
|
+
*/
|
|
72
|
+
const MAX_DATABASE_NAME_LENGTH = 63 - '_audit'.length;
|
|
73
|
+
const DATABASE_NAME_PATTERN = /^[a-zA-Z0-9]+$/;
|
|
74
|
+
/**
|
|
75
|
+
* immudb's password rule, checked here so a non-compliant value fails naming the application rather than as a bare
|
|
76
|
+
* gRPC error from the server.
|
|
77
|
+
* spec-cite: immudb v1.11.1 `pkg/auth/passwords.go` — "password must have between 8 and 32 letters, digits and
|
|
78
|
+
* special characters of which at least 1 uppercase letter, 1 digit and 1 special character"
|
|
79
|
+
* (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/passwords.go, fetched 2026-09-29).
|
|
80
|
+
*/
|
|
81
|
+
export function isImmudbCompliantPassword(password) {
|
|
82
|
+
return password.length >= 8
|
|
83
|
+
&& password.length <= 32
|
|
84
|
+
&& /[A-Z]/.test(password)
|
|
85
|
+
&& /[0-9]/.test(password)
|
|
86
|
+
&& /[^A-Za-z0-9]/.test(password);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The per-application database name: the namespace's lowercased letters and digits (capped) plus the first 8 hex of
|
|
90
|
+
* its SHA-256, so two namespaces differing only in punctuation still get two databases. Deterministic, so a revoke,
|
|
91
|
+
* a restore and a re-registration all address the database the first mint created.
|
|
92
|
+
*/
|
|
93
|
+
export function buildImmudbDatabaseName(applicationNamespace) {
|
|
94
|
+
const letters = applicationNamespace.toLowerCase().replace(/[^a-z0-9]/g, '').slice(0, 40);
|
|
95
|
+
const digest = createHash('sha256').update(applicationNamespace).digest('hex').slice(0, 8);
|
|
96
|
+
return `${letters}${digest}`;
|
|
97
|
+
}
|
|
98
|
+
/** The per-application audit user: the database name plus a role suffix, inside immudb's username rule. */
|
|
99
|
+
export function buildImmudbUsername(databaseName) {
|
|
100
|
+
return `${databaseName}_audit`;
|
|
101
|
+
}
|
|
102
|
+
function refuseNamedPrincipal(context, verb) {
|
|
103
|
+
if (context.principal && context.principal.kind !== ApplicationRuntimePrincipalKind.APPLICATION_BACKEND) {
|
|
104
|
+
throw new Error(`ImmudbSelfInfraProviderModule.${verb}: principal '${context.principal.kind}:${context.principal.name}' is not `
|
|
105
|
+
+ 'the application backend. An application has ONE audit database and ONE audit user; its runtimes write through '
|
|
106
|
+
+ 'the application\'s credential, so a per-principal immudb credential is never minted or revoked.');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function resolveDatabaseName(context) {
|
|
110
|
+
if (!context.applicationNamespace) {
|
|
111
|
+
throw new Error('ImmudbSelfInfraProviderModule: applicationNamespace is empty. The orchestrator MUST supply it.');
|
|
112
|
+
}
|
|
113
|
+
const recorded = context.applicationConfigInputs?.[DATABASE_NAME_INPUT_KEY];
|
|
114
|
+
if (recorded && (!DATABASE_NAME_PATTERN.test(recorded) || recorded.length > MAX_DATABASE_NAME_LENGTH)) {
|
|
115
|
+
throw new Error(`ImmudbSelfInfraProviderModule: the recorded database name '${recorded}' is outside immudb's rules (letters and `
|
|
116
|
+
+ `digits only, at most ${MAX_DATABASE_NAME_LENGTH} characters so its audit user fits the 63-character limit).`);
|
|
117
|
+
}
|
|
118
|
+
return recorded || buildImmudbDatabaseName(context.applicationNamespace);
|
|
119
|
+
}
|
|
120
|
+
export const ImmudbSelfInfraProviderModule = {
|
|
121
|
+
provider: InfraProvider.IMMUDB_SELF,
|
|
122
|
+
supportedCapabilities: [InfraCapability.AUDIT_LOG_STORAGE],
|
|
123
|
+
/**
|
|
124
|
+
* Empty: minions write through the application's audit credential (see the module JSDoc), so the delivery must
|
|
125
|
+
* not strip it from them.
|
|
126
|
+
*/
|
|
127
|
+
perPrincipalSecretBlobPaths: [],
|
|
128
|
+
plan() {
|
|
129
|
+
return {
|
|
130
|
+
dockerComposeServices: ['immudb'],
|
|
131
|
+
k8sResources: ['templates/infra/k8s/internal/immudb/deployment.yaml.hbs'],
|
|
132
|
+
platformAdmin: {
|
|
133
|
+
envVars: {
|
|
134
|
+
IMMUDB_ADMIN_HOST: 'immudb',
|
|
135
|
+
IMMUDB_ADMIN_PORT: String(DEFAULT_IMMUDB_PORT),
|
|
136
|
+
},
|
|
137
|
+
// The server's built-in sysadmin password: a framework-managed platform secret (`immudb.adminPassword`),
|
|
138
|
+
// written by the CLI's env builder into apps-manager's env only.
|
|
139
|
+
secretEnvVars: ['IMMUDB_ADMIN_PASSWORD'],
|
|
140
|
+
consumers: [InfraPlatformAdminConsumer.APPS_MANAGER],
|
|
141
|
+
},
|
|
142
|
+
appRuntime: {
|
|
143
|
+
perAppSecretBlobPaths: [IMMUDB_USERNAME_PATH, IMMUDB_PASSWORD_PATH, IMMUDB_DATABASE_PATH],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
// assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — READ_WRITE on the application's own database only, never ADMIN or SYSADMIN.
|
|
148
|
+
async mintAppCredentials(context) {
|
|
149
|
+
refuseNamedPrincipal(context, 'mintAppCredentials');
|
|
150
|
+
const password = context.secretInputs[IMMUDB_PASSWORD_PATH];
|
|
151
|
+
if (!password) {
|
|
152
|
+
throw new Error(`ImmudbSelfInfraProviderModule.mintAppCredentials: secretInputs is missing '${IMMUDB_PASSWORD_PATH}'. `
|
|
153
|
+
+ 'The orchestrator MUST supply the password — modules are upsert-only.');
|
|
154
|
+
}
|
|
155
|
+
if (!isImmudbCompliantPassword(password)) {
|
|
156
|
+
throw new Error('ImmudbSelfInfraProviderModule.mintAppCredentials: the supplied password does not meet immudb\'s rule '
|
|
157
|
+
+ '(8 to 32 characters with at least one uppercase letter, one digit and one special character).');
|
|
158
|
+
}
|
|
159
|
+
const databaseName = resolveDatabaseName(context);
|
|
160
|
+
const username = buildImmudbUsername(databaseName);
|
|
161
|
+
const adminClient = context.adminClient;
|
|
162
|
+
await adminClient.ensureDatabase({ databaseName });
|
|
163
|
+
await adminClient.upsertDatabaseUser({
|
|
164
|
+
username,
|
|
165
|
+
password,
|
|
166
|
+
databaseName,
|
|
167
|
+
permission: ImmudbDatabasePermission.READ_WRITE,
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
secretBlobValues: {
|
|
171
|
+
[IMMUDB_USERNAME_PATH]: username,
|
|
172
|
+
[IMMUDB_PASSWORD_PATH]: password,
|
|
173
|
+
[IMMUDB_DATABASE_PATH]: databaseName,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
// assurance-control: WILDO.IDENTITY.CREDENTIAL_LIFECYCLE — a withdrawn application's audit user is deactivated and its permission revoked.
|
|
178
|
+
async revokeAppCredentials(context) {
|
|
179
|
+
refuseNamedPrincipal(context, 'revokeAppCredentials');
|
|
180
|
+
const databaseName = resolveDatabaseName(context);
|
|
181
|
+
const adminClient = context.adminClient;
|
|
182
|
+
await adminClient.deactivateDatabaseUser({ username: buildImmudbUsername(databaseName), databaseName });
|
|
183
|
+
},
|
|
184
|
+
// No `mintPlatformServiceCredentials`: no platform service writes to the audit store.
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=immudb-self.infra.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"immudb-self.infra.module.js","sourceRoot":"","sources":["../../../src/immudb-self/immudb-self.infra.module.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `ImmudbSelfInfraProviderModule` — the self-hosted tamper-evident audit store (#1696).\n *\n * ## What it replaces\n *\n * Until #1696 the platform ran ONE immudb and every application's audit sink logged into it as the server's\n * built-in `immudb` SYSADMIN, into the same `defaultdb`: any application's backend held a superuser credential over\n * every application's tamper-evident audit data, and the server's admin password was copied from the OWNING\n * application's provider secret, so every hosted application had to be handed the owner's sysadmin password to write\n * at all. `IMMUDB_SELF` was servable only as an operator-credentialed exemption because nothing could mint anything\n * narrower.\n *\n * ## What it mints\n *\n * Per application: ONE immudb database and ONE user holding `READ_WRITE` on that database only — the permission an\n * audit sink needs to append and verify, and nothing that administers users, databases or the server. The values\n * reach the application in its platform secrets at `database.immudb.{username,password,database}`, the same paths the\n * engine's immudb provider reads first (`platformMintedSecretPath`), so the operator-authored `IMMUDB_USER` /\n * `IMMUDB_PASSWORD` / `IMMUDB_DATABASE` no longer decide anything on a self-hosted platform.\n *\n * The admin credential apps-manager mints with is a framework-managed PLATFORM secret (`immudb.adminPassword`),\n * delivered to apps-manager only (`IMMUDB_ADMIN_*`), and never to an application.\n *\n * ## Naming, and why it is this narrow\n *\n * immudb accepts only letters and digits in a database name (\"punctuation marks and symbols are not allowed in\n * database name\", immudb issue #1770) and `^[a-zA-Z0-9_]+$` up to 63 characters for a username. The application\n * namespace (`<slug>-<environment>`) carries hyphens, so the database name is its lowercased letters and digits plus\n * a short digest of the namespace itself: stripping punctuation alone would give `wonder-todos` and `wondertodos` the\n * SAME database, which is exactly the sharing this module exists to remove.\n * spec-cite: immudb v1.11.1 `pkg/auth/user.go` — `usernameRegex = ^[a-zA-Z0-9_]+$`, `maxUsernameLen = 63`\n * (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/user.go, fetched 2026-09-29); the database\n * name rule is the server's error text quoted in https://github.com/codenotary/immudb/issues/1770.\n *\n * ## Runtime principals\n *\n * The APPLICATION BACKEND only. A minion's audit events go through the same application's audit trail, so it\n * receives the application's credential through the ordinary delivery (`perPrincipalSecretBlobPaths` is empty, so\n * nothing is stripped for it). A named principal passed here is refused rather than given a second database.\n *\n * ## Revocation\n *\n * `revokeAppCredentials` DEACTIVATES the user and revokes its permission — immudb has no user deletion, and the\n * database and its events are kept, because an append-only audit history must outlive the credential that wrote it\n * (#1307, #1562). `mintAppCredentials` re-activates and re-grants, which is what a restore runs.\n */\n\nimport { createHash } from 'node:crypto';\n\nimport {\n ApplicationRuntimePrincipalKind,\n AppCredentialMintingContext,\n AppCredentialMintingResult,\n IImmudbAdminClient,\n ImmudbDatabasePermission,\n InfraCapability,\n InfraPlatformAdminConsumer,\n InfraProvider,\n InfraProviderModule,\n InfraProviderPlanContribution,\n} from '@wildo-ai/platform-config-lib';\n\n/** immudb's gRPC port (matches `INFRA_DEFAULT_PORTS.IMMUDB`). */\nconst DEFAULT_IMMUDB_PORT = 3322;\n\n/**\n * The `Wildo_Application_Secrets` paths this module writes — the SAME strings the engine's immudb provider names as\n * `platformMintedSecretPath` (`IMMUDB_MINTED_SECRET_PATHS` in external-connectors-private). Each side is pinned to the\n * engine's `AppConfigurationSecrets.database.immudb` schema, which is where the two ends meet: these constants by\n * apps-manager's `immudb-minted-secret-paths` test, the engine's by saas-backend-lib's\n * `app-config-secrets.boundaries` test. The lifecycle imports these, never literals.\n */\nexport const IMMUDB_USERNAME_PATH = 'database.immudb.username';\nexport const IMMUDB_PASSWORD_PATH = 'database.immudb.password';\nexport const IMMUDB_DATABASE_PATH = 'database.immudb.database';\n\n/**\n * `applicationConfigInputs` key for the database name RECORDED at the first mint (apps-manager passes the stored\n * `database.immudb.database` back, so a revoke, a restore and a re-registration address the database the first mint\n * created even if the derivation ever changes). Not an authored value: `backingServices.immudb.database` is not read\n * for a self-hosted store.\n */\nconst DATABASE_NAME_INPUT_KEY = 'databaseName';\n\n/**\n * The longest database name whose `<name>_audit` user still fits immudb's 63-character username limit, and the\n * database name's own character rule (letters and digits). A recorded name outside either is refused rather than sent.\n */\nconst MAX_DATABASE_NAME_LENGTH = 63 - '_audit'.length;\nconst DATABASE_NAME_PATTERN = /^[a-zA-Z0-9]+$/;\n\n/**\n * immudb's password rule, checked here so a non-compliant value fails naming the application rather than as a bare\n * gRPC error from the server.\n * spec-cite: immudb v1.11.1 `pkg/auth/passwords.go` — \"password must have between 8 and 32 letters, digits and\n * special characters of which at least 1 uppercase letter, 1 digit and 1 special character\"\n * (https://raw.githubusercontent.com/codenotary/immudb/v1.11.1/pkg/auth/passwords.go, fetched 2026-09-29).\n */\nexport function isImmudbCompliantPassword(password: string): boolean {\n return password.length >= 8\n && password.length <= 32\n && /[A-Z]/.test(password)\n && /[0-9]/.test(password)\n && /[^A-Za-z0-9]/.test(password);\n}\n\n/**\n * The per-application database name: the namespace's lowercased letters and digits (capped) plus the first 8 hex of\n * its SHA-256, so two namespaces differing only in punctuation still get two databases. Deterministic, so a revoke,\n * a restore and a re-registration all address the database the first mint created.\n */\nexport function buildImmudbDatabaseName(applicationNamespace: string): string {\n const letters = applicationNamespace.toLowerCase().replace(/[^a-z0-9]/g, '').slice(0, 40);\n const digest = createHash('sha256').update(applicationNamespace).digest('hex').slice(0, 8);\n return `${letters}${digest}`;\n}\n\n/** The per-application audit user: the database name plus a role suffix, inside immudb's username rule. */\nexport function buildImmudbUsername(databaseName: string): string {\n return `${databaseName}_audit`;\n}\n\nfunction refuseNamedPrincipal(context: AppCredentialMintingContext, verb: string): void {\n if (context.principal && context.principal.kind !== ApplicationRuntimePrincipalKind.APPLICATION_BACKEND) {\n throw new Error(\n `ImmudbSelfInfraProviderModule.${verb}: principal '${context.principal.kind}:${context.principal.name}' is not `\n + 'the application backend. An application has ONE audit database and ONE audit user; its runtimes write through '\n + 'the application\\'s credential, so a per-principal immudb credential is never minted or revoked.',\n );\n }\n}\n\nfunction resolveDatabaseName(context: AppCredentialMintingContext): string {\n if (!context.applicationNamespace) {\n throw new Error('ImmudbSelfInfraProviderModule: applicationNamespace is empty. The orchestrator MUST supply it.');\n }\n const recorded = context.applicationConfigInputs?.[DATABASE_NAME_INPUT_KEY];\n if (recorded && (!DATABASE_NAME_PATTERN.test(recorded) || recorded.length > MAX_DATABASE_NAME_LENGTH)) {\n throw new Error(\n `ImmudbSelfInfraProviderModule: the recorded database name '${recorded}' is outside immudb's rules (letters and `\n + `digits only, at most ${MAX_DATABASE_NAME_LENGTH} characters so its audit user fits the 63-character limit).`,\n );\n }\n return recorded || buildImmudbDatabaseName(context.applicationNamespace);\n}\n\nexport const ImmudbSelfInfraProviderModule: InfraProviderModule = {\n provider: InfraProvider.IMMUDB_SELF,\n supportedCapabilities: [InfraCapability.AUDIT_LOG_STORAGE],\n\n /**\n * Empty: minions write through the application's audit credential (see the module JSDoc), so the delivery must\n * not strip it from them.\n */\n perPrincipalSecretBlobPaths: [],\n\n plan(): InfraProviderPlanContribution {\n return {\n dockerComposeServices: ['immudb'],\n k8sResources: ['templates/infra/k8s/internal/immudb/deployment.yaml.hbs'],\n platformAdmin: {\n envVars: {\n IMMUDB_ADMIN_HOST: 'immudb',\n IMMUDB_ADMIN_PORT: String(DEFAULT_IMMUDB_PORT),\n },\n // The server's built-in sysadmin password: a framework-managed platform secret (`immudb.adminPassword`),\n // written by the CLI's env builder into apps-manager's env only.\n secretEnvVars: ['IMMUDB_ADMIN_PASSWORD'],\n consumers: [InfraPlatformAdminConsumer.APPS_MANAGER],\n },\n appRuntime: {\n perAppSecretBlobPaths: [IMMUDB_USERNAME_PATH, IMMUDB_PASSWORD_PATH, IMMUDB_DATABASE_PATH],\n },\n };\n },\n\n // assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — READ_WRITE on the application's own database only, never ADMIN or SYSADMIN.\n async mintAppCredentials(context: AppCredentialMintingContext): Promise<AppCredentialMintingResult> {\n refuseNamedPrincipal(context, 'mintAppCredentials');\n const password = context.secretInputs[IMMUDB_PASSWORD_PATH];\n if (!password) {\n throw new Error(\n `ImmudbSelfInfraProviderModule.mintAppCredentials: secretInputs is missing '${IMMUDB_PASSWORD_PATH}'. `\n + 'The orchestrator MUST supply the password — modules are upsert-only.',\n );\n }\n if (!isImmudbCompliantPassword(password)) {\n throw new Error(\n 'ImmudbSelfInfraProviderModule.mintAppCredentials: the supplied password does not meet immudb\\'s rule '\n + '(8 to 32 characters with at least one uppercase letter, one digit and one special character).',\n );\n }\n const databaseName = resolveDatabaseName(context);\n const username = buildImmudbUsername(databaseName);\n const adminClient = context.adminClient as IImmudbAdminClient;\n await adminClient.ensureDatabase({ databaseName });\n await adminClient.upsertDatabaseUser({\n username,\n password,\n databaseName,\n permission: ImmudbDatabasePermission.READ_WRITE,\n });\n return {\n secretBlobValues: {\n [IMMUDB_USERNAME_PATH]: username,\n [IMMUDB_PASSWORD_PATH]: password,\n [IMMUDB_DATABASE_PATH]: databaseName,\n },\n };\n },\n\n // assurance-control: WILDO.IDENTITY.CREDENTIAL_LIFECYCLE — a withdrawn application's audit user is deactivated and its permission revoked.\n async revokeAppCredentials(context: AppCredentialMintingContext): Promise<void> {\n refuseNamedPrincipal(context, 'revokeAppCredentials');\n const databaseName = resolveDatabaseName(context);\n const adminClient = context.adminClient as IImmudbAdminClient;\n await adminClient.deactivateDatabaseUser({ username: buildImmudbUsername(databaseName), databaseName });\n },\n\n // No `mintPlatformServiceCredentials`: no platform service writes to the audit store.\n};\n"]}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* consumers iterate it (or look up by `InfraProvider` value) instead
|
|
17
17
|
* of importing modules one by one.
|
|
18
18
|
*/
|
|
19
|
-
import
|
|
19
|
+
import { InfraProvider, type InfraProviderModule } from '@wildo-ai/platform-config-lib';
|
|
20
20
|
export { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module';
|
|
21
21
|
export { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module';
|
|
22
22
|
export { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module';
|
|
@@ -25,6 +25,7 @@ export { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infr
|
|
|
25
25
|
export { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module';
|
|
26
26
|
export { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module';
|
|
27
27
|
export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module';
|
|
28
|
+
export * from './immudb-self/immudb-self.infra.module';
|
|
28
29
|
/**
|
|
29
30
|
* Canonical `InfraProvider` → `InfraProviderModule` catalog. Caller
|
|
30
31
|
* (CLI, apps-manager) builds a `Map<InfraProvider, InfraProviderModule>`
|
|
@@ -41,7 +42,9 @@ export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.m
|
|
|
41
42
|
* `MONGODB_ATLAS` — five stateful modules with mint/revoke
|
|
42
43
|
* methods.
|
|
43
44
|
* - `MINIO_SELF`, `AWS_S3` — object storage (shared-bucket model;
|
|
44
|
-
* no per-app credentials).
|
|
45
|
+
* no per-app credentials). `AWS_S3` declares `unservableReason`
|
|
46
|
+
* (no AWS STS path in the credential broker, #14), so it plans but is
|
|
47
|
+
* not servable.
|
|
45
48
|
* - `CLAMAV_SELF` — stateless infra (no auth, no per-app state;
|
|
46
49
|
* `plan()` only).
|
|
47
50
|
*
|
|
@@ -51,11 +54,38 @@ export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.m
|
|
|
51
54
|
* `POSTGRES_RENDER` — managed-Postgres brand catalog entries
|
|
52
55
|
* (Slice 4.B.0). No module yet; trigger = real customer.
|
|
53
56
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
+
* A declaration resolving to a provider outside
|
|
58
|
+
* {@link collectServableInfraProviders} is REFUSED by `wildo config
|
|
59
|
+
* validate`, `config sync` and `lock check` (#1693) — it no longer falls
|
|
60
|
+
* through to an authored-entry digest.
|
|
57
61
|
*/
|
|
58
62
|
export declare const INFRA_PROVIDER_MODULES: ReadonlyArray<InfraProviderModule>;
|
|
63
|
+
/**
|
|
64
|
+
* Providers the platform serves WITHOUT a module in {@link INFRA_PROVIDER_MODULES}, because their
|
|
65
|
+
* application credential is the operator's to supply rather than the catalogue's to mint.
|
|
66
|
+
*
|
|
67
|
+
* ## Why this is the one exception, and why it is a list of exemptions rather than of refusals
|
|
68
|
+
*
|
|
69
|
+
* The servable set is DERIVED from the catalogue ({@link collectServableInfraProviders}); a hand-kept
|
|
70
|
+
* list of refused providers would silently admit every provider added later. So the only thing
|
|
71
|
+
* written down by hand is the exception, and it must be argued for here, one entry at a time.
|
|
72
|
+
*
|
|
73
|
+
* EMPTY since #1696, and kept as the named place such an exemption would be argued. `IMMUDB_SELF` was the one entry:
|
|
74
|
+
* the self-hosted audit store had no module, and every application on the server logged in as its sysadmin into
|
|
75
|
+
* one shared database. Its module now mints one database and one confined user per application, which makes it
|
|
76
|
+
* servable on its own — and REFUSED on a platform that holds no immudb admin credential, like every minting kind.
|
|
77
|
+
*/
|
|
78
|
+
export declare const OPERATOR_CREDENTIALED_INFRA_PROVIDERS: ReadonlySet<InfraProvider>;
|
|
79
|
+
/**
|
|
80
|
+
* The providers a `backingServices` declaration may resolve to — every module in the catalogue that
|
|
81
|
+
* does not declare `unservableReason`, plus {@link OPERATOR_CREDENTIALED_INFRA_PROVIDERS}.
|
|
82
|
+
*
|
|
83
|
+
* The one source both lockfile projections (`wildo config sync`, `wildo lock check`) and
|
|
84
|
+
* `wildo config validate` pass to the shared check in `@wildo-ai/platform-config-lib`
|
|
85
|
+
* (`findUnservableBackingServiceDeclarations`), so all three refuse the same declarations (#1693).
|
|
86
|
+
* Derived, so a module entering the catalogue makes its provider declarable the day it lands.
|
|
87
|
+
*/
|
|
88
|
+
export declare function collectServableInfraProviders(): ReadonlySet<InfraProvider>;
|
|
59
89
|
/**
|
|
60
90
|
* Every `Wildo_Application_Secrets` JSON path that ANY provider module can mint per runtime
|
|
61
91
|
* principal — the union of the catalog's own static declarations.
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAaxF,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAC1F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,cAAc,wCAAwC,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC,mBAAmB,CAYrE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qCAAqC,EAAE,WAAW,CAAC,aAAa,CAA4B,CAAC;AAE1G;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,IAAI,WAAW,CAAC,aAAa,CAAC,CAM1E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,CAAC,CAQxE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,WAAW,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAY7F"}
|
package/dist/esm/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infr
|
|
|
25
25
|
import { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module.js';
|
|
26
26
|
import { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module.js';
|
|
27
27
|
import { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module.js';
|
|
28
|
+
import { ImmudbSelfInfraProviderModule } from './immudb-self/immudb-self.infra.module.js';
|
|
28
29
|
export { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module.js';
|
|
29
30
|
export { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module.js';
|
|
30
31
|
export { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module.js';
|
|
@@ -33,6 +34,7 @@ export { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infr
|
|
|
33
34
|
export { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module.js';
|
|
34
35
|
export { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module.js';
|
|
35
36
|
export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module.js';
|
|
37
|
+
export * from './immudb-self/immudb-self.infra.module.js';
|
|
36
38
|
/**
|
|
37
39
|
* Canonical `InfraProvider` → `InfraProviderModule` catalog. Caller
|
|
38
40
|
* (CLI, apps-manager) builds a `Map<InfraProvider, InfraProviderModule>`
|
|
@@ -49,7 +51,9 @@ export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.m
|
|
|
49
51
|
* `MONGODB_ATLAS` — five stateful modules with mint/revoke
|
|
50
52
|
* methods.
|
|
51
53
|
* - `MINIO_SELF`, `AWS_S3` — object storage (shared-bucket model;
|
|
52
|
-
* no per-app credentials).
|
|
54
|
+
* no per-app credentials). `AWS_S3` declares `unservableReason`
|
|
55
|
+
* (no AWS STS path in the credential broker, #14), so it plans but is
|
|
56
|
+
* not servable.
|
|
53
57
|
* - `CLAMAV_SELF` — stateless infra (no auth, no per-app state;
|
|
54
58
|
* `plan()` only).
|
|
55
59
|
*
|
|
@@ -59,9 +63,10 @@ export { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.m
|
|
|
59
63
|
* `POSTGRES_RENDER` — managed-Postgres brand catalog entries
|
|
60
64
|
* (Slice 4.B.0). No module yet; trigger = real customer.
|
|
61
65
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
66
|
+
* A declaration resolving to a provider outside
|
|
67
|
+
* {@link collectServableInfraProviders} is REFUSED by `wildo config
|
|
68
|
+
* validate`, `config sync` and `lock check` (#1693) — it no longer falls
|
|
69
|
+
* through to an authored-entry digest.
|
|
65
70
|
*/
|
|
66
71
|
export const INFRA_PROVIDER_MODULES = [
|
|
67
72
|
RabbitmqSelfInfraProviderModule,
|
|
@@ -72,7 +77,43 @@ export const INFRA_PROVIDER_MODULES = [
|
|
|
72
77
|
MinioSelfInfraProviderModule,
|
|
73
78
|
AwsS3InfraProviderModule,
|
|
74
79
|
ClamavSelfInfraProviderModule,
|
|
80
|
+
// #1696: one immudb database and one confined user per application, replacing the operator-credentialed
|
|
81
|
+
// exemption under which every application logged in as the server's sysadmin.
|
|
82
|
+
ImmudbSelfInfraProviderModule,
|
|
75
83
|
];
|
|
84
|
+
/**
|
|
85
|
+
* Providers the platform serves WITHOUT a module in {@link INFRA_PROVIDER_MODULES}, because their
|
|
86
|
+
* application credential is the operator's to supply rather than the catalogue's to mint.
|
|
87
|
+
*
|
|
88
|
+
* ## Why this is the one exception, and why it is a list of exemptions rather than of refusals
|
|
89
|
+
*
|
|
90
|
+
* The servable set is DERIVED from the catalogue ({@link collectServableInfraProviders}); a hand-kept
|
|
91
|
+
* list of refused providers would silently admit every provider added later. So the only thing
|
|
92
|
+
* written down by hand is the exception, and it must be argued for here, one entry at a time.
|
|
93
|
+
*
|
|
94
|
+
* EMPTY since #1696, and kept as the named place such an exemption would be argued. `IMMUDB_SELF` was the one entry:
|
|
95
|
+
* the self-hosted audit store had no module, and every application on the server logged in as its sysadmin into
|
|
96
|
+
* one shared database. Its module now mints one database and one confined user per application, which makes it
|
|
97
|
+
* servable on its own — and REFUSED on a platform that holds no immudb admin credential, like every minting kind.
|
|
98
|
+
*/
|
|
99
|
+
export const OPERATOR_CREDENTIALED_INFRA_PROVIDERS = new Set();
|
|
100
|
+
/**
|
|
101
|
+
* The providers a `backingServices` declaration may resolve to — every module in the catalogue that
|
|
102
|
+
* does not declare `unservableReason`, plus {@link OPERATOR_CREDENTIALED_INFRA_PROVIDERS}.
|
|
103
|
+
*
|
|
104
|
+
* The one source both lockfile projections (`wildo config sync`, `wildo lock check`) and
|
|
105
|
+
* `wildo config validate` pass to the shared check in `@wildo-ai/platform-config-lib`
|
|
106
|
+
* (`findUnservableBackingServiceDeclarations`), so all three refuse the same declarations (#1693).
|
|
107
|
+
* Derived, so a module entering the catalogue makes its provider declarable the day it lands.
|
|
108
|
+
*/
|
|
109
|
+
export function collectServableInfraProviders() {
|
|
110
|
+
const servable = new Set(OPERATOR_CREDENTIALED_INFRA_PROVIDERS);
|
|
111
|
+
for (const module of INFRA_PROVIDER_MODULES) {
|
|
112
|
+
if (module.unservableReason === undefined)
|
|
113
|
+
servable.add(module.provider);
|
|
114
|
+
}
|
|
115
|
+
return servable;
|
|
116
|
+
}
|
|
76
117
|
/**
|
|
77
118
|
* Every `Wildo_Application_Secrets` JSON path that ANY provider module can mint per runtime
|
|
78
119
|
* principal — the union of the catalog's own static declarations.
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAC1F,6EAA6E;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAEvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAC1F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAuC;IACxE,+BAA+B;IAC/B,4BAA4B;IAC5B,+BAA+B;IAC/B,+BAA+B;IAC/B,8BAA8B;IAC9B,4BAA4B;IAC5B,wBAAwB;IACxB,6BAA6B;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kCAAkC;IAChD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,sBAAsB,EAAE,CAAC;QAC5C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,2BAA2B,EAAE,CAAC;YACtD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsC,CAAC;IAC1D,KAAK,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC;QACvC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,uDAAuD,CAAC,CAAC,QAAQ,MAAM;gBACvE,iDAAiD,CAClD,CAAC;QACJ,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * `@wildo-ai/platform-infra-providers` — concrete `InfraProviderModule`\n * catalog (Slice 2.5c-1 of `infra-provider-planner.md`).\n *\n * Tier-portable: the modules import only `@wildo-ai/platform-config-lib`\n * (contracts) and have no DI / mongoose / axios runtime dependencies.\n * This lets both `platform-apps-manager` (orchestrator) and\n * `wildo-cli` (lockfile materializer) consume the same module\n * objects — apps-manager passes a real admin-client implementation\n * via `AppCredentialMintingContext.adminClient`; wildo-cli only\n * needs `module.plan()` for the lockfile digest.\n *\n * Each module is exported by name (no intermediary barrels per\n * platform/CLAUDE.md \"no intermediary index.ts barrels\"). The\n * `INFRA_PROVIDER_MODULES` map below is the canonical catalog —\n * consumers iterate it (or look up by `InfraProvider` value) instead\n * of importing modules one by one.\n */\n\nimport type { InfraProvider, InfraProviderModule } from '@wildo-ai/platform-config-lib';\n\nimport { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module';\nimport { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module';\nimport { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module';\nimport { MongodbAtlasInfraProviderModule } from './mongodb-atlas/mongodb-atlas.infra.module';\nimport { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infra.module';\n// Slice 5 of `infra-provider-planner.md` — object-storage + stateless infra.\nimport { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module';\nimport { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module';\nimport { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module';\n\nexport { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module';\nexport { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module';\nexport { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module';\nexport { MongodbAtlasInfraProviderModule } from './mongodb-atlas/mongodb-atlas.infra.module';\nexport { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infra.module';\nexport { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module';\nexport { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module';\nexport { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module';\n\n/**\n * Canonical `InfraProvider` → `InfraProviderModule` catalog. Caller\n * (CLI, apps-manager) builds a `Map<InfraProvider, InfraProviderModule>`\n * from this constant when threading modules into\n * `materializeInfraSection`.\n *\n * **Why a const array instead of a `Map` literal**: arrays serialize\n * stably under tsc and roll up to a deterministic order. The\n * downstream `Map` is built once at program start; the catalog\n * itself is a value-level fixture.\n *\n * **Coverage** (Slice 5 baseline, 2026-05-10):\n * - `RABBITMQ_SELF`, `REDIS_SELF`, `POSTGRES_SELF`, `MONGODB_SELF`,\n * `MONGODB_ATLAS` — five stateful modules with mint/revoke\n * methods.\n * - `MINIO_SELF`, `AWS_S3` — object storage (shared-bucket model;\n * no per-app credentials).\n * - `CLAMAV_SELF` — stateless infra (no auth, no per-app state;\n * `plan()` only).\n *\n * **NOT covered** (catalog entries without modules):\n * - `POSTGRES_MANAGED`, `POSTGRES_AWS_RDS`, `POSTGRES_GCP_CLOUD_SQL`,\n * `POSTGRES_AZURE_DATABASE`, `POSTGRES_SUPABASE`, `POSTGRES_NEON`,\n * `POSTGRES_RENDER` — managed-Postgres brand catalog entries\n * (Slice 4.B.0). No module yet; trigger = real customer.\n *\n * `materializeInfraSection` falls back to the authored-entry digest\n * when a selected `InfraProvider` is not in the map (preserves the\n * Slice 2.5b behavior for uncovered providers).\n */\nexport const INFRA_PROVIDER_MODULES: ReadonlyArray<InfraProviderModule> = [\n RabbitmqSelfInfraProviderModule,\n RedisSelfInfraProviderModule,\n PostgresSelfInfraProviderModule,\n MongodbAtlasInfraProviderModule,\n MongodbSelfInfraProviderModule,\n MinioSelfInfraProviderModule,\n AwsS3InfraProviderModule,\n ClamavSelfInfraProviderModule,\n];\n\n/**\n * Every `Wildo_Application_Secrets` JSON path that ANY provider module can mint per runtime\n * principal — the union of the catalog's own static declarations.\n *\n * ## Why this is derived rather than written down\n *\n * The consumer is the secret-DELIVERY path in apps-manager: it strips exactly this set from the\n * application blob before overlaying a principal's own material, so a principal receives a\n * credential only where one was minted FOR IT. A hand-maintained copy at that consumer would be a\n * second source — add a provider that mints a new credential path and delivery keeps shipping the\n * APPLICATION's value for it, silently. That is the defect class this repo has paid for twice: the\n * party that CONSTRAINS is not the party that DECLARES.\n *\n * Derived from `INFRA_PROVIDER_MODULES`, so a new module is covered the day it enters the catalog.\n *\n * Deliberately the union across ALL modules, not the ones a given application selected: a principal\n * must not receive an application-wide credential for a provider it does not use either, and the\n * selected set is not knowable at the delivery call site without threading app config through it.\n * Stripping a path no module minted for this app is harmless — it is absent from the blob anyway.\n */\nexport function collectPerPrincipalSecretBlobPaths(): ReadonlySet<string> {\n const paths = new Set<string>();\n for (const module of INFRA_PROVIDER_MODULES) {\n for (const path of module.perPrincipalSecretBlobPaths) {\n paths.add(path);\n }\n }\n return paths;\n}\n\n/**\n * Build a `Map<InfraProvider, InfraProviderModule>` for the\n * canonical catalog. Callers store the result once at startup and\n * pass it to `materializeInfraSection` (digest derivation) or to\n * orchestrator paths that look up modules by `InfraProvider`.\n */\nexport function buildInfraProviderModuleMap(): ReadonlyMap<InfraProvider, InfraProviderModule> {\n const map = new Map<InfraProvider, InfraProviderModule>();\n for (const m of INFRA_PROVIDER_MODULES) {\n if (map.has(m.provider)) {\n throw new Error(\n `INFRA_PROVIDER_MODULES contains duplicate provider '${m.provider}' — ` +\n `each InfraProvider may have at most one module.`,\n );\n }\n map.set(m.provider, m);\n }\n return map;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `@wildo-ai/platform-infra-providers` — concrete `InfraProviderModule`\n * catalog (Slice 2.5c-1 of `infra-provider-planner.md`).\n *\n * Tier-portable: the modules import only `@wildo-ai/platform-config-lib`\n * (contracts) and have no DI / mongoose / axios runtime dependencies.\n * This lets both `platform-apps-manager` (orchestrator) and\n * `wildo-cli` (lockfile materializer) consume the same module\n * objects — apps-manager passes a real admin-client implementation\n * via `AppCredentialMintingContext.adminClient`; wildo-cli only\n * needs `module.plan()` for the lockfile digest.\n *\n * Each module is exported by name (no intermediary barrels per\n * platform/CLAUDE.md \"no intermediary index.ts barrels\"). The\n * `INFRA_PROVIDER_MODULES` map below is the canonical catalog —\n * consumers iterate it (or look up by `InfraProvider` value) instead\n * of importing modules one by one.\n */\n\nimport { InfraProvider, type InfraProviderModule } from '@wildo-ai/platform-config-lib';\n\nimport { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module';\nimport { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module';\nimport { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module';\nimport { MongodbAtlasInfraProviderModule } from './mongodb-atlas/mongodb-atlas.infra.module';\nimport { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infra.module';\n// Slice 5 of `infra-provider-planner.md` — object-storage + stateless infra.\nimport { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module';\nimport { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module';\nimport { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module';\nimport { ImmudbSelfInfraProviderModule } from './immudb-self/immudb-self.infra.module';\n\nexport { RabbitmqSelfInfraProviderModule } from './rabbitmq-self/rabbitmq-self.infra.module';\nexport { RedisSelfInfraProviderModule } from './redis-self/redis-self.infra.module';\nexport { PostgresSelfInfraProviderModule } from './postgres-self/postgres-self.infra.module';\nexport { MongodbAtlasInfraProviderModule } from './mongodb-atlas/mongodb-atlas.infra.module';\nexport { MongodbSelfInfraProviderModule } from './mongodb-self/mongodb-self.infra.module';\nexport { MinioSelfInfraProviderModule } from './minio-self/minio-self.infra.module';\nexport { AwsS3InfraProviderModule } from './aws-s3/aws-s3.infra.module';\nexport { ClamavSelfInfraProviderModule } from './clamav-self/clamav-self.infra.module';\nexport * from './immudb-self/immudb-self.infra.module';\n\n/**\n * Canonical `InfraProvider` → `InfraProviderModule` catalog. Caller\n * (CLI, apps-manager) builds a `Map<InfraProvider, InfraProviderModule>`\n * from this constant when threading modules into\n * `materializeInfraSection`.\n *\n * **Why a const array instead of a `Map` literal**: arrays serialize\n * stably under tsc and roll up to a deterministic order. The\n * downstream `Map` is built once at program start; the catalog\n * itself is a value-level fixture.\n *\n * **Coverage** (Slice 5 baseline, 2026-05-10):\n * - `RABBITMQ_SELF`, `REDIS_SELF`, `POSTGRES_SELF`, `MONGODB_SELF`,\n * `MONGODB_ATLAS` — five stateful modules with mint/revoke\n * methods.\n * - `MINIO_SELF`, `AWS_S3` — object storage (shared-bucket model;\n * no per-app credentials). `AWS_S3` declares `unservableReason`\n * (no AWS STS path in the credential broker, #14), so it plans but is\n * not servable.\n * - `CLAMAV_SELF` — stateless infra (no auth, no per-app state;\n * `plan()` only).\n *\n * **NOT covered** (catalog entries without modules):\n * - `POSTGRES_MANAGED`, `POSTGRES_AWS_RDS`, `POSTGRES_GCP_CLOUD_SQL`,\n * `POSTGRES_AZURE_DATABASE`, `POSTGRES_SUPABASE`, `POSTGRES_NEON`,\n * `POSTGRES_RENDER` — managed-Postgres brand catalog entries\n * (Slice 4.B.0). No module yet; trigger = real customer.\n *\n * A declaration resolving to a provider outside\n * {@link collectServableInfraProviders} is REFUSED by `wildo config\n * validate`, `config sync` and `lock check` (#1693) — it no longer falls\n * through to an authored-entry digest.\n */\nexport const INFRA_PROVIDER_MODULES: ReadonlyArray<InfraProviderModule> = [\n RabbitmqSelfInfraProviderModule,\n RedisSelfInfraProviderModule,\n PostgresSelfInfraProviderModule,\n MongodbAtlasInfraProviderModule,\n MongodbSelfInfraProviderModule,\n MinioSelfInfraProviderModule,\n AwsS3InfraProviderModule,\n ClamavSelfInfraProviderModule,\n // #1696: one immudb database and one confined user per application, replacing the operator-credentialed\n // exemption under which every application logged in as the server's sysadmin.\n ImmudbSelfInfraProviderModule,\n];\n\n/**\n * Providers the platform serves WITHOUT a module in {@link INFRA_PROVIDER_MODULES}, because their\n * application credential is the operator's to supply rather than the catalogue's to mint.\n *\n * ## Why this is the one exception, and why it is a list of exemptions rather than of refusals\n *\n * The servable set is DERIVED from the catalogue ({@link collectServableInfraProviders}); a hand-kept\n * list of refused providers would silently admit every provider added later. So the only thing\n * written down by hand is the exception, and it must be argued for here, one entry at a time.\n *\n * EMPTY since #1696, and kept as the named place such an exemption would be argued. `IMMUDB_SELF` was the one entry:\n * the self-hosted audit store had no module, and every application on the server logged in as its sysadmin into\n * one shared database. Its module now mints one database and one confined user per application, which makes it\n * servable on its own — and REFUSED on a platform that holds no immudb admin credential, like every minting kind.\n */\nexport const OPERATOR_CREDENTIALED_INFRA_PROVIDERS: ReadonlySet<InfraProvider> = new Set<InfraProvider>();\n\n/**\n * The providers a `backingServices` declaration may resolve to — every module in the catalogue that\n * does not declare `unservableReason`, plus {@link OPERATOR_CREDENTIALED_INFRA_PROVIDERS}.\n *\n * The one source both lockfile projections (`wildo config sync`, `wildo lock check`) and\n * `wildo config validate` pass to the shared check in `@wildo-ai/platform-config-lib`\n * (`findUnservableBackingServiceDeclarations`), so all three refuse the same declarations (#1693).\n * Derived, so a module entering the catalogue makes its provider declarable the day it lands.\n */\nexport function collectServableInfraProviders(): ReadonlySet<InfraProvider> {\n const servable = new Set<InfraProvider>(OPERATOR_CREDENTIALED_INFRA_PROVIDERS);\n for (const module of INFRA_PROVIDER_MODULES) {\n if (module.unservableReason === undefined) servable.add(module.provider);\n }\n return servable;\n}\n\n/**\n * Every `Wildo_Application_Secrets` JSON path that ANY provider module can mint per runtime\n * principal — the union of the catalog's own static declarations.\n *\n * ## Why this is derived rather than written down\n *\n * The consumer is the secret-DELIVERY path in apps-manager: it strips exactly this set from the\n * application blob before overlaying a principal's own material, so a principal receives a\n * credential only where one was minted FOR IT. A hand-maintained copy at that consumer would be a\n * second source — add a provider that mints a new credential path and delivery keeps shipping the\n * APPLICATION's value for it, silently. That is the defect class this repo has paid for twice: the\n * party that CONSTRAINS is not the party that DECLARES.\n *\n * Derived from `INFRA_PROVIDER_MODULES`, so a new module is covered the day it enters the catalog.\n *\n * Deliberately the union across ALL modules, not the ones a given application selected: a principal\n * must not receive an application-wide credential for a provider it does not use either, and the\n * selected set is not knowable at the delivery call site without threading app config through it.\n * Stripping a path no module minted for this app is harmless — it is absent from the blob anyway.\n */\nexport function collectPerPrincipalSecretBlobPaths(): ReadonlySet<string> {\n const paths = new Set<string>();\n for (const module of INFRA_PROVIDER_MODULES) {\n for (const path of module.perPrincipalSecretBlobPaths) {\n paths.add(path);\n }\n }\n return paths;\n}\n\n/**\n * Build a `Map<InfraProvider, InfraProviderModule>` for the\n * canonical catalog. Callers store the result once at startup and\n * pass it to `materializeInfraSection` (digest derivation) or to\n * orchestrator paths that look up modules by `InfraProvider`.\n */\nexport function buildInfraProviderModuleMap(): ReadonlyMap<InfraProvider, InfraProviderModule> {\n const map = new Map<InfraProvider, InfraProviderModule>();\n for (const m of INFRA_PROVIDER_MODULES) {\n if (map.has(m.provider)) {\n throw new Error(\n `INFRA_PROVIDER_MODULES contains duplicate provider '${m.provider}' — ` +\n `each InfraProvider may have at most one module.`,\n );\n }\n map.set(m.provider, m);\n }\n return map;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minio-self.infra.module.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"minio-self.infra.module.d.ts","sourceRoot":"","sources":["../../../src/minio-self/minio-self.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAEH,OAAO,EAIL,mBAAmB,EAEpB,MAAM,+BAA+B,CAAC;AAIvC,eAAO,MAAM,4BAA4B,EAAE,mBA6C1C,CAAC"}
|