@harperfast/harper 5.2.10 → 5.3.0-alpha.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.
- package/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +46 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +59 -3
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +2414 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +150 -74
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +37 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +340 -30
- package/components/componentPreparationLock.ts +16 -5
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +270 -78
- package/components/operationsValidation.js +49 -1
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +80 -34
- package/config/configUtils.ts +291 -34
- package/config/harperConfigEnvVars.ts +170 -27
- package/config-root.schema.json +29 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +52 -8
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +48 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +54 -5
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +139 -16
- package/dist/components/Application.js +2215 -267
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +1 -0
- package/dist/components/OptionsWatcher.js +141 -74
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +38 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +279 -22
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.js +231 -77
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +49 -1
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +7 -1
- package/dist/config/RootConfigWatcher.js +64 -27
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configUtils.d.ts +9 -1
- package/dist/config/configUtils.js +254 -33
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +51 -10
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +52 -0
- package/dist/resources/DatabaseTransaction.d.ts +55 -3
- package/dist/resources/DatabaseTransaction.js +460 -134
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.js +22 -4
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +30 -2
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +94 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +20 -11
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +20 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -10
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +14 -1
- package/dist/resources/RocksTransactionLogStore.js +57 -17
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +112 -8
- package/dist/resources/Table.js +1071 -197
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.d.ts +11 -2
- package/dist/resources/auditStore.js +183 -18
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/databases.d.ts +150 -9
- package/dist/resources/databases.js +1247 -525
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +50 -15
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +1 -0
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +6 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/recordLock.d.ts +80 -0
- package/dist/resources/recordLock.js +184 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +152 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/search.js +158 -32
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +75 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +73 -0
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +11 -0
- package/dist/server/http.js +88 -15
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +25 -0
- package/dist/server/serverHelpers/Headers.js +139 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +9 -0
- package/dist/server/serverHelpers/contentTypes.js +32 -25
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +90 -20
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +16 -0
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +26 -4
- package/dist/server/threads/manageThreads.js +517 -72
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +89 -26
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +46 -15
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +17 -0
- package/dist/utility/errors/hdbError.js +30 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +16 -0
- package/dist/utility/hdbTerms.js +18 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +91 -14
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logRotator.js +76 -49
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +9 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +86 -0
- package/dist/utility/watcherFallback.js +278 -1
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +199 -72
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +2 -0
- package/json/systemSchema.json +52 -0
- package/npm-shrinkwrap.json +235 -233
- package/package.json +8 -7
- package/resources/DESIGN.md +114 -52
- package/resources/DatabaseTransaction.ts +522 -130
- package/resources/LMDBTransaction.ts +26 -4
- package/resources/PrimaryRocksDatabase.ts +29 -3
- package/resources/RecordEncoder.ts +103 -8
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +17 -9
- package/resources/ResourceInterface.ts +23 -0
- package/resources/RocksIndexStore.ts +30 -10
- package/resources/RocksTransactionLogStore.ts +78 -21
- package/resources/Table.ts +1107 -164
- package/resources/auditStore.ts +187 -21
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/databases.ts +1354 -522
- package/resources/defineTable.ts +18 -2
- package/resources/graphql.ts +70 -16
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +6 -2
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/recordLock.ts +253 -0
- package/resources/replayLogs.ts +147 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/search.ts +154 -32
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +81 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +183 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +79 -1
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +99 -18
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +131 -0
- package/server/serverHelpers/contentTypes.ts +29 -21
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +104 -31
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +13 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/manageThreads.js +526 -63
- package/server/threads/socketRouter.ts +81 -26
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +43 -15
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-Br06zdMA.js → Chat-BnCBegQz.js} +1 -1
- package/studio/web/assets/{FloatingChat-BWImX5fA.js → FloatingChat-CoDW1ySS.js} +3 -3
- package/studio/web/assets/{apiToken-DN0nmDsq.js → apiToken-Bwk5BLXW.js} +1 -1
- package/studio/web/assets/{applications-kSxVoyeU.js → applications-DHxGi7JH.js} +1 -1
- package/studio/web/assets/{cssMode-C1JeufH5.js → cssMode-s0cWI-_M.js} +1 -1
- package/studio/web/assets/{editor-qoo9CrGO.js → editor-DNcRHK54.js} +1 -1
- package/studio/web/assets/{html-Dt4IIy04.js → html-Bdssedlg.js} +1 -1
- package/studio/web/assets/{htmlMode-DXgKKr4C.js → htmlMode-CoDlJ3fw.js} +1 -1
- package/studio/web/assets/{index-6onkYFOG.js → index-D6sxmFLR.js} +5 -5
- package/studio/web/assets/{index.lazy-BrCFnpNJ.js → index.lazy-tmU5BS8s.js} +1 -1
- package/studio/web/assets/{javascript-DNCQGUBc.js → javascript-B8meVSTH.js} +1 -1
- package/studio/web/assets/{jsonMode-CR6HWruP.js → jsonMode-DpIPd35T.js} +1 -1
- package/studio/web/assets/{languageServices-BM4fI4rS.js → languageServices-C_5FMJzQ.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-DSa1ttcD.js → lspLanguageFeatures-BIzNBzPK.js} +1 -1
- package/studio/web/assets/{notifications-BHXLnh6x.js → notifications-CQf18QKb.js} +1 -1
- package/studio/web/assets/{notifications-CUmtIA6z.js → notifications-CvZivSbh.js} +1 -1
- package/studio/web/assets/{profile-8BeFSF3j.js → profile-DdOwtntb.js} +1 -1
- package/studio/web/assets/{regions-C8qR0HhD.js → regions-n69fwagr.js} +1 -1
- package/studio/web/assets/{register-B4n5i0SD.js → register-PfWTCXWB.js} +2 -2
- package/studio/web/assets/{setComponentFile-g0_B0lgX.js → setComponentFile-Bg6O7X0S.js} +1 -1
- package/studio/web/assets/{setup-B0CTj_Q5.js → setup-CUx_aUDl.js} +2 -2
- package/studio/web/assets/{status-C6Yib7-K.js → status-D7BVKqX9.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Dgta7bVi.js → toggleHighContrast-DBSyXzMr.js} +1 -1
- package/studio/web/assets/{tsMode-CH_jHvU-.js → tsMode-BByKCjBS.js} +1 -1
- package/studio/web/assets/{typescript-Co9LCXd5.js → typescript-DDLnLpw9.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-wKC8NsC_.js → useEntityRestURL-31CHGaHk.js} +1 -1
- package/studio/web/assets/{workers-CWeLxCXA.js → workers-pR3jRY9D.js} +1 -1
- package/studio/web/assets/{xml-BadC-0Rk.js → xml-2iRnMhQO.js} +1 -1
- package/studio/web/assets/{yaml-BiUfxPbC.js → yaml-Bf92gJpd.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +29 -0
- package/utility/hdbTerms.ts +17 -0
- package/utility/logging/harper_logger.ts +87 -14
- package/utility/logging/logRotator.ts +72 -45
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +10 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +270 -0
- package/validation/configValidator.ts +209 -72
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
package/dist/security/keys.js
CHANGED
|
@@ -59,7 +59,6 @@ exports.getPrimaryHostName = getPrimaryHostName;
|
|
|
59
59
|
exports.hostnamesFromCert = hostnamesFromCert;
|
|
60
60
|
exports.getHostnamesFromCertificate = getHostnamesFromCertificate;
|
|
61
61
|
const path = __importStar(require("path"));
|
|
62
|
-
const chokidar_1 = require("chokidar");
|
|
63
62
|
const fs = __importStar(require("fs-extra"));
|
|
64
63
|
const forge = __importStar(require("node-forge"));
|
|
65
64
|
const net = __importStar(require("net"));
|
|
@@ -86,7 +85,10 @@ exports.getPrivateKeys = getPrivateKeys;
|
|
|
86
85
|
const node_fs_1 = require("node:fs");
|
|
87
86
|
const manageThreads_js_1 = require("../server/threads/manageThreads.js");
|
|
88
87
|
const worker_threads_1 = require("worker_threads");
|
|
88
|
+
const watcherFallback_ts_1 = require("../utility/watcherFallback.js");
|
|
89
|
+
const watchPath_ts_1 = require("../utility/watchPath.js");
|
|
89
90
|
const node_tls_1 = require("node:tls");
|
|
91
|
+
const trustedIssuers_ts_1 = require("./certificateVerification/trustedIssuers.js");
|
|
90
92
|
const CERT_VALIDITY_DAYS = 3650;
|
|
91
93
|
// Default interval (ms) for the periodic cert-file re-read safety net. The chokidar (inotify)
|
|
92
94
|
// watcher is the fast path; this poll catches changes on filesystems where inotify is unreliable
|
|
@@ -192,6 +194,11 @@ const privateKeys = new Map();
|
|
|
192
194
|
// Debounce window (ms) for rebuilding TLS secure contexts. Shared by the hdb_certificate
|
|
193
195
|
// subscription and the private-key hot-reload trigger so both coalesce on the same cadence.
|
|
194
196
|
const TLS_REBUILD_DEBOUNCE_MS = 1500;
|
|
197
|
+
// Self-retry backoff cap: a permanently bad record must not cost every selector on every
|
|
198
|
+
// thread a table scan + X509 parse per debounce interval, forever.
|
|
199
|
+
const TLS_FAILURE_RETRY_MAX_DELAY_MS = 300_000;
|
|
200
|
+
// While a failure signature is unchanged, repeat occurrences log a summary at most this often.
|
|
201
|
+
const TLS_FAILURE_SUMMARY_INTERVAL_MS = 3_600_000;
|
|
195
202
|
// Debounced rebuild triggers, one per live server TLS selector (registered in createTLSSelector's
|
|
196
203
|
// initialize). When a private key is hot-reloaded on this thread, every live selector re-runs
|
|
197
204
|
// updateTLS so a secure context built with a stale key — or built before this key arrived — is
|
|
@@ -296,7 +303,9 @@ function loadCertificates() {
|
|
|
296
303
|
logger.info?.(`Certificate ${certCn} at ${path} is older (${new Date(fileTimestamp)}) than the certificate in the database (${recordTimestamp > 1 ? new Date(recordTimestamp) : 'only self signed certificate available'})`);
|
|
297
304
|
return;
|
|
298
305
|
}
|
|
299
|
-
|
|
306
|
+
// Returned so loadAndWatch can roll back its mtime latch if the write fails —
|
|
307
|
+
// assigned as well to preserve loadCertificates()'s awaited-return contract.
|
|
308
|
+
return (promise = certificateTable.put({
|
|
300
309
|
name: certCn,
|
|
301
310
|
uses: config.uses ?? (configKey.includes('operations') ? ['operations-api'] : []),
|
|
302
311
|
ciphers: config.ciphers,
|
|
@@ -313,7 +322,7 @@ function loadCertificates() {
|
|
|
313
322
|
valid_from: x509Cert.validFrom,
|
|
314
323
|
valid_to: x509Cert.validTo,
|
|
315
324
|
},
|
|
316
|
-
});
|
|
325
|
+
}));
|
|
317
326
|
}, ca ? 'certificate authority' : 'certificate');
|
|
318
327
|
}
|
|
319
328
|
}
|
|
@@ -364,27 +373,72 @@ const certificateWatchPollers = new Map();
|
|
|
364
373
|
function loadAndWatch(path, loadCert, type) {
|
|
365
374
|
let lastModified;
|
|
366
375
|
const loadFile = (path, stats) => {
|
|
376
|
+
// The latch dedupes chokidar/poll but must mean "last successfully APPLIED", or a failed
|
|
377
|
+
// apply is deduplicated forever (#2382). Rollbacks are equality-guarded so an old failure
|
|
378
|
+
// can't unlatch a newer successful reload.
|
|
379
|
+
const previousModified = lastModified;
|
|
380
|
+
let modified;
|
|
367
381
|
try {
|
|
368
382
|
// chokidar's 'change' event omits stats unless alwaysStat is set (default off in v4), so
|
|
369
383
|
// stat the file here when it's missing — otherwise the inotify fast path would throw and
|
|
370
384
|
// silently never reload, leaving only the periodic poll to catch the change.
|
|
371
|
-
|
|
385
|
+
modified = (stats ?? (0, node_fs_1.statSync)(path)).mtimeMs;
|
|
372
386
|
if (modified && modified !== lastModified) {
|
|
373
387
|
if (lastModified && worker_threads_1.isMainThread)
|
|
374
388
|
logger.warn?.(`Reloading ${type}:`, path);
|
|
375
389
|
lastModified = modified;
|
|
376
|
-
loadCert(readPEM(path));
|
|
390
|
+
const applied = loadCert(readPEM(path));
|
|
391
|
+
if (typeof applied?.then === 'function') {
|
|
392
|
+
applied.catch((error) => {
|
|
393
|
+
logger.error?.(`Error applying ${type}:`, path, error);
|
|
394
|
+
if (lastModified === modified)
|
|
395
|
+
lastModified = previousModified;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
377
398
|
}
|
|
378
399
|
}
|
|
379
400
|
catch (error) {
|
|
380
401
|
logger.error?.(`Error loading ${type}:`, path, error);
|
|
402
|
+
if (modified !== undefined && lastModified === modified)
|
|
403
|
+
lastModified = previousModified;
|
|
381
404
|
}
|
|
382
405
|
};
|
|
383
406
|
if (fs.existsSync(path))
|
|
384
407
|
loadFile(path, (0, node_fs_1.statSync)(path));
|
|
385
408
|
else
|
|
386
409
|
logger.error?.(`${type} file not found:`, path);
|
|
387
|
-
(0,
|
|
410
|
+
const watchTarget = (0, watchPath_ts_1.resolveWatchTarget)(path);
|
|
411
|
+
let usingPolling = watchTarget.mustPoll;
|
|
412
|
+
let liveWatcher;
|
|
413
|
+
const openWatcher = () => {
|
|
414
|
+
const opened = (liveWatcher = (0, watcherFallback_ts_1.guardedWatch)(watchTarget.path, {
|
|
415
|
+
persistent: false,
|
|
416
|
+
...(usingPolling ? watcherFallback_ts_1.POLLING_FALLBACK_OPTIONS : {}),
|
|
417
|
+
}));
|
|
418
|
+
opened
|
|
419
|
+
// The event carries the watched spelling, which is not the configured one once canonicalized;
|
|
420
|
+
// reload through the configured path so a retargeted link is followed.
|
|
421
|
+
.on('change', () => loadFile(path))
|
|
422
|
+
// chokidar emits 'error' unguarded for anything but ENOENT/ENOTDIR.
|
|
423
|
+
.on('error', (error) => {
|
|
424
|
+
if ((0, watcherFallback_ts_1.claimLostNativeWatchError)(error))
|
|
425
|
+
return;
|
|
426
|
+
if ((0, watcherFallback_ts_1.isWatcherExhaustionError)(error)) {
|
|
427
|
+
if (usingPolling || liveWatcher !== opened)
|
|
428
|
+
return;
|
|
429
|
+
(0, watcherFallback_ts_1.warnWatcherFallback)(path);
|
|
430
|
+
usingPolling = true;
|
|
431
|
+
Promise.resolve()
|
|
432
|
+
.then(() => opened.close())
|
|
433
|
+
.catch(() => { })
|
|
434
|
+
.then(openWatcher)
|
|
435
|
+
.catch((error) => logger.error?.(`Could not reopen the ${type} watch on polling:`, path, error));
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
logger.error?.(`Error watching ${type}:`, path, error);
|
|
439
|
+
});
|
|
440
|
+
};
|
|
441
|
+
openWatcher();
|
|
388
442
|
// Periodic re-read safety net. For certificates, this runs on the main thread only — workers
|
|
389
443
|
// receive cert updates via the hdb_certificate table subscription, so polling the cert file on
|
|
390
444
|
// every worker would be wasteful. Private keys are different: each worker loads its own key
|
|
@@ -421,13 +475,15 @@ function loadAndWatch(path, loadCert, type) {
|
|
|
421
475
|
}
|
|
422
476
|
}
|
|
423
477
|
function getHost() {
|
|
424
|
-
|
|
425
|
-
|
|
478
|
+
// urlToNodeName returns undefined for a missing or malformed node/replication URL, so a bad
|
|
479
|
+
// replication.url falls back to the default host here rather than throwing during cert review.
|
|
480
|
+
const name = (0, nodeName_ts_1.urlToNodeName)((0, nodeName_ts_1.getThisNodeUrl)());
|
|
481
|
+
if (name == null) {
|
|
426
482
|
const host = CERT_DOMAINS[0];
|
|
427
483
|
logger.info?.('node url is missing from harperdb-config.yaml, using default host' + host);
|
|
428
484
|
return host;
|
|
429
485
|
}
|
|
430
|
-
return
|
|
486
|
+
return name;
|
|
431
487
|
}
|
|
432
488
|
function getCommonName() {
|
|
433
489
|
let node_name = (0, nodeName_ts_1.getThisNodeName)();
|
|
@@ -961,10 +1017,79 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
961
1017
|
let subscribedTable = null;
|
|
962
1018
|
let activeSubscription = null;
|
|
963
1019
|
return (SNICallback.ready = new Promise((resolve, reject) => {
|
|
1020
|
+
// Pass-level failure before `.ready` settles still rejects (boot surfaces it); after,
|
|
1021
|
+
// the only safe response is to keep serving live state and retry.
|
|
1022
|
+
let readySettled = false;
|
|
1023
|
+
const settle = (value) => {
|
|
1024
|
+
readySettled = true;
|
|
1025
|
+
resolve(value);
|
|
1026
|
+
};
|
|
1027
|
+
// Self-retry state for passes with per-record failures: the signature identifies the
|
|
1028
|
+
// failure set, the delay backs off while it is unchanged, and summaries are rate-limited.
|
|
1029
|
+
let failureSignature = '';
|
|
1030
|
+
let failureRetryDelay = TLS_REBUILD_DEBOUNCE_MS;
|
|
1031
|
+
let failureRetryTimer;
|
|
1032
|
+
let failureRetryCount = 0;
|
|
1033
|
+
let failureLastSummaryAt = 0;
|
|
1034
|
+
const scheduleFailureRetry = () => {
|
|
1035
|
+
// An armed external rebuild (or an armed retry) will run a pass that re-arms if needed.
|
|
1036
|
+
if (failureRetryTimer || rebuildTimer)
|
|
1037
|
+
return;
|
|
1038
|
+
failureRetryTimer = setTimeout(() => {
|
|
1039
|
+
failureRetryTimer = undefined;
|
|
1040
|
+
updateTLS();
|
|
1041
|
+
}, failureRetryDelay).unref();
|
|
1042
|
+
failureRetryDelay = Math.min(failureRetryDelay * 2, TLS_FAILURE_RETRY_MAX_DELAY_MS);
|
|
1043
|
+
};
|
|
1044
|
+
// Log each failure on a new/changed failure set; while unchanged, stay silent apart from a
|
|
1045
|
+
// rate-limited summary — an un-throttled 1.5s retry would emit ~57k lines/day per selector.
|
|
1046
|
+
const reportFailures = (failures) => {
|
|
1047
|
+
const signature = failures
|
|
1048
|
+
.map(({ cert, error }) => `${cert.name}: ${error?.message}`)
|
|
1049
|
+
.sort()
|
|
1050
|
+
.join('; ');
|
|
1051
|
+
if (signature !== failureSignature) {
|
|
1052
|
+
failureSignature = signature;
|
|
1053
|
+
failureRetryDelay = TLS_REBUILD_DEBOUNCE_MS;
|
|
1054
|
+
failureRetryCount = 0;
|
|
1055
|
+
failureLastSummaryAt = Date.now();
|
|
1056
|
+
// A timer armed for the previous signature would run the next pass on its stale
|
|
1057
|
+
// (possibly maxed-out) delay; re-arm fresh for the new failure set.
|
|
1058
|
+
if (failureRetryTimer) {
|
|
1059
|
+
clearTimeout(failureRetryTimer);
|
|
1060
|
+
failureRetryTimer = undefined;
|
|
1061
|
+
}
|
|
1062
|
+
for (const { cert, error } of failures)
|
|
1063
|
+
logger.error?.('Error applying TLS for', cert.name, `on the '${type}' listener`, error);
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
failureRetryCount++;
|
|
1067
|
+
// Stays at error: a stuck rotation must keep an alertable signal — the retained cert
|
|
1068
|
+
// is aging toward its notAfter the whole time.
|
|
1069
|
+
if (Date.now() - failureLastSummaryAt >= TLS_FAILURE_SUMMARY_INTERVAL_MS) {
|
|
1070
|
+
failureLastSummaryAt = Date.now();
|
|
1071
|
+
logger.error?.(`TLS rebuild for the '${type}' listener is still failing for [${failures
|
|
1072
|
+
.map(({ cert }) => cert.name)
|
|
1073
|
+
.join(', ')}] after ${failureRetryCount} retries; serving the last good state`);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
const clearFailureState = () => {
|
|
1078
|
+
if (failureSignature) {
|
|
1079
|
+
logger.warn?.(`TLS rebuild for the '${type}' listener recovered; all certificates applied`);
|
|
1080
|
+
}
|
|
1081
|
+
failureSignature = '';
|
|
1082
|
+
failureRetryDelay = TLS_REBUILD_DEBOUNCE_MS;
|
|
1083
|
+
failureRetryCount = 0;
|
|
1084
|
+
if (failureRetryTimer) {
|
|
1085
|
+
clearTimeout(failureRetryTimer);
|
|
1086
|
+
failureRetryTimer = undefined;
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
964
1089
|
function updateTLS() {
|
|
965
1090
|
try {
|
|
966
1091
|
if (databases_ts_1.databases === undefined) {
|
|
967
|
-
|
|
1092
|
+
settle();
|
|
968
1093
|
return;
|
|
969
1094
|
}
|
|
970
1095
|
if (databases_ts_1.databases.system?.hdb_certificate === undefined) {
|
|
@@ -992,19 +1117,19 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
992
1117
|
scheduleRebuild();
|
|
993
1118
|
return;
|
|
994
1119
|
}
|
|
995
|
-
//
|
|
996
|
-
//
|
|
997
|
-
//
|
|
998
|
-
|
|
999
|
-
|
|
1120
|
+
// Transactional publication (#2382): build the whole replacement state off to the
|
|
1121
|
+
// side and reconcile the live maps only after the pass completes, so a failure of
|
|
1122
|
+
// any shape leaves the currently-served state intact.
|
|
1123
|
+
const candidateContexts = new Map();
|
|
1124
|
+
const candidateCAs = new Map();
|
|
1125
|
+
let candidateHasWildcards = false;
|
|
1000
1126
|
let bestQuality = 0;
|
|
1001
|
-
|
|
1002
|
-
//
|
|
1003
|
-
//
|
|
1004
|
-
//
|
|
1005
|
-
// forever, which would let a later transient zero-cert rebuild skip the retry and
|
|
1006
|
-
// publish an empty certificates list (the #1998 symptom) on the post-boot path.
|
|
1127
|
+
let candidateDefault;
|
|
1128
|
+
// Whether THIS pass produced a default. The `defaultContext` closure variable is never
|
|
1129
|
+
// reset (a transient zero-cert pass keeps serving the prior default), so keying the
|
|
1130
|
+
// zero-cert retry off it would republish empty post-boot — the #1998 symptom.
|
|
1007
1131
|
let defaultContextSetThisPass = false;
|
|
1132
|
+
const failedThisPass = [];
|
|
1008
1133
|
// Track the actual table instance, not just whether we've ever subscribed: resetDatabases()
|
|
1009
1134
|
// (copy_db, ITC restart handling) replaces databases.system.hdb_certificate with a new
|
|
1010
1135
|
// table object, and a boolean flag would never re-subscribe to it, permanently losing
|
|
@@ -1035,24 +1160,28 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1035
1160
|
previousSubscription.then((subscription) => subscription?.end?.()).catch(() => { });
|
|
1036
1161
|
}
|
|
1037
1162
|
}
|
|
1038
|
-
|
|
1163
|
+
// One snapshot drives both loops: separate search() calls own separate read
|
|
1164
|
+
// snapshots, and a write committing between them could publish a renewed leaf
|
|
1165
|
+
// against the previous CA set.
|
|
1166
|
+
const certRecords = Array.from(databases_ts_1.databases.system.hdb_certificate.search([]));
|
|
1167
|
+
for (const cert of certRecords) {
|
|
1039
1168
|
const certificate = cert.certificate;
|
|
1040
1169
|
let certParsed;
|
|
1041
1170
|
try {
|
|
1042
1171
|
certParsed = new node_crypto_1.X509Certificate(certificate);
|
|
1043
1172
|
}
|
|
1044
1173
|
catch (error) {
|
|
1045
|
-
//
|
|
1046
|
-
//
|
|
1047
|
-
|
|
1174
|
+
// A pass failure like any other (throttle + retry). Its caCerts entry can't be
|
|
1175
|
+
// retained — the subject is unrecoverable from a PEM that won't parse.
|
|
1176
|
+
failedThisPass.push({ cert, error });
|
|
1048
1177
|
continue;
|
|
1049
1178
|
}
|
|
1050
1179
|
if (cert.is_authority) {
|
|
1051
1180
|
certParsed.asString = certificate;
|
|
1052
|
-
|
|
1181
|
+
candidateCAs.set(certParsed.subject, certificate);
|
|
1053
1182
|
}
|
|
1054
1183
|
}
|
|
1055
|
-
for (const cert of
|
|
1184
|
+
for (const cert of certRecords) {
|
|
1056
1185
|
try {
|
|
1057
1186
|
if (cert.is_authority) {
|
|
1058
1187
|
continue;
|
|
@@ -1070,8 +1199,8 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1070
1199
|
const private_key = getPrivateKeyByName(cert.private_key_name);
|
|
1071
1200
|
let certificate = cert.certificate;
|
|
1072
1201
|
const certParsed = new node_crypto_1.X509Certificate(certificate);
|
|
1073
|
-
if (
|
|
1074
|
-
certificate += '\n' +
|
|
1202
|
+
if (candidateCAs.has(certParsed.issuer)) {
|
|
1203
|
+
certificate += '\n' + candidateCAs.get(certParsed.issuer);
|
|
1075
1204
|
}
|
|
1076
1205
|
if (!private_key || !certificate) {
|
|
1077
1206
|
throw new Error('Missing private key or certificate for secure server');
|
|
@@ -1079,8 +1208,10 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1079
1208
|
const secureOptions = {
|
|
1080
1209
|
ciphers: cert.ciphers,
|
|
1081
1210
|
ticketKeys: (0, manageThreads_js_1.getTicketKeys)(),
|
|
1082
|
-
|
|
1083
|
-
|
|
1211
|
+
// the live map, not the candidate: its identity survives publication, so contexts
|
|
1212
|
+
// keep seeing the current CA set after later rebuilds
|
|
1213
|
+
availableCAs: caCerts,
|
|
1214
|
+
ca: mtlsOptions && Array.from(candidateCAs.values()),
|
|
1084
1215
|
cert: certificate,
|
|
1085
1216
|
key: private_key,
|
|
1086
1217
|
key_file: cert.private_key_name,
|
|
@@ -1099,7 +1230,7 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1099
1230
|
secureContext.name = cert.name;
|
|
1100
1231
|
secureContext.options = secureOptions;
|
|
1101
1232
|
secureContext.quality = quality;
|
|
1102
|
-
secureContext.certificateAuthorities = Array.from(
|
|
1233
|
+
secureContext.certificateAuthorities = Array.from(candidateCAs);
|
|
1103
1234
|
// we store the first 100 bytes of the certificate just for debug logging
|
|
1104
1235
|
secureContext.certStart = certificate.toString().slice(0, 100);
|
|
1105
1236
|
// we want to configure SNI handling to pick the right certificate based on all the registered SANs
|
|
@@ -1107,14 +1238,14 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1107
1238
|
for (let hostname of hostnames) {
|
|
1108
1239
|
if (hostname) {
|
|
1109
1240
|
if (hostname[0] === '*') {
|
|
1110
|
-
|
|
1241
|
+
candidateHasWildcards = true;
|
|
1111
1242
|
hostname = hostname.slice(1);
|
|
1112
1243
|
}
|
|
1113
1244
|
// we use this certificate if it has a higher quality than the existing one for this hostname
|
|
1114
|
-
let existingCertQuality =
|
|
1245
|
+
let existingCertQuality = candidateContexts.get(hostname)?.quality ?? 0;
|
|
1115
1246
|
logger.trace?.('Assigning TLS for hostname', hostname, 'if', quality, '>', existingCertQuality);
|
|
1116
1247
|
if (quality > existingCertQuality) {
|
|
1117
|
-
|
|
1248
|
+
candidateContexts.set(hostname, secureContext);
|
|
1118
1249
|
}
|
|
1119
1250
|
}
|
|
1120
1251
|
else {
|
|
@@ -1124,54 +1255,147 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1124
1255
|
logger.trace?.('Adding TLS', secureContext.name, 'for', server?.ports || 'client', 'cert named', cert.name, 'hostnames', hostnames, 'quality', quality, 'best quality', bestQuality);
|
|
1125
1256
|
if (quality > bestQuality /* && hasIpAddress*/) {
|
|
1126
1257
|
// we use this certificate as the default if it has a higher quality than the existing one
|
|
1127
|
-
|
|
1258
|
+
candidateDefault = secureContext;
|
|
1128
1259
|
defaultContextSetThisPass = true;
|
|
1129
1260
|
bestQuality = quality;
|
|
1130
|
-
if (server) {
|
|
1131
|
-
server.defaultContext = secureContext;
|
|
1132
|
-
// note that we can not set the secure context on the server here, because this creates an
|
|
1133
|
-
// indeterminate situation of whether openssl will use this certificate or the one from the SNI
|
|
1134
|
-
// callback
|
|
1135
|
-
//server.setSecureContext?.(server, secureOptions);
|
|
1136
|
-
}
|
|
1137
1261
|
}
|
|
1138
1262
|
}
|
|
1139
1263
|
catch (error) {
|
|
1140
|
-
|
|
1264
|
+
failedThisPass.push({ cert, error });
|
|
1141
1265
|
}
|
|
1142
1266
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
//
|
|
1161
|
-
//
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1267
|
+
// Retain-last-good: a record still in the table whose build failed keeps its live
|
|
1268
|
+
// hostname entries and its default candidacy; deletion remains the way to drop them.
|
|
1269
|
+
// On an mTLS listener whose CA set changed, the retained pair is rebuilt against the
|
|
1270
|
+
// current trust material — new handshakes never see stale trust (established sessions
|
|
1271
|
+
// and outstanding tickets are unaffected, as on any build); if the rebuild fails the entries drop
|
|
1272
|
+
// unless nothing else is servable (the zero-cert guard below then keeps the old
|
|
1273
|
+
// state). Full contract in DESIGN.md "TLS hot-reload".
|
|
1274
|
+
const caSetUnchanged = (previous) => {
|
|
1275
|
+
const builtWith = previous.certificateAuthorities;
|
|
1276
|
+
if (!Array.isArray(builtWith))
|
|
1277
|
+
return candidateCAs.size === 0;
|
|
1278
|
+
return (builtWith.length === candidateCAs.size &&
|
|
1279
|
+
builtWith.every(([subject, pem]) => candidateCAs.get(subject) === pem));
|
|
1280
|
+
};
|
|
1281
|
+
const rebuiltRetentions = new Map();
|
|
1282
|
+
const retentionFailures = [];
|
|
1283
|
+
const retainable = (previous) => {
|
|
1284
|
+
// Without mTLS nothing consulted depends on the CA set — skip the rebuild, but
|
|
1285
|
+
// refresh the CA bookkeeping mirrored into socket metadata for fronting proxies.
|
|
1286
|
+
if (!mtlsOptions || caSetUnchanged(previous)) {
|
|
1287
|
+
previous.certificateAuthorities = Array.from(candidateCAs);
|
|
1288
|
+
return previous;
|
|
1289
|
+
}
|
|
1290
|
+
if (rebuiltRetentions.has(previous))
|
|
1291
|
+
return rebuiltRetentions.get(previous);
|
|
1292
|
+
try {
|
|
1293
|
+
const secureOptions = {
|
|
1294
|
+
...previous.options,
|
|
1295
|
+
ticketKeys: (0, manageThreads_js_1.getTicketKeys)(),
|
|
1296
|
+
availableCAs: caCerts,
|
|
1297
|
+
ca: mtlsOptions && Array.from(candidateCAs.values()),
|
|
1298
|
+
};
|
|
1299
|
+
const rebuilt = tls.createSecureContext(secureOptions);
|
|
1300
|
+
rebuilt.name = previous.name;
|
|
1301
|
+
rebuilt.options = secureOptions;
|
|
1302
|
+
rebuilt.quality = previous.quality;
|
|
1303
|
+
rebuilt.certificateAuthorities = Array.from(candidateCAs);
|
|
1304
|
+
rebuilt.certStart = previous.certStart;
|
|
1305
|
+
rebuiltRetentions.set(previous, rebuilt);
|
|
1306
|
+
return rebuilt;
|
|
1307
|
+
}
|
|
1308
|
+
catch (error) {
|
|
1309
|
+
retentionFailures.push({
|
|
1310
|
+
cert: { name: `${previous.name} (retained-context rebuild)` },
|
|
1311
|
+
error,
|
|
1312
|
+
});
|
|
1313
|
+
rebuiltRetentions.set(previous, undefined);
|
|
1314
|
+
return undefined;
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
for (const { cert } of failedThisPass) {
|
|
1318
|
+
// Ties go to the incumbent: a hostname the retained context already owned, and the
|
|
1319
|
+
// live default when it is the retained record, must not flip to an equal-quality
|
|
1320
|
+
// sibling because of a transient failure. A context retained only for a hostname
|
|
1321
|
+
// still needs strict > to become the default.
|
|
1322
|
+
const retain = (previous, hostname) => {
|
|
1323
|
+
const retained = retainable(previous);
|
|
1324
|
+
if (!retained)
|
|
1325
|
+
return;
|
|
1326
|
+
const previousQuality = retained.quality ?? 0;
|
|
1327
|
+
if (hostname !== undefined) {
|
|
1328
|
+
if (previousQuality >= (candidateContexts.get(hostname)?.quality ?? 0)) {
|
|
1329
|
+
candidateContexts.set(hostname, retained);
|
|
1330
|
+
}
|
|
1331
|
+
if (hostname[0] === '.')
|
|
1332
|
+
candidateHasWildcards = true;
|
|
1333
|
+
}
|
|
1334
|
+
const winsDefault = previous === defaultContext ? previousQuality >= bestQuality : previousQuality > bestQuality;
|
|
1335
|
+
if (winsDefault) {
|
|
1336
|
+
candidateDefault = retained;
|
|
1337
|
+
defaultContextSetThisPass = true;
|
|
1338
|
+
bestQuality = previousQuality;
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
for (const [hostname, previous] of secureContexts) {
|
|
1342
|
+
if (previous.name === cert.name)
|
|
1343
|
+
retain(previous, hostname);
|
|
1344
|
+
}
|
|
1345
|
+
if (defaultContext?.name === cert.name)
|
|
1346
|
+
retain(defaultContext);
|
|
1347
|
+
}
|
|
1348
|
+
if (liveReload && candidateContexts.size === 0 && !defaultContextSetThisPass) {
|
|
1349
|
+
// Every row failed to apply (e.g. keys not yet on this thread). Publishing or
|
|
1350
|
+
// resolving would write an empty `certificates:` list (the #1998 symptom), so keep
|
|
1351
|
+
// live state and retry. `!defaultContextSetThisPass`, not the persistent
|
|
1352
|
+
// `defaultContext`: a cert with no usable hostnames still sets a serviceable
|
|
1353
|
+
// default (must resolve, not retry forever), while the closure variable is truthy
|
|
1354
|
+
// forever after the first success. Gated on liveReload: transient selectors
|
|
1355
|
+
// (getReplicationCert) legitimately resolve empty — bootstrap depends on that
|
|
1356
|
+
// meaning "no cert yet". Warn is latched: unlatched would emit ~57k lines/day.
|
|
1168
1357
|
if (server && !server.tlsSelectorWarnedZeroCerts) {
|
|
1169
1358
|
server.tlsSelectorWarnedZeroCerts = true;
|
|
1170
1359
|
logger.warn?.(`TLS selector for the '${type}' listener resolved zero certificates; retrying every ${TLS_REBUILD_DEBOUNCE_MS}ms`);
|
|
1171
1360
|
}
|
|
1172
|
-
|
|
1361
|
+
if (failedThisPass.length > 0) {
|
|
1362
|
+
// Surface WHY the pass came up empty and put the retry on the backoff.
|
|
1363
|
+
reportFailures(failedThisPass.concat(retentionFailures));
|
|
1364
|
+
scheduleFailureRetry();
|
|
1365
|
+
}
|
|
1366
|
+
else {
|
|
1367
|
+
scheduleRebuild();
|
|
1368
|
+
}
|
|
1173
1369
|
return;
|
|
1174
1370
|
}
|
|
1371
|
+
// Publish: reconcile the live maps in place (their identity is aliased by
|
|
1372
|
+
// server.secureContexts and every context's availableCAs) and advance all default
|
|
1373
|
+
// references together so SNI and non-SNI traffic can't diverge.
|
|
1374
|
+
secureContexts.clear();
|
|
1375
|
+
for (const [hostname, context] of candidateContexts)
|
|
1376
|
+
secureContexts.set(hostname, context);
|
|
1377
|
+
caCerts.clear();
|
|
1378
|
+
for (const [subject, certificate] of candidateCAs)
|
|
1379
|
+
caCerts.set(subject, certificate);
|
|
1380
|
+
// only listener selectors publish: a one-shot client selector's pass may see no authority rows
|
|
1381
|
+
if (liveReload)
|
|
1382
|
+
(0, trustedIssuers_ts_1.publishTrustedAuthorities)(caCerts.values());
|
|
1383
|
+
hasWildcards = candidateHasWildcards;
|
|
1384
|
+
if (candidateDefault) {
|
|
1385
|
+
SNICallback.defaultContext = defaultContext = candidateDefault;
|
|
1386
|
+
// note that we can not set the secure context on the server here, because this creates an
|
|
1387
|
+
// indeterminate situation of whether openssl will use this certificate or the one from the SNI
|
|
1388
|
+
// callback
|
|
1389
|
+
if (server)
|
|
1390
|
+
server.defaultContext = candidateDefault;
|
|
1391
|
+
}
|
|
1392
|
+
if (failedThisPass.length > 0) {
|
|
1393
|
+
reportFailures(failedThisPass.concat(retentionFailures));
|
|
1394
|
+
scheduleFailureRetry();
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
clearFailureState();
|
|
1398
|
+
}
|
|
1175
1399
|
// A successful pass ends any warn latches so a later recurrence logs again.
|
|
1176
1400
|
if (server) {
|
|
1177
1401
|
server.tlsSelectorWaitedForSystemDb = false;
|
|
@@ -1194,9 +1418,15 @@ function createTLSSelector(type, mtlsOptions, liveReload = true) {
|
|
|
1194
1418
|
}
|
|
1195
1419
|
}
|
|
1196
1420
|
server?.secureContextsListeners.forEach((listener) => listener());
|
|
1197
|
-
|
|
1421
|
+
settle(defaultContext);
|
|
1198
1422
|
}
|
|
1199
1423
|
catch (error) {
|
|
1424
|
+
if (readySettled) {
|
|
1425
|
+
// Live state is untouched (candidates are pass-local): keep serving it and retry.
|
|
1426
|
+
reportFailures([{ cert: { name: `(${type} rebuild pass)` }, error }]);
|
|
1427
|
+
scheduleFailureRetry();
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1200
1430
|
reject(error);
|
|
1201
1431
|
}
|
|
1202
1432
|
}
|