SecretDAO { @VisibleForTesting public long partialUpdateSecret(String name, String creator, PartialUpdateSecretRequestV2 request) { return dslContext.transactionResult(configuration -> { long now = OffsetDateTime.now().toEpochSecond(); SecretContentDAO secretContentDAO = secretContentDAOFactory.using(configuration); SecretSeriesDAO secretSeriesDAO = secretSeriesDAOFactory.using(configuration); SecretSeries secretSeries = secretSeriesDAO.getSecretSeriesByName(name).orElseThrow( NotFoundException::new); Long currentVersion = secretSeries.currentVersion().orElseThrow(NotFoundException::new); SecretContent secretContent = secretContentDAO.getSecretContentById(currentVersion).orElseThrow(NotFoundException::new); long secretId = secretSeries.id(); String description = request.descriptionPresent() ? request.description() : secretSeries.description(); String type = request.typePresent() ? request.type() : secretSeries.type().orElse(""); ImmutableMap<String, String> metadata = request.metadataPresent() ? request.metadata() : secretContent.metadata(); Long expiry = request.expiryPresent() ? request.expiry() : secretContent.expiry(); String encryptedContent = secretContent.encryptedContent(); String hmac = secretContent.hmac(); if (request.contentPresent()) { checkArgument(!request.content().isEmpty()); hmac = cryptographer.computeHmac( request.content().getBytes(UTF_8), "hmackey"); if (hmac == null) { throw new ContentEncodingException("Error encoding content for SecretBuilder!"); } encryptedContent = cryptographer.encryptionKeyDerivedFrom(name).encrypt(request.content()); } secretSeriesDAO.updateSecretSeries(secretId, name, creator, description, type, secretSeries.generationOptions(), now); long secretContentId = secretContentDAO.createSecretContent(secretId, encryptedContent, hmac, creator, metadata, expiry, now); secretSeriesDAO.setCurrentVersion(secretId, secretContentId, creator, now); return secretId; }); } SecretDAO(DSLContext dslContext, SecretContentDAOFactory secretContentDAOFactory,
      SecretSeriesDAOFactory secretSeriesDAOFactory, ContentCryptographer cryptographer); @VisibleForTesting long createSecret(String name, String encryptedSecret, String hmac,
      String creator, Map<String, String> metadata, long expiry, String description,
      @Nullable String type, @Nullable Map<String, String> generationOptions); @VisibleForTesting long createOrUpdateSecret(String name, String encryptedSecret, String hmac, String creator,
      Map<String, String> metadata, long expiry, String description, @Nullable String type,
      @Nullable Map<String, String> generationOptions); @VisibleForTesting long partialUpdateSecret(String name, String creator,
      PartialUpdateSecretRequestV2 request); boolean setExpiration(String name, Instant expiration); Optional<SecretSeriesAndContent> getSecretById(long secretId); Optional<SecretSeriesAndContent> getSecretByName(String name); List<SecretSeriesAndContent> getSecretsByName(List<String> names); ImmutableList<SecretSeriesAndContent> getSecrets(@Nullable Long expireMaxTime,
      @Nullable Group group, @Nullable Long expireMinTime, @Nullable String minName,
      @Nullable Integer limit); ImmutableList<SimpleEntry<Long, String>> getSecretsNameOnly(); ImmutableList<SecretSeriesAndContent> getSecretsBatched(int idx, int num,
      boolean newestFirst); Optional<ImmutableList<SanitizedSecret>> getSecretVersionsByName(String name,
      int versionIdx, int numVersions); void setCurrentSecretVersionByName(String name, long versionId, String updater); void deleteSecretsByName(String name); int countDeletedSecrets(); int countSecretsDeletedBeforeDate(DateTime deleteBefore); void dangerPermanentlyRemoveSecretsDeletedBeforeDate(DateTime deletedBefore,
      int sleepMillis);  }
@Test(expected = NotFoundException.class) public void partialUpdateSecretWhenSecretSeriesDoesNotExist() { String name = "newSecret"; String content = "c2VjcmV0MQ=="; PartialUpdateSecretRequestV2 request = PartialUpdateSecretRequestV2.builder().contentPresent(true).content(content).build(); secretDAO.partialUpdateSecret(name, "test", request); }
@Test(expected = NotFoundException.class) public void partialUpdateSecretWhenSecretContentDoesNotExist() { String name = "newSecret"; String content = "c2VjcmV0MQ=="; PartialUpdateSecretRequestV2 request = PartialUpdateSecretRequestV2.builder().contentPresent(true).content(content).build(); jooqContext.insertInto(SECRETS) .set(SECRETS.ID, 12L) .set(SECRETS.NAME, name) .set(SECRETS.DESCRIPTION, series1.description()) .set(SECRETS.CREATEDBY, series1.createdBy()) .set(SECRETS.CREATEDAT, series1.createdAt().toEpochSecond()) .set(SECRETS.UPDATEDBY, series1.updatedBy()) .set(SECRETS.UPDATEDAT, series1.updatedAt().toEpochSecond()) .set(SECRETS.CURRENT, 12L) .execute(); secretDAO.partialUpdateSecret(name, "test", request); }
@Test(expected = NotFoundException.class) public void partialUpdateSecretWhenSecretCurrentIsNotSet() { String content = "c2VjcmV0MQ=="; PartialUpdateSecretRequestV2 request = PartialUpdateSecretRequestV2.builder().contentPresent(true).content(content).build(); secretDAO.partialUpdateSecret(series3.name(), "test", request); }