@autohq/cli 0.1.365 → 0.1.366

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.
@@ -23492,7 +23492,7 @@ Object.assign(lookup, {
23492
23492
  // package.json
23493
23493
  var package_default = {
23494
23494
  name: "@autohq/cli",
23495
- version: "0.1.365",
23495
+ version: "0.1.366",
23496
23496
  license: "SEE LICENSE IN README.md",
23497
23497
  publishConfig: {
23498
23498
  access: "public"
@@ -26200,6 +26200,9 @@ var EncryptedSecretValueSchema = external_exports.object({
26200
26200
  dekAuthTag: SecretAesGcmAuthTagSchema
26201
26201
  });
26202
26202
  var SecretDescriptionSchema = external_exports.string().trim().max(1024);
26203
+ var SECRET_IDLE_EXPIRY_MAX_SECONDS = 10 * 365 * 24 * 60 * 60;
26204
+ var SecretExpiresAtSchema = external_exports.string().datetime({ offset: true });
26205
+ var SecretIdleExpirySecondsSchema = external_exports.number().int().min(1).max(SECRET_IDLE_EXPIRY_MAX_SECONDS);
26203
26206
  var SECRET_BINDING_HOST_PATTERN = /^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
26204
26207
  var SECRET_BINDING_HEADER_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
26205
26208
  var SECRET_BINDING_FORBIDDEN_HEADERS = /* @__PURE__ */ new Set([
@@ -26228,8 +26231,17 @@ var SecretSetRequestSchema = external_exports.object({
26228
26231
  value: external_exports.string(),
26229
26232
  description: SecretDescriptionSchema.nullable().optional(),
26230
26233
  protected: external_exports.boolean().optional(),
26231
- binding: SecretBindingSchema.nullable().optional()
26234
+ binding: SecretBindingSchema.nullable().optional(),
26235
+ expiresAt: SecretExpiresAtSchema.nullable().optional(),
26236
+ idleExpirySeconds: SecretIdleExpirySecondsSchema.nullable().optional()
26232
26237
  });
26238
+ var SecretExpiryUpdateRequestSchema = external_exports.object({
26239
+ expiresAt: SecretExpiresAtSchema.nullable().optional(),
26240
+ idleExpirySeconds: SecretIdleExpirySecondsSchema.nullable().optional()
26241
+ }).refine(
26242
+ (input) => input.expiresAt !== void 0 || input.idleExpirySeconds !== void 0,
26243
+ { message: "Provide expiresAt and/or idleExpirySeconds" }
26244
+ );
26233
26245
  var SecretRotateRequestSchema = external_exports.object({
26234
26246
  value: external_exports.string()
26235
26247
  });
@@ -26246,7 +26258,15 @@ var SecretMetadataSchema = external_exports.object({
26246
26258
  createdAt: external_exports.string().datetime(),
26247
26259
  updatedAt: external_exports.string().datetime(),
26248
26260
  lastRotatedAt: external_exports.string().datetime().nullable(),
26249
- lastAccessedAt: external_exports.string().datetime().nullable()
26261
+ lastAccessedAt: external_exports.string().datetime().nullable(),
26262
+ // Like binding, defaulted for deploy skew: an older server that never sends
26263
+ // expiry fields parses as a secret that never expires.
26264
+ expiresAt: external_exports.string().datetime().nullable().default(null),
26265
+ idleExpirySeconds: external_exports.number().int().nullable().default(null),
26266
+ // Computed server-side: true when expiresAt has passed or the secret has
26267
+ // been unused past idleExpirySeconds. Expired secrets resolve as absent
26268
+ // everywhere but stay listed so operators can see and delete them.
26269
+ expired: external_exports.boolean().default(false)
26250
26270
  });
26251
26271
  var SecretSetResponseSchema = external_exports.object({
26252
26272
  secret: SecretMetadataSchema
@@ -26257,6 +26277,9 @@ var SecretListResponseSchema = external_exports.object({
26257
26277
  var SecretDeleteResponseSchema = external_exports.object({
26258
26278
  secret: SecretMetadataSchema
26259
26279
  });
26280
+ var SecretExpiryUpdateResponseSchema = external_exports.object({
26281
+ secret: SecretMetadataSchema
26282
+ });
26260
26283
  var SecretRevealResponseSchema = external_exports.object({
26261
26284
  secret: SecretMetadataSchema,
26262
26285
  value: external_exports.string()
package/dist/index.js CHANGED
@@ -17599,7 +17599,7 @@ var init_mounts = __esm({
17599
17599
  });
17600
17600
 
17601
17601
  // ../../packages/schemas/src/secrets.ts
17602
- var SECRET_ENCRYPTION_ALGORITHM, SecretEnvNameSchema, SecretCiphertextFieldSchema, SecretAesGcmIvSchema, SecretAesGcmAuthTagSchema, SecretEnvValueSchema, SecretEnvSchema, EncryptedSecretValueSchema, SecretDescriptionSchema, SECRET_BINDING_HOST_PATTERN, SECRET_BINDING_HEADER_PATTERN, SECRET_BINDING_FORBIDDEN_HEADERS, SecretBindingHostSchema, SecretBindingHeaderSchema, SecretBindingSchema, SecretSetRequestSchema, SecretRotateRequestSchema, SecretMetadataSchema, SecretSetResponseSchema, SecretListResponseSchema, SecretDeleteResponseSchema, SecretRevealResponseSchema;
17602
+ var SECRET_ENCRYPTION_ALGORITHM, SecretEnvNameSchema, SecretCiphertextFieldSchema, SecretAesGcmIvSchema, SecretAesGcmAuthTagSchema, SecretEnvValueSchema, SecretEnvSchema, EncryptedSecretValueSchema, SecretDescriptionSchema, SECRET_IDLE_EXPIRY_MAX_SECONDS, SecretExpiresAtSchema, SecretIdleExpirySecondsSchema, SECRET_BINDING_HOST_PATTERN, SECRET_BINDING_HEADER_PATTERN, SECRET_BINDING_FORBIDDEN_HEADERS, SecretBindingHostSchema, SecretBindingHeaderSchema, SecretBindingSchema, SecretSetRequestSchema, SecretExpiryUpdateRequestSchema, SecretRotateRequestSchema, SecretMetadataSchema, SecretSetResponseSchema, SecretListResponseSchema, SecretDeleteResponseSchema, SecretExpiryUpdateResponseSchema, SecretRevealResponseSchema;
17603
17603
  var init_secrets = __esm({
17604
17604
  "../../packages/schemas/src/secrets.ts"() {
17605
17605
  "use strict";
@@ -17632,6 +17632,9 @@ var init_secrets = __esm({
17632
17632
  dekAuthTag: SecretAesGcmAuthTagSchema
17633
17633
  });
17634
17634
  SecretDescriptionSchema = external_exports.string().trim().max(1024);
17635
+ SECRET_IDLE_EXPIRY_MAX_SECONDS = 10 * 365 * 24 * 60 * 60;
17636
+ SecretExpiresAtSchema = external_exports.string().datetime({ offset: true });
17637
+ SecretIdleExpirySecondsSchema = external_exports.number().int().min(1).max(SECRET_IDLE_EXPIRY_MAX_SECONDS);
17635
17638
  SECRET_BINDING_HOST_PATTERN = /^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
17636
17639
  SECRET_BINDING_HEADER_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
17637
17640
  SECRET_BINDING_FORBIDDEN_HEADERS = /* @__PURE__ */ new Set([
@@ -17660,8 +17663,17 @@ var init_secrets = __esm({
17660
17663
  value: external_exports.string(),
17661
17664
  description: SecretDescriptionSchema.nullable().optional(),
17662
17665
  protected: external_exports.boolean().optional(),
17663
- binding: SecretBindingSchema.nullable().optional()
17666
+ binding: SecretBindingSchema.nullable().optional(),
17667
+ expiresAt: SecretExpiresAtSchema.nullable().optional(),
17668
+ idleExpirySeconds: SecretIdleExpirySecondsSchema.nullable().optional()
17664
17669
  });
17670
+ SecretExpiryUpdateRequestSchema = external_exports.object({
17671
+ expiresAt: SecretExpiresAtSchema.nullable().optional(),
17672
+ idleExpirySeconds: SecretIdleExpirySecondsSchema.nullable().optional()
17673
+ }).refine(
17674
+ (input) => input.expiresAt !== void 0 || input.idleExpirySeconds !== void 0,
17675
+ { message: "Provide expiresAt and/or idleExpirySeconds" }
17676
+ );
17665
17677
  SecretRotateRequestSchema = external_exports.object({
17666
17678
  value: external_exports.string()
17667
17679
  });
@@ -17678,7 +17690,15 @@ var init_secrets = __esm({
17678
17690
  createdAt: external_exports.string().datetime(),
17679
17691
  updatedAt: external_exports.string().datetime(),
17680
17692
  lastRotatedAt: external_exports.string().datetime().nullable(),
17681
- lastAccessedAt: external_exports.string().datetime().nullable()
17693
+ lastAccessedAt: external_exports.string().datetime().nullable(),
17694
+ // Like binding, defaulted for deploy skew: an older server that never sends
17695
+ // expiry fields parses as a secret that never expires.
17696
+ expiresAt: external_exports.string().datetime().nullable().default(null),
17697
+ idleExpirySeconds: external_exports.number().int().nullable().default(null),
17698
+ // Computed server-side: true when expiresAt has passed or the secret has
17699
+ // been unused past idleExpirySeconds. Expired secrets resolve as absent
17700
+ // everywhere but stay listed so operators can see and delete them.
17701
+ expired: external_exports.boolean().default(false)
17682
17702
  });
17683
17703
  SecretSetResponseSchema = external_exports.object({
17684
17704
  secret: SecretMetadataSchema
@@ -17689,6 +17709,9 @@ var init_secrets = __esm({
17689
17709
  SecretDeleteResponseSchema = external_exports.object({
17690
17710
  secret: SecretMetadataSchema
17691
17711
  });
17712
+ SecretExpiryUpdateResponseSchema = external_exports.object({
17713
+ secret: SecretMetadataSchema
17714
+ });
17692
17715
  SecretRevealResponseSchema = external_exports.object({
17693
17716
  secret: SecretMetadataSchema,
17694
17717
  value: external_exports.string()
@@ -30539,6 +30562,25 @@ function createApiClient(input) {
30539
30562
  }
30540
30563
  return SecretSetResponseSchema.parse(await response.json());
30541
30564
  },
30565
+ async updateSecretExpiry(name, request, options = {}) {
30566
+ const organization = await activeOrganization();
30567
+ const path2 = `${secretPath(organization.organizationId, options.projectId, name)}/expiry`;
30568
+ const response = await authenticatedFetch(
30569
+ apiUrl(path2, options.apiBaseUrl),
30570
+ {
30571
+ method: "PATCH",
30572
+ headers: {
30573
+ "content-type": "application/json"
30574
+ },
30575
+ body: JSON.stringify(request)
30576
+ },
30577
+ options.apiBaseUrl
30578
+ );
30579
+ if (!response.ok) {
30580
+ throw new Error(await responseErrorMessage(response));
30581
+ }
30582
+ return SecretExpiryUpdateResponseSchema.parse(await response.json());
30583
+ },
30542
30584
  async revealSecret(name, options = {}) {
30543
30585
  const organization = await activeOrganization();
30544
30586
  const path2 = `${secretPath(organization.organizationId, options.projectId, name)}/value`;
@@ -31605,7 +31647,7 @@ var init_package = __esm({
31605
31647
  "package.json"() {
31606
31648
  package_default = {
31607
31649
  name: "@autohq/cli",
31608
- version: "0.1.365",
31650
+ version: "0.1.366",
31609
31651
  license: "SEE LICENSE IN README.md",
31610
31652
  publishConfig: {
31611
31653
  access: "public"
@@ -50047,6 +50089,7 @@ function memberLine2(member, style) {
50047
50089
  }
50048
50090
 
50049
50091
  // src/commands/secrets/actions.ts
50092
+ init_src();
50050
50093
  async function setSecret(input) {
50051
50094
  const value = await secretValue({
50052
50095
  options: input.commandOptions,
@@ -50059,6 +50102,7 @@ async function setSecret(input) {
50059
50102
  value,
50060
50103
  ...input.commandOptions.description === void 0 ? {} : { description: input.commandOptions.description },
50061
50104
  ...resolveProtectedFlag(input.commandOptions),
50105
+ ...resolveExpiryFields(input.commandOptions),
50062
50106
  ...resolveBindingFlags(input.commandOptions)
50063
50107
  },
50064
50108
  {
@@ -50084,6 +50128,17 @@ async function rotateSecret(input) {
50084
50128
  );
50085
50129
  writeRotateResponse(response, input);
50086
50130
  }
50131
+ async function updateSecretExpiry(input) {
50132
+ const fields = resolveExpiryFields(input.commandOptions);
50133
+ if (fields.expiresAt === void 0 && fields.idleExpirySeconds === void 0) {
50134
+ throw new Error("Provide --expires-at and/or --idle-expiry.");
50135
+ }
50136
+ const response = await input.client.updateSecretExpiry(input.name, fields, {
50137
+ projectId: await secretProjectId(input),
50138
+ apiBaseUrl: input.commandOptions.apiBaseUrl
50139
+ });
50140
+ writeExpiryResponse(response, input);
50141
+ }
50087
50142
  async function revealSecret(input) {
50088
50143
  const response = await input.client.revealSecret(input.name, {
50089
50144
  projectId: await secretProjectId(input),
@@ -50106,9 +50161,23 @@ async function listSecrets(input) {
50106
50161
  }
50107
50162
  for (const secret of response.secrets) {
50108
50163
  const flags = secret.protected ? "protected" : "revealable";
50109
- input.context.writeOutput(
50110
- `${secret.name} ${scopeLabel(secret.projectId)} ${flags} updated ${secret.updatedAt}`
50111
- );
50164
+ const parts = [
50165
+ secret.name,
50166
+ scopeLabel(secret.projectId),
50167
+ flags,
50168
+ `updated ${secret.updatedAt}`
50169
+ ];
50170
+ if (secret.expired) {
50171
+ parts.push("expired");
50172
+ } else {
50173
+ if (secret.expiresAt !== null) {
50174
+ parts.push(`expires ${secret.expiresAt}`);
50175
+ }
50176
+ if (secret.idleExpirySeconds !== null) {
50177
+ parts.push(`idle-expiry ${secret.idleExpirySeconds}s`);
50178
+ }
50179
+ }
50180
+ input.context.writeOutput(parts.join(" "));
50112
50181
  }
50113
50182
  }
50114
50183
  function resolveProtectedFlag(options) {
@@ -50123,6 +50192,43 @@ function resolveProtectedFlag(options) {
50123
50192
  }
50124
50193
  return {};
50125
50194
  }
50195
+ function parseExpiresAt(input) {
50196
+ if (input === "never") {
50197
+ return null;
50198
+ }
50199
+ const parsed = new Date(input);
50200
+ if (Number.isNaN(parsed.getTime())) {
50201
+ throw new Error(
50202
+ `Invalid --expires-at value "${input}". Use an ISO 8601 timestamp or "never".`
50203
+ );
50204
+ }
50205
+ return parsed.toISOString();
50206
+ }
50207
+ function parseIdleExpiry(input) {
50208
+ if (input === "never") {
50209
+ return null;
50210
+ }
50211
+ const match = /^(\d+)(s|m|h|d)?$/.exec(input);
50212
+ if (!match) {
50213
+ throw new Error(
50214
+ `Invalid --idle-expiry value "${input}". Use seconds or a duration like 30d, 12h, 90m, 3600s, or "never".`
50215
+ );
50216
+ }
50217
+ const unitSeconds = { s: 1, m: 60, h: 3600, d: 86400 }[match[2] ?? "s"] ?? 1;
50218
+ const seconds = Number(match[1]) * unitSeconds;
50219
+ if (seconds < 1 || seconds > SECRET_IDLE_EXPIRY_MAX_SECONDS) {
50220
+ throw new Error(
50221
+ `--idle-expiry must be between 1 second and ${SECRET_IDLE_EXPIRY_MAX_SECONDS} seconds (10 years).`
50222
+ );
50223
+ }
50224
+ return seconds;
50225
+ }
50226
+ function resolveExpiryFields(options) {
50227
+ return {
50228
+ ...options.expiresAt === void 0 ? {} : { expiresAt: parseExpiresAt(options.expiresAt) },
50229
+ ...options.idleExpiry === void 0 ? {} : { idleExpirySeconds: parseIdleExpiry(options.idleExpiry) }
50230
+ };
50231
+ }
50126
50232
  function resolveBindingFlags(options) {
50127
50233
  const hasBindingFlags = (options.bindHost?.length ?? 0) > 0 || options.bindHeader !== void 0 || options.bindFormat !== void 0;
50128
50234
  if (options.unbind) {
@@ -50228,6 +50334,16 @@ function writeRotateResponse(response, input) {
50228
50334
  `secret ${response.secret.name} rotated scope=${scopeLabel(response.secret.projectId)}`
50229
50335
  );
50230
50336
  }
50337
+ function writeExpiryResponse(response, input) {
50338
+ if (input.commandOptions.json) {
50339
+ input.context.writeOutput(JSON.stringify(response));
50340
+ return;
50341
+ }
50342
+ const idle = response.secret.idleExpirySeconds === null ? "never" : `${response.secret.idleExpirySeconds}s`;
50343
+ input.context.writeOutput(
50344
+ `secret ${response.secret.name} expiry updated scope=${scopeLabel(response.secret.projectId)} expires=${response.secret.expiresAt ?? "never"} idle=${idle}`
50345
+ );
50346
+ }
50231
50347
  function writeRevealResponse(response, input) {
50232
50348
  if (input.commandOptions.json) {
50233
50349
  input.context.writeOutput(JSON.stringify(response));
@@ -50315,7 +50431,13 @@ function registerSecretCommands(program, context) {
50315
50431
  ).option("--unbind", "clear an existing destination binding").option("--protected", "mark write-only: refuse plaintext reveal (default)").option(
50316
50432
  "--unprotected",
50317
50433
  "allow scope-gated plaintext reveal of this secret"
50318
- ).option("--raw", "allow empty values and preserve stdin exactly").option("--json", "print the updated secret metadata as JSON").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (name, commandOptions) => {
50434
+ ).option("--raw", "allow empty values and preserve stdin exactly").option(
50435
+ "--expires-at <timestamp>",
50436
+ 'absolute expiry as an ISO 8601 timestamp, or "never" to clear'
50437
+ ).option(
50438
+ "--idle-expiry <duration>",
50439
+ 'expire after this long unused (seconds or 30d/12h/90m/3600s), or "never" to clear'
50440
+ ).option("--json", "print the updated secret metadata as JSON").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (name, commandOptions) => {
50319
50441
  await setSecret({
50320
50442
  client: createContextApiClient(context),
50321
50443
  commandOptions: withApiBaseUrl(context, commandOptions),
@@ -50334,6 +50456,20 @@ function registerSecretCommands(program, context) {
50334
50456
  name
50335
50457
  });
50336
50458
  });
50459
+ secrets.command("expiry").description("Update a secret's expiry without changing its value.").argument("<name>", "secret name").option("--project <project>", "project id; defaults to organization scope").option(
50460
+ "--expires-at <timestamp>",
50461
+ 'absolute expiry as an ISO 8601 timestamp, or "never" to clear'
50462
+ ).option(
50463
+ "--idle-expiry <duration>",
50464
+ 'expire after this long unused (seconds or 30d/12h/90m/3600s), or "never" to clear'
50465
+ ).option("--json", "print the updated secret metadata as JSON").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (name, commandOptions) => {
50466
+ await updateSecretExpiry({
50467
+ client: createContextApiClient(context),
50468
+ commandOptions: withApiBaseUrl(context, commandOptions),
50469
+ context,
50470
+ name
50471
+ });
50472
+ });
50337
50473
  secrets.command("reveal").description(
50338
50474
  "Print the decrypted value of a non-protected secret (audited)."
50339
50475
  ).argument("<name>", "secret name").option("--project <project>", "project id; defaults to organization scope").option("--json", "print the secret value and metadata as JSON").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (name, commandOptions) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.365",
3
+ "version": "0.1.366",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"