This is an automated email from the ASF dual-hosted git repository.
ppkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-release-plugin.git
The following commit(s) were added to refs/heads/master by this push:
new 546dfbf Add SLSA data models
546dfbf is described below
commit 546dfbf92a3d016d6bb54ebdda175b3db59762bd
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Tue May 5 09:24:57 2026 +0200
Add SLSA data models
Adds SLSA data models annotated with Jackson annotation for
serialization/deserialization to JSON.
---
fb-excludes.xml | 6 +
pom.xml | 17 ++
.../release/plugin/slsa/v1_2/BuildDefinition.java | 187 ++++++++++++++++
.../release/plugin/slsa/v1_2/BuildMetadata.java | 141 +++++++++++++
.../commons/release/plugin/slsa/v1_2/Builder.java | 129 +++++++++++
.../release/plugin/slsa/v1_2/DsseEnvelope.java | 130 ++++++++++++
.../release/plugin/slsa/v1_2/Provenance.java | 124 +++++++++++
.../plugin/slsa/v1_2/ResourceDescriptor.java | 235 +++++++++++++++++++++
.../release/plugin/slsa/v1_2/RunDetails.java | 149 +++++++++++++
.../release/plugin/slsa/v1_2/Signature.java | 107 ++++++++++
.../release/plugin/slsa/v1_2/Statement.java | 131 ++++++++++++
.../release/plugin/slsa/v1_2/package-info.java | 34 +++
12 files changed, 1390 insertions(+)
diff --git a/fb-excludes.xml b/fb-excludes.xml
index 2cba281..9681064 100644
--- a/fb-excludes.xml
+++ b/fb-excludes.xml
@@ -18,6 +18,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0
https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
+ <!-- SLSA provenance data models are short-lived DTOs serialized to JSON;
defensive copying adds no safety. -->
+ <Match>
+ <Package name="org.apache.commons.release.plugin.slsa.v1_2" />
+ <Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2" />
+ </Match>
+
<!-- Omit junit tests -->
<Match>
<Class name="~.*\.*Test.*"/>
diff --git a/pom.xml b/pom.xml
index 0e61c9e..23b1da9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,7 +102,20 @@
<!-- Until Maven plugins used here don't fail the Moditect plugin -->
<moditect.skip>true</moditect.skip>
<japicmp.skip>true</japicmp.skip>
+ <!-- Dependency versions -->
+ <commons.jackson.version>2.21.2</commons.jackson.version>
</properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.fasterxml.jackson</groupId>
+ <artifactId>jackson-bom</artifactId>
+ <version>${commons.jackson.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
@@ -160,6 +173,10 @@
<artifactId>commons-compress</artifactId>
<version>1.28.0</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildDefinition.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildDefinition.java
new file mode 100644
index 0000000..43bcb94
--- /dev/null
+++
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildDefinition.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Inputs that define the build: the build type, external and internal
parameters, and resolved dependencies.
+ *
+ * <p>Specifies everything that influenced the build output. Together with
{@link RunDetails}, it forms the complete
+ * {@link Provenance} record.</p>
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+public class BuildDefinition {
+
+ /**
+ * URI indicating what type of build was performed.
+ */
+ @JsonProperty("buildType")
+ private String buildType =
"https://commons.apache.org/proper/commons-release-plugin/slsa/v0.1.0";
+
+ /**
+ * Inputs passed to the build.
+ */
+ @JsonProperty("externalParameters")
+ private Map<String, Object> externalParameters = new HashMap<>();
+
+ /**
+ * Parameters set by the build platform.
+ */
+ @JsonProperty("internalParameters")
+ private Map<String, Object> internalParameters = new HashMap<>();
+
+ /**
+ * Artifacts the build depends on, specified by URI and digest.
+ */
+ @JsonProperty("resolvedDependencies")
+ private List<ResourceDescriptor> resolvedDependencies;
+
+ /**
+ * Creates a new BuildDefinition instance with the default build type.
+ */
+ public BuildDefinition() {
+ }
+
+ /**
+ * Creates a new BuildDefinition with the given build type and external
parameters.
+ *
+ * @param buildType URI indicating what type of build was
performed
+ * @param externalParameters inputs passed to the build
+ */
+ public BuildDefinition(String buildType, Map<String, Object>
externalParameters) {
+ this.buildType = buildType;
+ this.externalParameters = externalParameters;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ BuildDefinition that = (BuildDefinition) o;
+ return Objects.equals(buildType, that.buildType) &&
Objects.equals(externalParameters, that.externalParameters) &&
Objects.equals(internalParameters,
+ that.internalParameters) &&
Objects.equals(resolvedDependencies, that.resolvedDependencies);
+ }
+
+ /**
+ * Gets the URI indicating what type of build was performed.
+ *
+ * <p>Determines the meaning of {@code externalParameters} and {@code
internalParameters}.</p>
+ *
+ * @return the build type URI
+ */
+ public String getBuildType() {
+ return buildType;
+ }
+
+ /**
+ * Gets the inputs passed to the build, such as command-line arguments or
environment variables.
+ *
+ * @return the external parameters map, or {@code null} if not set
+ */
+ public Map<String, Object> getExternalParameters() {
+ return externalParameters;
+ }
+
+ /**
+ * Gets the artifacts the build depends on, such as sources, dependencies,
build tools, and base images,
+ * specified by URI and digest.
+ *
+ * @return the internal parameters map, or {@code null} if not set
+ */
+ public Map<String, Object> getInternalParameters() {
+ return internalParameters;
+ }
+
+ /**
+ * Gets the materials that influenced the build.
+ *
+ * <p>Considered incomplete unless resolved materials are present.</p>
+ *
+ * @return the list of resolved dependencies, or {@code null} if not set
+ */
+ public List<ResourceDescriptor> getResolvedDependencies() {
+ return resolvedDependencies;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(buildType, externalParameters, internalParameters,
resolvedDependencies);
+ }
+
+ /**
+ * Sets the URI indicating what type of build was performed.
+ *
+ * @param buildType the build type URI
+ * @return this for chaining
+ */
+ public BuildDefinition setBuildType(String buildType) {
+ this.buildType = buildType;
+ return this;
+ }
+
+ /**
+ * Sets the inputs passed to the build.
+ *
+ * @param externalParameters the external parameters map
+ * @return this for chaining
+ */
+ public BuildDefinition setExternalParameters(Map<String, Object>
externalParameters) {
+ this.externalParameters = externalParameters;
+ return this;
+ }
+
+ /**
+ * Sets the artifacts the build depends on.
+ *
+ * @param internalParameters the internal parameters map
+ * @return this for chaining
+ */
+ public BuildDefinition setInternalParameters(Map<String, Object>
internalParameters) {
+ this.internalParameters = internalParameters;
+ return this;
+ }
+
+ /**
+ * Sets the materials that influenced the build.
+ *
+ * @param resolvedDependencies the list of resolved dependencies
+ * @return this for chaining
+ */
+ public BuildDefinition setResolvedDependencies(List<ResourceDescriptor>
resolvedDependencies) {
+ this.resolvedDependencies = resolvedDependencies;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "BuildDefinition{buildType='" + buildType + '\''
+ + ", externalParameters=" + externalParameters
+ + ", internalParameters=" + internalParameters
+ + ", resolvedDependencies=" + resolvedDependencies + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildMetadata.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildMetadata.java
new file mode 100644
index 0000000..595e0f7
--- /dev/null
+++
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/BuildMetadata.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.time.OffsetDateTime;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Metadata about a build invocation: its identifier and start and finish
timestamps.
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class BuildMetadata {
+
+ /** Timestamp when the build completed. */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern =
"yyyy-MM-dd'T'HH:mm:ss'Z'")
+ @JsonProperty("finishedOn")
+ private OffsetDateTime finishedOn;
+ /** Identifier for this build invocation. */
+ @JsonProperty("invocationId")
+ private String invocationId;
+ /** Timestamp when the build started. */
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern =
"yyyy-MM-dd'T'HH:mm:ss'Z'")
+ @JsonProperty("startedOn")
+ private OffsetDateTime startedOn;
+
+ /** Creates a new BuildMetadata instance. */
+ public BuildMetadata() {
+ }
+
+ /**
+ * Creates a new BuildMetadata instance with all fields set.
+ *
+ * @param invocationId identifier for this build invocation
+ * @param startedOn timestamp when the build started
+ * @param finishedOn timestamp when the build completed
+ */
+ public BuildMetadata(String invocationId, OffsetDateTime startedOn,
OffsetDateTime finishedOn) {
+ this.invocationId = invocationId;
+ this.startedOn = startedOn;
+ this.finishedOn = finishedOn;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof BuildMetadata)) {
+ return false;
+ }
+ BuildMetadata that = (BuildMetadata) o;
+ return Objects.equals(invocationId, that.invocationId) &&
Objects.equals(startedOn, that.startedOn) && Objects.equals(finishedOn,
that.finishedOn);
+ }
+
+ /**
+ * Gets the timestamp of when the build completed, serialized as RFC 3339
in UTC ({@code "Z"} suffix).
+ *
+ * @return the completion timestamp, or {@code null} if not set
+ */
+ public OffsetDateTime getFinishedOn() {
+ return finishedOn;
+ }
+
+ /**
+ * Gets the identifier for this build invocation.
+ *
+ * @return the invocation identifier, or {@code null} if not set
+ */
+ public String getInvocationId() {
+ return invocationId;
+ }
+
+ /**
+ * Gets the timestamp of when the build started, serialized as RFC 3339 in
UTC ({@code "Z"} suffix).
+ *
+ * @return the start timestamp, or {@code null} if not set
+ */
+ public OffsetDateTime getStartedOn() {
+ return startedOn;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(invocationId, startedOn, finishedOn);
+ }
+
+ /**
+ * Sets the timestamp of when the build completed.
+ *
+ * @param finishedOn the completion timestamp
+ * @return this for chaining
+ */
+ public BuildMetadata setFinishedOn(OffsetDateTime finishedOn) {
+ this.finishedOn = finishedOn;
+ return this;
+ }
+
+ /**
+ * Sets the identifier for this build invocation.
+ *
+ * @param invocationId the invocation identifier
+ * @return this for chaining
+ */
+ public BuildMetadata setInvocationId(String invocationId) {
+ this.invocationId = invocationId;
+ return this;
+ }
+
+ /**
+ * Sets the timestamp of when the build started.
+ *
+ * @param startedOn the start timestamp
+ * @return this for chaining
+ */
+ public BuildMetadata setStartedOn(OffsetDateTime startedOn) {
+ this.startedOn = startedOn;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "BuildMetadata{invocationId='" + invocationId + "', startedOn="
+ startedOn + ", finishedOn=" + finishedOn + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Builder.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Builder.java
new file mode 100644
index 0000000..508d622
--- /dev/null
+++ b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Builder.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Entity that executed the build and is trusted to have correctly performed
the operation and populated the provenance.
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+public class Builder {
+
+ /** Orchestrator dependencies that may affect provenance generation. */
+ @JsonProperty("builderDependencies")
+ private List<ResourceDescriptor> builderDependencies = new ArrayList<>();
+ /** Identifier URI of the builder. */
+ @JsonProperty("id")
+ private String id;
+ /** Map of build platform component names to their versions. */
+ @JsonProperty("version")
+ private Map<String, String> version = new HashMap<>();
+
+ /** Creates a new Builder instance. */
+ public Builder() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Builder)) {
+ return false;
+ }
+ Builder that = (Builder) o;
+ return Objects.equals(id, that.id)
+ && Objects.equals(builderDependencies,
that.builderDependencies)
+ && Objects.equals(version, that.version);
+ }
+
+ /**
+ * Gets orchestrator dependencies that do not run within the build
workload and do not affect the build output,
+ * but may affect provenance generation or security guarantees.
+ *
+ * @return the list of builder dependencies, or {@code null} if not set
+ */
+ public List<ResourceDescriptor> getBuilderDependencies() {
+ return builderDependencies;
+ }
+
+ /**
+ * Gets the identifier of the builder.
+ *
+ * @return the builder identifier URI
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets a map of build platform component names to their versions.
+ *
+ * @return the version map, or {@code null} if not set
+ */
+ public Map<String, String> getVersion() {
+ return version;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, builderDependencies, version);
+ }
+
+ /**
+ * Sets the orchestrator dependencies that may affect provenance
generation or security guarantees.
+ *
+ * @param builderDependencies the list of builder dependencies
+ * @return this for chaining
+ */
+ public Builder setBuilderDependencies(List<ResourceDescriptor>
builderDependencies) {
+ this.builderDependencies = builderDependencies;
+ return this;
+ }
+
+ /**
+ * Sets the identifier of the builder.
+ *
+ * @param id the builder identifier URI
+ * @return this for chaining
+ */
+ public Builder setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Sets the map of build platform component names to their versions.
+ *
+ * @param version the version map
+ * @return this for chaining
+ */
+ public Builder setVersion(Map<String, String> version) {
+ this.version = version;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "Builder{id='" + id + "', builderDependencies=" +
builderDependencies + ", version=" + version + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/DsseEnvelope.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/DsseEnvelope.java
new file mode 100644
index 0000000..e68e575
--- /dev/null
+++
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/DsseEnvelope.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * DSSE (Dead Simple Signing Envelope) that wraps a signed in-toto statement
payload.
+ *
+ * @see <a
href="https://github.com/secure-systems-lab/dsse/blob/v1.0.2/envelope.md">DSSE
Envelope specification</a>
+ */
+public class DsseEnvelope {
+
+ /** The payload type URI for in-toto attestation statements. */
+ public static final String PAYLOAD_TYPE = "application/vnd.in-toto+json";
+ /** Serialized statement bytes, Base64-encoded in JSON. */
+ @JsonProperty("payload")
+ private byte[] payload;
+ /** Content type identifying the format of {@link #payload}. */
+ @JsonProperty("payloadType")
+ private String payloadType = PAYLOAD_TYPE;
+ /** One or more signatures over the PAE-encoded payload. */
+ @JsonProperty("signatures")
+ private List<Signature> signatures;
+
+ /** Creates a new DsseEnvelope instance with {@code payloadType} pre-set
to {@link #PAYLOAD_TYPE}. */
+ public DsseEnvelope() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof DsseEnvelope)) {
+ return false;
+ }
+ DsseEnvelope envelope = (DsseEnvelope) o;
+ return Objects.equals(payloadType, envelope.payloadType) &&
Arrays.equals(payload, envelope.payload)
+ && Objects.equals(signatures, envelope.signatures);
+ }
+
+ /**
+ * Gets the serialized payload bytes.
+ *
+ * <p>When serialized to JSON the bytes are Base64-encoded.</p>
+ *
+ * @return the payload bytes, or {@code null} if not set
+ */
+ public byte[] getPayload() {
+ return payload;
+ }
+
+ /**
+ * Gets the payload type URI.
+ *
+ * @return the payload type, never {@code null} in a valid envelope
+ */
+ public String getPayloadType() {
+ return payloadType;
+ }
+
+ /**
+ * Gets the list of signatures over the PAE-encoded payload.
+ *
+ * @return the signatures, or {@code null} if not set
+ */
+ public List<Signature> getSignatures() {
+ return signatures;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(payloadType, Arrays.hashCode(payload), signatures);
+ }
+
+ /**
+ * Sets the serialized payload bytes.
+ *
+ * @param payload the payload bytes
+ * @return this for chaining
+ */
+ public DsseEnvelope setPayload(byte[] payload) {
+ this.payload = payload;
+ return this;
+ }
+
+ /**
+ * Sets the payload type URI.
+ *
+ * @param payloadType the payload type URI
+ * @return this for chaining
+ */
+ public DsseEnvelope setPayloadType(String payloadType) {
+ this.payloadType = payloadType;
+ return this;
+ }
+
+ /**
+ * Sets the list of signatures over the PAE-encoded payload.
+ *
+ * @param signatures the signatures
+ * @return this for chaining
+ */
+ public DsseEnvelope setSignatures(List<Signature> signatures) {
+ this.signatures = signatures;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "DsseEnvelope{payloadType='" + payloadType + "', payload=<" +
(payload != null ? payload.length : 0)
+ + " bytes>, signatures=" + signatures + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Provenance.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Provenance.java
new file mode 100644
index 0000000..6002dce
--- /dev/null
+++ b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Provenance.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Root predicate of an SLSA v1.2 provenance attestation, describing what was
built and how.
+ *
+ * <p>Combines a {@link BuildDefinition} (the inputs) with {@link RunDetails}
(the execution context). Intended to be
+ * used as the {@code predicate} field of an in-toto {@link Statement}.</p>
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Provenance {
+
+ /** Predicate type URI used in the in-toto {@link Statement} wrapping this
provenance. */
+ public static final String PREDICATE_TYPE =
"https://slsa.dev/provenance/v1";
+
+ /** Inputs that defined the build. */
+ @JsonProperty("buildDefinition")
+ private BuildDefinition buildDefinition;
+
+ /** Details about the build invocation. */
+ @JsonProperty("runDetails")
+ private RunDetails runDetails;
+
+ /** Creates a new Provenance instance. */
+ public Provenance() {
+ }
+
+ /**
+ * Creates a new Provenance with the given build definition and run
details.
+ *
+ * @param buildDefinition inputs that defined the build
+ * @param runDetails details about the build invocation
+ */
+ public Provenance(BuildDefinition buildDefinition, RunDetails runDetails) {
+ this.buildDefinition = buildDefinition;
+ this.runDetails = runDetails;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Provenance that = (Provenance) o;
+ return Objects.equals(buildDefinition, that.buildDefinition) &&
Objects.equals(runDetails, that.runDetails);
+ }
+
+ /**
+ * Gets the build definition describing all inputs that produced the build
output.
+ *
+ * <p>Includes source code, dependencies, build tools, base images, and
other materials.</p>
+ *
+ * @return the build definition, or {@code null} if not set
+ */
+ public BuildDefinition getBuildDefinition() {
+ return buildDefinition;
+ }
+
+ /**
+ * Gets the details about the invocation of the build tool and the
environment in which it was run.
+ *
+ * @return the run details, or {@code null} if not set
+ */
+ public RunDetails getRunDetails() {
+ return runDetails;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(buildDefinition, runDetails);
+ }
+
+ /**
+ * Sets the build definition describing all inputs that produced the build
output.
+ *
+ * @param buildDefinition the build definition
+ * @return this for chaining
+ */
+ public Provenance setBuildDefinition(BuildDefinition buildDefinition) {
+ this.buildDefinition = buildDefinition;
+ return this;
+ }
+
+ /**
+ * Sets the details about the invocation of the build tool and the
environment in which it was run.
+ *
+ * @param runDetails the run details
+ * @return this for chaining
+ */
+ public Provenance setRunDetails(RunDetails runDetails) {
+ this.runDetails = runDetails;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "Provenance{buildDefinition=" + buildDefinition + ",
runDetails=" + runDetails + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/ResourceDescriptor.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/ResourceDescriptor.java
new file mode 100644
index 0000000..cb3510e
--- /dev/null
+++
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/ResourceDescriptor.java
@@ -0,0 +1,235 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Description of an artifact or resource referenced in the build, identified
by URI and cryptographic digest.
+ *
+ * <p>Used to represent inputs to, outputs from, or byproducts of the build
process.</p>
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResourceDescriptor {
+
+ /** Additional key-value metadata about the resource. */
+ @JsonProperty("annotations")
+ private Map<String, Object> annotations;
+ /** Raw contents of the resource, base64-encoded in JSON. */
+ @JsonProperty("content")
+ private byte[] content;
+ /** Map of digest algorithm names to hex-encoded values. */
+ @JsonProperty("digest")
+ private Map<String, String> digest;
+ /** Download URI for the resource, if different from {@link #uri}. */
+ @JsonProperty("downloadLocation")
+ private String downloadLocation;
+ /** Media type of the resource. */
+ @JsonProperty("mediaType")
+ private String mediaType;
+ /** Human-readable name of the resource. */
+ @JsonProperty("name")
+ private String name;
+ /** URI identifying the resource. */
+ @JsonProperty("uri")
+ private String uri;
+
+ /** Creates a new ResourceDescriptor instance. */
+ public ResourceDescriptor() {
+ }
+
+ /**
+ * Creates a new ResourceDescriptor with the given URI and digest.
+ *
+ * @param uri URI identifying the resource
+ * @param digest map of digest algorithm names to their hex-encoded values
+ */
+ public ResourceDescriptor(String uri, Map<String, String> digest) {
+ this.uri = uri;
+ this.digest = digest;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ResourceDescriptor that = (ResourceDescriptor) o;
+ return Objects.equals(uri, that.uri) && Objects.equals(digest,
that.digest);
+ }
+
+ /**
+ * Gets additional key-value metadata about the resource, such as
filename, size, or builder-specific attributes.
+ *
+ * @return the annotations map, or {@code null} if not set
+ */
+ public Map<String, Object> getAnnotations() {
+ return annotations;
+ }
+
+ /**
+ * Gets the raw contents of the resource, base64-encoded when serialized
to JSON.
+ *
+ * @return the resource content, or {@code null} if not set
+ */
+ public byte[] getContent() {
+ return content;
+ }
+
+ /**
+ * Gets the map of cryptographic digest algorithms to their corresponding
hex-encoded values for this resource.
+ *
+ * <p>Common keys include {@code "sha256"} and {@code "sha512"}.</p>
+ *
+ * @return the digest map, or {@code null} if not set
+ */
+ public Map<String, String> getDigest() {
+ return digest;
+ }
+
+ /**
+ * Gets the download URI for the resource, if different from {@link
#getUri()}.
+ *
+ * @return the download location URI, or {@code null} if not set
+ */
+ public String getDownloadLocation() {
+ return downloadLocation;
+ }
+
+ /**
+ * Gets the media type of the resource (e.g., {@code
"application/octet-stream"}).
+ *
+ * @return the media type, or {@code null} if not set
+ */
+ public String getMediaType() {
+ return mediaType;
+ }
+
+ /**
+ * Gets the name of the resource.
+ *
+ * @return the resource name, or {@code null} if not set
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the URI identifying the resource.
+ *
+ * @return the resource URI, or {@code null} if not set
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uri, digest);
+ }
+
+ /**
+ * Sets additional key-value metadata about the resource.
+ *
+ * @param annotations the annotations map
+ * @return this for chaining
+ */
+ public ResourceDescriptor setAnnotations(Map<String, Object> annotations) {
+ this.annotations = annotations;
+ return this;
+ }
+
+ /**
+ * Sets the raw contents of the resource.
+ *
+ * @param content the resource content
+ * @return this for chaining
+ */
+ public ResourceDescriptor setContent(byte[] content) {
+ this.content = content;
+ return this;
+ }
+
+ /**
+ * Sets the map of cryptographic digest algorithms to their hex-encoded
values.
+ *
+ * @param digest the digest map
+ * @return this for chaining
+ */
+ public ResourceDescriptor setDigest(Map<String, String> digest) {
+ this.digest = digest;
+ return this;
+ }
+
+ /**
+ * Sets the download URI for the resource.
+ *
+ * @param downloadLocation the download location URI
+ * @return this for chaining
+ */
+ public ResourceDescriptor setDownloadLocation(String downloadLocation) {
+ this.downloadLocation = downloadLocation;
+ return this;
+ }
+
+ /**
+ * Sets the media type of the resource.
+ *
+ * @param mediaType the media type
+ * @return this for chaining
+ */
+ public ResourceDescriptor setMediaType(String mediaType) {
+ this.mediaType = mediaType;
+ return this;
+ }
+
+ /**
+ * Sets the name of the resource.
+ *
+ * @param name the resource name
+ * @return this for chaining
+ */
+ public ResourceDescriptor setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Sets the URI identifying the resource.
+ *
+ * @param uri the resource URI
+ * @return this for chaining
+ */
+ public ResourceDescriptor setUri(String uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "ResourceDescriptor{uri='" + uri + '\'' + ", digest=" + digest
+ '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/RunDetails.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/RunDetails.java
new file mode 100644
index 0000000..da14aef
--- /dev/null
+++ b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/RunDetails.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Details about the build invocation: the builder identity, execution
metadata, and any byproduct artifacts.
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class RunDetails {
+
+ /**
+ * Entity that executed the build.
+ */
+ @JsonProperty("builder")
+ private Builder builder;
+ /**
+ * Artifacts produced as a side effect of the build.
+ */
+ @JsonProperty("byproducts")
+ private List<ResourceDescriptor> byproducts;
+ /**
+ * Metadata about the build invocation.
+ */
+ @JsonProperty("metadata")
+ private BuildMetadata metadata;
+
+ /**
+ * Creates a new RunDetails instance.
+ */
+ public RunDetails() {
+ }
+
+ /**
+ * Creates a new RunDetails with the given builder and metadata.
+ *
+ * @param builder entity that executed the build
+ * @param metadata metadata about the build invocation
+ */
+ public RunDetails(Builder builder, BuildMetadata metadata) {
+ this.builder = builder;
+ this.metadata = metadata;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RunDetails that = (RunDetails) o;
+ return Objects.equals(builder, that.builder) &&
Objects.equals(metadata, that.metadata) && Objects.equals(byproducts,
that.byproducts);
+ }
+
+ /**
+ * Gets the builder that executed the invocation.
+ *
+ * <p>Trusted to have correctly performed the operation and populated this
provenance.</p>
+ *
+ * @return the builder, or {@code null} if not set
+ */
+ public Builder getBuilder() {
+ return builder;
+ }
+
+ /**
+ * Gets artifacts produced as a side effect of the build that are not the
primary output.
+ *
+ * @return the list of byproduct artifacts, or {@code null} if not set
+ */
+ public List<ResourceDescriptor> getByproducts() {
+ return byproducts;
+ }
+
+ /**
+ * Gets the metadata about the build invocation, including its identifier
and timing.
+ *
+ * @return the build metadata, or {@code null} if not set
+ */
+ public BuildMetadata getMetadata() {
+ return metadata;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(builder, metadata, byproducts);
+ }
+
+ /**
+ * Sets the builder that executed the invocation.
+ *
+ * @param builder the builder
+ * @return this for chaining
+ */
+ public RunDetails setBuilder(Builder builder) {
+ this.builder = builder;
+ return this;
+ }
+
+ /**
+ * Sets the artifacts produced as a side effect of the build that are not
the primary output.
+ *
+ * @param byproducts the list of byproduct artifacts
+ * @return this for chaining
+ */
+ public RunDetails setByproducts(List<ResourceDescriptor> byproducts) {
+ this.byproducts = byproducts;
+ return this;
+ }
+
+ /**
+ * Sets the metadata about the build invocation.
+ *
+ * @param metadata the build metadata
+ * @return this for chaining
+ */
+ public RunDetails setMetadata(BuildMetadata metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "RunDetails{builder=" + builder + ", metadata=" + metadata + ",
byproducts=" + byproducts + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Signature.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Signature.java
new file mode 100644
index 0000000..77e7698
--- /dev/null
+++ b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Signature.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * A single cryptographic signature within a DSSE envelope.
+ *
+ * @see <a
href="https://github.com/secure-systems-lab/dsse/blob/v1.0.2/envelope.md">DSSE
Envelope specification</a>
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class Signature {
+
+ /**
+ * Hint for which key was used to sign; unset is treated as empty.
+ *
+ * <p>Consumers MUST NOT require this field to be set, and MUST NOT use it
for security decisions.</p>
+ */
+ @JsonProperty("keyid")
+ private String keyid;
+
+ /** Raw signature bytes of the PAE-encoded payload. */
+ @JsonProperty("sig")
+ private byte[] sig;
+
+ /** Creates a new Signature instance. */
+ public Signature() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Signature)) {
+ return false;
+ }
+ Signature signature = (Signature) o;
+ return Objects.equals(keyid, signature.keyid) && Arrays.equals(sig,
signature.sig);
+ }
+
+ /**
+ * Gets the key identifier hint, or {@code null} if not set.
+ *
+ * @return the key identifier, or {@code null}
+ */
+ public String getKeyid() {
+ return keyid;
+ }
+
+ /**
+ * Gets the raw signature bytes.
+ *
+ * @return the signature bytes, or {@code null} if not set
+ */
+ public byte[] getSig() {
+ return sig;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(keyid, Arrays.hashCode(sig));
+ }
+
+ /**
+ * Sets the key identifier hint.
+ *
+ * @param keyid the key identifier, or {@code null} to leave unset
+ * @return this for chaining
+ */
+ public Signature setKeyid(String keyid) {
+ this.keyid = keyid;
+ return this;
+ }
+
+ /**
+ * Sets the raw signature bytes.
+ *
+ * @param sig the signature bytes
+ * @return this for chaining
+ */
+ public Signature setSig(byte[] sig) {
+ this.sig = sig;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "Signature{keyid='" + keyid + "', sig=<" + (sig != null ?
sig.length : 0) + " bytes>}";
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Statement.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Statement.java
new file mode 100644
index 0000000..1d779c6
--- /dev/null
+++ b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/Statement.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * In-toto v1 attestation envelope that binds a set of subject artifacts to an
SLSA provenance predicate.
+ *
+ * @see <a
href="https://github.com/in-toto/attestation/blob/main/spec/v1/statement.md">in-toto
Statement v1</a>
+ */
+public class Statement {
+
+ /** The in-toto statement schema URI. */
+ public static final String TYPE = "https://in-toto.io/Statement/v1";
+ /** The provenance predicate. */
+ @JsonProperty("predicate")
+ private Provenance predicate;
+ /** URI identifying the type of the predicate. */
+ @JsonProperty("predicateType")
+ private String predicateType;
+ /** Software artifacts that the attestation applies to. */
+ @JsonProperty("subject")
+ private List<ResourceDescriptor> subject;
+
+ /** Creates a new Statement instance. */
+ public Statement() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Statement)) {
+ return false;
+ }
+ Statement statement = (Statement) o;
+ return Objects.equals(subject, statement.subject) &&
Objects.equals(predicateType, statement.predicateType) &&
Objects.equals(predicate,
+ statement.predicate);
+ }
+
+ /**
+ * Type of JSON object.
+ *
+ * @return Always {@value TYPE}
+ */
+ @JsonProperty("_type")
+ public String getType() {
+ return TYPE;
+ }
+
+ /**
+ * Gets the provenance predicate.
+ *
+ * <p>Unset is treated the same as set-but-empty. May be omitted if {@code
predicateType} fully describes the
+ * predicate.</p>
+ *
+ * @return the provenance predicate, or {@code null} if not set
+ */
+ public Provenance getPredicate() {
+ return predicate;
+ }
+
+ /**
+ * Gets the URI identifying the type of the predicate.
+ *
+ * @return the predicate type URI, or {@code null} if no predicate has
been set
+ */
+ public String getPredicateType() {
+ return predicateType;
+ }
+
+ /**
+ * Gets the set of software artifacts that the attestation applies to.
+ *
+ * <p>Each element represents a single artifact. Artifacts are matched
purely by digest, regardless of content type.</p>
+ *
+ * @return the list of subject artifacts, or {@code null} if not set
+ */
+ public List<ResourceDescriptor> getSubject() {
+ return subject;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subject, predicateType, predicate);
+ }
+
+ /**
+ * Sets the provenance predicate and automatically assigns {@code
predicateType} to the SLSA provenance v1 URI.
+ *
+ * @param predicate the provenance predicate
+ * @return this for chaining
+ */
+ public Statement setPredicate(Provenance predicate) {
+ this.predicate = predicate;
+ this.predicateType = Provenance.PREDICATE_TYPE;
+ return this;
+ }
+
+ /**
+ * Sets the set of software artifacts that the attestation applies to.
+ *
+ * @param subject the list of subject artifacts
+ * @return this for chaining
+ */
+ public Statement setSubject(List<ResourceDescriptor> subject) {
+ this.subject = subject;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "Statement{_type='" + TYPE + "', subject=" + subject + ",
predicateType='" + predicateType + "', predicate=" + predicate + '}';
+ }
+}
diff --git
a/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/package-info.java
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/package-info.java
new file mode 100644
index 0000000..69a5ce2
--- /dev/null
+++
b/src/main/java/org/apache/commons/release/plugin/slsa/v1_2/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SLSA 1.2 Build Attestation Models.
+ *
+ * <p>This package provides Jackson-annotated model classes that implement the
<a href="https://slsa.dev/spec/v1.2">Supply-chain Levels for Software Artifacts
+ * (SLSA) v1.2 specification</a>.</p>
+ *
+ * <h2>Overview</h2>
+ *
+ * <p>SLSA is a framework for evaluating and improving the security posture of
build systems. SLSA v1.2 defines a standard for recording build provenance:
+ * information about how software artifacts were produced.</p>
+ *
+ * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
+ * @see <a href="https://github.com/in-toto/attestation">In-toto Attestation
Framework</a>
+ * @see <a href="https://github.com/FasterXML/jackson">Jackson JSON
processor</a>
+ */
+package org.apache.commons.release.plugin.slsa.v1_2;
+