Skip to content

Commit be9f3e9

Browse files
keyring preview
1 parent 60b9974 commit be9f3e9

20 files changed

Lines changed: 302 additions & 132 deletions

File tree

mysql-test/suite/villagesql/examples/vsql-keyring-reader/r/keyring_no_component.result renamed to mysql-test/suite/villagesql/extension/vsql-keyring/r/keyring_no_component.result

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
SET PERSIST vsql_allow_preview_extensions = ON;
12
# Install extension
23
INSTALL EXTENSION vsql_keyring_reader;
34
# Read raises error when no keyring component is installed
@@ -23,6 +24,8 @@ vsql_keyring_reader.keyring_read('vsql_test_key', NULL)
2324
my_secret_value
2425
# Uninstall extension
2526
UNINSTALL EXTENSION vsql_keyring_reader;
27+
SET PERSIST vsql_allow_preview_extensions = OFF;
28+
RESET PERSIST vsql_allow_preview_extensions;
2629
# Uninstall keyring component
2730
# ----------------------------------------------------------------------
2831
# Teardown

mysql-test/suite/villagesql/examples/vsql-keyring-reader/r/keyring_read.result renamed to mysql-test/suite/villagesql/extension/vsql-keyring/r/keyring_read.result

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Creating manifest file for current MySQL server instance
55
# Re-starting mysql server with manifest file
66
# ----------------------------------------------------------------------
7+
SET PERSIST vsql_allow_preview_extensions = ON;
78
# Install extension
89
INSTALL EXTENSION vsql_keyring_reader;
910
# Store a secret in the keyring
@@ -30,6 +31,8 @@ vsql_keyring_reader.keyring_read(NULL, NULL) IS NULL
3031
1
3132
# Uninstall extension
3233
UNINSTALL EXTENSION vsql_keyring_reader;
34+
SET PERSIST vsql_allow_preview_extensions = OFF;
35+
RESET PERSIST vsql_allow_preview_extensions;
3336
# ----------------------------------------------------------------------
3437
# Teardown
3538
# Removing manifest file for current MySQL server instance

mysql-test/suite/villagesql/examples/vsql-keyring-reader/t/keyring_no_component.test renamed to mysql-test/suite/villagesql/extension/vsql-keyring/t/keyring_no_component.test

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
--source include/have_component_keyring_file.inc
55

6+
SET PERSIST vsql_allow_preview_extensions = ON;
7+
68
--echo # Install extension
79
INSTALL EXTENSION vsql_keyring_reader;
810

@@ -25,6 +27,8 @@ SELECT vsql_keyring_reader.keyring_read('vsql_test_key', NULL);
2527

2628
--echo # Uninstall extension
2729
UNINSTALL EXTENSION vsql_keyring_reader;
30+
SET PERSIST vsql_allow_preview_extensions = OFF;
31+
RESET PERSIST vsql_allow_preview_extensions;
2832

2933
--echo # Uninstall keyring component
3034
--source suite/component_keyring_file/inc/teardown_component.inc

mysql-test/suite/villagesql/examples/vsql-keyring-reader/t/keyring_read.test renamed to mysql-test/suite/villagesql/extension/vsql-keyring/t/keyring_read.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
--source include/have_component_keyring_file.inc
55
--source suite/component_keyring_file/inc/setup_component.inc
6+
SET PERSIST vsql_allow_preview_extensions = ON;
67

78
--echo # Install extension
89
--let $veb_dir = `SELECT @@veb_dir`
@@ -30,5 +31,7 @@ SELECT vsql_keyring_reader.keyring_read(NULL, NULL) IS NULL;
3031

3132
--echo # Uninstall extension
3233
UNINSTALL EXTENSION vsql_keyring_reader;
34+
SET PERSIST vsql_allow_preview_extensions = OFF;
35+
RESET PERSIST vsql_allow_preview_extensions;
3336

3437
--source suite/component_keyring_file/inc/teardown_component.inc

villagesql/CMakeLists.txt

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -243,20 +243,6 @@ IF(NOT WITHOUT_SERVER)
243243
INSTALL_COMMAND ""
244244
)
245245

246-
ExternalProject_Add(vsql_keyring_reader_extension
247-
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples/vsql-keyring-reader
248-
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/examples/vsql-keyring-reader-build
249-
CMAKE_GENERATOR ${CMAKE_GENERATOR}
250-
CMAKE_ARGS
251-
"-DCMAKE_PREFIX_PATH=${CMAKE_SOURCE_DIR}"
252-
"-DVillageSQLExtensionFramework_INCLUDE_DIR=${SDK_STAGING_DIR}/include-dev"
253-
"-DVillageSQL_VEB_INSTALL_DIR=${CMAKE_BINARY_DIR}/lib/veb"
254-
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
255-
DEPENDS sdk
256-
BUILD_ALWAYS ON
257-
INSTALL_COMMAND ""
258-
)
259-
260246
add_custom_target(copy_vsql_config_vars_test_veb
261247
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/veb_output_directory
262248
COMMAND ${CMAKE_COMMAND} -E copy
@@ -321,18 +307,6 @@ IF(NOT WITHOUT_SERVER)
321307
add_custom_target(range_clamp_test_veb ALL)
322308
add_dependencies(range_clamp_test_veb copy_vsql_range_clamp_test_veb)
323309

324-
add_custom_target(copy_vsql_keyring_reader_veb
325-
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/veb_output_directory
326-
COMMAND ${CMAKE_COMMAND} -E copy
327-
${CMAKE_CURRENT_BINARY_DIR}/examples/vsql-keyring-reader-build/vsql_keyring_reader.veb
328-
${CMAKE_BINARY_DIR}/veb_output_directory/
329-
DEPENDS vsql_keyring_reader_extension
330-
COMMENT "Copying vsql_keyring_reader.veb to veb_output_directory"
331-
)
332-
333-
add_custom_target(keyring_reader_veb ALL)
334-
add_dependencies(keyring_reader_veb copy_vsql_keyring_reader_veb)
335-
336310
ExternalProject_Add(vsql_test_only_extension
337311
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test-extensions/vsql-test-only
338312
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/test-extensions/vsql-test-only-build
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) 2026 VillageSQL Contributors
2+
//
3+
// This program is free software; you can redistribute it and/or
4+
// modify it under the terms of the GNU General Public License
5+
// as published by the Free Software Foundation; either version 2
6+
// of the License, or (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License, version 2.0, for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program; if not, see <https://www.gnu.org/licenses/>.
15+
16+
#ifndef VILLAGESQL_ABI_PREVIEW_KEYRING_H
17+
#define VILLAGESQL_ABI_PREVIEW_KEYRING_H
18+
19+
#include <stddef.h>
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
// Preview capability: "vsql::keyring"
26+
//
27+
// Provides access to the MySQL keyring component. Extensions that require
28+
// this capability can read and write secrets via the vtable functions below.
29+
//
30+
// Capability name: VEF_PREVIEW_KEYRING_NAME
31+
32+
#define VEF_PREVIEW_KEYRING_NAME "vsql::keyring"
33+
34+
typedef enum {
35+
VEF_KEYRING_OK = 0,
36+
VEF_KEYRING_NOT_FOUND = 1, // key does not exist
37+
VEF_KEYRING_UNAVAILABLE = 2, // no keyring component is installed
38+
VEF_KEYRING_ERROR = 3, // other error
39+
} vef_keyring_result_t;
40+
41+
// Read a secret from the MySQL keyring component.
42+
// data_id: identifier for the secret.
43+
// auth_id: owner of the secret, or NULL for internal keys.
44+
// buf: caller-provided buffer to receive the secret bytes.
45+
// buf_len: size of buf in bytes.
46+
// out_len: set to the actual number of bytes written on success.
47+
typedef vef_keyring_result_t (*vef_read_keyring_fn)(const char *data_id,
48+
const char *auth_id,
49+
unsigned char *buf,
50+
size_t buf_len,
51+
size_t *out_len);
52+
53+
// Write a secret to the MySQL keyring component.
54+
// data_id: identifier for the secret.
55+
// auth_id: owner of the secret, or NULL for internal keys.
56+
// data: secret bytes to store.
57+
// data_len: length of data in bytes.
58+
typedef vef_keyring_result_t (*vef_write_keyring_fn)(const char *data_id,
59+
const char *auth_id,
60+
const unsigned char *data,
61+
size_t data_len);
62+
63+
typedef struct {
64+
vef_read_keyring_fn read;
65+
vef_write_keyring_fn write;
66+
} vef_preview_keyring_t;
67+
68+
#ifdef __cplusplus
69+
}
70+
#endif
71+
72+
#endif // VILLAGESQL_ABI_PREVIEW_KEYRING_H

villagesql/sdk/include/villagesql/abi/types.h

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,8 @@ typedef enum : unsigned int {
170170
// + Extension system variables (vef_sys_var_desc_t):
171171
// server registers these as MySQL component system
172172
// variables on the extension's behalf.
173-
// + get_variable/set_variable/read_keyring/write_keyring
174-
// function pointers in vef_register_arg_t: access to
175-
// MySQL system variables and keyring component.
173+
// + get_variable/set_variable function pointers in
174+
// vef_register_arg_t: access to MySQL system variables.
176175
// + Preview capability system: extensions declare named
177176
// capabilities they require in vef_registration_t;
178177
// the server populates their function pointers before
@@ -230,35 +229,6 @@ typedef bool (*vef_set_variable_fn)(const char *component_name,
230229
const char *name, const char *scope,
231230
const char *val);
232231

233-
typedef enum {
234-
VEF_KEYRING_OK = 0,
235-
VEF_KEYRING_NOT_FOUND = 1, // key does not exist
236-
VEF_KEYRING_UNAVAILABLE = 2, // no keyring component is installed
237-
VEF_KEYRING_ERROR = 3, // other error
238-
} vef_keyring_result_t;
239-
240-
// read_keyring: read a secret from the MySQL keyring component.
241-
// data_id: identifier for the secret.
242-
// auth_id: owner of the secret, or NULL for internal keys.
243-
// buf: caller-provided buffer to receive the secret bytes.
244-
// buf_len: size of buf in bytes.
245-
// out_len: set to the actual number of bytes written on success.
246-
typedef vef_keyring_result_t (*vef_read_keyring_fn)(const char *data_id,
247-
const char *auth_id,
248-
unsigned char *buf,
249-
size_t buf_len,
250-
size_t *out_len);
251-
252-
// write_keyring: write a secret to the MySQL keyring component.
253-
// data_id: identifier for the secret.
254-
// auth_id: owner of the secret, or NULL for internal keys.
255-
// data: secret bytes to store.
256-
// data_len: length of data in bytes.
257-
typedef vef_keyring_result_t (*vef_write_keyring_fn)(const char *data_id,
258-
const char *auth_id,
259-
const unsigned char *data,
260-
size_t data_len);
261-
262232
typedef struct {
263233
// protocol >= VEF_PROTOCOL_1
264234
vef_protocol_t protocol;
@@ -268,14 +238,12 @@ typedef struct {
268238

269239
// protocol >= VEF_PROTOCOL_2
270240
// TODO(villagesql-beta): How do extension authors opt into requiring these
271-
// APIs? An extension that uses get_variable/set_variable/read_keyring/
272-
// write_keyring should be able to declare that dependency so the server can
273-
// reject loading it with a clear error on older servers that do not provide
274-
// these functions (where these pointers would be nullptr).
241+
// APIs? An extension that uses get_variable/set_variable should be able to
242+
// declare that dependency so the server can reject loading it with a clear
243+
// error on older servers that do not provide these functions (where these
244+
// pointers would be nullptr).
275245
vef_get_variable_fn get_variable;
276246
vef_set_variable_fn set_variable;
277-
vef_read_keyring_fn read_keyring;
278-
vef_write_keyring_fn write_keyring;
279247
} vef_register_arg_t;
280248

281249
typedef struct {

villagesql/sdk/include/villagesql/detail/vef_register.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ namespace sys_var {
3838
extern vef_get_variable_fn g_get_variable;
3939
extern vef_set_variable_fn g_set_variable;
4040
} // namespace sys_var
41-
namespace keyring {
42-
extern vef_read_keyring_fn g_read_keyring;
43-
extern vef_write_keyring_fn g_write_keyring;
44-
} // namespace keyring
4541

4642
// Define materialize_func_desc here so it is available to both old
4743
// (villagesql::func_builder) and new (vsql::func_builder) API users without
@@ -187,8 +183,6 @@ vef_registration_t *vef_register_impl(vef_registration_t &reg,
187183
if (arg->protocol >= VEF_PROTOCOL_2) {
188184
vsql::sys_var::g_get_variable = arg->get_variable;
189185
vsql::sys_var::g_set_variable = arg->set_variable;
190-
vsql::keyring::g_read_keyring = arg->read_keyring;
191-
vsql::keyring::g_write_keyring = arg->write_keyring;
192186
}
193187
}
194188

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright (c) 2026 VillageSQL Contributors
2+
//
3+
// This program is free software; you can redistribute it and/or
4+
// modify it under the terms of the GNU General Public License
5+
// as published by the Free Software Foundation; either version 2
6+
// of the License, or (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program; if not, see <https://www.gnu.org/licenses/>.
15+
16+
#ifndef VILLAGESQL_PREVIEW_KEYRING_H
17+
#define VILLAGESQL_PREVIEW_KEYRING_H
18+
19+
#include <string>
20+
#include <string_view>
21+
22+
#include <villagesql/abi/preview/keyring.h>
23+
#include <villagesql/detail/capability_hash.h>
24+
#include <villagesql/vsql/extension_builder.h>
25+
26+
namespace vsql::preview::keyring {
27+
28+
// C++ wrapper around vef_preview_keyring_t.
29+
//
30+
// Usage:
31+
// static auto g_keyring = vsql::preview::keyring::make_capability();
32+
//
33+
// // In extension code:
34+
// auto result = g_keyring.read("my-key", "", value);
35+
//
36+
// Register with:
37+
// make_extension().with<preview_keyring<g_keyring>>()
38+
class Capability {
39+
public:
40+
static constexpr const char *kName = VEF_PREVIEW_KEYRING_NAME;
41+
42+
// Read a secret from the MySQL keyring component into value.
43+
// auth_id may be empty to read internal keys.
44+
// Returns VEF_KEYRING_OK on success, VEF_KEYRING_NOT_FOUND if the key does
45+
// not exist, VEF_KEYRING_UNAVAILABLE if no keyring component is installed,
46+
// or VEF_KEYRING_ERROR on other failures.
47+
vef_keyring_result_t read(std::string_view data_id, std::string_view auth_id,
48+
std::string &value) const {
49+
if (abi_.read == nullptr) return VEF_KEYRING_UNAVAILABLE;
50+
value.resize(4096);
51+
size_t out_len = 0;
52+
vef_keyring_result_t result =
53+
abi_.read(data_id.data(), auth_id.empty() ? nullptr : auth_id.data(),
54+
reinterpret_cast<unsigned char *>(value.data()), value.size(),
55+
&out_len);
56+
if (result == VEF_KEYRING_OK) value.resize(out_len);
57+
return result;
58+
}
59+
60+
// Write a secret to the MySQL keyring component.
61+
// auth_id may be empty to store as an internal key.
62+
// Returns VEF_KEYRING_OK on success, VEF_KEYRING_UNAVAILABLE if no keyring
63+
// component is installed, or VEF_KEYRING_ERROR on other failures.
64+
vef_keyring_result_t write(std::string_view data_id, std::string_view auth_id,
65+
std::string_view data) const {
66+
if (abi_.write == nullptr) return VEF_KEYRING_UNAVAILABLE;
67+
return abi_.write(
68+
data_id.data(), auth_id.empty() ? nullptr : auth_id.data(),
69+
reinterpret_cast<const unsigned char *>(data.data()), data.size());
70+
}
71+
72+
bool available() const { return abi_.read != nullptr; }
73+
74+
// Public so that cap_receive() can access abi_ via a pointer.
75+
// Do not access directly — use read(), write(), and available() instead.
76+
vef_preview_keyring_t abi_;
77+
};
78+
79+
inline Capability make_capability() { return Capability{}; }
80+
81+
} // namespace vsql::preview::keyring
82+
83+
namespace vsql::preview {
84+
85+
// Traits type for registering the keyring capability via
86+
// .with<preview_keyring<cap>>. Only available when this header is included.
87+
template <auto &cap>
88+
struct preview_keyring {
89+
template <typename Inner>
90+
static constexpr auto bind(Inner builder) {
91+
using Cap = keyring::Capability;
92+
return builder.required_capability(
93+
{Cap::kName, &::vsql::cap_receive<Cap, &cap>,
94+
::villagesql::detail::abi_type_hash<decltype(cap.abi_)>()});
95+
}
96+
};
97+
98+
} // namespace vsql::preview
99+
100+
#endif // VILLAGESQL_PREVIEW_KEYRING_H

0 commit comments

Comments
 (0)