@SneakyThrows
  public static String generatePolicy(Set<CredentialContext.Privilege> privileges, List<String> locations) {
    JsonNode policyRoot = loadYaml(POLICY_STATEMENT);
    ArrayNode policyStatement = (ArrayNode) policyRoot.findPath("Statement");
    JsonNode operationsStatement = loadYaml(OPERATION_STATEMENT);
    policyStatement.add(operationsStatement);

    // Add the appropriate S3 operations for the privileges requested
    ArrayNode actions = (ArrayNode) operationsStatement.findPath("Action");
    if (privileges.contains(CredentialContext.Privilege.UPDATE)) {
      UPDATE_ACTIONS.forEach(actions::add);
    } else if (privileges.contains(CredentialContext.Privilege.SELECT)) {
      SELECT_ACTIONS.forEach(actions::add);
    } else {
      throw new NotAuthorizedException(
        "Can't generate policy for unknown privileges '%s' for locations: '%s'"
          .formatted(privileges, locations));
    }

    // Group each location by s3 bucket it's located in, then for each
    // bucket, add the bucket arn for the listBucket and operations statements,
    // then add each path as a conditional prefix
    getBucketToPathsMap(locations).forEach(
      (bucketName, paths) -> {
        JsonNode listStatement = loadYaml(BUCKET_STATEMENT);
        policyStatement.add(listStatement);

        ArrayNode bucketResource = (ArrayNode) listStatement.findPath("Resource");
        ArrayNode operationsResource = (ArrayNode) operationsStatement.findPath("Resource");
        bucketResource.add("arn:aws:s3:::%s".formatted(bucketName));

        ArrayNode conditionalPrefixes = (ArrayNode) listStatement.findPath("s3:prefix");
        paths.forEach(
          path -> {
            // remove any preceding forward slashes
            // TODO: potentially sanitize/encode the whole path to deal with problematic chars
            String sanitizedPath = path.replaceAll("^/+", "");

            if (sanitizedPath.isEmpty()) {
              conditionalPrefixes.add("*");
              operationsResource.add("arn:aws:s3:::%s/*".formatted(bucketName));
            } else {
              conditionalPrefixes.add(sanitizedPath);
              conditionalPrefixes.add(sanitizedPath + "/");
              conditionalPrefixes.add(sanitizedPath + "/*");

              operationsResource.add("arn:aws:s3:::%s/%s/*".formatted(bucketName, sanitizedPath));
              operationsResource.add("arn:aws:s3:::%s/%s".formatted(bucketName, sanitizedPath));
            }
          });
      });

    return JSON_MAPPER.writeValueAsString(policyRoot);
  }
@Test
  public void testPolicyWithStorageProfileLocations() {
    String updatePolicy =
        AwsPolicyGenerator.generatePolicy(
            Set.of(SELECT, UPDATE),
            List.of(
                "s3://my-bucket1/path1/table1", "s3://profile-bucket2/", "s3://profile-bucket3"));

    assertThat(updatePolicy)
        .contains("s3:PutO*")
        .contains("s3:GetO*")
        .contains("s3:DeleteO*")
        .contains("arn:aws:s3:::profile-bucket2/*")
        .contains("arn:aws:s3:::profile-bucket3/*");

    String selectPolicy =
        AwsPolicyGenerator.generatePolicy(
            Set.of(SELECT),
            List.of(
                "s3://my-bucket1/path1/table1",
                "s3://my-bucket2/path2/table2",
                "s3://my-bucket1/path3/table3"));

    assertThat(selectPolicy)
        .doesNotContain("s3:PutO*")
        .doesNotContain("s3:DeleteO*")
        .contains("s3:GetO*");
  }