@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.
Files changed (48) hide show
  1. package/dist/esm/aws-s3/aws-s3.infra.module.d.ts +5 -3
  2. package/dist/esm/aws-s3/aws-s3.infra.module.d.ts.map +1 -1
  3. package/dist/esm/aws-s3/aws-s3.infra.module.js +12 -3
  4. package/dist/esm/aws-s3/aws-s3.infra.module.js.map +1 -1
  5. package/dist/esm/clamav-self/clamav-self.infra.module.d.ts.map +1 -1
  6. package/dist/esm/immudb-self/immudb-self.infra.module.d.ts +75 -0
  7. package/dist/esm/immudb-self/immudb-self.infra.module.d.ts.map +1 -0
  8. package/dist/esm/immudb-self/immudb-self.infra.module.js +186 -0
  9. package/dist/esm/immudb-self/immudb-self.infra.module.js.map +1 -0
  10. package/dist/esm/index.d.ts +35 -5
  11. package/dist/esm/index.d.ts.map +1 -1
  12. package/dist/esm/index.js +45 -4
  13. package/dist/esm/index.js.map +1 -1
  14. package/dist/esm/minio-self/minio-self.infra.module.d.ts.map +1 -1
  15. package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.d.ts +38 -16
  16. package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.d.ts.map +1 -1
  17. package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.js +174 -39
  18. package/dist/esm/mongodb-atlas/mongodb-atlas.infra.module.js.map +1 -1
  19. package/dist/esm/mongodb-self/mongodb-self.infra.module.d.ts +25 -9
  20. package/dist/esm/mongodb-self/mongodb-self.infra.module.d.ts.map +1 -1
  21. package/dist/esm/mongodb-self/mongodb-self.infra.module.js +29 -18
  22. package/dist/esm/mongodb-self/mongodb-self.infra.module.js.map +1 -1
  23. package/dist/esm/postgres-self/postgres-self.infra.module.d.ts +5 -2
  24. package/dist/esm/postgres-self/postgres-self.infra.module.d.ts.map +1 -1
  25. package/dist/esm/postgres-self/postgres-self.infra.module.js +25 -11
  26. package/dist/esm/postgres-self/postgres-self.infra.module.js.map +1 -1
  27. package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.d.ts +4 -2
  28. package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.d.ts.map +1 -1
  29. package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.js +7 -4
  30. package/dist/esm/rabbitmq-self/rabbitmq-self.infra.module.js.map +1 -1
  31. package/dist/esm/redis-self/redis-self.infra.module.d.ts +4 -2
  32. package/dist/esm/redis-self/redis-self.infra.module.d.ts.map +1 -1
  33. package/dist/esm/redis-self/redis-self.infra.module.js +7 -4
  34. package/dist/esm/redis-self/redis-self.infra.module.js.map +1 -1
  35. package/dist/tsconfig.build.tsbuildinfo +1 -1
  36. package/package.json +2 -2
  37. package/src/__tests__/servable-infra-providers.test.ts +137 -0
  38. package/src/aws-s3/aws-s3.infra.module.ts +14 -3
  39. package/src/immudb-self/__tests__/immudb-self.infra.module.test.ts +117 -0
  40. package/src/immudb-self/immudb-self.infra.module.ts +221 -0
  41. package/src/index.ts +47 -5
  42. package/src/mongodb-atlas/__tests__/mongodb-atlas.infra.module.test.ts +105 -0
  43. package/src/mongodb-atlas/mongodb-atlas.infra.module.ts +198 -39
  44. package/src/mongodb-self/mongodb-self.infra.module.ts +29 -18
  45. package/src/postgres-self/__tests__/postgres-self.infra.module.test.ts +24 -7
  46. package/src/postgres-self/postgres-self.infra.module.ts +26 -12
  47. package/src/rabbitmq-self/rabbitmq-self.infra.module.ts +7 -4
  48. 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. But it IS reachable — `s3: { source:
28
- * MANAGED }` or `provider: 'aws'` resolves here — so **do not select
29
- * `AWS_S3` until the AWS STS path exists.** Tracked in
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":["../../../../src/aws-s3/aws-s3.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAIL,mBAAmB,EAEpB,MAAM,+BAA+B,CAAC;AAEvC,eAAO,MAAM,wBAAwB,EAAE,mBAkDtC,CAAC"}
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. But it IS reachable — `s3: { source:
28
- * MANAGED }` or `provider: 'aws'` resolves here — so **do not select
29
- * `AWS_S3` until the AWS STS path exists.** Tracked in
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":["../../../../src/aws-s3/aws-s3.infra.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;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,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. But it IS reachable — `s3: { source:\n * MANAGED }` or `provider: 'aws'` resolves here — so **do not select\n * `AWS_S3` until the AWS STS path 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 * 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
+ {"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":["../../../../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"}
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"]}
@@ -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 type { InfraProvider, InfraProviderModule } from '@wildo-ai/platform-config-lib';
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
- * `materializeInfraSection` falls back to the authored-entry digest
55
- * when a selected `InfraProvider` is not in the map (preserves the
56
- * Slice 2.5b behavior for uncovered providers).
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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAYxF,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,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC,mBAAmB,CASrE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,CAAC,CAQxE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,WAAW,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAY7F"}
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
- * `materializeInfraSection` falls back to the authored-entry digest
63
- * when a selected `InfraProvider` is not in the map (preserves the
64
- * Slice 2.5b behavior for uncovered providers).
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.
@@ -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":["../../../../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"}
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"}