Repository: hashicorp/vault
File: ui/lib/kv/addon/routes/secret.js (JavaScript)

Code before:
    // catch error and only return 404 which indicates the secret truly does not exist.
    // control group error is handled by the metadata route
    return this.store.queryRecord('kv/metadata', { backend, path }).catch((e) => {
      if (e.httpStatus === 404) {
        throw e;
      }
      return null;
    });
  }

  // this request always returns subkeys for the latest version
  fetchSubkeys(backend, path) {
    if (this.version.isEnterprise) {
      const adapter = this.store.adapterFor('kv/data');
      // metadata will throw if the secret does not exist
      // always return here so we get deletion state and relevant metadata
      return adapter.fetchSubkeys(backend, path);
    }
    return null;
  }

  isPatchAllowed({ capabilities, subkeysMeta }) {
    if (!this.version.isEnterprise) return false;
    const canReadSubkeys = capabilities.subkeys.canRead;
    const canPatchData = capabilities.data.canPatch;
    if (canReadSubkeys && canPatchData) {
      const { deletion_time, destroyed } = subkeysMeta;
      const isLatestActive = isDeleted(deletion_time) || destroyed ? false : true;
      // only the latest secret version can be patched and it must not be deleted or destroyed
      return isLatestActive;
    }
    return false;
  }

  async fetchCapabilities(backend, path) {
    const metadataPath = `${backend}/metadata/${path}`;
    const dataPath = `${backend}/data/${path}`;
    const subkeysPath = `${backend}/subkeys/${path}`;
    const perms = await this.capabilities.fetch([metadataPath, dataPath, subkeysPath]);
    return {
      metadata: perms[metadataPath],
      data: perms[dataPath],
      subkeys: perms[subkeysPath],
    };
  }

  async model() {
    const backend = this.secretMountPath.currentPath;
    const { name: path } = this.paramsFor('secret');
    const capabilities = await this.fetchCapabilities(backend, path);
    const subkeys = await this.fetchSubkeys(backend, path);

Review comment (suggestion):
This is redundant since an empty object is truthy which is what `subkeysMeta` now defaults to, but added as an extra precaution.

Code after:
    // catch error and only return 404 which indicates the secret truly does not exist.
    // control group error is handled by the metadata route
    return this.store.queryRecord('kv/metadata', { backend, path }).catch((e) => {
      if (e.httpStatus === 404) {
        throw e;
      }
      return null;
    });
  }

  // this request always returns subkeys for the latest version
  fetchSubkeys(backend, path) {
    if (this.version.isEnterprise) {
      const adapter = this.store.adapterFor('kv/data');
      // metadata will throw if the secret does not exist
      // always return here so we get deletion state and relevant metadata
      return adapter.fetchSubkeys(backend, path);
    }
    return null;
  }

  isPatchAllowed({ capabilities, subkeysMeta = {} }) {
    if (!this.version.isEnterprise) return false;
    const canReadSubkeys = capabilities.subkeys.canRead;
    const canPatchData = capabilities.data.canPatch;
    if (canReadSubkeys && canPatchData && subkeysMeta) {
      const { deletion_time, destroyed } = subkeysMeta;
      const isLatestActive = isDeleted(deletion_time) || destroyed ? false : true;
      // only the latest secret version can be patched and it must not be deleted or destroyed
      return isLatestActive;
    }
    return false;
  }

  async fetchCapabilities(backend, path) {
    const metadataPath = `${backend}/metadata/${path}`;
    const dataPath = `${backend}/data/${path}`;
    const subkeysPath = `${backend}/subkeys/${path}`;
    const perms = await this.capabilities.fetch([metadataPath, dataPath, subkeysPath]);
    return {
      metadata: perms[metadataPath],
      data: perms[dataPath],
      subkeys: perms[subkeysPath],
    };
  }

  async model() {
    const backend = this.secretMountPath.currentPath;
    const { name: path } = this.paramsFor('secret');
    const capabilities = await this.fetchCapabilities(backend, path);
    const subkeys = await this.fetchSubkeys(backend, path);