sdlc-agent-4-enterprise-server 1.42.3 → 1.44.0
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/.env.example +23 -0
- package/README.md +4 -2
- package/dist/admin/db/config.js +14 -3
- package/dist/admin/db/config.js.map +1 -1
- package/dist/admin/db/core.d.ts +6 -0
- package/dist/admin/db/core.js +14 -6
- package/dist/admin/db/core.js.map +1 -1
- package/dist/admin/db/schema.d.ts +0 -1
- package/dist/admin/db/schema.js +217 -4
- package/dist/admin/db/schema.js.map +1 -1
- package/dist/admin/db/sessions.d.ts +3 -3
- package/dist/admin/db/sessions.js +12 -7
- package/dist/admin/db/sessions.js.map +1 -1
- package/dist/admin/db/users.js +2 -2
- package/dist/admin/db/users.js.map +1 -1
- package/dist/config/EntraConfig.d.ts +77 -0
- package/dist/config/EntraConfig.js +190 -0
- package/dist/config/EntraConfig.js.map +1 -0
- package/dist/config/index.d.ts +6 -2
- package/dist/config/index.js +25 -0
- package/dist/config/index.js.map +1 -1
- package/dist/database/adapters/SqliteAdapter.d.ts +11 -0
- package/dist/database/adapters/SqliteAdapter.js +79 -8
- package/dist/database/adapters/SqliteAdapter.js.map +1 -1
- package/dist/database/migration/ensure-pega-category-counters.js +4 -2
- package/dist/database/migration/ensure-pega-category-counters.js.map +1 -1
- package/dist/database/migrations/000-init-system-tables.cjs +126 -0
- package/dist/database/migrations/000-init-system-tables.cjs.map +1 -0
- package/dist/database/migrations/000-init-system-tables.d.cts +2 -0
- package/dist/database/repositories/UserRepository.d.ts +13 -2
- package/dist/database/repositories/UserRepository.js +62 -0
- package/dist/database/repositories/UserRepository.js.map +1 -1
- package/dist/database/repositories/interfaces.d.ts +17 -0
- package/dist/database/schema-registry/ensure-engine-schema.d.ts +14 -0
- package/dist/database/schema-registry/ensure-engine-schema.js +36 -0
- package/dist/database/schema-registry/ensure-engine-schema.js.map +1 -0
- package/dist/database/schema-registry/ensure-sa4e-276.d.ts +4 -0
- package/dist/database/schema-registry/ensure-sa4e-276.js +40 -0
- package/dist/database/schema-registry/ensure-sa4e-276.js.map +1 -0
- package/dist/database/schema-registry/ensure-sa4e-300.js +19 -0
- package/dist/database/schema-registry/ensure-sa4e-300.js.map +1 -1
- package/dist/database/schema-registry/ensure-sa4e-303.d.ts +1 -0
- package/dist/database/schema-registry/ensure-sa4e-303.js +43 -8
- package/dist/database/schema-registry/ensure-sa4e-303.js.map +1 -1
- package/dist/engine/graph/migrator.js +4 -1
- package/dist/engine/graph/migrator.js.map +1 -1
- package/dist/index.js +42 -10
- package/dist/index.js.map +1 -1
- package/dist/models/pega-schema.models.d.ts +42 -42
- package/dist/modules/kb-graph/service/sync.js +15 -0
- package/dist/modules/kb-graph/service/sync.js.map +1 -1
- package/dist/modules/memory/engine/edge-on-ingest.d.ts +7 -0
- package/dist/modules/memory/engine/edge-on-ingest.js +14 -4
- package/dist/modules/memory/engine/edge-on-ingest.js.map +1 -1
- package/dist/modules/memory/migrations/001-add-scope-columns.d.ts +3 -1
- package/dist/modules/memory/migrations/001-add-scope-columns.js +11 -16
- package/dist/modules/memory/migrations/001-add-scope-columns.js.map +1 -1
- package/dist/modules/memory/migrations/002-add-evolution-columns.d.ts +3 -0
- package/dist/modules/memory/migrations/002-add-evolution-columns.js +32 -28
- package/dist/modules/memory/migrations/002-add-evolution-columns.js.map +1 -1
- package/dist/modules/memory/migrations/003-pending-tasks.d.ts +2 -0
- package/dist/modules/memory/migrations/003-pending-tasks.js +12 -11
- package/dist/modules/memory/migrations/003-pending-tasks.js.map +1 -1
- package/dist/rag/async-queue.d.ts +16 -0
- package/dist/rag/async-queue.js +20 -0
- package/dist/rag/async-queue.js.map +1 -0
- package/dist/rag/query-router.d.ts +12 -0
- package/dist/rag/query-router.js +42 -0
- package/dist/rag/query-router.js.map +1 -0
- package/dist/rag/semantic-cache.d.ts +14 -0
- package/dist/rag/semantic-cache.js +20 -0
- package/dist/rag/semantic-cache.js.map +1 -0
- package/dist/rag/summary-tree.d.ts +20 -0
- package/dist/rag/summary-tree.js +28 -0
- package/dist/rag/summary-tree.js.map +1 -0
- package/dist/routes/rag.d.ts +2 -0
- package/dist/routes/rag.js +62 -0
- package/dist/routes/rag.js.map +1 -0
- package/dist/server/HttpServer.js +18 -1
- package/dist/server/HttpServer.js.map +1 -1
- package/dist/server/auth/index.d.ts +3 -0
- package/dist/server/auth/index.js +4 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/server/auth/models/GitHubProfile.d.ts +75 -0
- package/dist/server/auth/models/GitHubProfile.js +34 -0
- package/dist/server/auth/models/GitHubProfile.js.map +1 -0
- package/dist/server/auth/models/GoogleClaims.d.ts +75 -0
- package/dist/server/auth/models/GoogleClaims.js +44 -0
- package/dist/server/auth/models/GoogleClaims.js.map +1 -0
- package/dist/server/auth/models/NormalizedProfile.d.ts +8 -0
- package/dist/server/auth/models/NormalizedProfile.js +2 -0
- package/dist/server/auth/models/NormalizedProfile.js.map +1 -0
- package/dist/server/auth/models/SsoProviderConfig.d.ts +14 -0
- package/dist/server/auth/models/SsoProviderConfig.js +2 -0
- package/dist/server/auth/models/SsoProviderConfig.js.map +1 -0
- package/dist/server/auth/strategies/EntraProviderStrategy.d.ts +7 -0
- package/dist/server/auth/strategies/EntraProviderStrategy.js +112 -0
- package/dist/server/auth/strategies/EntraProviderStrategy.js.map +1 -0
- package/dist/server/auth/strategies/GitHubProviderStrategy.d.ts +24 -0
- package/dist/server/auth/strategies/GitHubProviderStrategy.js +133 -0
- package/dist/server/auth/strategies/GitHubProviderStrategy.js.map +1 -0
- package/dist/server/auth/strategies/GoogleProviderConfig.d.ts +23 -0
- package/dist/server/auth/strategies/GoogleProviderConfig.js +50 -0
- package/dist/server/auth/strategies/GoogleProviderConfig.js.map +1 -0
- package/dist/server/auth/strategies/GoogleProviderStrategy.d.ts +35 -0
- package/dist/server/auth/strategies/GoogleProviderStrategy.js +104 -0
- package/dist/server/auth/strategies/GoogleProviderStrategy.js.map +1 -0
- package/dist/server/auth/strategies/SsoProviderStrategy.d.ts +33 -0
- package/dist/server/auth/strategies/SsoProviderStrategy.js +2 -0
- package/dist/server/auth/strategies/SsoProviderStrategy.js.map +1 -0
- package/dist/server/auth/strategies/SsoStrategyRegistry.d.ts +13 -0
- package/dist/server/auth/strategies/SsoStrategyRegistry.js +30 -0
- package/dist/server/auth/strategies/SsoStrategyRegistry.js.map +1 -0
- package/dist/server/auth/strategies/index.d.ts +5 -0
- package/dist/server/auth/strategies/index.js +14 -0
- package/dist/server/auth/strategies/index.js.map +1 -0
- package/dist/server/auth/utils/callback-url.d.ts +22 -0
- package/dist/server/auth/utils/callback-url.js +34 -0
- package/dist/server/auth/utils/callback-url.js.map +1 -0
- package/dist/server/auth/utils/pkce-helper.d.ts +6 -0
- package/dist/server/auth/utils/pkce-helper.js +29 -0
- package/dist/server/auth/utils/pkce-helper.js.map +1 -0
- package/dist/server/auth/utils/sso-config-loader.d.ts +15 -0
- package/dist/server/auth/utils/sso-config-loader.js +35 -0
- package/dist/server/auth/utils/sso-config-loader.js.map +1 -0
- package/dist/server/middleware/jwt-auth.js +19 -12
- package/dist/server/middleware/jwt-auth.js.map +1 -1
- package/dist/server/middleware/verifiers/EntraRS256Verifier.d.ts +46 -0
- package/dist/server/middleware/verifiers/EntraRS256Verifier.js +124 -0
- package/dist/server/middleware/verifiers/EntraRS256Verifier.js.map +1 -0
- package/dist/server/middleware/verifiers/GoogleIdTokenVerifier.d.ts +34 -0
- package/dist/server/middleware/verifiers/GoogleIdTokenVerifier.js +82 -0
- package/dist/server/middleware/verifiers/GoogleIdTokenVerifier.js.map +1 -0
- package/dist/server/middleware/verifiers/JwksCache.d.ts +34 -0
- package/dist/server/middleware/verifiers/JwksCache.js +82 -0
- package/dist/server/middleware/verifiers/JwksCache.js.map +1 -0
- package/dist/server/middleware/verifiers/LocalHS256Verifier.d.ts +11 -0
- package/dist/server/middleware/verifiers/LocalHS256Verifier.js +55 -0
- package/dist/server/middleware/verifiers/LocalHS256Verifier.js.map +1 -0
- package/dist/server/middleware/verifiers/TokenVerifier.d.ts +38 -0
- package/dist/server/middleware/verifiers/TokenVerifier.js +35 -0
- package/dist/server/middleware/verifiers/TokenVerifier.js.map +1 -0
- package/dist/server/middleware/verifiers/entra-auth.d.ts +32 -0
- package/dist/server/middleware/verifiers/entra-auth.js +104 -0
- package/dist/server/middleware/verifiers/entra-auth.js.map +1 -0
- package/dist/server/middleware/verifiers/verifier.test.d.ts +5 -0
- package/dist/server/middleware/verifiers/verifier.test.js +338 -0
- package/dist/server/middleware/verifiers/verifier.test.js.map +1 -0
- package/dist/server/routes/admin/auth.js +6 -109
- package/dist/server/routes/admin/auth.js.map +1 -1
- package/dist/server/routes/admin/config.js +87 -0
- package/dist/server/routes/admin/config.js.map +1 -1
- package/dist/server/routes/admin/context.js +4 -1
- package/dist/server/routes/admin/context.js.map +1 -1
- package/dist/server/routes/admin/database.js +11 -1
- package/dist/server/routes/admin/database.js.map +1 -1
- package/dist/server/routes/admin/index.js +2 -0
- package/dist/server/routes/admin/index.js.map +1 -1
- package/dist/server/routes/admin/kb-graph.js +27 -10
- package/dist/server/routes/admin/kb-graph.js.map +1 -1
- package/dist/server/routes/admin/sso-providers.d.ts +3 -0
- package/dist/server/routes/admin/sso-providers.js +112 -0
- package/dist/server/routes/admin/sso-providers.js.map +1 -0
- package/dist/server/routes/api-index.d.ts +31 -0
- package/dist/server/routes/api-index.js +270 -71
- package/dist/server/routes/api-index.js.map +1 -1
- package/dist/server/routes/auth/entra.d.ts +11 -0
- package/dist/server/routes/auth/entra.js +121 -0
- package/dist/server/routes/auth/entra.js.map +1 -0
- package/dist/server/routes/auth/sso-dynamic.d.ts +2 -0
- package/dist/server/routes/auth/sso-dynamic.js +40 -0
- package/dist/server/routes/auth/sso-dynamic.js.map +1 -0
- package/dist/server/routes/auth/sso-http-helpers.d.ts +61 -0
- package/dist/server/routes/auth/sso-http-helpers.js +162 -0
- package/dist/server/routes/auth/sso-http-helpers.js.map +1 -0
- package/dist/server/routes/auth/sso-provider.d.ts +12 -0
- package/dist/server/routes/auth/sso-provider.js +137 -0
- package/dist/server/routes/auth/sso-provider.js.map +1 -0
- package/dist/server/routes/auth/unified.d.ts +2 -0
- package/dist/server/routes/auth/unified.js +204 -0
- package/dist/server/routes/auth/unified.js.map +1 -0
- package/dist/server/routes/sa4e-215/auth.d.ts +1 -0
- package/dist/server/routes/sa4e-215/auth.js +2 -102
- package/dist/server/routes/sa4e-215/auth.js.map +1 -1
- package/dist/server/services/JitProvisioningService.d.ts +33 -0
- package/dist/server/services/JitProvisioningService.js +145 -0
- package/dist/server/services/JitProvisioningService.js.map +1 -0
- package/dist/server/services/SessionService.d.ts +15 -0
- package/dist/server/services/SessionService.js +20 -0
- package/dist/server/services/SessionService.js.map +1 -0
- package/dist/server/utils/ua.d.ts +2 -0
- package/dist/server/utils/ua.js +11 -0
- package/dist/server/utils/ua.js.map +1 -0
- package/dist/servers/atlassian/credentials/credential-schemas.d.ts +4 -4
- package/dist/shared/EventBus.d.ts +2 -0
- package/dist/shared/EventBus.js +2 -0
- package/dist/shared/EventBus.js.map +1 -1
- package/dist/viewer/admin/entra-sso.html +27 -0
- package/dist/viewer/admin/index.html +104 -8
- package/knexfile.cjs +91 -0
- package/package.json +6 -2
- package/src/admin/db/config.ts +15 -5
- package/src/admin/db/core.ts +14 -6
- package/src/admin/db/schema.ts +208 -4
- package/src/admin/db/sessions.ts +14 -6
- package/src/admin/db/users.ts +2 -2
- package/src/config/EntraConfig.ts +231 -0
- package/src/config/index.ts +26 -0
- package/src/database/adapters/SqliteAdapter.ts +77 -8
- package/src/database/migration/ensure-pega-category-counters.ts +4 -2
- package/src/database/migrations/000-init-system-tables.cjs +131 -0
- package/src/database/repositories/UserRepository.ts +70 -2
- package/src/database/repositories/__tests__/UserRepository.test.ts +99 -1
- package/src/database/repositories/interfaces.ts +13 -0
- package/src/database/schema-registry/ensure-engine-schema.ts +37 -0
- package/src/database/schema-registry/ensure-sa4e-276.ts +41 -0
- package/src/database/schema-registry/ensure-sa4e-300.ts +25 -1
- package/src/database/schema-registry/ensure-sa4e-303.ts +50 -9
- package/src/engine/graph/migrator.ts +8 -1
- package/src/index.ts +50 -14
- package/src/modules/kb-graph/service/sync.ts +14 -0
- package/src/modules/memory/__tests__/edge-on-ingest.test.ts +30 -0
- package/src/modules/memory/engine/edge-on-ingest.ts +18 -4
- package/src/modules/memory/migrations/001-add-scope-columns.ts +20 -20
- package/src/modules/memory/migrations/002-add-evolution-columns.ts +39 -33
- package/src/modules/memory/migrations/003-pending-tasks.ts +17 -11
- package/src/modules/memory/migrations/004-reset-sequences.ts +1 -1
- package/src/rag/__tests__/async-queue.test.ts +12 -0
- package/src/rag/__tests__/query-router.test.ts +20 -0
- package/src/rag/__tests__/semantic-cache.test.ts +11 -0
- package/src/rag/__tests__/summary-tree.test.ts +12 -0
- package/src/rag/async-queue.ts +29 -0
- package/src/rag/query-router.ts +41 -0
- package/src/rag/semantic-cache.ts +21 -0
- package/src/rag/summary-tree.ts +40 -0
- package/src/routes/rag.ts +60 -0
- package/src/server/HttpServer.ts +18 -1
- package/src/server/auth/index.ts +3 -0
- package/src/server/auth/models/GitHubProfile.ts +41 -0
- package/src/server/auth/models/GoogleClaims.ts +52 -0
- package/src/server/auth/models/NormalizedProfile.ts +8 -0
- package/src/server/auth/models/SsoProviderConfig.ts +14 -0
- package/src/server/auth/strategies/EntraProviderStrategy.ts +140 -0
- package/src/server/auth/strategies/GitHubProviderStrategy.ts +151 -0
- package/src/server/auth/strategies/GoogleProviderConfig.ts +78 -0
- package/src/server/auth/strategies/GoogleProviderStrategy.ts +148 -0
- package/src/server/auth/strategies/SsoProviderStrategy.ts +41 -0
- package/src/server/auth/strategies/SsoStrategyRegistry.ts +39 -0
- package/src/server/auth/strategies/__tests__/EntraProviderStrategy.state.test.ts +81 -0
- package/src/server/auth/strategies/__tests__/EntraProviderStrategy.test.ts +265 -0
- package/src/server/auth/strategies/__tests__/GitHubProviderStrategy.test.ts +129 -0
- package/src/server/auth/strategies/__tests__/GoogleProviderConfig.test.ts +69 -0
- package/src/server/auth/strategies/__tests__/GoogleProviderStrategy.test.ts +172 -0
- package/src/server/auth/strategies/__tests__/SsoStrategyRegistry.test.ts +75 -0
- package/src/server/auth/strategies/index.ts +15 -0
- package/src/server/auth/utils/callback-url.ts +35 -0
- package/src/server/auth/utils/pkce-helper.ts +32 -0
- package/src/server/auth/utils/sso-config-loader.ts +55 -0
- package/src/server/middleware/__tests__/jwt-auth.test.ts +1 -1
- package/src/server/middleware/jwt-auth.ts +19 -14
- package/src/server/middleware/verifiers/EntraRS256Verifier.ts +184 -0
- package/src/server/middleware/verifiers/GoogleIdTokenVerifier.ts +98 -0
- package/src/server/middleware/verifiers/JwksCache.ts +103 -0
- package/src/server/middleware/verifiers/LocalHS256Verifier.ts +66 -0
- package/src/server/middleware/verifiers/TokenVerifier.ts +65 -0
- package/src/server/middleware/verifiers/__tests__/GoogleIdTokenVerifier.test.ts +106 -0
- package/src/server/middleware/verifiers/entra-auth.ts +117 -0
- package/src/server/middleware/verifiers/verifier.test.ts +429 -0
- package/src/server/routes/__tests__/admin.test.ts +37 -0
- package/src/server/routes/__tests__/api-index-errors.test.ts +424 -0
- package/src/server/routes/admin/auth.ts +6 -112
- package/src/server/routes/admin/config.ts +69 -0
- package/src/server/routes/admin/context.ts +4 -1
- package/src/server/routes/admin/database.ts +11 -1
- package/src/server/routes/admin/index.ts +2 -0
- package/src/server/routes/admin/kb-graph.ts +29 -13
- package/src/server/routes/admin/sso-providers.ts +102 -0
- package/src/server/routes/api-index.ts +255 -71
- package/src/server/routes/auth/__tests__/sso-dynamic.test.ts +108 -0
- package/src/server/routes/auth/entra.ts +143 -0
- package/src/server/routes/auth/sso-dynamic.ts +50 -0
- package/src/server/routes/auth/sso-http-helpers.ts +176 -0
- package/src/server/routes/auth/sso-provider.ts +160 -0
- package/src/server/routes/auth/unified.ts +196 -0
- package/src/server/routes/sa4e-215/__tests__/sa4e-215.routes.test.ts +2 -2
- package/src/server/routes/sa4e-215/auth.ts +3 -123
- package/src/server/services/JitProvisioningService.ts +194 -0
- package/src/server/services/SessionService.ts +20 -0
- package/src/server/services/__tests__/JitProvisioningService.test.ts +187 -0
- package/src/server/utils/ua.ts +11 -0
- package/src/shared/EventBus.ts +2 -0
- package/src/viewer/admin/entra-sso.html +27 -0
- package/src/viewer/admin/index.html +104 -8
- package/tests/e2e/reindex.e2e.test.ts +4 -0
- package/tests/integration/auth.test.ts +1 -1
- package/tests/integration/entra-oauth.it.test.ts +169 -0
- package/tests/integration/google-oauth.it.test.ts +173 -0
- package/tests/unit/EntraConfig.test.ts +169 -0
- package/tests/unit/entra-loopback-redirect.test.ts +49 -0
- package/vitest.e2e.config.ts +8 -5
package/.env.example
CHANGED
|
@@ -72,3 +72,26 @@ CHECKSUM_MAX_ZIP_ENTRIES=50000 # trần số entry trong ZIP
|
|
|
72
72
|
# --- Bulk-check limits (SEC-04) ---
|
|
73
73
|
# Server-side cap on checksums per bulk-check request (client batches <= 1000).
|
|
74
74
|
BULK_CHECK_MAX_CHECKSUMS=5000
|
|
75
|
+
|
|
76
|
+
# =============================================================================
|
|
77
|
+
# SA4E-264 — Entra ID SSO config (env template — placeholders only)
|
|
78
|
+
# NEVER commit real values. Use local .env (untracked) or a secret manager.
|
|
79
|
+
# See FSD SA4E-264 §4.1 for validation rules.
|
|
80
|
+
# =============================================================================
|
|
81
|
+
|
|
82
|
+
# Gate flag: true/1 = enable SSO (Entra vars become REQUIRED at startup, fail-fast)
|
|
83
|
+
SSO_ENABLED=false
|
|
84
|
+
|
|
85
|
+
# --- Required when SSO_ENABLED=true (4 values from App Registration runbook SA4E-271) ---
|
|
86
|
+
ENTRA_TENANT_ID=<azure-ad-tenant-guid-or-common>
|
|
87
|
+
ENTRA_CLIENT_ID=<app-registration-client-guid>
|
|
88
|
+
ENTRA_CLIENT_SECRET=<set-via-secret-manager> # min 8 chars; NEVER a real secret in repo
|
|
89
|
+
ENTRA_REDIRECT_URI=http://localhost:48721/auth/entra/callback
|
|
90
|
+
|
|
91
|
+
# --- Optional (derived defaults when absent — see FSD §7.2) ---
|
|
92
|
+
# ENTRA_AUTHORITY=https://login.microsoftonline.com/<tenant-guid>
|
|
93
|
+
# ENTRA_ISSUER=https://login.microsoftonline.com/<tenant-guid>/v2.0
|
|
94
|
+
# ENTRA_JWKS_URI=https://login.microsoftonline.com/<tenant-guid>/discovery/v2.0/keys
|
|
95
|
+
# ENTRA_SCOPES=openid profile email offline_access
|
|
96
|
+
# SSO_ALLOWED_REDIRECTS=/admin?page=dashboard,/app/dashboard
|
|
97
|
+
# SSO_LEGACY_REDIRECT_WITH_TOKEN=false
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
|
-
<img src="https://img.shields.io/badge/version-1.
|
|
9
|
+
<img src="https://img.shields.io/badge/version-1.44.0-blue?style=for-the-badge" alt="Version">
|
|
10
10
|
<img src="https://img.shields.io/badge/tools-66+-teal?style=for-the-badge" alt="Tools">
|
|
11
11
|
<img src="https://img.shields.io/badge/node-%3E%3D18-green?style=for-the-badge" alt="Node">
|
|
12
12
|
</p>
|
|
@@ -38,7 +38,7 @@ Server starts at **http://localhost:48721**. Verify it's running:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
curl http://localhost:48721/health
|
|
41
|
-
# → {"status":"healthy","version":"1.
|
|
41
|
+
# → {"status":"healthy","version":"1.44.0","uptime":5,"tools_loaded":52}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
### Development Mode (auto-reload)
|
|
@@ -233,6 +233,8 @@ The embedding model is expected at `.code-intel/models/model.onnx`. Download it:
|
|
|
233
233
|
|
|
234
234
|
| Version | Date | Ticket | Changes |
|
|
235
235
|
|---------|------|--------|---------|
|
|
236
|
+
| 1.44.0 | 2026-09-23 | SA4E-320/323 | Extension-side release: opt-in HTTPS bypass for remote backend (workspace-scoped `allowInsecureRemote`, runtime apply without reload, restrictedConfigurations + trust gate, Pega endpoint HTTPS enforcement); per-workspace isolation of Pega/Atlassian settings with keychain namespacing + one-time migration. No backend runtime code changes — version aligned. |
|
|
237
|
+
| 1.43.0 | 2026-09-22 | SA4E-262 | Multi-provider SSO unified on `sso_providers` (Entra/Google/GitHub, Strategy pattern). Entra email verification via Microsoft `xms_edov` claim (Entra omits standard `email_verified`); loopback SSO sessions no longer User-Agent-bound so extension `/api/admin/auth/me` works; JIT provisioning rejections return `403 provisioning_rejected` with a clear reason. |
|
|
236
238
|
| 1.42.2 | 2026-09-11 | SA4E-257 | Wire DB-backed MCP server config to McpClientManager: McpServerConfigRepository loads `mcp_servers` table, initializeAll reads enabled servers from DB, real-time hooks auto connect/reconnect/disconnect on CRUD, transport normalization `streamable-http → httpStream`, mock logs removed. Regression tests pass. |
|
|
237
239
|
| 1.42.1 | 2026-09-10 | SA4E-258 | Tenant scope stamping for tool execution: `/api/tools/execute` + `/api/code/search` stamp trusted scope onto tool args via canonical `__projectId`/`__userId` (not only `_projectContext`), fixing code-intel tools (fail-closed on missing `__projectId`) that returned "No results found". Covers MCP call path (mcpServer) + KB API route. Graph migrator idempotency, query-layer scope resolution, indexing-engine fixes. KB Graph: FileContainsSymbolStrategy dir-based match for LWC/Aura components (LWC_COMPONENT no longer isolated). Regression tests added (tools-execute-scope, orchestration dynamic IT, mcpServer calltool IT). |
|
|
238
240
|
| 1.42.0 | 2026-09-08 | SA4E-301 | Multi-language tree-sitter parsers (C/C++/C#/PHP/Ruby/Scala/Swift/Kotlin) via shared GenericTreeSitterParser + regex fallback; symbol-kind fixes (struct/enum naming, method promotion, variable/property/constant separation, dedupe). Salesforce indexing (Apex/LWC/Aura/Visualforce/meta) with grammars copied to dist. KB Graph edges rebuilt from `relationships` (MembershipEdgeStrategy CONTAINS + FileContainsSymbolStrategy + inherits/implements resolve-by-name); auto-heal backfill (ensure-sa4e-301), unused edge tables dropped (303), unique index (302). Enrichment dedup (single CodeEnrichmentTaskCreator + PENDING guard, orphan task cleanup 300). Continuous budget-driven KB Graph LOD renderer. Node.js 22 LTS. |
|
package/dist/admin/db/config.js
CHANGED
|
@@ -33,9 +33,20 @@ export async function recordConfigChange(section, key, oldValue, newValue, chang
|
|
|
33
33
|
* @param limit - Max entries (default 10)
|
|
34
34
|
*/
|
|
35
35
|
export async function getConfigChanges(limit = 10) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
36
|
+
// Fail-safe: if the config_changes table is not ready yet (e.g. right after
|
|
37
|
+
// switching to a freshly-provisioned Postgres engine before migrations run),
|
|
38
|
+
// return an empty history instead of throwing. Throwing here would bubble up
|
|
39
|
+
// through GET /api/admin/config and blank out the ENTIRE config page
|
|
40
|
+
// (LLM / taskWorker / auth sections all disappear, leaving only Database).
|
|
41
|
+
// Mirrors the resilient pattern used by getLatestConfigValue/loadPersistedLLMConfig.
|
|
42
|
+
try {
|
|
43
|
+
const adapter = getDbAdapter();
|
|
44
|
+
const rows = await adapter.allAsync('SELECT * FROM config_changes ORDER BY changed_at DESC LIMIT ?', [limit]);
|
|
45
|
+
return rows.map(rowToConfigChange);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
39
50
|
}
|
|
40
51
|
/**
|
|
41
52
|
* Load the latest persisted value for a specific section.key from config_changes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/admin/db/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAazC,4CAA4C;AAC5C,SAAS,iBAAiB,CAAC,CAAM;IAC/B,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB;KACtC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,GAAW,EACX,QAAuB,EACvB,QAAgB,EAChB,SAAiB,EACjB,eAAwB;IAExB,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,MAAM,OAAO,CAAC,QAAQ,CACpB;kCAC8B,EAC9B,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACjG,CAAC;IACF,8CAA8C;IAC9C,MAAM,OAAO,CAAC,QAAQ,CACpB;;OAEG,CACJ,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAK,GAAG,EAAE;IAC/C,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/admin/db/config.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/db/core.d.ts
CHANGED
|
@@ -33,5 +33,11 @@ export declare function resetAdminDb(): void;
|
|
|
33
33
|
/**
|
|
34
34
|
* Get the raw DB instance.
|
|
35
35
|
* @deprecated Use getDbAdapter() for new code. Kept for backward compat with tests.
|
|
36
|
+
* SA4E-262 fix: delegates to getDbAdapter() to honor the unified-DB contract.
|
|
37
|
+
* The previous implementation force-initialized the SQLite adapter even when the
|
|
38
|
+
* active engine was PostgreSQL — splitting admin-UI writes (SQLite) from
|
|
39
|
+
* auth/login-page reads (PostgreSQL) and crashing the server on first
|
|
40
|
+
* sso-providers/config request (lazy SqliteAdapter.connect threw CANTOPEN and
|
|
41
|
+
* the rejection was unhandled).
|
|
36
42
|
*/
|
|
37
43
|
export declare function getAdminDb(): any;
|
package/dist/admin/db/core.js
CHANGED
|
@@ -81,10 +81,14 @@ let sqliteReady = null;
|
|
|
81
81
|
function getUnifiedSqliteAdapter() {
|
|
82
82
|
if (!sqliteAdapter) {
|
|
83
83
|
sqliteAdapter = new SqliteAdapter(DB_PATH);
|
|
84
|
-
//
|
|
85
|
-
void
|
|
84
|
+
// SA4E-262 fix: connect() MUST be chained into sqliteReady — the previous
|
|
85
|
+
// `void connect()` orphaned the rejection, so a CANTOPEN during lazy init
|
|
86
|
+
// crashed the whole server (unhandled rejection) instead of failing the
|
|
87
|
+
// caller's request with a 500.
|
|
86
88
|
const adapter = sqliteAdapter;
|
|
87
|
-
sqliteReady =
|
|
89
|
+
sqliteReady = adapter.connect()
|
|
90
|
+
.then(() => initSchema(adapter))
|
|
91
|
+
.then(() => seedDefaults(adapter))
|
|
88
92
|
.catch((err) => logger.error({ err }, '[admin] SQLite schema init failed'));
|
|
89
93
|
}
|
|
90
94
|
return sqliteAdapter;
|
|
@@ -162,10 +166,14 @@ export function resetAdminDb() {
|
|
|
162
166
|
/**
|
|
163
167
|
* Get the raw DB instance.
|
|
164
168
|
* @deprecated Use getDbAdapter() for new code. Kept for backward compat with tests.
|
|
169
|
+
* SA4E-262 fix: delegates to getDbAdapter() to honor the unified-DB contract.
|
|
170
|
+
* The previous implementation force-initialized the SQLite adapter even when the
|
|
171
|
+
* active engine was PostgreSQL — splitting admin-UI writes (SQLite) from
|
|
172
|
+
* auth/login-page reads (PostgreSQL) and crashing the server on first
|
|
173
|
+
* sso-providers/config request (lazy SqliteAdapter.connect threw CANTOPEN and
|
|
174
|
+
* the rejection was unhandled).
|
|
165
175
|
*/
|
|
166
176
|
export function getAdminDb() {
|
|
167
|
-
|
|
168
|
-
// getRawDb removed; return adapter directly for compat
|
|
169
|
-
return adapter;
|
|
177
|
+
return getDbAdapter();
|
|
170
178
|
}
|
|
171
179
|
//# sourceMappingURL=core.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/admin/db/core.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/admin/db/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* SQLite and PostgreSQL (PostgresAdapter throws on the sync exec/get/run methods).
|
|
6
6
|
*/
|
|
7
7
|
import type { DatabaseAdapter } from '../../database/adapters/DatabaseAdapter.js';
|
|
8
|
-
/** Initialize admin schema tables (idempotent CREATE IF NOT EXISTS). */
|
|
9
8
|
export declare function initSchema(db: DatabaseAdapter): Promise<void>;
|
|
10
9
|
/** Seed default access groups and admin user. */
|
|
11
10
|
export declare function seedDefaults(db: DatabaseAdapter): Promise<void>;
|
package/dist/admin/db/schema.js
CHANGED
|
@@ -20,9 +20,182 @@ function insertIgnore(engine, sql) {
|
|
|
20
20
|
return sql;
|
|
21
21
|
}
|
|
22
22
|
/** Initialize admin schema tables (idempotent CREATE IF NOT EXISTS). */
|
|
23
|
+
async function migrateUsersSso(db, engine) {
|
|
24
|
+
try {
|
|
25
|
+
if (engine === 'postgresql') {
|
|
26
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN IF NOT EXISTS account_type TEXT NOT NULL DEFAULT 'LOCAL'`);
|
|
27
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN IF NOT EXISTS external_provider TEXT`);
|
|
28
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN IF NOT EXISTS external_subject_id TEXT`);
|
|
29
|
+
await db.execAsync(`ALTER TABLE users ALTER COLUMN password_hash DROP NOT NULL`);
|
|
30
|
+
await db.execAsync(`CREATE UNIQUE INDEX IF NOT EXISTS uq_users_external_identity ON users (external_provider, external_subject_id)`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
try {
|
|
34
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN account_type TEXT NOT NULL DEFAULT 'LOCAL'`);
|
|
35
|
+
}
|
|
36
|
+
catch { }
|
|
37
|
+
try {
|
|
38
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN external_provider TEXT`);
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
try {
|
|
42
|
+
await db.execAsync(`ALTER TABLE users ADD COLUMN external_subject_id TEXT`);
|
|
43
|
+
}
|
|
44
|
+
catch { }
|
|
45
|
+
// SQLite cannot ALTER COLUMN nullability; recreate table if password_hash is NOT NULL
|
|
46
|
+
try {
|
|
47
|
+
const info = await db.allAsync(`PRAGMA table_info(users)`);
|
|
48
|
+
const col = info.find(c => c.name === 'password_hash');
|
|
49
|
+
if (col && col.notnull === 1) {
|
|
50
|
+
await db.execAsync(`ALTER TABLE users RENAME TO users_old`);
|
|
51
|
+
await db.execAsync(`CREATE TABLE users (
|
|
52
|
+
user_id TEXT PRIMARY KEY,
|
|
53
|
+
username TEXT,
|
|
54
|
+
email TEXT UNIQUE,
|
|
55
|
+
password_hash TEXT,
|
|
56
|
+
status TEXT,
|
|
57
|
+
access_group_id TEXT,
|
|
58
|
+
force_password_change INTEGER,
|
|
59
|
+
created_at TEXT,
|
|
60
|
+
last_login TEXT,
|
|
61
|
+
account_type TEXT NOT NULL DEFAULT 'LOCAL',
|
|
62
|
+
external_provider TEXT,
|
|
63
|
+
external_subject_id TEXT
|
|
64
|
+
)`);
|
|
65
|
+
await db.execAsync(`INSERT INTO users SELECT user_id, username, email, password_hash, status, access_group_id, force_password_change, created_at, last_login, COALESCE(account_type,'LOCAL'), external_provider, external_subject_id FROM users_old`);
|
|
66
|
+
await db.execAsync(`DROP TABLE users_old`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
await db.execAsync(`CREATE UNIQUE INDEX IF NOT EXISTS uq_users_external_identity ON users (external_provider, external_subject_id)`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.debug('[schema] users_sso migration:', err.message);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function seedDefaultSsoProviders(db) {
|
|
78
|
+
try {
|
|
79
|
+
const templates = [
|
|
80
|
+
{
|
|
81
|
+
// Hướng A (SA4E-262): Entra is configured via sso_providers like every
|
|
82
|
+
// other provider (single source of truth), so it must have a seed row too.
|
|
83
|
+
provider_type: 'entra',
|
|
84
|
+
name: 'Microsoft Entra ID',
|
|
85
|
+
enabled: 0,
|
|
86
|
+
login_ui_html: `<span class="sso-btn sso-entra"><svg width="18" height="18" viewBox="0 0 23 23"><path fill="#f35325" d="M1 1h10v10H1z"/><path fill="#81bc06" d="M12 1h10v10H12z"/><path fill="#05a6f0" d="M1 12h10v10H1z"/><path fill="#ffba08" d="M12 12h10v10H12z"/></svg> Sign in with Microsoft</span>`,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
provider_type: 'google',
|
|
90
|
+
name: 'Google',
|
|
91
|
+
enabled: 0,
|
|
92
|
+
// login_ui_html holds only the visual (icon + label) — NO navigation URL.
|
|
93
|
+
// The login page wraps it in an anchor built from basePath so it works
|
|
94
|
+
// under sub-path deploys (ui-relative-paths: never embed absolute hrefs).
|
|
95
|
+
login_ui_html: `<span class="sso-btn sso-google"><svg width="18" height="18" viewBox="0 0 24 24"><path fill="#EA4335" d="M12 10.2v3.6h5.1c-.2 1.2-1.5 3.6-5.1 3.6-3.1 0-5.6-2.5-5.6-5.6s2.5-5.6 5.6-5.6c1.8 0 3 .8 3.7 1.4l2.5-2.4C17 2.9 14.7 1.8 12 1.8 6.8 1.8 2.5 6.1 2.5 11.3S6.8 20.8 12 20.8c5.6 0 9.3-4 9.3-9.3 0-.6 0-1.2-.1-1.8H12z"/></svg> Sign in with Google</span>`,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
provider_type: 'github',
|
|
99
|
+
name: 'GitHub',
|
|
100
|
+
enabled: 0,
|
|
101
|
+
login_ui_html: `<span class="sso-btn sso-github"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .5a12 12 0 0 0-3.79 23.4c.6.11.82-.26.82-.58v-2.02c-3.34.73-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.1-.75.08-.73.08-.73 1.22.09 1.86 1.26 1.86 1.26 1.08 1.86 2.83 1.32 3.52 1.01.11-.79.42-1.32.76-1.62-2.67-.3-5.47-1.34-5.47-5.95 0-1.31.47-2.38 1.24-3.22-.12-.3-.54-1.52.12-3.18 0 0 1.01-.32 3.3 1.23a11.4 11.4 0 0 1 6 0c2.29-1.55 3.3-1.23 3.3-1.23.66 1.66.24 2.88.12 3.18.77.84 1.24 1.91 1.24 3.22 0 4.61-2.8 5.65-5.48 5.95.43.37.81 1.1.81 2.22v3.29c0 .32.22.69.82.58A12 12 0 0 0 12 .5Z"/></svg> Sign in with GitHub</span>`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
provider_type: 'x',
|
|
105
|
+
name: 'X',
|
|
106
|
+
enabled: 0,
|
|
107
|
+
login_ui_html: `<span class="sso-btn sso-x">Sign in with X</span>`,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
provider_type: 'facebook',
|
|
111
|
+
name: 'Facebook',
|
|
112
|
+
enabled: 0,
|
|
113
|
+
login_ui_html: `<span class="sso-btn sso-facebook"><svg width="18" height="18" viewBox="0 0 24 24"><path fill="#1877F2" d="M24 12.07C24 5.41 18.63 0 12 0S0 5.41 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.8-4.7 4.55-4.7 1.31 0 2.68.24 2.68.24v2.95h-1.51c-1.48 0-1.94.92-1.94 1.86v2.24h3.3l-.53 3.49h-2.77V24C19.61 23.1 24 18.1 24 12.07z"/></svg> Sign in with Facebook</span>`,
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
const now = new Date().toISOString();
|
|
117
|
+
for (const t of templates) {
|
|
118
|
+
const exists = await db.getAsync('SELECT 1 FROM sso_providers WHERE provider_type = ?', [t.provider_type]);
|
|
119
|
+
if (!exists) {
|
|
120
|
+
const provider_id = `${t.provider_type}-${Date.now()}`;
|
|
121
|
+
// 13 columns → 13 placeholders (fix SA4E-262: was 12 placeholders for 13 values)
|
|
122
|
+
await db.runAsync(`INSERT INTO sso_providers (provider_id, provider_type, name, enabled, client_id, client_secret, tenant_id, redirect_uri, allowed_redirects, scopes, login_ui_html, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`, [provider_id, t.provider_type, t.name, t.enabled, '', '', '', '', '', '', t.login_ui_html, now, now]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
// Non-fatal: seed of default provider templates is optional, but surface the
|
|
128
|
+
// error (console.error, not debug) so a broken INSERT is not swallowed silently.
|
|
129
|
+
console.error('[schema] seedDefaultSsoProviders failed:', err.message);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Rewrite legacy login_ui_html that embedded an absolute login URL
|
|
134
|
+
* (`<a href="/auth/{provider}/login">…</a>`) into a URL-less `<span>` so the
|
|
135
|
+
* login page can wrap it in a basePath-aware anchor. Runs outside any
|
|
136
|
+
* transaction (autocommit) — safe to re-run (idempotent on already-migrated rows).
|
|
137
|
+
*/
|
|
138
|
+
async function migrateLoginUiHtmlToUrlless(db) {
|
|
139
|
+
try {
|
|
140
|
+
const rows = await db.allAsync("SELECT provider_id, login_ui_html FROM sso_providers WHERE login_ui_html LIKE '%href=%/auth/%/login%'");
|
|
141
|
+
for (const row of rows || []) {
|
|
142
|
+
// Drop the opening <a ...> (keeping inner content) and turn </a> into </span>.
|
|
143
|
+
const migrated = row.login_ui_html
|
|
144
|
+
.replace(/<a\b[^>]*\bhref=["'][^"']*\/auth\/[^"']*\/login["'][^>]*>/i, '<span class="sso-btn">')
|
|
145
|
+
.replace(/<\/a>/i, '</span>');
|
|
146
|
+
await db.runAsync('UPDATE sso_providers SET login_ui_html = ? WHERE provider_id = ?', [migrated, row.provider_id]);
|
|
147
|
+
}
|
|
148
|
+
if (rows && rows.length > 0) {
|
|
149
|
+
console.debug(`[schema] migrated ${rows.length} login_ui_html row(s) to URL-less form`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
// Non-fatal: surface the error but do not block schema init.
|
|
154
|
+
console.error('[schema] migrateLoginUiHtmlToUrlless failed:', err.message);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function seedSsoProvidersFromEnv(db) {
|
|
158
|
+
try {
|
|
159
|
+
const cnt = await db.getAsync('SELECT COUNT(*) as count FROM sso_providers');
|
|
160
|
+
if (cnt && cnt.count > 0)
|
|
161
|
+
return;
|
|
162
|
+
const env = process.env;
|
|
163
|
+
if (!env.SSO_ENABLED || env.SSO_ENABLED !== 'true')
|
|
164
|
+
return;
|
|
165
|
+
const tenant = env.ENTRA_TENANT_ID || '';
|
|
166
|
+
const clientId = env.ENTRA_CLIENT_ID || '';
|
|
167
|
+
const clientSecret = env.ENTRA_CLIENT_SECRET || '';
|
|
168
|
+
if (!tenant || !clientId)
|
|
169
|
+
return;
|
|
170
|
+
const now = new Date().toISOString();
|
|
171
|
+
const provider_id = `entra-${Date.now()}`;
|
|
172
|
+
const name = 'Entra ID';
|
|
173
|
+
const enabled = 1;
|
|
174
|
+
const redirect_uri = env.ENTRA_REDIRECT_URI || '';
|
|
175
|
+
const allowed_redirects = env.SSO_ALLOWED_REDIRECTS || '';
|
|
176
|
+
const scopes = env.ENTRA_SCOPES || 'openid profile email offline_access';
|
|
177
|
+
const login_ui_html = `<button class="sso-btn sso-entra">Sign in with Entra ID</button>`;
|
|
178
|
+
// 13 columns → 13 placeholders (fix SA4E-262: was 12 placeholders for 13 values)
|
|
179
|
+
await db.runAsync(`INSERT INTO sso_providers (provider_id, provider_type, name, enabled, client_id, client_secret, tenant_id, redirect_uri, allowed_redirects, scopes, login_ui_html, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`, [provider_id, 'entra', name, enabled, clientId, clientSecret, tenant, redirect_uri, allowed_redirects, scopes, login_ui_html, now, now]);
|
|
180
|
+
console.debug('[schema] sso_providers seeded from env');
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
// Non-fatal, but surface the error so a broken INSERT is not swallowed silently.
|
|
184
|
+
console.error('[schema] seedSsoProvidersFromEnv failed:', err.message);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
23
187
|
export async function initSchema(db) {
|
|
24
188
|
const engine = db.getEngine();
|
|
25
189
|
await db.execAsync(schemaSql(engine));
|
|
190
|
+
// SA4E-265 migration: users_sso
|
|
191
|
+
await migrateUsersSso(db, engine);
|
|
192
|
+
// SA4E-262 migration: add user_agent_hash to sessions for session fixation hardening
|
|
193
|
+
try {
|
|
194
|
+
await db.execAsync(`ALTER TABLE sessions ADD COLUMN user_agent_hash TEXT DEFAULT ''`);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
console.debug('[schema] sessions.user_agent_hash already exists :', err.message);
|
|
198
|
+
}
|
|
26
199
|
// Idempotent migration: add project_id to graph_nodes for existing DBs
|
|
27
200
|
try {
|
|
28
201
|
await db.execAsync(`ALTER TABLE graph_nodes ADD COLUMN project_id TEXT NOT NULL DEFAULT ''`);
|
|
@@ -59,6 +232,22 @@ export async function initSchema(db) {
|
|
|
59
232
|
catch (err) {
|
|
60
233
|
console.debug('[schema] group_permissions unique index :', err.message);
|
|
61
234
|
}
|
|
235
|
+
// Migration: add login_ui_html column if missing
|
|
236
|
+
try {
|
|
237
|
+
await db.execAsync(`ALTER TABLE sso_providers ADD COLUMN login_ui_html TEXT NOT NULL DEFAULT ''`);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
console.debug('[schema] login_ui_html already exists:', err.message);
|
|
241
|
+
}
|
|
242
|
+
// Migration (SA4E-310): strip absolute-path anchors from stored login_ui_html.
|
|
243
|
+
// Old seeds embedded <a href="/auth/{p}/login">…</a> which breaks sub-path
|
|
244
|
+
// deploys. The login page now builds the URL from basePath, so stored HTML
|
|
245
|
+
// must carry only the visual content — rewrite legacy <a href=...> to <span>.
|
|
246
|
+
await migrateLoginUiHtmlToUrlless(db);
|
|
247
|
+
// Migration: seed sso_providers from env if table empty
|
|
248
|
+
await seedSsoProvidersFromEnv(db);
|
|
249
|
+
// Seed default provider templates for Google/GitHub/X/Facebook
|
|
250
|
+
await seedDefaultSsoProviders(db);
|
|
62
251
|
}
|
|
63
252
|
/** Seed default access groups and admin user. */
|
|
64
253
|
export async function seedDefaults(db) {
|
|
@@ -103,8 +292,8 @@ async function seedAdminUser(db) {
|
|
|
103
292
|
? envPassword
|
|
104
293
|
: crypto.randomBytes(18).toString('base64url');
|
|
105
294
|
const hash = hashPassword(initialPassword);
|
|
106
|
-
await db.runAsync(`INSERT INTO users (user_id, username, email, password_hash, status, access_group_id, force_password_change, created_at)
|
|
107
|
-
VALUES (?, ?, ?, ?, 'ACTIVE', 'grp-admin', 1,
|
|
295
|
+
await db.runAsync(`INSERT INTO users (user_id, username, email, password_hash, status, access_group_id, force_password_change, created_at, account_type)
|
|
296
|
+
VALUES (?, ?, ?, ?, 'ACTIVE', 'grp-admin', 1, ?, 'LOCAL')`, ['user-admin-001', 'admin', 'admin@localhost', hash, now]);
|
|
108
297
|
if (!envPassword) {
|
|
109
298
|
process.stdout.write('\n============================================================\n' +
|
|
110
299
|
' ADMIN ACCOUNT CREATED — generated one-time password:\n' +
|
|
@@ -137,12 +326,15 @@ function schemaSql(engine) {
|
|
|
137
326
|
user_id TEXT PRIMARY KEY,
|
|
138
327
|
username TEXT UNIQUE NOT NULL,
|
|
139
328
|
email TEXT NOT NULL DEFAULT '',
|
|
140
|
-
password_hash TEXT
|
|
329
|
+
password_hash TEXT,
|
|
141
330
|
status TEXT NOT NULL DEFAULT 'ACTIVE',
|
|
142
331
|
access_group_id TEXT NOT NULL,
|
|
143
332
|
force_password_change INTEGER NOT NULL DEFAULT 0,
|
|
144
333
|
created_at TEXT NOT NULL,
|
|
145
|
-
last_login TEXT
|
|
334
|
+
last_login TEXT,
|
|
335
|
+
account_type TEXT NOT NULL DEFAULT 'LOCAL' CHECK (account_type IN ('LOCAL','SSO')),
|
|
336
|
+
external_provider TEXT,
|
|
337
|
+
external_subject_id TEXT
|
|
146
338
|
);
|
|
147
339
|
|
|
148
340
|
CREATE TABLE IF NOT EXISTS access_groups (
|
|
@@ -168,6 +360,7 @@ function schemaSql(engine) {
|
|
|
168
360
|
token TEXT UNIQUE NOT NULL,
|
|
169
361
|
device TEXT DEFAULT '',
|
|
170
362
|
ip_address TEXT DEFAULT '',
|
|
363
|
+
user_agent_hash TEXT DEFAULT '',
|
|
171
364
|
login_at TEXT NOT NULL,
|
|
172
365
|
expires_at TEXT NOT NULL,
|
|
173
366
|
is_active INTEGER NOT NULL DEFAULT 1,
|
|
@@ -203,6 +396,26 @@ function schemaSql(engine) {
|
|
|
203
396
|
CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_log(user_id);
|
|
204
397
|
CREATE INDEX IF NOT EXISTS idx_config_changes_time ON config_changes(changed_at);
|
|
205
398
|
|
|
399
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_users_external_identity ON users (external_provider, external_subject_id);
|
|
400
|
+
|
|
401
|
+
CREATE TABLE IF NOT EXISTS sso_providers (
|
|
402
|
+
provider_id TEXT PRIMARY KEY,
|
|
403
|
+
provider_type TEXT NOT NULL CHECK (provider_type IN ('entra','google','github','x','facebook','azuread')),
|
|
404
|
+
name TEXT NOT NULL,
|
|
405
|
+
enabled INTEGER NOT NULL DEFAULT 0,
|
|
406
|
+
client_id TEXT NOT NULL DEFAULT '',
|
|
407
|
+
client_secret TEXT NOT NULL DEFAULT '',
|
|
408
|
+
tenant_id TEXT NOT NULL DEFAULT '',
|
|
409
|
+
redirect_uri TEXT NOT NULL DEFAULT '',
|
|
410
|
+
allowed_redirects TEXT NOT NULL DEFAULT '',
|
|
411
|
+
scopes TEXT NOT NULL DEFAULT '',
|
|
412
|
+
login_ui_html TEXT NOT NULL DEFAULT '',
|
|
413
|
+
created_at TEXT NOT NULL DEFAULT ${now},
|
|
414
|
+
updated_at TEXT NOT NULL DEFAULT ${now}
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_sso_providers_type ON sso_providers(provider_type);
|
|
418
|
+
|
|
206
419
|
CREATE TABLE IF NOT EXISTS graph_nodes (
|
|
207
420
|
entry_id TEXT PRIMARY KEY,
|
|
208
421
|
label TEXT NOT NULL DEFAULT '',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/admin/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,MAAsB,EAAE,GAAW;IACvD,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAAG,yBAAyB,CAAC;IAChF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAmB;IAClD,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/admin/db/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import type { Session } from '../types/rbac.types.js';
|
|
|
7
7
|
* Create a new session for a user.
|
|
8
8
|
* @returns Session with plain-text token
|
|
9
9
|
*/
|
|
10
|
-
export declare function createSession(userId: string, device?: string, ip?: string): Promise<Session & {
|
|
10
|
+
export declare function createSession(userId: string, device?: string, ip?: string, userAgentHash?: string): Promise<Session & {
|
|
11
11
|
token: string;
|
|
12
12
|
}>;
|
|
13
13
|
/**
|
|
@@ -15,7 +15,7 @@ export declare function createSession(userId: string, device?: string, ip?: stri
|
|
|
15
15
|
* Checks is_active, expiry, and user status.
|
|
16
16
|
* @returns Session identity or null if invalid/expired
|
|
17
17
|
*/
|
|
18
|
-
export declare function validateSession(token: string): Promise<{
|
|
18
|
+
export declare function validateSession(token: string, currentUserAgentHash?: string): Promise<{
|
|
19
19
|
userId: string;
|
|
20
20
|
username: string;
|
|
21
21
|
accessGroupId: string;
|
|
@@ -31,7 +31,7 @@ export declare function invalidateUserSessions(userId: string): Promise<number>;
|
|
|
31
31
|
* Rotate a session token (sliding expiry).
|
|
32
32
|
* @returns New token + expiry or null if session is invalid
|
|
33
33
|
*/
|
|
34
|
-
export declare function refreshSession(token: string): Promise<{
|
|
34
|
+
export declare function refreshSession(token: string, currentUserAgentHash?: string): Promise<{
|
|
35
35
|
token: string;
|
|
36
36
|
expiresAt: string;
|
|
37
37
|
} | null>;
|
|
@@ -9,14 +9,14 @@ import { generateToken } from './password.js';
|
|
|
9
9
|
* Create a new session for a user.
|
|
10
10
|
* @returns Session with plain-text token
|
|
11
11
|
*/
|
|
12
|
-
export async function createSession(userId, device, ip) {
|
|
12
|
+
export async function createSession(userId, device, ip, userAgentHash) {
|
|
13
13
|
const adapter = getDbAdapter();
|
|
14
14
|
const sessionId = 'sess-' + crypto.randomUUID().slice(0, 8);
|
|
15
15
|
const token = generateToken();
|
|
16
16
|
const now = new Date();
|
|
17
17
|
const expires = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
|
18
|
-
await adapter.runAsync(`INSERT INTO sessions (session_id, user_id, token, device, ip_address, login_at, expires_at, is_active)
|
|
19
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 1)`, [sessionId, userId, token, device || '', ip || '', now.toISOString(), expires.toISOString()]);
|
|
18
|
+
await adapter.runAsync(`INSERT INTO sessions (session_id, user_id, token, device, ip_address, user_agent_hash, login_at, expires_at, is_active)
|
|
19
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`, [sessionId, userId, token, device || '', ip || '', userAgentHash || '', now.toISOString(), expires.toISOString()]);
|
|
20
20
|
return {
|
|
21
21
|
sessionId, userId, token,
|
|
22
22
|
device, ipAddress: ip,
|
|
@@ -30,11 +30,14 @@ export async function createSession(userId, device, ip) {
|
|
|
30
30
|
* Checks is_active, expiry, and user status.
|
|
31
31
|
* @returns Session identity or null if invalid/expired
|
|
32
32
|
*/
|
|
33
|
-
export async function validateSession(token) {
|
|
33
|
+
export async function validateSession(token, currentUserAgentHash) {
|
|
34
34
|
const adapter = getDbAdapter();
|
|
35
|
-
const row = await adapter.getAsync(`SELECT s.user_id, s.expires_at, s.is_active, u.username, u.access_group_id, u.status
|
|
35
|
+
const row = await adapter.getAsync(`SELECT s.user_id, s.expires_at, s.is_active, s.user_agent_hash, u.username, u.access_group_id, u.status
|
|
36
36
|
FROM sessions s JOIN users u ON s.user_id = u.user_id
|
|
37
37
|
WHERE s.token = ?`, [token]);
|
|
38
|
+
if (currentUserAgentHash && row?.user_agent_hash && row.user_agent_hash !== currentUserAgentHash) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
38
41
|
if (!row)
|
|
39
42
|
return null;
|
|
40
43
|
if (!row.is_active)
|
|
@@ -67,13 +70,15 @@ export async function invalidateUserSessions(userId) {
|
|
|
67
70
|
* Rotate a session token (sliding expiry).
|
|
68
71
|
* @returns New token + expiry or null if session is invalid
|
|
69
72
|
*/
|
|
70
|
-
export async function refreshSession(token) {
|
|
73
|
+
export async function refreshSession(token, currentUserAgentHash) {
|
|
71
74
|
const adapter = getDbAdapter();
|
|
72
|
-
const row = await adapter.getAsync(`SELECT s.user_id, s.expires_at, s.is_active, u.status
|
|
75
|
+
const row = await adapter.getAsync(`SELECT s.user_id, s.expires_at, s.is_active, s.user_agent_hash, u.status
|
|
73
76
|
FROM sessions s JOIN users u ON s.user_id = u.user_id
|
|
74
77
|
WHERE s.token = ?`, [token]);
|
|
75
78
|
if (!row || !row.is_active || row.status !== 'ACTIVE')
|
|
76
79
|
return null;
|
|
80
|
+
if (currentUserAgentHash && row.user_agent_hash && row.user_agent_hash !== currentUserAgentHash)
|
|
81
|
+
return null;
|
|
77
82
|
if (new Date(row.expires_at) < new Date()) {
|
|
78
83
|
await adapter.runAsync('UPDATE sessions SET is_active = 0 WHERE token = ?', [token]);
|
|
79
84
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/admin/db/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/admin/db/sessions.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/db/users.js
CHANGED
|
@@ -84,8 +84,8 @@ export async function createUser(username, email, password, accessGroupId) {
|
|
|
84
84
|
const userId = 'user-' + crypto.randomUUID().slice(0, 8);
|
|
85
85
|
const now = new Date().toISOString();
|
|
86
86
|
const hash = hashPassword(password);
|
|
87
|
-
await adapter.runAsync(`INSERT INTO users (user_id, username, email, password_hash, status, access_group_id, force_password_change, created_at)
|
|
88
|
-
VALUES (?, ?, ?, ?, 'ACTIVE', ?, 1,
|
|
87
|
+
await adapter.runAsync(`INSERT INTO users (user_id, username, email, password_hash, status, access_group_id, force_password_change, created_at, account_type)
|
|
88
|
+
VALUES (?, ?, ?, ?, 'ACTIVE', ?, 1, ?, 'LOCAL')`, [userId, username, email, hash, accessGroupId, now]);
|
|
89
89
|
return { userId, username, email, status: 'ACTIVE', accessGroupId, forcePasswordChange: true, createdAt: now };
|
|
90
90
|
}
|
|
91
91
|
/**
|