@hyperbrowser/sdk 1.4.1 → 1.5.1

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.
@@ -1,5 +1,5 @@
1
1
  import { RuntimeSSEStream, RuntimeTransport } from "./base";
2
- import { WireOnePassword, WireSecretReference } from "./secret-references";
2
+ import { WireOnePassword, WireSecretReference, WireVaultSource } from "./secret-references";
3
3
  import { SandboxExecParams, SandboxExecOptions, SandboxResolvedSecret, SandboxProcessListParams, SandboxProcessListResponse, SandboxProcessResult, SandboxProcessSignal, SandboxProcessStdinParams, SandboxProcessStreamEvent, SandboxProcessSummary, SandboxProcessWaitParams } from "../types/sandbox";
4
4
  export interface RawProcessSummary extends Partial<SandboxProcessSummary> {
5
5
  id: string;
@@ -20,8 +20,8 @@ export interface SecretProcessStartPayload {
20
20
  timeoutMs?: number;
21
21
  runAs?: string;
22
22
  secrets?: Record<string, WireSecretReference>;
23
- /** A vault name; `secrets` is merged over its entries. */
24
- vault?: string;
23
+ /** A vault, by name or with unwrapped entries; `secrets` is merged over its entries. */
24
+ vault?: WireVaultSource;
25
25
  /** 1Password fields; their variables can't come from any other source. */
26
26
  onePassword?: WireOnePassword;
27
27
  }
@@ -557,8 +557,8 @@ class SandboxProcessesApi {
557
557
  throw new error_1.HyperbrowserError("Starting a process with secrets requires a sandbox handle");
558
558
  }
559
559
  const secrets = (0, secret_references_1.serializeSecretReferences)(params.secrets);
560
- const vault = params.vault;
561
- const onePassword = params.onePassword;
560
+ const vault = (0, secret_references_1.serializeVaultSource)(params.vault);
561
+ const onePassword = (0, secret_references_1.serializeOnePassword)(params.onePassword);
562
562
  // A clash between env and the vault's variables is reported by the API.
563
563
  if (secrets !== undefined)
564
564
  (0, secret_references_1.assertNoEnvSecretOverlap)(params.env, secrets);
@@ -1,4 +1,4 @@
1
- import { SandboxSecrets } from "../types/sandbox";
1
+ import { SandboxOnePassword, SandboxSecrets, SandboxVaultSource } from "../types/sandbox";
2
2
  /** Names of secrets and vaults. */
3
3
  export declare const SECRET_NAME_PATTERN: RegExp;
4
4
  /** The largest version number the API stores. */
@@ -8,12 +8,34 @@ export declare const isSecretEnvName: (name: unknown) => name is string;
8
8
  export interface WireSecretReference {
9
9
  name: string;
10
10
  version?: number | "latest";
11
+ unwrapped?: string;
12
+ }
13
+ export interface WireVaultReference {
14
+ name: string;
15
+ unwrapped: Record<string, {
16
+ version: number;
17
+ unwrapped: string;
18
+ }>;
19
+ }
20
+ /** A vault as the API takes it: its name, or its name with unwrapped entries. */
21
+ export type WireVaultSource = string | WireVaultReference;
22
+ export interface WireOnePassword extends Omit<SandboxOnePassword, "token"> {
23
+ token: string | WireSecretReference;
11
24
  }
12
25
  /**
13
26
  * Check secret references locally and convert them to the API's
14
- * `{ name, version? }` shape. Returns undefined when there are none.
27
+ * `{ name, version?, unwrapped? }` shape. Returns undefined when there are none.
15
28
  */
16
29
  export declare const serializeSecretReferences: (secrets: SandboxSecrets | undefined) => Record<string, WireSecretReference> | undefined;
30
+ /**
31
+ * Check a vault source and convert it to the API's shape: a name is passed
32
+ * as is, and a `VaultReference` keeps only its name and unwrapped entries.
33
+ */
34
+ export declare const serializeVaultSource: (vault: SandboxVaultSource | undefined) => WireVaultSource | undefined;
35
+ /**
36
+ * Check a 1Password source's token, the one member that can be a secret
37
+ * reference; the API checks the rest.
38
+ */
39
+ export declare const serializeOnePassword: <T extends Pick<SandboxOnePassword, "token">>(onePassword: T | undefined) => (Omit<T, "token"> & Pick<WireOnePassword, "token">) | undefined;
17
40
  /** An environment variable must come from either `env` or `secrets`, not both. */
18
41
  export declare const assertNoEnvSecretOverlap: (env: Record<string, string> | undefined, secrets: Record<string, WireSecretReference>) => void;
19
- export type { SandboxOnePassword as WireOnePassword } from "../types/sandbox";
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertNoEnvSecretOverlap = exports.serializeSecretReferences = exports.isSecretEnvName = exports.MAX_SECRET_VERSION = exports.SECRET_NAME_PATTERN = void 0;
3
+ exports.assertNoEnvSecretOverlap = exports.serializeOnePassword = exports.serializeVaultSource = exports.serializeSecretReferences = exports.isSecretEnvName = exports.MAX_SECRET_VERSION = exports.SECRET_NAME_PATTERN = void 0;
4
4
  const error_1 = require("../error");
5
+ const secrets_envelope_1 = require("../secrets-envelope");
5
6
  const ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
6
7
  /** The longest environment variable name the API stores. */
7
8
  const MAX_ENV_NAME_LENGTH = 256;
@@ -10,15 +11,44 @@ exports.SECRET_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/;
10
11
  /** The largest version number the API stores. */
11
12
  exports.MAX_SECRET_VERSION = 2147483647;
12
13
  const MAX_SECRETS = 32;
14
+ /** The longest unwrapped envelope the API takes. */
15
+ const MAX_UNWRAPPED_LENGTH = 64 * 1024;
13
16
  /** An environment variable name the API accepts for a secret or a vault entry. */
14
17
  const isSecretEnvName = (name) => typeof name === "string" &&
15
18
  name.length <= MAX_ENV_NAME_LENGTH &&
16
19
  ENV_NAME_PATTERN.test(name) &&
17
20
  name !== "__proto__";
18
21
  exports.isSecretEnvName = isSecretEnvName;
22
+ const isVersionNumber = (version) => Number.isSafeInteger(version) &&
23
+ version >= 1 &&
24
+ version <= exports.MAX_SECRET_VERSION;
25
+ const isUnwrappedEnvelope = (unwrapped) => typeof unwrapped === "string" &&
26
+ unwrapped.length >= 1 &&
27
+ unwrapped.length <= MAX_UNWRAPPED_LENGTH;
28
+ /** Check one secret reference and convert it to the API's `{ name, version?, unwrapped? }`. */
29
+ const serializeSecretReference = (reference, label) => {
30
+ const { name, version, unwrapped } = (typeof reference === "string" ? { name: reference } : (reference ?? {}));
31
+ if (typeof name !== "string" || !exports.SECRET_NAME_PATTERN.test(name)) {
32
+ throw new error_1.HyperbrowserError(`Invalid secret name for ${label}: ${String(name)}`);
33
+ }
34
+ if (version !== undefined && version !== "latest" && !isVersionNumber(version)) {
35
+ throw new error_1.HyperbrowserError(`Secret version for ${label} must be an integer from 1 to ${exports.MAX_SECRET_VERSION} or "latest"`);
36
+ }
37
+ if (unwrapped === undefined) {
38
+ return version === undefined ? { name } : { name, version: version };
39
+ }
40
+ if (!isUnwrappedEnvelope(unwrapped)) {
41
+ throw new error_1.HyperbrowserError(`The unwrapped envelope for ${label} must be a string of 1 to ${MAX_UNWRAPPED_LENGTH} characters`);
42
+ }
43
+ // An unwrapped envelope is one version's value; "latest" could move on.
44
+ if (typeof version !== "number") {
45
+ throw new error_1.HyperbrowserError(`Pin the version of ${label} to the version you unwrapped when passing "unwrapped"`, { code: "invalid_request" });
46
+ }
47
+ return { name, version, unwrapped };
48
+ };
19
49
  /**
20
50
  * Check secret references locally and convert them to the API's
21
- * `{ name, version? }` shape. Returns undefined when there are none.
51
+ * `{ name, version?, unwrapped? }` shape. Returns undefined when there are none.
22
52
  */
23
53
  const serializeSecretReferences = (secrets) => {
24
54
  if (secrets === undefined || secrets === null) {
@@ -39,22 +69,64 @@ const serializeSecretReferences = (secrets) => {
39
69
  if (!(0, exports.isSecretEnvName)(env)) {
40
70
  throw new error_1.HyperbrowserError(`Invalid environment variable name for a secret: ${env}`);
41
71
  }
42
- const { name, version } = typeof reference === "string" ? { name: reference, version: undefined } : (reference ?? {});
43
- if (typeof name !== "string" || !exports.SECRET_NAME_PATTERN.test(name)) {
44
- throw new error_1.HyperbrowserError(`Invalid secret name for ${env}: ${String(name)}`);
45
- }
46
- if (version !== undefined &&
47
- version !== "latest" &&
48
- (!Number.isSafeInteger(version) ||
49
- version < 1 ||
50
- version > exports.MAX_SECRET_VERSION)) {
51
- throw new error_1.HyperbrowserError(`Secret version for ${env} must be an integer from 1 to ${exports.MAX_SECRET_VERSION} or "latest"`);
52
- }
53
- wire[env] = version === undefined ? { name } : { name, version };
72
+ wire[env] = serializeSecretReference(reference, env);
54
73
  }
55
74
  return wire;
56
75
  };
57
76
  exports.serializeSecretReferences = serializeSecretReferences;
77
+ /**
78
+ * Check a vault source and convert it to the API's shape: a name is passed
79
+ * as is, and a `VaultReference` keeps only its name and unwrapped entries.
80
+ */
81
+ const serializeVaultSource = (vault) => {
82
+ if (vault === undefined || typeof vault === "string") {
83
+ return vault;
84
+ }
85
+ if (!vault || typeof vault !== "object" || Array.isArray(vault)) {
86
+ throw new error_1.HyperbrowserError("vault must be a vault's name or the reference vaults.unwrap() returns");
87
+ }
88
+ const { name, unwrapped } = vault;
89
+ if (typeof name !== "string" || !exports.SECRET_NAME_PATTERN.test(name)) {
90
+ throw new error_1.HyperbrowserError(`Invalid vault name: ${String(name)}`);
91
+ }
92
+ if (!unwrapped || typeof unwrapped !== "object" || Array.isArray(unwrapped)) {
93
+ throw new error_1.HyperbrowserError(`vault.unwrapped must map vault ${name}'s variables to { version, unwrapped }`);
94
+ }
95
+ const entries = Object.entries(unwrapped);
96
+ if (entries.length > MAX_SECRETS) {
97
+ throw new error_1.HyperbrowserError(`At most ${MAX_SECRETS} unwrapped vault entries are allowed`);
98
+ }
99
+ const wire = {};
100
+ for (const [env, entry] of entries) {
101
+ if (!(0, exports.isSecretEnvName)(env)) {
102
+ throw new error_1.HyperbrowserError(`Invalid environment variable name in vault ${name}: ${env}`);
103
+ }
104
+ const { version, unwrapped: envelope } = (entry ?? {});
105
+ if (!isVersionNumber(version)) {
106
+ throw new error_1.HyperbrowserError(`The version of vault ${name}'s ${env} must be the integer it was unwrapped from`);
107
+ }
108
+ if (!isUnwrappedEnvelope(envelope)) {
109
+ throw new error_1.HyperbrowserError(`The unwrapped envelope of vault ${name}'s ${env} must be a string of 1 to ${MAX_UNWRAPPED_LENGTH} characters`);
110
+ }
111
+ wire[env] = { version, unwrapped: envelope };
112
+ }
113
+ return { name, unwrapped: wire };
114
+ };
115
+ exports.serializeVaultSource = serializeVaultSource;
116
+ /**
117
+ * Check a 1Password source's token, the one member that can be a secret
118
+ * reference; the API checks the rest.
119
+ */
120
+ const serializeOnePassword = (onePassword) => {
121
+ if (!(0, secrets_envelope_1.isPlainObject)(onePassword))
122
+ return onePassword;
123
+ const { token } = onePassword;
124
+ return {
125
+ ...onePassword,
126
+ token: typeof token === "string" ? token : serializeSecretReference(token, "the 1Password token"),
127
+ };
128
+ };
129
+ exports.serializeOnePassword = serializeOnePassword;
58
130
  /** An environment variable must come from either `env` or `secrets`, not both. */
59
131
  const assertNoEnvSecretOverlap = (env, secrets) => {
60
132
  const overlap = Object.keys(env ?? {}).filter((name) => Object.prototype.hasOwnProperty.call(secrets, name));
@@ -13,7 +13,8 @@ export declare const secretValueBytes: (value: SecretValue) => Buffer;
13
13
  export declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
14
14
  /** Encrypts values to a verified secrets public key. */
15
15
  export declare class SecretsSealer {
16
- private readonly kid;
16
+ /** The platform key's ID, which every envelope it seals names. */
17
+ readonly kid: string;
17
18
  private readonly publicKey;
18
19
  private constructor();
19
20
  /**
@@ -62,7 +62,9 @@ const rsaThumbprint = (n, e) => base64Url(crypto_1.default
62
62
  .digest());
63
63
  /** Encrypts values to a verified secrets public key. */
64
64
  class SecretsSealer {
65
- constructor(kid, publicKey) {
65
+ constructor(
66
+ /** The platform key's ID, which every envelope it seals names. */
67
+ kid, publicKey) {
66
68
  this.kid = kid;
67
69
  this.publicKey = publicKey;
68
70
  }
@@ -13,7 +13,14 @@ const getRequestId = (response) => {
13
13
  /** The API's machine codes, such as SECRET_NOT_FOUND. */
14
14
  const SERVER_ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)+$/;
15
15
  /** Codes whose retryable status default (such as 503) would be wrong. */
16
- const NON_RETRYABLE_ERROR_CODES = new Set(["SECRETS_NOT_CONFIGURED"]);
16
+ const NON_RETRYABLE_ERROR_CODES = new Set([
17
+ "SECRETS_ADMIN_REQUIRED",
18
+ "SECRETS_NOT_CONFIGURED",
19
+ "SECRET_KEY_UNAVAILABLE",
20
+ "SECRET_DECRYPT_FAILED",
21
+ "SECRET_ENVELOPE_INVALID",
22
+ "SECRET_VALUE_INVALID",
23
+ ]);
17
24
  /** The sandbox and secret an error is about, when the API names them. */
18
25
  const errorMessageContext = (errorData) => {
19
26
  let context = "";
@@ -13,7 +13,11 @@ export declare class CredentialsService extends BaseService {
13
13
  * `op_token` secret must have been attached at session creation as
14
14
  * `{ onePassword: name }`, and the request's `allowedOrigins` are the
15
15
  * origins the values may be typed on. Each field's result carries the
16
- * `reference` read, and there is no top-level `version`.
16
+ * `reference` read, and there is no top-level `version`. A
17
+ * customer-protected token is passed as `secrets.unwrap()` returns it.
18
+ *
19
+ * A `vault` fill needs the vault attached to the session; it fills the
20
+ * entries as they are now. Customer-protected secrets can't be filled.
17
21
  *
18
22
  * API errors are `HyperbrowserError`s whose `details` is the error body; the
19
23
  * server's own details are in `details.details`, such as `details.details.pages`
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CredentialsService = void 0;
4
4
  const error_1 = require("../error");
5
+ const secret_references_1 = require("../sandbox/secret-references");
5
6
  const secrets_envelope_1 = require("../secrets-envelope");
6
7
  const base_1 = require("./base");
7
8
  /** The API gives up on a fill after about 18 seconds. */
@@ -19,7 +20,11 @@ class CredentialsService extends base_1.BaseService {
19
20
  * `op_token` secret must have been attached at session creation as
20
21
  * `{ onePassword: name }`, and the request's `allowedOrigins` are the
21
22
  * origins the values may be typed on. Each field's result carries the
22
- * `reference` read, and there is no top-level `version`.
23
+ * `reference` read, and there is no top-level `version`. A
24
+ * customer-protected token is passed as `secrets.unwrap()` returns it.
25
+ *
26
+ * A `vault` fill needs the vault attached to the session; it fills the
27
+ * entries as they are now. Customer-protected secrets can't be filled.
23
28
  *
24
29
  * API errors are `HyperbrowserError`s whose `details` is the error body; the
25
30
  * server's own details are in `details.details`, such as `details.details.pages`
@@ -38,9 +43,14 @@ class CredentialsService extends base_1.BaseService {
38
43
  }
39
44
  // Preserve request members so the API can reject unknown or conflicting options.
40
45
  const { frameUrl, ...body } = params;
46
+ const onePassword = (0, secret_references_1.serializeOnePassword)(body.onePassword);
41
47
  return this.request(`/session/${encodeURIComponent(sessionId)}/credentials/fill`, {
42
48
  method: "POST",
43
- body: JSON.stringify({ ...body, frame: frameUrl == null ? undefined : { url: frameUrl } }),
49
+ body: JSON.stringify({
50
+ ...body,
51
+ onePassword,
52
+ frame: frameUrl == null ? undefined : { url: frameUrl },
53
+ }),
44
54
  timeout: Math.max(this.timeout, MIN_FILL_TIMEOUT_MS),
45
55
  });
46
56
  }
@@ -25,6 +25,7 @@ export declare class SandboxHandle {
25
25
  get diskMiB(): number | null | undefined;
26
26
  get timeoutMinutes(): number | null | undefined;
27
27
  get exposedPorts(): SandboxExposeResult[];
28
+ get startupSecrets(): SandboxDetail["startupSecrets"];
28
29
  toJSON(): SandboxDetail;
29
30
  info(): Promise<SandboxDetail>;
30
31
  refresh(): Promise<SandboxHandle>;
@@ -48,7 +49,6 @@ export declare class SandboxHandle {
48
49
  forceRefresh?: boolean;
49
50
  }): Promise<SandboxRuntimeSession>;
50
51
  private ensureRuntimeSession;
51
- private applyRuntimeSession;
52
52
  private clearRuntimeSession;
53
53
  private assertRuntimeAvailable;
54
54
  private static toRuntimeSession;
@@ -71,8 +71,8 @@ const serializeCreateSandboxParams = (params) => {
71
71
  throw new error_1.HyperbrowserError("Unsupported sandbox runtimeClass");
72
72
  if (typeof params.imageName === "string") {
73
73
  const secrets = (0, secret_references_1.serializeSecretReferences)(params.secrets);
74
- const vault = params.vault;
75
- const onePassword = params.onePassword;
74
+ const vault = (0, secret_references_1.serializeVaultSource)(params.vault);
75
+ const onePassword = (0, secret_references_1.serializeOnePassword)(params.onePassword);
76
76
  // The startup command with secrets runs only in Firecracker sandboxes.
77
77
  if ((secrets !== undefined || vault !== undefined || onePassword !== undefined) &&
78
78
  params.runtimeClass === "gvisor-cpu")
@@ -256,6 +256,9 @@ class SandboxHandle {
256
256
  get exposedPorts() {
257
257
  return (this.detail.exposedPorts ?? []).map((entry) => ({ ...entry }));
258
258
  }
259
+ get startupSecrets() {
260
+ return this.detail.startupSecrets?.map((entry) => ({ ...entry }));
261
+ }
259
262
  toJSON() {
260
263
  return { ...this.detail };
261
264
  }
@@ -379,17 +382,6 @@ class SandboxHandle {
379
382
  }
380
383
  return { ...this.runtimeSession };
381
384
  }
382
- applyRuntimeSession(session) {
383
- this.runtimeSession = { ...session };
384
- this.detail = {
385
- ...this.detail,
386
- status: session.status,
387
- region: session.region,
388
- runtime: session.runtime,
389
- token: session.token,
390
- tokenExpiresAt: session.tokenExpiresAt,
391
- };
392
- }
393
385
  clearRuntimeSession(status = this.detail.status) {
394
386
  this.runtimeSession = null;
395
387
  this.detail = {
@@ -1,9 +1,15 @@
1
- import { CreateSecretParams, Secret, SecretDeleteResult, SecretDetail, SecretListParams, SecretListResponse, SecretsPublicKey, SecretValue, SecretVersion, SecretVersionDeleteResult, UpdateSecretParams } from "../types/secret";
1
+ import { CustomerKey } from "../customer-key";
2
+ import { AddSecretVersionOptions, CreateSecretParams, ReplaceSecretVersionWrappingParams, RewrapSecretParams, Secret, SecretDeleteResult, SecretDetail, SecretListParams, SecretListResponse, SecretsPublicKey, SecretValue, SecretVersion, SecretVersionDeleteResult, UnwrappedSecretReference, UnwrapSecretOptions, UpdateSecretParams, WrappedSecretVersion } from "../types/secret";
2
3
  import { BaseService } from "./base";
3
4
  /**
4
5
  * Secrets are encrypted locally to the platform's public key; the API only
5
6
  * ever receives envelopes, and values are never returned.
6
7
  *
8
+ * A customer-protected secret's versions are also wrapped locally with your
9
+ * own key (`createCustomerKey()`, or your own `CustomerKey`), so the platform
10
+ * stores nothing it can open alone. Each use passes the reference `unwrap()`
11
+ * returns.
12
+ *
7
13
  * Methods that take `secret` accept its ID or its exact name. A UUID-shaped
8
14
  * argument is tried as an ID first and then as a name, since names may look
9
15
  * like UUIDs.
@@ -31,7 +37,36 @@ export declare class SecretsService extends BaseService {
31
37
  * value is checked against the rules of the secret's type, such as a TOTP
32
38
  * seed's format, before it is sealed.
33
39
  */
34
- addVersion(secret: string, value: SecretValue): Promise<SecretVersion>;
40
+ addVersion(secret: string, value: SecretValue, options?: AddSecretVersionOptions): Promise<SecretVersion>;
41
+ /**
42
+ * A customer-protected version's wrapped envelope, for unwrapping with
43
+ * your own key. Most callers want `unwrap()`, which also unwraps it.
44
+ */
45
+ getWrappedVersion(secret: string, version?: number | "latest"): Promise<WrappedSecretVersion>;
46
+ /**
47
+ * Unwrap a customer-protected version locally with your own key, giving
48
+ * the reference each use passes: as a sandbox's or process's `secrets`
49
+ * entry, or as a 1Password `token`. It is pinned to the version unwrapped.
50
+ * The unwrapped envelope is checked against the digest stored with the
51
+ * version, and only the platform can open it.
52
+ *
53
+ * `customerKey` may be several keys, such as during a rotation; the one
54
+ * whose `kid` wrapped the version is used.
55
+ */
56
+ unwrap(secret: string, customerKey: CustomerKey | readonly CustomerKey[], options?: UnwrapSecretOptions): Promise<UnwrappedSecretReference>;
57
+ /**
58
+ * Rewrap a customer-protected secret's versions with a new key, for
59
+ * rotating your own key. Each version is unwrapped with `from` and wrapped
60
+ * with `to` locally; the value never changes and the platform never sees
61
+ * it. Returns the versions rewrapped.
62
+ */
63
+ rewrap(secret: string, params: RewrapSecretParams): Promise<WrappedSecretVersion[]>;
64
+ /**
65
+ * Replace a customer-protected version's outer envelope with one you
66
+ * wrapped yourself. `innerDigest` must match the version's: only the
67
+ * wrapping changes, never the value. `rewrap()` does this for you.
68
+ */
69
+ replaceVersionWrapping(secret: string, version: number, params: ReplaceSecretVersionWrappingParams): Promise<WrappedSecretVersion>;
35
70
  /**
36
71
  * Replace the origins a secret may be filled into in browser sessions, or
37
72
  * clear them with `null` (it then can't be filled until origins are set
@@ -45,8 +80,14 @@ export declare class SecretsService extends BaseService {
45
80
  delete(secret: string): Promise<SecretDeleteResult>;
46
81
  /** Delete one stored version. The latest version cannot be deleted. */
47
82
  deleteVersion(secret: string, version: number): Promise<SecretVersionDeleteResult>;
48
- /** Sealed to the context the API returned for the secret; never one built here. */
83
+ /**
84
+ * Sealed to the context the API returned for the secret; never one built
85
+ * here. With a customer key, the sealed envelope is wrapped to the same
86
+ * context and the API keeps only the wrapped one and the inner digest.
87
+ */
49
88
  private uploadVersion;
89
+ private fetchWrapped;
90
+ private putWrapping;
50
91
  private resolve;
51
92
  private resolveDetail;
52
93
  /** Found by ID, the result already includes the versions. */