@aigne/secrets 0.1.1-beta.1 → 0.1.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.1-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/secrets-v0.1.1-beta.2...secrets-v0.1.1-beta.3) (2025-11-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **secrets:** simplify default item handling in KeyringStore ([#780](https://github.com/AIGNE-io/aigne-framework/issues/780)) ([4c1ff51](https://github.com/AIGNE-io/aigne-framework/commit/4c1ff51e982ed5787df37b127a381276537ec92f))
9
+
10
+ ## [0.1.1-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/secrets-v0.1.1-beta.1...secrets-v0.1.1-beta.2) (2025-11-27)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **secrets:** improve keyring availability detection with environment checks ([#778](https://github.com/AIGNE-io/aigne-framework/issues/778)) ([75dceab](https://github.com/AIGNE-io/aigne-framework/commit/75dceabeb7d6fd8c057759f003e703a2ebb41afd))
16
+
3
17
  ## [0.1.1-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/secrets-v0.1.1-beta...secrets-v0.1.1-beta.1) (2025-11-26)
4
18
 
5
19
 
@@ -3,8 +3,9 @@ import type { CredentialEntry, ItemInfo, StoreOptions } from "./types.js";
3
3
  export declare class KeyringStore extends BaseSecretStore {
4
4
  private _impl;
5
5
  private serviceName;
6
- private defaultAccount;
7
6
  private _forceUnavailable;
7
+ private _environmentChecked;
8
+ private _environmentReady;
8
9
  constructor(options: StoreOptions);
9
10
  available(): Promise<boolean>;
10
11
  setItem(key: string, value: ItemInfo): Promise<any>;
package/lib/cjs/keytar.js CHANGED
@@ -34,24 +34,38 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.KeyringStore = void 0;
37
+ const logger_js_1 = require("@aigne/core/utils/logger.js");
37
38
  const base_js_1 = require("./base.js");
38
- const DEFAULT_SERVICE_NAME = "-secrets";
39
- const DEFAULT_ACCOUNT_NAME_FOR_DEFAULT = "-default";
39
+ const util_js_1 = require("./util.js");
40
+ const DEFAULT_SERVICE_NAME = "-api-key";
41
+ const DEFAULT_ACCOUNT_NAME_FOR_DEFAULT = "default";
40
42
  class KeyringStore extends base_js_1.BaseSecretStore {
41
43
  _impl = null;
42
44
  serviceName;
43
- defaultAccount;
44
45
  _forceUnavailable;
46
+ _environmentChecked = false;
47
+ _environmentReady = false;
45
48
  constructor(options) {
46
49
  super();
47
50
  const { serviceName, forceKeytarUnavailable = false } = options;
48
51
  this.serviceName = `${serviceName}${DEFAULT_SERVICE_NAME}`;
49
- this.defaultAccount = `${serviceName}${DEFAULT_ACCOUNT_NAME_FOR_DEFAULT}`;
50
52
  this._forceUnavailable = !!forceKeytarUnavailable;
51
53
  }
52
54
  async available() {
53
55
  if (this._forceUnavailable)
54
56
  return false;
57
+ // Check environment prerequisites before attempting to load the module
58
+ if (!this._environmentChecked) {
59
+ const { ready, reason } = (0, util_js_1.isKeyringEnvironmentReady)();
60
+ this._environmentReady = ready;
61
+ if (!ready) {
62
+ logger_js_1.logger.warn(`Keyring environment not ready: ${reason}`);
63
+ }
64
+ this._environmentChecked = true;
65
+ }
66
+ if (!this._environmentReady) {
67
+ return false;
68
+ }
55
69
  try {
56
70
  if (!this._impl) {
57
71
  const module = await Promise.resolve().then(() => __importStar(require("@zowe/secrets-for-zowe-sdk")));
@@ -62,7 +76,8 @@ class KeyringStore extends base_js_1.BaseSecretStore {
62
76
  typeof this._impl.setPassword === "function" &&
63
77
  typeof this._impl.deletePassword === "function");
64
78
  }
65
- catch {
79
+ catch (error) {
80
+ logger_js_1.logger.error(`Failed to load keyring: ${error.message}`);
66
81
  return false;
67
82
  }
68
83
  }
@@ -109,7 +124,9 @@ class KeyringStore extends base_js_1.BaseSecretStore {
109
124
  try {
110
125
  if (typeof this._impl.findCredentials === "function") {
111
126
  const list = await this._impl.findCredentials(this.serviceName);
112
- return Array.isArray(list) && list.length > 0 ? list : null;
127
+ return Array.isArray(list) && list.length > 0
128
+ ? list.filter((c) => c.account !== DEFAULT_ACCOUNT_NAME_FOR_DEFAULT)
129
+ : null;
113
130
  }
114
131
  return null;
115
132
  }
@@ -148,33 +165,21 @@ class KeyringStore extends base_js_1.BaseSecretStore {
148
165
  throw new Error("Keyring not available");
149
166
  if (!this._impl)
150
167
  throw new Error("Keyring not loaded");
151
- const account = this.defaultAccount;
152
- return this._impl.setPassword(account, account, JSON.stringify(value));
168
+ return this.setItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT, value);
153
169
  }
154
170
  async getDefaultItem() {
155
171
  if (!(await this.available()))
156
172
  return null;
157
173
  if (!this._impl)
158
174
  return null;
159
- const account = this.defaultAccount;
160
- try {
161
- const value = await this._impl.getPassword(account, account);
162
- if (!value)
163
- return null;
164
- return this.parseKey(value);
165
- }
166
- catch {
167
- // ignore
168
- }
169
- return null;
175
+ return this.getItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT);
170
176
  }
171
177
  async deleteDefaultItem() {
172
178
  if (!(await this.available()))
173
179
  throw new Error("Keyring not available");
174
180
  if (!this._impl)
175
181
  throw new Error("Keyring not loaded");
176
- const account = this.defaultAccount;
177
- await this._impl.deletePassword(account, account);
182
+ await this.deleteItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT);
178
183
  }
179
184
  }
180
185
  exports.KeyringStore = KeyringStore;
@@ -0,0 +1,4 @@
1
+ export declare function isKeyringEnvironmentReady(): {
2
+ ready: boolean;
3
+ reason?: string;
4
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isKeyringEnvironmentReady = isKeyringEnvironmentReady;
4
+ const node_fs_1 = require("node:fs");
5
+ function isWSL() {
6
+ if (process.platform !== "linux")
7
+ return false;
8
+ // env checks
9
+ if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP)
10
+ return true;
11
+ try {
12
+ const v = (0, node_fs_1.readFileSync)("/proc/version", "utf8").toLowerCase();
13
+ if (v.includes("microsoft") || v.includes("wsl"))
14
+ return true;
15
+ }
16
+ catch { }
17
+ try {
18
+ const r = (0, node_fs_1.readFileSync)("/proc/sys/kernel/osrelease", "utf8").toLowerCase();
19
+ if (r.includes("microsoft") || r.includes("wsl"))
20
+ return true;
21
+ }
22
+ catch { }
23
+ // some WSL setups have /run/WSL or other hints
24
+ if ((0, node_fs_1.existsSync)("/run/WSL") || (0, node_fs_1.existsSync)("/run/WSL/"))
25
+ return true;
26
+ return false;
27
+ }
28
+ function isDBusAvailable() {
29
+ return !!process.env.DBUS_SESSION_BUS_ADDRESS;
30
+ }
31
+ function isDisplayAvailable() {
32
+ return !!(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
33
+ }
34
+ function isKeyringEnvironmentReady() {
35
+ if (process.platform === "win32")
36
+ return { ready: true };
37
+ if (process.platform === "darwin")
38
+ return { ready: true };
39
+ if (process.platform === "linux") {
40
+ if (!process.env.CI) {
41
+ if (isWSL()) {
42
+ return { ready: false, reason: "Detected WSL (no GNOME keyring by default)" };
43
+ }
44
+ // Check for D-Bus (required for libsecret)
45
+ if (!isDBusAvailable()) {
46
+ return { ready: false, reason: "D-Bus not available" };
47
+ }
48
+ // Check for display server (most keyring services need it)
49
+ if (!isDisplayAvailable()) {
50
+ return { ready: false, reason: "Display not available" };
51
+ }
52
+ }
53
+ return { ready: true };
54
+ }
55
+ // Unknown platform
56
+ return { ready: false, reason: `Unsupported platform: ${process.platform}` };
57
+ }
@@ -3,8 +3,9 @@ import type { CredentialEntry, ItemInfo, StoreOptions } from "./types.js";
3
3
  export declare class KeyringStore extends BaseSecretStore {
4
4
  private _impl;
5
5
  private serviceName;
6
- private defaultAccount;
7
6
  private _forceUnavailable;
7
+ private _environmentChecked;
8
+ private _environmentReady;
8
9
  constructor(options: StoreOptions);
9
10
  available(): Promise<boolean>;
10
11
  setItem(key: string, value: ItemInfo): Promise<any>;
package/lib/esm/keytar.js CHANGED
@@ -1,21 +1,35 @@
1
+ import { logger } from "@aigne/core/utils/logger.js";
1
2
  import { BaseSecretStore } from "./base.js";
2
- const DEFAULT_SERVICE_NAME = "-secrets";
3
- const DEFAULT_ACCOUNT_NAME_FOR_DEFAULT = "-default";
3
+ import { isKeyringEnvironmentReady } from "./util.js";
4
+ const DEFAULT_SERVICE_NAME = "-api-key";
5
+ const DEFAULT_ACCOUNT_NAME_FOR_DEFAULT = "default";
4
6
  export class KeyringStore extends BaseSecretStore {
5
7
  _impl = null;
6
8
  serviceName;
7
- defaultAccount;
8
9
  _forceUnavailable;
10
+ _environmentChecked = false;
11
+ _environmentReady = false;
9
12
  constructor(options) {
10
13
  super();
11
14
  const { serviceName, forceKeytarUnavailable = false } = options;
12
15
  this.serviceName = `${serviceName}${DEFAULT_SERVICE_NAME}`;
13
- this.defaultAccount = `${serviceName}${DEFAULT_ACCOUNT_NAME_FOR_DEFAULT}`;
14
16
  this._forceUnavailable = !!forceKeytarUnavailable;
15
17
  }
16
18
  async available() {
17
19
  if (this._forceUnavailable)
18
20
  return false;
21
+ // Check environment prerequisites before attempting to load the module
22
+ if (!this._environmentChecked) {
23
+ const { ready, reason } = isKeyringEnvironmentReady();
24
+ this._environmentReady = ready;
25
+ if (!ready) {
26
+ logger.warn(`Keyring environment not ready: ${reason}`);
27
+ }
28
+ this._environmentChecked = true;
29
+ }
30
+ if (!this._environmentReady) {
31
+ return false;
32
+ }
19
33
  try {
20
34
  if (!this._impl) {
21
35
  const module = await import("@zowe/secrets-for-zowe-sdk");
@@ -26,7 +40,8 @@ export class KeyringStore extends BaseSecretStore {
26
40
  typeof this._impl.setPassword === "function" &&
27
41
  typeof this._impl.deletePassword === "function");
28
42
  }
29
- catch {
43
+ catch (error) {
44
+ logger.error(`Failed to load keyring: ${error.message}`);
30
45
  return false;
31
46
  }
32
47
  }
@@ -73,7 +88,9 @@ export class KeyringStore extends BaseSecretStore {
73
88
  try {
74
89
  if (typeof this._impl.findCredentials === "function") {
75
90
  const list = await this._impl.findCredentials(this.serviceName);
76
- return Array.isArray(list) && list.length > 0 ? list : null;
91
+ return Array.isArray(list) && list.length > 0
92
+ ? list.filter((c) => c.account !== DEFAULT_ACCOUNT_NAME_FOR_DEFAULT)
93
+ : null;
77
94
  }
78
95
  return null;
79
96
  }
@@ -112,33 +129,21 @@ export class KeyringStore extends BaseSecretStore {
112
129
  throw new Error("Keyring not available");
113
130
  if (!this._impl)
114
131
  throw new Error("Keyring not loaded");
115
- const account = this.defaultAccount;
116
- return this._impl.setPassword(account, account, JSON.stringify(value));
132
+ return this.setItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT, value);
117
133
  }
118
134
  async getDefaultItem() {
119
135
  if (!(await this.available()))
120
136
  return null;
121
137
  if (!this._impl)
122
138
  return null;
123
- const account = this.defaultAccount;
124
- try {
125
- const value = await this._impl.getPassword(account, account);
126
- if (!value)
127
- return null;
128
- return this.parseKey(value);
129
- }
130
- catch {
131
- // ignore
132
- }
133
- return null;
139
+ return this.getItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT);
134
140
  }
135
141
  async deleteDefaultItem() {
136
142
  if (!(await this.available()))
137
143
  throw new Error("Keyring not available");
138
144
  if (!this._impl)
139
145
  throw new Error("Keyring not loaded");
140
- const account = this.defaultAccount;
141
- await this._impl.deletePassword(account, account);
146
+ await this.deleteItem(DEFAULT_ACCOUNT_NAME_FOR_DEFAULT);
142
147
  }
143
148
  }
144
149
  export default KeyringStore;
@@ -0,0 +1,4 @@
1
+ export declare function isKeyringEnvironmentReady(): {
2
+ ready: boolean;
3
+ reason?: string;
4
+ };
@@ -0,0 +1,54 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ function isWSL() {
3
+ if (process.platform !== "linux")
4
+ return false;
5
+ // env checks
6
+ if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP)
7
+ return true;
8
+ try {
9
+ const v = readFileSync("/proc/version", "utf8").toLowerCase();
10
+ if (v.includes("microsoft") || v.includes("wsl"))
11
+ return true;
12
+ }
13
+ catch { }
14
+ try {
15
+ const r = readFileSync("/proc/sys/kernel/osrelease", "utf8").toLowerCase();
16
+ if (r.includes("microsoft") || r.includes("wsl"))
17
+ return true;
18
+ }
19
+ catch { }
20
+ // some WSL setups have /run/WSL or other hints
21
+ if (existsSync("/run/WSL") || existsSync("/run/WSL/"))
22
+ return true;
23
+ return false;
24
+ }
25
+ function isDBusAvailable() {
26
+ return !!process.env.DBUS_SESSION_BUS_ADDRESS;
27
+ }
28
+ function isDisplayAvailable() {
29
+ return !!(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
30
+ }
31
+ export function isKeyringEnvironmentReady() {
32
+ if (process.platform === "win32")
33
+ return { ready: true };
34
+ if (process.platform === "darwin")
35
+ return { ready: true };
36
+ if (process.platform === "linux") {
37
+ if (!process.env.CI) {
38
+ if (isWSL()) {
39
+ return { ready: false, reason: "Detected WSL (no GNOME keyring by default)" };
40
+ }
41
+ // Check for D-Bus (required for libsecret)
42
+ if (!isDBusAvailable()) {
43
+ return { ready: false, reason: "D-Bus not available" };
44
+ }
45
+ // Check for display server (most keyring services need it)
46
+ if (!isDisplayAvailable()) {
47
+ return { ready: false, reason: "Display not available" };
48
+ }
49
+ }
50
+ return { ready: true };
51
+ }
52
+ // Unknown platform
53
+ return { ready: false, reason: `Unsupported platform: ${process.platform}` };
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/secrets",
3
- "version": "0.1.1-beta.1",
3
+ "version": "0.1.1-beta.3",
4
4
  "description": "Secure credential storage for AIGNE Hub API keys with system keyring and file-based fallback",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -44,6 +44,7 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
+ "@aigne/core": "^1.69.0",
47
48
  "@zowe/secrets-for-zowe-sdk": "^8.29.4",
48
49
  "yaml": "^2.8.1"
49
50
  },