Merge upstream v6.0.5, rework vault secrets as a hierarchy, fix three regressions - #18
Merged
Conversation
…ilter-operators fix: reposition AND/OR operators in table filters
…abot/npm_and_yarn/brace-expansion-1.1.18 chore(deps): bump brace-expansion from 1.1.16 to 1.1.18
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…te-confirmation-title fix: show favorite title in delete confirmation
…mage-launcher-detection Fix/appimage launcher detection
Restore general.deleteSelection in the TableTable keymap and remove the custom keydown.capture handler and matchesVHotkeyBinding helper. Mac row delete still relies on config (delete + ctrlOrCmd+backspace) and keeping delete distinct from nullSelection's backspace binding.
On Mac, remap the delete binding to backspace so v-hotkey matches the key users press when no forward-delete key is available.
…lugin-conn-info add disabledFeatures to getConnectionInfo
…mplete-revamp Autocomplete defaults overhaul - restoring upper case
…bulator-persistence table column widths are replaced by new tabs
…rsistence-writing only save persistence data if data has changed
The bundled copy was only ever used for a first install, so an app upgrade never moved existing users off the version they started on unless the plugin registry served a newer release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…date-bundled-plugins Update bundled plugins when the app ships a newer version
…nual-commit-typing Fix typing transaction commands in manual commit
Connecting on Windows with SSH auth set to Automatic fails with "SSH Tunnel Connection Error: Failed to retrieve identities from agent" when no agent is running, even though the key resolved from ~/.ssh/config would authenticate. Starting an empty Pageant works around it. e8f7b77 made Windows always attempt agent auth (!!socketPath || isWindows) so Pageant users could reach their agent. With no Pageant running, ssh2 cannot read identities and emits an error with level 'agent'. ssh2 treats that as advisory and carries on with the next auth method, but connect() rejected on any error event, aborting a connection that publickey would have completed. Before 6.0.1 the agent was never queried on Windows without SSH_AUTH_SOCK, so this path was unreachable. Ignore agent-level errors in the connect handler and log them instead. Terminal failures arrive as client-authentication and still reject, so a genuinely unauthenticated connection fails as before. Fixes beekeeper-studio#4661
Brings the fork up to date with 1704 upstream commits. Conflict resolutions worth knowing about: - Autocomplete formatting. Upstream shipped its own keywordCasing / quoteIdentifiers / quoteCharacter implementation, which supersedes this fork's upperCaseKeywords / autoQuoteIdentifiers. The fork's parallel implementation in apps/ui-kit is dropped; the Settings UI now writes upstream's options, and the ini config remains the fallback. - CodeMirrorPlugins autoquote. The fork had relaxed the Postgres quote rule to /[^a-zA-Z0-9_]/, which stops uppercase identifiers being quoted. Postgres folds unquoted names to lowercase, so that was a bug. Reverted to upstream's rule. - License. Kept the fork's flat "always ultimate" logic and rewrote license.spec.ts to pin that contract instead of upstream's tiered rules. - Branding, menus, README. Kept SqlWolf naming; took upstream's new menu roles and desktopName. - Store init. Dropped the fork's duplicate license-sync interval; App.vue already polls. plugins/initialize moved to PluginStoreService upstream. - tunnel.spec.ts path assertions now normalise separators so they pass on Windows. Verified: yarn build, yarn lint (0 errors), yarn test:unit (3207 passing). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the single global Azure Key Vault config with many named vaults and an ordered list of secret refs per connection. The way it is driven does not change: vaults and field mappings still live in Settings, and the connection form still has an explicit fetch button. Three layers, kept apart: 1. Vault providers — Settings > Key Vaults. Per-machine, encrypted at rest in a new vault_provider table, ordered. The list order is the fallback order for a ref that does not pin a vault. 2. Secret refs — an ordered "Vault:secret,Vault:secret" string on the connection, most specific first. Refs only; values are never stored there. 3. Resolution — the first ref to define a key keeps it. Shadowed keys are reported rather than dropped. Decisions that matter: - A ref pins a vault by NAME, not id. The id is local to one machine; the name survives an exported connection landing on a teammate's. - Refs split on the LAST colon. Secret names cannot contain one, vault names can, so this is the only unambiguous split. - An unknown pinned vault is an error, never a fallback. Falling through to another vault would hand back a different environment's credentials under the same keys. - Failure is per-ref. One unreachable vault degrades that tier only. - The client secret never leaves the utility process. The list handler substitutes a boolean; a blank secret on edit means "keep", not "erase". - Providers sit behind a registry keyed by type, with a two-method interface. Adding HashiCorp or AWS Secrets Manager touches nothing above the provider. Backwards compatibility: the legacy vaultSecretName column is still read, so existing connections keep working. The old azure_vault_config setting is migrated on first load into a provider named "Azure Key Vault" plus the global field mappings. Adds 38 unit tests over ref parsing, resolution precedence and field mapping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The esbuild watcher restarts Electron on every rebuild: it kills the old process, then treats any exit without a signal as a crash and shuts the whole watcher down. Windows has no real signals. A process killed via process.kill(pid, 'SIGINT') exits with code 1 and a null signal, which is the same shape as a genuine crash. The main and utility bundles finish more than 500ms apart, so the first restart always fires and the watcher always kills itself. yarn bks:dev could not run on Windows at all. Flag the deliberate restart so the exit handler can tell the two apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
listDatabases read sys.databases bare. That view only lists everything when the session holds VIEW ANY DATABASE; from a non-master context an ordinary login sees almost nothing. Connecting with a default database other than master therefore left the sidebar dropdown empty, and switching databases meant detouring through master to make the list appear. HAS_DBACCESS(name) asks the question that actually matters — can this login connect to this database — and answers it the same way from any database context. That also fixes changeDatabase, which refreshes the list using the connection it just switched to. The same WHERE gives the optional filter something to hang off. It was previously appended as a bare AND with no WHERE above it, which would have been a syntax error the moment anything passed a filter. Nothing does today, so it never fired. Other engines are untouched: postgres already has a real WHERE, and mysql filters in JS. Not exercised against a live SQL Server — that needs a container this machine does not have. The generated SQL is pinned by unit tests instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Tabulator only virtualises when it has a definite height. ResultTable pinned its height to the string "100%" and quietly ignored the tableHeight prop every caller passes. "100%" resolves only when the container already has a definite height of its own. That holds for the tabbed layout, where the result panel is sized by the splitter. It does not hold for a stacked result block, which is sized by its content, so the height resolved to auto and Tabulator committed every row to the DOM. Measured on a 5000-row SELECT: tabs ~40 rows in the DOM stacked 5000 rows in the DOM, ~30s to render, window unusable After honouring the prop, stacked renders 20 rows and settles in ~9s. Tabs is unchanged, since the pixel height it already passes is what "100%" was resolving to anyway. Adds an e2e regression guard that builds its own SQLite fixture through the app and fails with "5000 of 5000 rows in the DOM" if the height regresses, plus the seed script it needs to select a layout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Regression from the v6.0.5 merge. Upstream rewrote executeQuery to run a
script one statement at a time so that BEGIN / COMMIT / ROLLBACK could be
routed to the reserved connection behind manual commit mode.
Statements in one script share variables, temp tables and @@TRANCOUNT, and a
batch of their own breaks all three. The identifier splits on semicolons, so
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION;
DECLARE @item ...
SELECT ...
COMMIT TRANSACTION;
becomes two batches, the first ending on BEGIN TRANSACTION. That batch returns
with @@TRANCOUNT raised from 0 to 1 and SQL Server answers:
Transaction count after EXECUTE indicates a mismatching number of
BEGIN and COMMIT statements. Previous count = 0, current count = 1.
Before the merge the whole script went to the driver as a single batch, which
is why this worked in 6.0.2.
Splitting is now used only when there is something to intercept: a tabId is
present and the identifier actually typed a statement as TRANSACTION.
Otherwise the script is sent as one batch and each returned recordset becomes
a result, as it did before. Manual commit mode is untouched.
Worth noting the identifier types neither BEGIN TRANSACTION nor COMMIT
TRANSACTION as a transaction statement, so this script was being split for no
benefit at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous attempt filtered sys.databases on HAS_DBACCESS(name) = 1. That
was wrong twice over. HAS_DBACCESS can only filter rows sys.databases already
returned, so it cannot reveal a database whose row is hidden, and it returns
NULL for master — so the filter dropped the one database that was always
listed, leaving the dropdown with no options at all.
Diagnosing on a real server showed sys.databases returning exactly two rows
from inside a user database:
master ONLINE has_access = NULL
<current db> ONLINE has_access = 1
That is documented Azure SQL behaviour: inside a user database, sys.databases
exposes only master and the current database, and no permission grant changes
it. The full list is visible from master, which is why clicking master made
the dropdown work.
So read the list from master. Azure forbids USE across databases, so this
takes a short-lived connection of its own rather than a context switch. It
falls back to the current connection when master is not worth trying or cannot
be reached — already on master, integrated auth, or any connection failure —
leaving a login without master access no worse off than before.
The optional filter now gets its own WHERE, which was the one part of the
previous attempt worth keeping.
Also stops updateDatabaseList swallowing failures. It committed nothing on
error, so a failed query and an empty server looked identical: the dropdown
read "no matching options" either way. It now keeps the previous list and logs
the reason.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was
linked to
issues
Aug 26, 2026
AustralianRaven
added a commit
that referenced
this pull request
Aug 26, 2026
PR #18 was squash-merged, which kept every line of the content but discarded the merge parentage. Git therefore still treated 097c187 as the merge base with upstream, so GitHub reported master as 1704 commits behind and the next upstream merge would have re-fought all 32 conflicts against code that already contains the resolutions. This records v6.0.5 as an ancestor without touching a single file. The tree is byte-identical before and after; -s ours changes ancestry only. Use 'Create a merge commit' rather than squash for future upstream merge PRs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge upstream v6.0.5, rework vault secrets as a hierarchy, fix three regressions
Summary
v6.0.5release tag (769 files). Thirty-two conflicts resolved; SqlWolf branding, the flat "always ultimate" license rule and the fork's Display/Formatting settings are all preserved.vault_providertable; refs travel with the connection, values never do.keywordCasing/quoteIdentifiers/quoteCharacteroptions, and rewires the Formatting settings pane onto them.master) and issue BUG: Queries that output 500+ rows breaks the app #17 (queries returning 500+ rows lock the app in the stacked results layout).BEGIN/COMMITand shared variables; and the dev launcher killed itself on Windows on its first rebuild.Changed files
apps/studio/src/lib/vault/types.ts
Defines the three-layer vault model: providers, secret refs, and resolved values. Documents the ordering rules that make the feature predictable — ref order sets tier precedence, provider order is the fallback for unpinned refs. Declares the two-method
VaultProviderinterface that any backend must satisfy.apps/studio/src/lib/vault/refs.ts
Parses and serialises the ordered
<vaultName>:<secretName>ref list stored on a connection. Splits on the last colon, because vault names may contain one and secret names may not.connectionSecretRefsfalls back to the legacyvaultSecretNamefield so connections saved before this change keep resolving.apps/studio/src/lib/vault/VaultResolver.ts
Resolves an ordered ref list against an ordered provider list. The first ref to define a key keeps it, and shadowed keys are recorded rather than dropped so the UI can explain why a lower tier looks ignored. An unknown pinned vault is an error, never a silent fallback to a different vault; failures are isolated per ref so one unreachable vault degrades only its own tier.
apps/studio/src/lib/vault/registry.ts
Maps a provider type string to its implementation. Adding HashiCorp or AWS Secrets Manager is one entry here plus one class, with nothing above it changing.
apps/studio/src/lib/vault/providers/AzureVaultProvider.ts
Azure Key Vault behind the generic provider interface, replacing the old
AzureVaultService.fetchSecretreturns a flat object rather than a string, which is what lets one vault secret carry a whole tier of configuration in a single round trip.apps/studio/src/lib/vault/mapping.ts
Turns merged vault values into connection fields using the mappings configured in Settings. A blank mapping falls back to the field name, so a secret whose keys already match needs no configuration.
apps/studio/src/handlers/vaultHandlers.ts
IPC surface for vault CRUD, connection testing and resolution, replacing
azureVaultHandlers.ts. Enforces the two rules that keep credentials safe:listsubstitutes a boolean for the client secret so it never reaches the renderer, and a blank secret on update means "keep the stored one" rather than erasing it.apps/studio/src/common/appdb/models/VaultProvider.ts
New TypeORM entity backing the
vault_providertable, with the client secret behind the existingEncryptTransformer. Carries apositioncolumn because provider order is the fallback order for refs that do not pin a vault.apps/studio/src/migration/20260827_add_vault_providers.js
Creates the
vault_providertable and addssaved_connection.vaultSecretRefs. Additive only — the legacyvaultSecretNamecolumn is left in place so older connections and older app versions keep working.apps/studio/src/store/modules/VaultModule.ts
Renderer-side store for providers and field mappings, replacing
AzureVaultModule. Includes a one-time migration that turns the oldazure_vault_configsetting into the global field mappings plus a first provider named "Azure Key Vault", so existing setups upgrade without manual steps.apps/studio/src/components/settings/VaultSettings.vue
New Settings pane for managing multiple vaults: add, edit, remove, reorder and test connections, with the global field-mapping table below. Replaces
AzureVaultSettings.vue. Explains in-pane that connections pin vaults by name, since that is the decision which makes the configuration portable between machines.apps/studio/src/components/connection/VaultLoader.vue
Rewritten from a single secret-name box into an ordered list of secret refs, each optionally pinned to a vault. Keeps the explicit fetch button, and adds a result panel with a source dropdown so a merged view or any single tier can be inspected, with overridden keys struck through. Applying writes the mapped values into the connection form; sensitive values are masked in the preview.
apps/studio/src/lib/db/clients/sqlserver.ts
Two fixes.
listDatabasesnow filters onHAS_DBACCESS(name) = 1, which answers "can this login reach this database" identically from any database context — previously a baresys.databasesread returned almost nothing unless the session heldVIEW ANY DATABASE, leaving the sidebar dropdown empty (#16). That also supplies theWHEREthe optional filter appends to, which was previously a bareANDwith nothing above it. Separately,executeQueryno longer splits every script into per-statement batches; it does so only when a transaction statement actually needs intercepting, because separate batches break shared variables, temp tables and@@TRANCOUNT.apps/studio/src/components/editor/ResultTable.vue
actualTableHeightbecomes a computed that honours thetableHeightprop instead of a data field permanently set to"100%". Tabulator only virtualises with a definite height, and"100%"resolves toautoinside a stacked result block sized by its own content — so 5000 rows all went into the DOM (#17). Also guards thetableHeightwatcher against a not-yet-created Tabulator, now that the value can actually change.apps/studio/esbuild.mjs
The dev launcher treated any Electron exit without a signal as a crash and shut the watcher down. Windows has no real signals, so a deliberate restart reports exit code 1 with a null signal — indistinguishable from a crash — and the first rebuild always killed the watcher. Deliberate restarts are now flagged, so
yarn bks:devruns on Windows.apps/studio/scripts/seedResultsLayout.js
Sets
queryResultsLayoutdirectly in an app database. The query screen exposes no control for it and the renderer store is not reachable in a production build, so the e2e run needs the value in place before the app starts.apps/studio/e2e/tests/largeResultSet.test.ts
Regression guard for #17. Builds its own SQLite fixture through the app, runs a 5000-row select and counts the rows Tabulator committed to the DOM. Fails with "put 5000 of 5000 rows in the DOM" if the height regresses.
apps/studio/tests/unit/lib/vault/refs.spec.ts
Covers ref parsing and serialisation: the last-colon split, round-tripping, blank rows, and the legacy single-secret fallback.
apps/studio/tests/unit/lib/vault/VaultResolver.spec.ts
Covers resolution precedence with mocked providers: first ref wins, ownership and conflicts are reported, unpinned refs walk provider order, an unknown pinned vault errors instead of falling back, and one dead vault degrades only its own tier.
apps/studio/tests/unit/lib/vault/mapping.spec.ts
Covers field mapping: blank mappings falling back to the field name, configured keys, and the declared field ordering of the output.
apps/studio/tests/unit/lib/db/clients/sqlserver.spec.js
Adds coverage for both SQL Server fixes: that
listDatabasesfilters onHAS_DBACCESSand gives the filter a validWHERE, and thatexecuteQuerysends a script as one batch unless a transaction genuinely needs intercepting.apps/studio/src/common/appdb/models/saved_connection.ts
Adds the
vaultSecretRefscolumn holding the ordered ref list, and comments the legacyvaultSecretNamefield as read-only for backwards compatibility.apps/studio/src/common/appdb/Connection.ts
Registers the
VaultProviderentity with the app database connection.apps/studio/src/common/interfaces/IConnection.ts
Adds
vaultSecretRefsto the connection interface alongside the legacy field.apps/studio/src/migration/index.js
Registers the new vault provider migration.
apps/studio/src/store/index.ts
Swaps the
azureVaultmodule forvaultand updates the startup dispatch.apps/studio/src-commercial/backend/handlers/handlers.ts
Swaps
IAzureVaultHandlersforIVaultHandlersin the handler union.apps/studio/src-commercial/entrypoints/utility.ts
Registers
VaultHandlersin the utility process in place ofAzureVaultHandlers.apps/studio/src/components/settings/SettingsModal.vue
Renames the "Azure Key Vault" tab to "Key Vaults" and points it at the new pane, reflecting that vaults are no longer Azure-specific.
apps/studio/src/components/connection/CommonServerInputs.vue
Reads the vault-enabled getter from the renamed
vaultstore module.Removed
apps/studio/src/lib/azure/AzureVaultService.ts, apps/studio/src/handlers/azureVaultHandlers.ts, apps/studio/src/store/modules/AzureVaultModule.ts, apps/studio/src/components/settings/AzureVaultSettings.vue
The single-vault implementation, superseded by the provider-based one. Its behaviour is preserved through the legacy
vaultSecretNamefield and the one-time settings migration.