@ouro.bot/cli 0.1.0-alpha.737 → 0.1.0-alpha.739

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.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.739",
6
+ "changes": [
7
+ "Allow Linux auto vault unlock reads to reuse an already-approved plaintext fallback when no secure local store has usable material."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.738",
12
+ "changes": [
13
+ "Allow the path-locked Sanctuary legacy adoption to discard only the exact obsolete MiniMax provider record in memory while preserving the original envelope and keeping canonical credential validation strict.",
14
+ "Validate the complete provider discard allowlist and every projected runtime message before the first vault write, with recoverable retry semantics and counts-only audit evidence."
15
+ ]
16
+ },
4
17
  {
5
18
  "version": "0.1.0-alpha.737",
6
19
  "changes": [
@@ -713,12 +713,18 @@ local unlock: available
713
713
  machineIdMigration: {
714
714
  sourceMachineId: process.argv[1],
715
715
  targetMachineId: process.argv[2],
716
+ discardProviderCredentialRecords: { providers: ["minimax"] },
716
717
  },
717
718
  }).then(
718
719
  () => process.exit(0),
719
720
  () => { process.stderr.write("credential bootstrap failed\n"); process.exit(1) },
720
721
  )
721
722
  ' "$BOOTSTRAP_SOURCE_MACHINE_ID" "$BOOTSTRAP_TARGET_MACHINE_ID" || return $?
723
+ # The path-locked Sanctuary migration projects the exact obsolete Minimax
724
+ # provider record out of memory before strict validation and persistence.
725
+ # The original legacy envelope remains byte-for-byte unchanged and is the
726
+ # sole digest authority; current GLM and Gemini credentials are established
727
+ # only by the separate hidden-input authentication commands below.
722
728
  ! docker container inspect ouro-butler-credential-bootstrap >/dev/null 2>&1 || return 1
723
729
  test ! -e "$BOOTSTRAP_CREDENTIAL_SOURCE" || return $?
724
730
  test ! -e "$BOOTSTRAP_CREDENTIAL_CLAIM" || return $?
@@ -139,13 +139,20 @@ async function loadContainerCredentialBootstrap(enabledAgents, options = {}) {
139
139
  }
140
140
  if (loaded.has(message.agentName))
141
141
  throw new Error("container credential bootstrap contains a duplicate agent");
142
- if (!(0, runtime_credentials_1.isRuntimeCredentialBootstrapMessage)(message))
143
- throw new Error("container credential bootstrap message is invalid");
144
142
  loaded.add(message.agentName);
145
143
  }
146
- const machineId = (0, machine_identity_1.loadOrCreateMachineIdentity)().machineId;
147
144
  const migration = options.machineIdMigration;
145
+ const discardProviderCredentialRecords = migration?.discardProviderCredentialRecords;
146
+ if (discardProviderCredentialRecords === undefined) {
147
+ for (const message of envelope.credentials) {
148
+ if (!(0, runtime_credentials_1.isRuntimeCredentialBootstrapMessage)(message)) {
149
+ throw new Error("container credential bootstrap message is invalid");
150
+ }
151
+ }
152
+ }
153
+ const machineId = (0, machine_identity_1.loadOrCreateMachineIdentity)().machineId;
148
154
  let messages = envelope.credentials;
155
+ let discardedProviderRecordCount = 0;
149
156
  if (migration) {
150
157
  const { sourceMachineId, targetMachineId } = migration;
151
158
  if (!sourceMachineId
@@ -163,7 +170,46 @@ async function loadContainerCredentialBootstrap(enabledAgents, options = {}) {
163
170
  throw new Error("container credential bootstrap machineId migration source does not match");
164
171
  }
165
172
  }
166
- messages = messages.map((message) => ({ ...message, machineId: targetMachineId }));
173
+ if (discardProviderCredentialRecords !== undefined) {
174
+ if (!isRecord(discardProviderCredentialRecords) || !Array.isArray(discardProviderCredentialRecords.providers)) {
175
+ throw new Error("container credential bootstrap provider discard policy is invalid");
176
+ }
177
+ const configuredProviders = discardProviderCredentialRecords.providers;
178
+ if (configuredProviders.length === 0
179
+ || configuredProviders.some((provider) => (typeof provider !== "string" || provider.length === 0 || provider !== provider.trim()))
180
+ || new Set(configuredProviders).size !== configuredProviders.length) {
181
+ throw new Error("container credential bootstrap provider discard allowlist is invalid");
182
+ }
183
+ const legacyProviders = [];
184
+ for (const message of messages) {
185
+ const records = message.providerCredentialRecords;
186
+ if (records === undefined)
187
+ continue;
188
+ if (!Array.isArray(records) || records.length === 0) {
189
+ throw new Error("container credential bootstrap discarded provider records are invalid");
190
+ }
191
+ for (const record of records) {
192
+ if (!isRecord(record) || typeof record.provider !== "string" || record.provider.length === 0) {
193
+ throw new Error("container credential bootstrap discarded provider record is invalid");
194
+ }
195
+ legacyProviders.push(record.provider);
196
+ }
197
+ }
198
+ if (new Set(legacyProviders).size !== legacyProviders.length) {
199
+ throw new Error("container credential bootstrap discarded providers contain duplicates");
200
+ }
201
+ if ([...legacyProviders].sort().join(",")
202
+ !== [...configuredProviders].sort().join(",")) {
203
+ throw new Error("container credential bootstrap discarded providers do not match the allowlist");
204
+ }
205
+ discardedProviderRecordCount = legacyProviders.length;
206
+ }
207
+ messages = messages.map((message) => {
208
+ const projected = { ...message, machineId: targetMachineId };
209
+ if (discardProviderCredentialRecords !== undefined)
210
+ delete projected.providerCredentialRecords;
211
+ return projected;
212
+ });
167
213
  }
168
214
  else {
169
215
  for (const message of messages) {
@@ -172,6 +218,13 @@ async function loadContainerCredentialBootstrap(enabledAgents, options = {}) {
172
218
  }
173
219
  }
174
220
  }
221
+ if (discardProviderCredentialRecords !== undefined) {
222
+ for (const message of messages) {
223
+ if (!(0, runtime_credentials_1.isRuntimeCredentialBootstrapMessage)(message)) {
224
+ throw new Error("container credential bootstrap message is invalid");
225
+ }
226
+ }
227
+ }
175
228
  const persist = options.persist ?? ((message) => (0, runtime_credentials_1.persistRuntimeCredentialBootstrapMessage)(message, {
176
229
  machineId,
177
230
  }));
@@ -198,6 +251,18 @@ async function loadContainerCredentialBootstrap(enabledAgents, options = {}) {
198
251
  }
199
252
  }
200
253
  deleteDurably(consumingPath);
254
+ if (discardedProviderRecordCount > 0) {
255
+ (0, runtime_1.emitNervesEvent)({
256
+ component: "config/identity",
257
+ event: "config.container_provider_credentials_discarded",
258
+ message: "discarded allowlisted legacy provider credentials during container migration",
259
+ meta: {
260
+ agentCount: loaded.size,
261
+ recordCount: discardedProviderRecordCount,
262
+ mode: "machine-id-migration",
263
+ },
264
+ });
265
+ }
201
266
  (0, runtime_1.emitNervesEvent)({
202
267
  component: "config/identity",
203
268
  event: "config.container_credentials_loaded",
@@ -517,6 +517,15 @@ function deleteFromStoreExact(config, store, deps) {
517
517
  return deleteFromWindowsDpapiExact(config, deps);
518
518
  return deleteFromPlaintextFileExact(config, deps);
519
519
  }
520
+ function readFromAutoPlaintextFallback(config, deps) {
521
+ if (deps.store !== undefined && deps.store !== "auto")
522
+ return null;
523
+ const store = resolveVaultUnlockStore(config, { ...deps, store: "plaintext-file" });
524
+ const loaded = readFromStore(config, store, deps);
525
+ if (!loaded)
526
+ return null;
527
+ return { secret: loaded.secret, store, source: loaded.source };
528
+ }
520
529
  function clearVaultUnlockSecret(config, deps = {}) {
521
530
  const canonicalConfig = canonicalizeVaultUnlockConfig(config);
522
531
  const store = resolveVaultUnlockStore(canonicalConfig, deps);
@@ -540,9 +549,34 @@ function clearVaultUnlockSecret(config, deps = {}) {
540
549
  }
541
550
  function readVaultUnlockSecret(config, deps = {}) {
542
551
  const canonicalConfig = canonicalizeVaultUnlockConfig(config);
543
- const store = resolveVaultUnlockStore(canonicalConfig, deps);
552
+ let store;
553
+ try {
554
+ store = resolveVaultUnlockStore(canonicalConfig, deps);
555
+ }
556
+ catch (error) {
557
+ const fallback = readFromAutoPlaintextFallback(canonicalConfig, deps);
558
+ if (!fallback)
559
+ throw error;
560
+ (0, runtime_1.emitNervesEvent)({
561
+ component: "repertoire",
562
+ event: "repertoire.vault_unlock_loaded",
563
+ message: "loaded vault unlock material from local store",
564
+ meta: { store: fallback.store.kind, secure: fallback.store.secure, hasAgentName: !!config.agentName, sourceServerUrl: fallback.source.serverUrl },
565
+ });
566
+ return fallback;
567
+ }
544
568
  const loaded = readFromStore(canonicalConfig, store, deps);
545
569
  if (!loaded) {
570
+ const fallback = readFromAutoPlaintextFallback(canonicalConfig, deps);
571
+ if (fallback) {
572
+ (0, runtime_1.emitNervesEvent)({
573
+ component: "repertoire",
574
+ event: "repertoire.vault_unlock_loaded",
575
+ message: "loaded vault unlock material from local store",
576
+ meta: { store: fallback.store.kind, secure: fallback.store.secure, hasAgentName: !!config.agentName, sourceServerUrl: fallback.source.serverUrl },
577
+ });
578
+ return fallback;
579
+ }
546
580
  throw new Error(lockedMessage(canonicalConfig, store));
547
581
  }
548
582
  (0, runtime_1.emitNervesEvent)({
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.737",
3
+ "version": "0.1.0-alpha.739",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@ouro.bot/cli",
9
- "version": "0.1.0-alpha.737",
9
+ "version": "0.1.0-alpha.739",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.737",
3
+ "version": "0.1.0-alpha.739",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },