@hsuite/smart-engines-cli 1.4.2 → 1.5.1

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.
@@ -1,61 +1,54 @@
1
1
  /**
2
- * Runtime-env forwarding for `hsuite deploy` / `hsuite redeploy` (issue #1564).
2
+ * Runtime-env forwarding for `hsuite deploy` / `hsuite redeploy`.
3
3
  *
4
- * THE BUG THIS FIXES
5
- * ------------------
6
- * The CLI reads the developer's `.env.local` (`--env`) ONLY for deploy-time auth
7
- * + build-attestation signing. It never forwarded those runtime vars into the
8
- * deployed container the deployed container's env came SOLELY from
9
- * `manifest.backend.env`. So a subscribed app deployed credential-less: the
10
- * smart-app's `BaaSAuthService` found no `XRPL_SEED` and silently booted
11
- * OPEN / in-memory mode (`/baas/status` → `{"mode":"memory","appId":null}`).
4
+ * THE MODEL
5
+ * ---------
6
+ * The CLI reads the developer's `.env.local` (`--env`) and forwards its runtime
7
+ * vars into the deployed customer-env the per-app k8s Secret the deployer
8
+ * mirrors, PQC-encrypted (kyber-aes-v1) at rest. So the deployed app runs with
9
+ * the SAME config the developer runs locally, with no allowlist to maintain.
12
10
  *
13
- * THE FIX
14
- * -------
15
- * On deploy, the runtime-relevant vars from `.env.local` are merged into the
16
- * customer-env the deployer mirrors into the per-app k8s Secret, so the deployed
17
- * app runs with the SAME identity + config it runs with locally. The identity is
18
- * the developer's OWN XRPL wallet (`XRPL_SEED` in `.env.local`, whose address
19
- * holds the subscription NFT) — there is NO separate app / protocol identity.
11
+ * FORWARD-ALL, MINUS A SMALL DENYLIST
12
+ * -----------------------------------
13
+ * EVERY key in `.env.local` is forwarded EXCEPT {@link NON_FORWARDED_KEYS} — so
14
+ * ANY variable the app reads (including ones this CLI has never heard of) "just
15
+ * works" in the deployed container. The denylist withholds only:
20
16
  *
21
- * WHAT COUNTS AS "RUNTIME-RELEVANT"
22
- * ---------------------------------
23
- * The source of truth is the smart-app env schema
24
- * (`apps/showcase/smart-app/src/config/env-validation.ts` in the hsuite-ecosystem
25
- * repo). {@link RUNTIME_ENV_KEYS} mirrors that key set. Anything not in the set —
26
- * purely deploy-time / CLI-only knobs the container never reads
27
- * (`DEPLOYED_APP_ID` book-keeping, `SUBSCRIPTION_NFT_SERIAL`, `VALIDATOR_API_KEY`,
28
- * docker/build flags, etc.) is NOT forwarded.
17
+ * 1. The PLATFORM-RESOLVED connection URLs (`SMART_HOST_URL` / `VALIDATOR_URL`
18
+ * / `GATEWAY_URL`). Locally these point at the public testnet gateway (from
19
+ * `hsuite init`); IN-CLUSTER the deployer's cluster-env injects the INTERNAL
20
+ * service URL plus a TSS-minted `APP_TOKEN`. Forwarding the developer's
21
+ * external URL would OVERRIDE the internal one, and the pod would try to
22
+ * reach the public gateway from inside the cluster (unreachable) → the app
23
+ * silently boots open/in-memory mode. So these are cluster-resolved, never
24
+ * forwarded the SDK consumes them via `BaasClient.fromEnv`.
25
+ * 2. The LOCAL-ONLY safety toggles (`DEV_MODE` / `ALLOW_INSECURE`) — a stale
26
+ * `true` in a developer's `.env.local` must never silently propagate into a
27
+ * live deployment. A deploy that genuinely needs one sets it explicitly via
28
+ * `manifest.backend.env`.
29
29
  *
30
- * The customer-env Secret is PQC-encrypted (kyber-aes-v1) at rest that is the
31
- * containment boundary. No secret is ever written into a committed manifest.
30
+ * The developer's identity secret (`XRPL_SEED`, whose wallet holds the
31
+ * subscription NFT) IS forwarded the app uses it for owner-signed chain ops;
32
+ * the in-cluster BaaS *session* itself comes from the deployer's `APP_TOKEN`, not
33
+ * from a challenge.
32
34
  */
33
35
  import type { EnvMap } from './env';
34
36
  /**
35
- * Runtime env keys forwarded from `.env.local` into the deployed customer-env.
36
- *
37
- * MIRRORS the smart-app `EnvSchema`
38
- * (`apps/showcase/smart-app/src/config/env-validation.ts`). Keep this in lockstep
39
- * with that schema: a key the smart-app reads at runtime but that is absent here
40
- * would not reach the container (the #1564 class of bug), and a key here that the
41
- * smart-app never reads is harmless noise in the Secret.
42
- *
43
- * Deliberately EXCLUDES purely deploy-time / CLI-only vars that the deployed
44
- * container never consumes:
45
- * - `SUBSCRIPTION_NFT_SERIAL` — a `hsuite subscribe` book-keeping value.
46
- * - `VALIDATOR_API_KEY` / `SMART_HOST_API_KEY` — the in-cluster app authenticates
47
- * as its wallet (Web3 challenge-response); a raw API key is a deploy-time /
48
- * local-only convenience, not a container runtime credential, and the deployer
49
- * injects the mediated `SMART_HOST_URL` / `APP_TOKEN` via the cluster-env
50
- * Secret. (Forwarding a raw validator key would also widen the tenant's
51
- * credential surface for no runtime benefit.)
37
+ * Keys withheld from customer-env forwarding. See the file header for the two
38
+ * classes (platform-resolved connection URLs + local-only safety toggles) and
39
+ * WHY forwarding them breaks or endangers a deployment. Everything else in
40
+ * `.env.local` is forwarded verbatim.
52
41
  */
53
- export declare const RUNTIME_ENV_KEYS: readonly string[];
42
+ export declare const NON_FORWARDED_KEYS: ReadonlySet<string>;
54
43
  /**
55
- * Env keys whose presence makes the deployed app boot in cluster (subscribed)
56
- * mode rather than open / in-memory mode. The smart-app's `BaaSAuthService`
57
- * builds its signer from `XRPL_SEED` (`createXrplWeb3Signer(seed)`), so a missing
58
- * `XRPL_SEED` in the container is exactly the #1564 open-mode footgun.
44
+ * Keys whose presence lets the deployed app authenticate as the developer's
45
+ * wallet for owner-signed chain operations. `XRPL_SEED` is forwarded (it is NOT
46
+ * on the denylist); this guard fails a deploy loud rather than silently shipping
47
+ * an app with no owner key, unless `allowOpenMode` opts into a zero-cred fork.
48
+ *
49
+ * (The in-cluster BaaS *session* comes from the deployer's `APP_TOKEN`, so a
50
+ * deployed app reaches cluster mode regardless; this guard is about the owner
51
+ * signing key the developer almost always intends to ship.)
59
52
  */
60
53
  export declare const CLUSTER_MODE_REQUIRED_KEYS: readonly string[];
61
54
  export interface ResolveRuntimeEnvInput {
@@ -64,19 +57,13 @@ export interface ResolveRuntimeEnvInput {
64
57
  /** `manifest.backend.env` — explicit, committed, NON-secret overrides. */
65
58
  manifestEnv?: Record<string, string>;
66
59
  /**
67
- * Opt-in escape hatch for an intentional OPEN-MODE deploy — e.g. a zero-cred
68
- * fork demo the developer wants to run unsubscribed/in-memory.
69
- *
70
- * When true, the developer's `XRPL_SEED` is DELIBERATELY WITHHELD from the
71
- * forwarded container env (so the deployed app boots open/in-memory mode), and
72
- * the fail-loud {@link OpenModeDeployError} is suppressed. The seed still exists
73
- * in `.env.local` for the local deploy-time work (auth + attestation signing) —
74
- * it is just not injected into the running container.
60
+ * Opt-in escape hatch for an intentional zero-cred deploy — e.g. a fork demo
61
+ * the developer wants to run without shipping their `XRPL_SEED`.
75
62
  *
76
- * When false (the default), the developer's runtime creds including
77
- * `XRPL_SEED` are forwarded so the deployed app runs cluster/subscribed mode,
78
- * and a resolved env with no `XRPL_SEED` throws {@link OpenModeDeployError}
79
- * rather than silently shipping open mode.
63
+ * When true, `XRPL_SEED` is DELIBERATELY WITHHELD from the forwarded container
64
+ * env and the fail-loud {@link OpenModeDeployError} is suppressed. The seed
65
+ * still exists in `.env.local` for the local deploy-time work (auth +
66
+ * attestation signing) it is just not injected into the running container.
80
67
  */
81
68
  allowOpenMode?: boolean;
82
69
  /**
@@ -87,12 +74,11 @@ export interface ResolveRuntimeEnvInput {
87
74
  warn?: (message: string) => void;
88
75
  }
89
76
  /**
90
- * A subscribed-but-credential-less deploy was blocked. Thrown by
91
- * {@link resolveRuntimeEnv} when the resolved container env carries no
92
- * `XRPL_SEED` and `allowOpenMode` is not set — so a deploy never SILENTLY ships
93
- * an open-mode app (the #1564 invisible failure). The remedy (populate
94
- * `.env.local` via `hsuite init` + `hsuite subscribe`, or opt in explicitly) is
95
- * on the message.
77
+ * A credential-less deploy was blocked. Thrown by {@link resolveRuntimeEnv} when
78
+ * the resolved container env carries no `XRPL_SEED` and `allowOpenMode` is not
79
+ * set — so a deploy never SILENTLY ships an app with no owner signing key. The
80
+ * remedy (populate `.env.local` via `hsuite init` + `hsuite subscribe`, or opt
81
+ * in explicitly) is on the message.
96
82
  */
97
83
  export declare class OpenModeDeployError extends Error {
98
84
  constructor(missing: readonly string[]);
@@ -100,24 +86,21 @@ export declare class OpenModeDeployError extends Error {
100
86
  /**
101
87
  * Resolve the runtime env the deployed container should receive.
102
88
  *
103
- * Merge + precedence (issue #1564, criterion "define + document the precedence"):
104
- * 1. Start from the runtime-relevant vars in `.env.local` (secrets like
105
- * `XRPL_SEED` + app config) {@link RUNTIME_ENV_KEYS} filtered.
89
+ * Merge + precedence:
90
+ * 1. Forward EVERY var from `.env.local` EXCEPT {@link NON_FORWARDED_KEYS}
91
+ * (platform-resolved URLs + local-only toggles). Empty values are dropped.
106
92
  * 2. Overlay `manifest.backend.env` LAST, so an explicitly-set manifest key
107
93
  * WINS. The manifest is the committed, explicit override surface for
108
- * NON-secret config (ports, feature flags, Discord/AI endpoints); secrets
109
- * are supplied automatically by `.env.local` and never need to be
110
- * hand-written into a committed manifest.
94
+ * NON-secret config (ports, feature flags); secrets flow from `.env.local`
95
+ * automatically and never need to live in a committed manifest.
111
96
  *
112
97
  * Rationale for manifest-wins: a value a developer deliberately typed into the
113
98
  * manifest is an intentional per-deploy override and must not be silently shadowed
114
- * by whatever happens to sit in their local `.env.local`. Secrets, by contrast,
115
- * are NOT expected in the manifest — they flow from `.env.local` — so the two
116
- * surfaces do not normally collide on secret keys.
99
+ * by whatever happens to sit in their local `.env.local`.
117
100
  *
118
- * Fail-loud (criterion "a subscribed-but-credential-less deploy fails loudly"):
119
- * if the merged result has no `XRPL_SEED` and `allowOpenMode` is not set, throws
120
- * {@link OpenModeDeployError} rather than shipping a silent open-mode app.
101
+ * Fail-loud: if the merged result has no `XRPL_SEED` and `allowOpenMode` is not
102
+ * set, throws {@link OpenModeDeployError} rather than shipping a silent
103
+ * credential-less app.
121
104
  *
122
105
  * @throws {OpenModeDeployError} when the resolved env is credential-less and
123
106
  * `allowOpenMode` is not set.
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../../src/_lib/runtime-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EA4C7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAAkB,CAAC;AAE3E,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAWD;;;;;;;GAOG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,SAAS,MAAM,EAAE;CAYvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiDxB"}
1
+ {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../../src/_lib/runtime-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CASjD,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAAkB,CAAC;AAE3E,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAWD;;;;;;GAMG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,SAAS,MAAM,EAAE;CAWvC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6CxB"}
@@ -1,76 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpenModeDeployError = exports.CLUSTER_MODE_REQUIRED_KEYS = exports.RUNTIME_ENV_KEYS = void 0;
3
+ exports.OpenModeDeployError = exports.CLUSTER_MODE_REQUIRED_KEYS = exports.NON_FORWARDED_KEYS = void 0;
4
4
  exports.resolveRuntimeEnv = resolveRuntimeEnv;
5
5
  /**
6
- * Runtime env keys forwarded from `.env.local` into the deployed customer-env.
7
- *
8
- * MIRRORS the smart-app `EnvSchema`
9
- * (`apps/showcase/smart-app/src/config/env-validation.ts`). Keep this in lockstep
10
- * with that schema: a key the smart-app reads at runtime but that is absent here
11
- * would not reach the container (the #1564 class of bug), and a key here that the
12
- * smart-app never reads is harmless noise in the Secret.
13
- *
14
- * Deliberately EXCLUDES purely deploy-time / CLI-only vars that the deployed
15
- * container never consumes:
16
- * - `SUBSCRIPTION_NFT_SERIAL` — a `hsuite subscribe` book-keeping value.
17
- * - `VALIDATOR_API_KEY` / `SMART_HOST_API_KEY` — the in-cluster app authenticates
18
- * as its wallet (Web3 challenge-response); a raw API key is a deploy-time /
19
- * local-only convenience, not a container runtime credential, and the deployer
20
- * injects the mediated `SMART_HOST_URL` / `APP_TOKEN` via the cluster-env
21
- * Secret. (Forwarding a raw validator key would also widen the tenant's
22
- * credential surface for no runtime benefit.)
6
+ * Keys withheld from customer-env forwarding. See the file header for the two
7
+ * classes (platform-resolved connection URLs + local-only safety toggles) and
8
+ * WHY forwarding them breaks or endangers a deployment. Everything else in
9
+ * `.env.local` is forwarded verbatim.
23
10
  */
24
- exports.RUNTIME_ENV_KEYS = [
25
- // Application
26
- 'NODE_ENV',
27
- 'PORT',
28
- 'APP_ID',
29
- 'APP_NAME',
30
- 'APP_DESCRIPTION',
31
- // CORS
32
- 'CORS_ORIGINS',
33
- // XRPL — the developer's own wallet identity (holds the subscription NFT).
34
- 'XRPL_NETWORK',
35
- 'XRPL_ADDRESS',
36
- 'XRPL_SEED',
37
- 'XRPL_PUBLIC_KEY',
38
- // Subscription binding
39
- 'SUBSCRIPTION_APP_ID',
40
- 'DEPLOYED_APP_ID',
41
- // Cluster connection (the deployer also injects mediated in-cluster URLs via
42
- // the cluster-env Secret; a developer override still forwards here).
43
- 'VALIDATOR_URL',
11
+ exports.NON_FORWARDED_KEYS = new Set([
12
+ // Platform-resolved connection URLs — the deployer injects the INTERNAL ones
13
+ // (+ APP_TOKEN) via cluster-env; the developer's external values must not win.
44
14
  'SMART_HOST_URL',
45
- // Agent AI / templates
46
- 'AI_PROVIDER',
47
- 'AI_MODEL',
48
- 'ANTHROPIC_API_KEY',
49
- 'ANTHROPIC_MODEL',
50
- 'OPENAI_API_KEY',
51
- 'GEMINI_API_KEY',
52
- 'AI_BASE_URL',
53
- 'AI_API_KEY',
54
- 'AI_MAX_TOKENS',
55
- 'DISCORD_WEBHOOK_URL',
56
- 'WEATHER_PAYOUT_ADDRESS',
57
- // Misc runtime
58
- 'REQUEST_TIMEOUT',
59
- 'DEBUG',
60
- // Subscription behaviour
61
- 'AUTO_SUBSCRIBE',
62
- 'SUBSCRIPTION_TIER',
63
- // NOTE: `DEV_MODE` / `ALLOW_INSECURE` are deliberately NOT forwarded — they are
64
- // local-dev safety toggles, and a stale `DEV_MODE=true` / `ALLOW_INSECURE=true`
65
- // sitting in a developer's `.env.local` must not silently propagate into a live
66
- // deployment. A deploy that genuinely needs one can set it explicitly (and
67
- // intentionally) via `manifest.backend.env`.
68
- ];
15
+ 'VALIDATOR_URL',
16
+ 'GATEWAY_URL',
17
+ // Local-only safety toggles — never propagate into a live deploy.
18
+ 'DEV_MODE',
19
+ 'ALLOW_INSECURE',
20
+ ]);
69
21
  /**
70
- * Env keys whose presence makes the deployed app boot in cluster (subscribed)
71
- * mode rather than open / in-memory mode. The smart-app's `BaaSAuthService`
72
- * builds its signer from `XRPL_SEED` (`createXrplWeb3Signer(seed)`), so a missing
73
- * `XRPL_SEED` in the container is exactly the #1564 open-mode footgun.
22
+ * Keys whose presence lets the deployed app authenticate as the developer's
23
+ * wallet for owner-signed chain operations. `XRPL_SEED` is forwarded (it is NOT
24
+ * on the denylist); this guard fails a deploy loud rather than silently shipping
25
+ * an app with no owner key, unless `allowOpenMode` opts into a zero-cred fork.
26
+ *
27
+ * (The in-cluster BaaS *session* comes from the deployer's `APP_TOKEN`, so a
28
+ * deployed app reaches cluster mode regardless; this guard is about the owner
29
+ * signing key the developer almost always intends to ship.)
74
30
  */
75
31
  exports.CLUSTER_MODE_REQUIRED_KEYS = ['XRPL_SEED'];
76
32
  /**
@@ -82,20 +38,18 @@ function looksLikeSecretKey(key) {
82
38
  return /(_SEED|_PRIVATE_KEY|_API_KEY|_SECRET|_TOKEN|_PASSWORD|_MNEMONIC)$/.test(key);
83
39
  }
84
40
  /**
85
- * A subscribed-but-credential-less deploy was blocked. Thrown by
86
- * {@link resolveRuntimeEnv} when the resolved container env carries no
87
- * `XRPL_SEED` and `allowOpenMode` is not set — so a deploy never SILENTLY ships
88
- * an open-mode app (the #1564 invisible failure). The remedy (populate
89
- * `.env.local` via `hsuite init` + `hsuite subscribe`, or opt in explicitly) is
90
- * on the message.
41
+ * A credential-less deploy was blocked. Thrown by {@link resolveRuntimeEnv} when
42
+ * the resolved container env carries no `XRPL_SEED` and `allowOpenMode` is not
43
+ * set — so a deploy never SILENTLY ships an app with no owner signing key. The
44
+ * remedy (populate `.env.local` via `hsuite init` + `hsuite subscribe`, or opt
45
+ * in explicitly) is on the message.
91
46
  */
92
47
  class OpenModeDeployError extends Error {
93
48
  constructor(missing) {
94
- super(`Refusing to deploy an OPEN-MODE (credential-less) app: the resolved ` +
95
- `container env is missing ${missing.join(', ')}. The deployed smart-app ` +
96
- `authenticates as YOUR XRPL wallet (the XRPL_SEED in --env), which holds ` +
97
- `the subscription NFT; without it the app boots in-memory/unsubscribed ` +
98
- `and BaaS routes 503. Run \`hsuite init\` + \`hsuite subscribe\` so ` +
49
+ super(`Refusing to deploy a credential-less app: the resolved container env is ` +
50
+ `missing ${missing.join(', ')}. The deployed smart-app signs owner ops ` +
51
+ `with YOUR XRPL wallet (the XRPL_SEED in --env), which holds the ` +
52
+ `subscription NFT. Run \`hsuite init\` + \`hsuite subscribe\` so ` +
99
53
  `.env.local carries the creds, or pass --allow-open-mode for an ` +
100
54
  `intentional zero-cred fork deploy.`);
101
55
  this.name = 'OpenModeDeployError';
@@ -105,24 +59,21 @@ exports.OpenModeDeployError = OpenModeDeployError;
105
59
  /**
106
60
  * Resolve the runtime env the deployed container should receive.
107
61
  *
108
- * Merge + precedence (issue #1564, criterion "define + document the precedence"):
109
- * 1. Start from the runtime-relevant vars in `.env.local` (secrets like
110
- * `XRPL_SEED` + app config) {@link RUNTIME_ENV_KEYS} filtered.
62
+ * Merge + precedence:
63
+ * 1. Forward EVERY var from `.env.local` EXCEPT {@link NON_FORWARDED_KEYS}
64
+ * (platform-resolved URLs + local-only toggles). Empty values are dropped.
111
65
  * 2. Overlay `manifest.backend.env` LAST, so an explicitly-set manifest key
112
66
  * WINS. The manifest is the committed, explicit override surface for
113
- * NON-secret config (ports, feature flags, Discord/AI endpoints); secrets
114
- * are supplied automatically by `.env.local` and never need to be
115
- * hand-written into a committed manifest.
67
+ * NON-secret config (ports, feature flags); secrets flow from `.env.local`
68
+ * automatically and never need to live in a committed manifest.
116
69
  *
117
70
  * Rationale for manifest-wins: a value a developer deliberately typed into the
118
71
  * manifest is an intentional per-deploy override and must not be silently shadowed
119
- * by whatever happens to sit in their local `.env.local`. Secrets, by contrast,
120
- * are NOT expected in the manifest — they flow from `.env.local` — so the two
121
- * surfaces do not normally collide on secret keys.
72
+ * by whatever happens to sit in their local `.env.local`.
122
73
  *
123
- * Fail-loud (criterion "a subscribed-but-credential-less deploy fails loudly"):
124
- * if the merged result has no `XRPL_SEED` and `allowOpenMode` is not set, throws
125
- * {@link OpenModeDeployError} rather than shipping a silent open-mode app.
74
+ * Fail-loud: if the merged result has no `XRPL_SEED` and `allowOpenMode` is not
75
+ * set, throws {@link OpenModeDeployError} rather than shipping a silent
76
+ * credential-less app.
126
77
  *
127
78
  * @throws {OpenModeDeployError} when the resolved env is credential-less and
128
79
  * `allowOpenMode` is not set.
@@ -130,26 +81,23 @@ exports.OpenModeDeployError = OpenModeDeployError;
130
81
  function resolveRuntimeEnv(input) {
131
82
  const { env, manifestEnv = {}, allowOpenMode = false, warn } = input;
132
83
  const merged = {};
133
- // 1. Runtime-relevant vars from .env.local (only keys the smart-app reads).
134
- // Under an explicit open-mode deploy, the cluster-mode secrets (XRPL_SEED)
135
- // are DELIBERATELY WITHHELD from the container so it boots open/in-memory —
136
- // the seed still exists locally for attestation, it is just not injected.
137
- const withhold = allowOpenMode ? new Set(exports.CLUSTER_MODE_REQUIRED_KEYS) : new Set();
138
- for (const key of exports.RUNTIME_ENV_KEYS) {
84
+ // 1. Forward every .env.local var except the denylist. Under an explicit
85
+ // open-mode deploy, the owner key (XRPL_SEED) is ALSO withheld so the
86
+ // deployed app ships zero-cred the seed still exists locally for
87
+ // attestation, it is just not injected into the container.
88
+ const withhold = allowOpenMode
89
+ ? new Set([...exports.NON_FORWARDED_KEYS, ...exports.CLUSTER_MODE_REQUIRED_KEYS])
90
+ : exports.NON_FORWARDED_KEYS;
91
+ for (const [key, val] of env) {
139
92
  if (withhold.has(key))
140
93
  continue;
141
- const val = env.get(key);
142
94
  if (val !== undefined && val !== '') {
143
95
  merged[key] = val;
144
96
  }
145
97
  }
146
98
  // 2. manifest.backend.env wins (explicit, committed, non-secret overrides).
147
- // NOTE: manifest keys are NOT bounded by RUNTIME_ENV_KEYS the manifest is
148
- // the explicit, developer-authored, committed override surface, so a
149
- // manifest-only key (e.g. a custom feature flag) passes through verbatim.
150
- // The allowlist governs only the `.env.local` source (step 1). An empty
151
- // manifest value is forwarded as-is (an explicit author choice), unlike an
152
- // empty `.env.local` value which is dropped in step 1.
99
+ // An empty manifest value is forwarded as-is (an explicit author choice),
100
+ // unlike an empty `.env.local` value which is dropped in step 1.
153
101
  for (const [key, val] of Object.entries(manifestEnv)) {
154
102
  if (warn && looksLikeSecretKey(key)) {
155
103
  warn(`manifest.backend.env sets a secret-shaped key "${key}" — the manifest is ` +
@@ -159,8 +107,7 @@ function resolveRuntimeEnv(input) {
159
107
  }
160
108
  merged[key] = val;
161
109
  }
162
- // 3. Fail loud on a credential-less (open-mode) deploy unless opted in — so a
163
- // subscribed app never SILENTLY ships open mode (the #1564 invisible bug).
110
+ // 3. Fail loud on a credential-less deploy unless opted in.
164
111
  if (!allowOpenMode) {
165
112
  const missing = exports.CLUSTER_MODE_REQUIRED_KEYS.filter((k) => merged[k] === undefined || merged[k] === '');
166
113
  if (missing.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-env.js","sourceRoot":"","sources":["../../src/_lib/runtime-env.ts"],"names":[],"mappings":";;;AAiMA,8CAmDC;AAlND;;;;;;;;;;;;;;;;;;GAkBG;AACU,QAAA,gBAAgB,GAAsB;IACjD,cAAc;IACd,UAAU;IACV,MAAM;IACN,QAAQ;IACR,UAAU;IACV,iBAAiB;IACjB,OAAO;IACP,cAAc;IACd,2EAA2E;IAC3E,cAAc;IACd,cAAc;IACd,WAAW;IACX,iBAAiB;IACjB,uBAAuB;IACvB,qBAAqB;IACrB,iBAAiB;IACjB,6EAA6E;IAC7E,qEAAqE;IACrE,eAAe;IACf,gBAAgB;IAChB,uBAAuB;IACvB,aAAa;IACb,UAAU;IACV,mBAAmB;IACnB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,YAAY;IACZ,eAAe;IACf,qBAAqB;IACrB,wBAAwB;IACxB,eAAe;IACf,iBAAiB;IACjB,OAAO;IACP,yBAAyB;IACzB,gBAAgB;IAChB,mBAAmB;IACnB,gFAAgF;IAChF,gFAAgF;IAChF,gFAAgF;IAChF,2EAA2E;IAC3E,6CAA6C;CAC9C,CAAC;AAEF;;;;;GAKG;AACU,QAAA,0BAA0B,GAAsB,CAAC,WAAW,CAAC,CAAC;AA+B3E;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO,mEAAmE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;;GAOG;AACH,MAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAA0B;QACpC,KAAK,CACH,sEAAsE;YACpE,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,2BAA2B;YACzE,0EAA0E;YAC1E,wEAAwE;YACxE,qEAAqE;YACrE,iEAAiE;YACjE,oCAAoC,CACvC,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAbD,kDAaC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAgB,iBAAiB,CAC/B,KAA6B;IAE7B,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,EAAE,EAAE,aAAa,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAErE,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,4EAA4E;IAC5E,8EAA8E;IAC9E,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,kCAA0B,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAC;IACzF,KAAK,MAAM,GAAG,IAAI,wBAAgB,EAAE,CAAC;QACnC,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAChC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACpB,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,+EAA+E;IAC/E,wEAAwE;IACxE,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,0DAA0D;IAC1D,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CACF,kDAAkD,GAAG,sBAAsB;gBACzE,kEAAkE;gBAClE,kEAAkE;gBAClE,mCAAmC,CACtC,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,8EAA8E;IAC9E,8EAA8E;IAC9E,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,kCAA0B,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CACnD,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"runtime-env.js","sourceRoot":"","sources":["../../src/_lib/runtime-env.ts"],"names":[],"mappings":";;;AA4IA,8CA+CC;AAvJD;;;;;GAKG;AACU,QAAA,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IAC7D,6EAA6E;IAC7E,+EAA+E;IAC/E,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,kEAAkE;IAClE,UAAU;IACV,gBAAgB;CACjB,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACU,QAAA,0BAA0B,GAAsB,CAAC,WAAW,CAAC,CAAC;AAyB3E;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO,mEAAmE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;GAMG;AACH,MAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAA0B;QACpC,KAAK,CACH,0EAA0E;YACxE,WAAW,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,2CAA2C;YACxE,kEAAkE;YAClE,kEAAkE;YAClE,iEAAiE;YACjE,oCAAoC,CACvC,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAZD,kDAYC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,iBAAiB,CAC/B,KAA6B;IAE7B,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,EAAE,EAAE,aAAa,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAErE,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,yEAAyE;IACzE,yEAAyE;IACzE,sEAAsE;IACtE,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,aAAa;QAC5B,CAAC,CAAC,IAAI,GAAG,CAAS,CAAC,GAAG,0BAAkB,EAAE,GAAG,kCAA0B,CAAC,CAAC;QACzE,CAAC,CAAC,0BAAkB,CAAC;IACvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAChC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACpB,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,6EAA6E;IAC7E,oEAAoE;IACpE,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CACF,kDAAkD,GAAG,sBAAsB;gBACzE,kEAAkE;gBAClE,kEAAkE;gBAClE,mCAAmC,CACtC,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,kCAA0B,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CACnD,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hsuite/smart-engines-cli",
3
- "version": "1.4.2",
3
+ "version": "1.5.1",
4
4
  "description": "HSuite CLI for smart-app deployment and management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  "dev": "ts-node src/index.ts",
16
16
  "start": "node dist/index.js",
17
17
  "test": "jest",
18
- "prepublishOnly": "npm run clean && npm run build"
18
+ "prepublishOnly": "npm run clean && turbo run build --filter=@hsuite/smart-engines-cli..."
19
19
  },
20
20
  "dependencies": {
21
21
  "@hsuite/smart-engines-sdk": "*",