public record ConstraintElement()

in sources/src/main/java/com/google/solutions/jitaccess/catalog/policy/PolicyDocument.java [721:839]


  public record ConstraintElement(
    @JsonProperty("type") String type,
    @JsonProperty("name") String name,
    @JsonProperty("displayName") String displayName,
    @JsonProperty("min") String expiryMinDuration,
    @JsonProperty("max") String expiryMaxDuration,
    @JsonProperty("expression") String celExpression,
    @JsonProperty("variables") List<CelVariableElement> celVariables
  ) {
    static ConstraintElement toYaml(@NotNull Constraint constraint) {
      if (constraint instanceof ExpiryConstraint expiryConstraint) {
        return new ConstraintElement(
          "expiry",
          null,
          null,
          expiryConstraint.minDuration().toString(),
          expiryConstraint.maxDuration().toString(),
          null,
          null);
      }
      else if (constraint instanceof CelConstraint celConstraint) {
        return new ConstraintElement(
          "expression",
          celConstraint.name(),
          celConstraint.displayName(),
          null,
          null,
          celConstraint.expression(),
          celConstraint.variables()
            .stream()
            .map(CelVariableElement::toYaml)
            .toList());
      }
      else {
        throw new UnsupportedOperationException("The constraint type is not supported");
      }
    }

    @NotNull Optional<Constraint> toPolicy(@NotNull IssueCollection issues) {
      return Optional
        .ofNullable(switch (Strings.nullToEmpty(this.type).trim().toLowerCase()) {
          case "expiry" -> {
            if (!Strings.isNullOrEmpty(this.celExpression) || this.celVariables != null) {
              issues.error(
                Issue.Code.CONSTRAINT_INVALID_EXPIRY,
                "Expiry constraints must not specify an expression",
                this.type);
            }

            try {
              yield new ExpiryConstraint(
                Duration.parse(this.expiryMinDuration),
                Duration.parse(this.expiryMaxDuration));
            }
            catch (Exception e) {
              issues.error(
                Issue.Code.CONSTRAINT_INVALID_EXPIRY,
                "The format of the duration '%s - %s' is invalid: %s",
                this.expiryMinDuration,
                this.expiryMaxDuration,
                e.getMessage());
              yield null;
            }
          }

          case "expression" -> {
            if (this.expiryMinDuration != null || this.expiryMaxDuration != null) {
              issues.error(
                Issue.Code.CONSTRAINT_INVALID_EXPRESSION,
                "Expression constraints must not specify an expiry",
                this.type);
            }

            var variables = Coalesce.emptyIfNull(this.celVariables)
              .stream()
              .map(v -> v.toPolicy(issues))
              .toList();

            if (variables.stream().allMatch(Optional::isPresent)) {
              try {
                var constraint = new CelConstraint(
                  this.name,
                  this.displayName,
                  variables.stream().map(Optional::get).toList(),
                  this.celExpression);

                for (var issue : constraint.lint()) {
                  issues.error(
                    Issue.Code.CONSTRAINT_INVALID_EXPRESSION,
                    "The constraint '%s' uses an invalid CEL expression: %s",
                    this.name,
                    issue.getMessage());
                }

                yield constraint;
              }
              catch (Exception e) {
                issues.error(
                  Issue.Code.CONSTRAINT_INVALID_EXPRESSION,
                  "The CEL constraint is invalid: %s",
                  e.getMessage());
                yield null;
              }
            }
            else {
              yield null;
            }
          }

          default -> {
            issues.error(
              Issue.Code.CONSTRAINT_INVALID_TYPE,
              "The constraint type '%s' is invalid",
              this.type);
            yield null;
          }
        });
    }
  }