@getstrata/bootstrap 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/dist/entries/context.js +2 -1
- package/dist/entries/dependencies.js +2 -1
- package/dist/entries/providers.js +2 -1
- package/dist/entries/secretsGuard.js +10 -16
- package/dist/index.js +14 -19
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @getstrata/bootstrap changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.4
|
|
4
|
+
|
|
5
|
+
- `assertProductionSecrets()` uses `isProductionEnv()`, so `NODE_ENV=production`, `APP_ENV=Production`, and `APP_ENV=staging` cannot skip the guard.
|
|
6
|
+
- Feature flags parse with `envFlagEnabled()` (`=== "true"` only).
|
|
7
|
+
|
|
8
|
+
## 1.0.3
|
|
9
|
+
|
|
10
|
+
- Lockstep with `create-strata` 1.0.3. No runtime changes.
|
|
11
|
+
|
|
3
12
|
## 1.0.2
|
|
4
13
|
|
|
5
14
|
- Lockstep with `create-strata` 1.0.2. No runtime changes.
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ bun add @getstrata/bootstrap @getstrata/core
|
|
|
20
20
|
import { coreProviders, createAppContext, createHttpKernel } from "@getstrata/bootstrap";
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
`createAppContext()` does not call `assertProductionSecrets`. Call that yourself when `APP_ENV
|
|
23
|
+
`createAppContext()` does not call `assertProductionSecrets`. Call that yourself when `isProductionEnv()` is true (`APP_ENV` or `NODE_ENV` production, `APP_ENV=staging`, or an unrecognized `APP_ENV`); it is feature-gated, so an HTML app with API tokens off is not asked for token secrets. It rejects empty secrets, short `SESSION_SECRET` values, wildcard `CORS_ALLOWED_ORIGINS`, `AUTH_DEV_HEADERS` other than `false`, `FEATURE_PUBLIC_READS=true`, and any secret still holding a generated `change-me` placeholder.
|
|
24
24
|
|
|
25
25
|
Build routes with `buildWebModuleRoutes` and `buildModuleRoutes`.
|
|
26
26
|
|
package/dist/entries/context.js
CHANGED
|
@@ -105,8 +105,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
|
|
|
105
105
|
import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
|
|
106
106
|
|
|
107
107
|
// ../../src/config/auth.ts
|
|
108
|
+
import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
|
|
108
109
|
var authConfig = {
|
|
109
|
-
allowDevHeaders: process.env.AUTH_DEV_HEADERS
|
|
110
|
+
allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
|
|
110
111
|
tokenDefaultAbilities: ["*"]
|
|
111
112
|
};
|
|
112
113
|
|
|
@@ -105,8 +105,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
|
|
|
105
105
|
import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
|
|
106
106
|
|
|
107
107
|
// ../../src/config/auth.ts
|
|
108
|
+
import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
|
|
108
109
|
var authConfig = {
|
|
109
|
-
allowDevHeaders: process.env.AUTH_DEV_HEADERS
|
|
110
|
+
allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
|
|
110
111
|
tokenDefaultAbilities: ["*"]
|
|
111
112
|
};
|
|
112
113
|
|
|
@@ -11,8 +11,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
|
|
|
11
11
|
import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
|
|
12
12
|
|
|
13
13
|
// ../../src/config/auth.ts
|
|
14
|
+
import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
|
|
14
15
|
var authConfig = {
|
|
15
|
-
allowDevHeaders: process.env.AUTH_DEV_HEADERS
|
|
16
|
+
allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
|
|
16
17
|
tokenDefaultAbilities: ["*"]
|
|
17
18
|
};
|
|
18
19
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/bootstrap/secretsGuard.ts
|
|
3
|
+
import { envFlagEnabled, isProductionEnv } from "@getstrata/core/runtime/appEnv";
|
|
3
4
|
import { isViewsMode, parseFrontendMode } from "@getstrata/core/runtime/frontendMode";
|
|
4
5
|
var PUBLISHED_TEST_ADMIN_API_TOKEN = "strata-admin-test-token";
|
|
5
6
|
var PUBLISHED_TEST_MEMBER_API_TOKEN = "strata-member-test-token";
|
|
@@ -29,23 +30,17 @@ function assertNoPlaceholderSecrets(env) {
|
|
|
29
30
|
throw new Error(`Production startup blocked: replace the generated placeholder values for ${unrotated.join(", ")}.`);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
function isEnabled(value, defaultEnabled) {
|
|
33
|
-
if (value === undefined) {
|
|
34
|
-
return defaultEnabled;
|
|
35
|
-
}
|
|
36
|
-
return defaultEnabled ? value !== "false" : value === "true";
|
|
37
|
-
}
|
|
38
33
|
function isTokenAuthEnabled(env) {
|
|
39
|
-
return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || env.FEATURE_API_TOKENS
|
|
34
|
+
return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || envFlagEnabled(env.FEATURE_API_TOKENS);
|
|
40
35
|
}
|
|
41
36
|
function isOAuthEnabled(env) {
|
|
42
|
-
return
|
|
37
|
+
return envFlagEnabled(env.FEATURE_OAUTH) || envFlagEnabled(env.FEATURE_SAML) || Boolean(env.GITHUB_CLIENT_ID?.trim()) || Boolean(env.OIDC_ISSUER?.trim()) || Boolean(env.SAML_LOGIN_URL?.trim());
|
|
43
38
|
}
|
|
44
39
|
function isCorsConfigured(env) {
|
|
45
40
|
return env.CORS_ALLOWED_ORIGINS !== undefined;
|
|
46
41
|
}
|
|
47
42
|
function assertAuthDevHeadersDisabled(env) {
|
|
48
|
-
if (
|
|
43
|
+
if (env.AUTH_DEV_HEADERS !== "false") {
|
|
49
44
|
throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
|
|
50
45
|
}
|
|
51
46
|
}
|
|
@@ -76,16 +71,16 @@ function assertTokenAuthProductionSecrets(env) {
|
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
function assertFeatureProductionSecrets(env) {
|
|
79
|
-
if (
|
|
74
|
+
if (envFlagEnabled(env.FEATURE_SCIM)) {
|
|
80
75
|
const scimToken = env.SCIM_BEARER_TOKEN ?? PUBLISHED_TEST_SCIM_BEARER_TOKEN;
|
|
81
76
|
if (PUBLISHED_TEST_SCIM_TOKENS.has(scimToken) || !env.SCIM_BEARER_TOKEN?.trim()) {
|
|
82
77
|
throw new Error("Production startup blocked: rotate SCIM_BEARER_TOKEN away from published test defaults.");
|
|
83
78
|
}
|
|
84
79
|
}
|
|
85
|
-
if (
|
|
80
|
+
if (envFlagEnabled(env.FEATURE_FIELD_ENCRYPTION) && !env.KMS_ENCRYPTION_KEY?.trim()) {
|
|
86
81
|
throw new Error("Production startup blocked: set KMS_ENCRYPTION_KEY when field encryption is enabled.");
|
|
87
82
|
}
|
|
88
|
-
if (
|
|
83
|
+
if (envFlagEnabled(env.FEATURE_BILLING) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
|
|
89
84
|
throw new Error("Production startup blocked: set STRIPE_WEBHOOK_SECRET when billing webhooks are enabled.");
|
|
90
85
|
}
|
|
91
86
|
if (isOAuthEnabled(env) && !env.OAUTH_STATE_SECRET?.trim()) {
|
|
@@ -97,10 +92,10 @@ function assertFeatureProductionSecrets(env) {
|
|
|
97
92
|
throw new Error("Production startup blocked: set explicit CORS_ALLOWED_ORIGINS instead of wildcard.");
|
|
98
93
|
}
|
|
99
94
|
}
|
|
100
|
-
if (
|
|
95
|
+
if (envFlagEnabled(env.FEATURE_PUBLIC_READS)) {
|
|
101
96
|
throw new Error("Production startup blocked: set FEATURE_PUBLIC_READS=false for authenticated-only reads.");
|
|
102
97
|
}
|
|
103
|
-
if (!env.SIEM_EXPORT_URL?.trim() &&
|
|
98
|
+
if (!env.SIEM_EXPORT_URL?.trim() && envFlagEnabled(env.FEATURE_SIEM_EXPORT)) {
|
|
104
99
|
console.warn("[secrets] SIEM_EXPORT_URL is not configured; audit logs remain database-only.");
|
|
105
100
|
}
|
|
106
101
|
}
|
|
@@ -121,8 +116,7 @@ function assertPublicAppUrl(env) {
|
|
|
121
116
|
}
|
|
122
117
|
}
|
|
123
118
|
function assertProductionSecrets(env = process.env) {
|
|
124
|
-
|
|
125
|
-
if (appEnv !== "production") {
|
|
119
|
+
if (!isProductionEnv(env)) {
|
|
126
120
|
return;
|
|
127
121
|
}
|
|
128
122
|
assertNoPlaceholderSecrets(env);
|
package/dist/index.js
CHANGED
|
@@ -538,8 +538,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
|
|
|
538
538
|
import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
|
|
539
539
|
|
|
540
540
|
// ../../src/config/auth.ts
|
|
541
|
+
import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
|
|
541
542
|
var authConfig = {
|
|
542
|
-
allowDevHeaders: process.env.AUTH_DEV_HEADERS
|
|
543
|
+
allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
|
|
543
544
|
tokenDefaultAbilities: ["*"]
|
|
544
545
|
};
|
|
545
546
|
|
|
@@ -1139,6 +1140,7 @@ import {
|
|
|
1139
1140
|
// ../../src/bootstrap/membershipService.ts
|
|
1140
1141
|
import { resolveMembershipService } from "@getstrata/core/auth/membershipService";
|
|
1141
1142
|
// ../../src/bootstrap/secretsGuard.ts
|
|
1143
|
+
import { envFlagEnabled as envFlagEnabled2, isProductionEnv } from "@getstrata/core/runtime/appEnv";
|
|
1142
1144
|
import { isViewsMode, parseFrontendMode } from "@getstrata/core/runtime/frontendMode";
|
|
1143
1145
|
var PUBLISHED_TEST_ADMIN_API_TOKEN = "strata-admin-test-token";
|
|
1144
1146
|
var PUBLISHED_TEST_MEMBER_API_TOKEN = "strata-member-test-token";
|
|
@@ -1168,23 +1170,17 @@ function assertNoPlaceholderSecrets(env) {
|
|
|
1168
1170
|
throw new Error(`Production startup blocked: replace the generated placeholder values for ${unrotated.join(", ")}.`);
|
|
1169
1171
|
}
|
|
1170
1172
|
}
|
|
1171
|
-
function isEnabled(value, defaultEnabled) {
|
|
1172
|
-
if (value === undefined) {
|
|
1173
|
-
return defaultEnabled;
|
|
1174
|
-
}
|
|
1175
|
-
return defaultEnabled ? value !== "false" : value === "true";
|
|
1176
|
-
}
|
|
1177
1173
|
function isTokenAuthEnabled(env) {
|
|
1178
|
-
return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || env.FEATURE_API_TOKENS
|
|
1174
|
+
return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || envFlagEnabled2(env.FEATURE_API_TOKENS);
|
|
1179
1175
|
}
|
|
1180
1176
|
function isOAuthEnabled(env) {
|
|
1181
|
-
return
|
|
1177
|
+
return envFlagEnabled2(env.FEATURE_OAUTH) || envFlagEnabled2(env.FEATURE_SAML) || Boolean(env.GITHUB_CLIENT_ID?.trim()) || Boolean(env.OIDC_ISSUER?.trim()) || Boolean(env.SAML_LOGIN_URL?.trim());
|
|
1182
1178
|
}
|
|
1183
1179
|
function isCorsConfigured(env) {
|
|
1184
1180
|
return env.CORS_ALLOWED_ORIGINS !== undefined;
|
|
1185
1181
|
}
|
|
1186
1182
|
function assertAuthDevHeadersDisabled(env) {
|
|
1187
|
-
if (
|
|
1183
|
+
if (env.AUTH_DEV_HEADERS !== "false") {
|
|
1188
1184
|
throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
|
|
1189
1185
|
}
|
|
1190
1186
|
}
|
|
@@ -1215,16 +1211,16 @@ function assertTokenAuthProductionSecrets(env) {
|
|
|
1215
1211
|
}
|
|
1216
1212
|
}
|
|
1217
1213
|
function assertFeatureProductionSecrets(env) {
|
|
1218
|
-
if (
|
|
1214
|
+
if (envFlagEnabled2(env.FEATURE_SCIM)) {
|
|
1219
1215
|
const scimToken = env.SCIM_BEARER_TOKEN ?? PUBLISHED_TEST_SCIM_BEARER_TOKEN;
|
|
1220
1216
|
if (PUBLISHED_TEST_SCIM_TOKENS.has(scimToken) || !env.SCIM_BEARER_TOKEN?.trim()) {
|
|
1221
1217
|
throw new Error("Production startup blocked: rotate SCIM_BEARER_TOKEN away from published test defaults.");
|
|
1222
1218
|
}
|
|
1223
1219
|
}
|
|
1224
|
-
if (
|
|
1220
|
+
if (envFlagEnabled2(env.FEATURE_FIELD_ENCRYPTION) && !env.KMS_ENCRYPTION_KEY?.trim()) {
|
|
1225
1221
|
throw new Error("Production startup blocked: set KMS_ENCRYPTION_KEY when field encryption is enabled.");
|
|
1226
1222
|
}
|
|
1227
|
-
if (
|
|
1223
|
+
if (envFlagEnabled2(env.FEATURE_BILLING) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
|
|
1228
1224
|
throw new Error("Production startup blocked: set STRIPE_WEBHOOK_SECRET when billing webhooks are enabled.");
|
|
1229
1225
|
}
|
|
1230
1226
|
if (isOAuthEnabled(env) && !env.OAUTH_STATE_SECRET?.trim()) {
|
|
@@ -1236,10 +1232,10 @@ function assertFeatureProductionSecrets(env) {
|
|
|
1236
1232
|
throw new Error("Production startup blocked: set explicit CORS_ALLOWED_ORIGINS instead of wildcard.");
|
|
1237
1233
|
}
|
|
1238
1234
|
}
|
|
1239
|
-
if (
|
|
1235
|
+
if (envFlagEnabled2(env.FEATURE_PUBLIC_READS)) {
|
|
1240
1236
|
throw new Error("Production startup blocked: set FEATURE_PUBLIC_READS=false for authenticated-only reads.");
|
|
1241
1237
|
}
|
|
1242
|
-
if (!env.SIEM_EXPORT_URL?.trim() &&
|
|
1238
|
+
if (!env.SIEM_EXPORT_URL?.trim() && envFlagEnabled2(env.FEATURE_SIEM_EXPORT)) {
|
|
1243
1239
|
console.warn("[secrets] SIEM_EXPORT_URL is not configured; audit logs remain database-only.");
|
|
1244
1240
|
}
|
|
1245
1241
|
}
|
|
@@ -1260,8 +1256,7 @@ function assertPublicAppUrl(env) {
|
|
|
1260
1256
|
}
|
|
1261
1257
|
}
|
|
1262
1258
|
function assertProductionSecrets(env = process.env) {
|
|
1263
|
-
|
|
1264
|
-
if (appEnv !== "production") {
|
|
1259
|
+
if (!isProductionEnv(env)) {
|
|
1265
1260
|
return;
|
|
1266
1261
|
}
|
|
1267
1262
|
assertNoPlaceholderSecrets(env);
|
|
@@ -1436,7 +1431,7 @@ import { getDefaultDatabasePool as getDefaultDatabasePool2 } from "@getstrata/co
|
|
|
1436
1431
|
import { currentSqlDialect, sqlTimestamp } from "@getstrata/core/database/dialect";
|
|
1437
1432
|
import { readRequestCookie } from "@getstrata/core/http/cookies";
|
|
1438
1433
|
import { currentRequestMeta as currentRequestMeta3 } from "@getstrata/core/http/requestMetaContext";
|
|
1439
|
-
import { isProductionEnv } from "@getstrata/core/runtime/appEnv";
|
|
1434
|
+
import { isProductionEnv as isProductionEnv2 } from "@getstrata/core/runtime/appEnv";
|
|
1440
1435
|
import { timingSafeCompareString } from "@getstrata/core/security/timingSafeCompare";
|
|
1441
1436
|
function sqlPlaceholder(index) {
|
|
1442
1437
|
return currentSqlDialect().placeholder(index);
|
|
@@ -1539,7 +1534,7 @@ class CookieSessionStore {
|
|
|
1539
1534
|
return sessionId;
|
|
1540
1535
|
}
|
|
1541
1536
|
withSecureFlag(header) {
|
|
1542
|
-
if (!
|
|
1537
|
+
if (!isProductionEnv2()) {
|
|
1543
1538
|
return header;
|
|
1544
1539
|
}
|
|
1545
1540
|
return header.includes("Secure") ? header : `${header}; Secure`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstrata/bootstrap",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Strata application bootstrap: HttpKernel, DI, web session helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"access": "public"
|
|
176
176
|
},
|
|
177
177
|
"peerDependencies": {
|
|
178
|
-
"@getstrata/core": "^1.0.
|
|
178
|
+
"@getstrata/core": "^1.0.4",
|
|
179
179
|
"typescript": "^5.9.0"
|
|
180
180
|
},
|
|
181
181
|
"engines": {
|