Skip to content

Commit

Permalink
feat: add the SLSA models for its v1.0 spec
Browse files Browse the repository at this point in the history
Signed-off-by: Chi Zhang <[email protected]>
  • Loading branch information
chizhg committed Mar 31, 2024
1 parent 1a137d3 commit c9934f0
Show file tree
Hide file tree
Showing 14 changed files with 1,482 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>io.github.in-toto</groupId>
<artifactId>in-toto</artifactId>
<packaging>jar</packaging>
<version>0.5.0</version>
<version>0.6.0</version>
<name>in-toto</name>
<url>https://maven.apache.org</url>
<description>A framework to secure software supply chains.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

/** Implementation of the https://slsa.dev/provenance/v0.1 */
/** Implementation of the https://slsa.dev/provenance/v0.2 */
public class Provenance extends Predicate {

/**
Expand Down Expand Up @@ -109,6 +109,6 @@ public int hashCode() {

@Override
public String getPredicateType() {
return "https://slsa.dev/provenance/v0.1";
return "https://slsa.dev/provenance/v0.2";
}
}
140 changes: 140 additions & 0 deletions src/main/java/io/github/intoto/slsa/models/v1/BuildDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package io.github.intoto.slsa.models.v1;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* The BuildDefinition describes all of the inputs to the build. It SHOULD contain all the
* information necessary and sufficient to initialize the build and begin execution.
*
* <p>The externalParameters and internalParameters are the top-level inputs to the template,
* meaning inputs not derived from another input. Each is an arbitrary JSON object, though it is
* RECOMMENDED to keep the structure simple with string values to aid verification. The same field
* name SHOULD NOT be used for both externalParameters and internalParameters.
*
* <p>The parameters SHOULD only contain the actual values passed in through the interface to the
* build platform. Metadata about those parameter values, particularly digests of artifacts
* referenced by those parameters, SHOULD instead go in resolvedDependencies. The documentation for
* buildType SHOULD explain how to convert from a parameter to the dependency uri. For example:
*
* <pre>
* {@code <script>}
* "externalParameters": {
* "repository": "https://github.com/octocat/hello-world",
* "ref": "refs/heads/main"
* },
* "resolvedDependencies": [{
* "uri": "git+https://github.com/octocat/hello-world@refs/heads/main",
* "digest": {"gitCommit": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d"}
* }]
* {@code </script>}
* </pre>
*/
public class BuildDefinition {

/**
* Identifies the template for how to perform the build and interpret the parameters and
* dependencies.
*
* <p>The URI SHOULD resolve to a human-readable specification that includes: overall description
* of the build type; schema for externalParameters and internalParameters; unambiguous
* instructions for how to initiate the build given this BuildDefinition, and a complete example.
* Example: https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1
*/
@NotBlank(message = "buildType must not be empty or blank")
private String buildType;

/**
* The parameters that are under external control, such as those set by a user or tenant of the
* build platform. They MUST be complete at SLSA Build L3, meaning that there is no additional
* mechanism for an external party to influence the build. (At lower SLSA Build levels, the
* completeness MAY be best effort.)
*
* <p>The build platform SHOULD be designed to minimize the size and complexity of
* externalParameters, in order to reduce fragility and ease verification. Consumers SHOULD have
* an expectation of what “good” looks like; the more information that they need to check, the
* harder that task becomes.
*
* <p>Verifiers SHOULD reject unrecognized or unexpected fields within externalParameters.
*/
@NotEmpty(message = "externalParameters must not be empty")
private Map<String, Object> externalParameters;

/**
* The parameters that are under the control of the entity represented by builder.id. The primary
* intention of this field is for debugging, incident response, and vulnerability management. The
* values here MAY be necessary for reproducing the build. There is no need to verify these
* parameters because the build platform is already trusted, and in many cases it is not practical
* to do so.
*/
@JsonInclude(Include.NON_EMPTY)
private Map<String, Object> internalParameters;

/**
* Unordered collection of artifacts needed at build time. Completeness is best effort, at least
* through SLSA Build L3. For example, if the build script fetches and executes
* “example.com/foo.sh”, which in turn fetches “example.com/bar.tar.gz”, then both “foo.sh” and
* “bar.tar.gz” SHOULD be listed here.
*/
private List<ResourceDescriptor> resolvedDependencies;

public String getBuildType() {
return buildType;
}

public void setBuildType(String buildType) {
this.buildType = buildType;
}

public Map<String, Object> getExternalParameters() {
return externalParameters;
}

public void setExternalParameters(Map<String, Object> externalParameters) {
this.externalParameters = externalParameters;
}

public Map<String, Object> getInternalParameters() {
return internalParameters;
}

public void setInternalParameters(Map<String, Object> internalParameters) {
this.internalParameters = internalParameters;
}

public List<ResourceDescriptor> getResolvedDependencies() {
return resolvedDependencies;
}

public void setResolvedDependencies(
List<ResourceDescriptor> resolvedDependencies) {
this.resolvedDependencies = resolvedDependencies;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
io.github.intoto.slsa.models.v1.BuildDefinition buildDefinition = (io.github.intoto.slsa.models.v1.BuildDefinition) o;
return buildType.equals(buildDefinition.buildType) && Objects.equals(externalParameters,
buildDefinition.externalParameters)
&& Objects.equals(internalParameters, buildDefinition.internalParameters) && Objects.equals(
resolvedDependencies, buildDefinition.resolvedDependencies);
}

@Override
public int hashCode() {
return Objects.hash(buildType, externalParameters, internalParameters,
resolvedDependencies);
}
}
73 changes: 73 additions & 0 deletions src/main/java/io/github/intoto/slsa/models/v1/BuildMetadata.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.github.intoto.slsa.models.v1;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.OffsetDateTime;
import java.util.Objects;

public class BuildMetadata {

/**
* Identifies this particular build invocation, which can be useful for finding associated logs or
* other ad-hoc analysis. The exact meaning and format is defined by builder.id; by default it is
* treated as opaque and case-sensitive. The value SHOULD be globally unique.
*/
private String invocationId;

/**
* The timestamp of when the build started. A point in time, represented as a string in RFC 3339
* format in the UTC time zone ("Z").
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
private OffsetDateTime startedOn;

/**
* The timestamp of when the build completed.A point in time, represented as a string in RFC 3339
* format in the UTC time zone ("Z").
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
private OffsetDateTime finishedOn;

public String getInvocationId() {
return invocationId;
}

public void setInvocationId(String invocationId) {
this.invocationId = invocationId;
}

public OffsetDateTime getStartedOn() {
return startedOn;
}

public void setStartedOn(OffsetDateTime startedOn) {
this.startedOn = startedOn;
}

public OffsetDateTime getFinishedOn() {
return finishedOn;
}

public void setFinishedOn(OffsetDateTime finishedOn) {
this.finishedOn = finishedOn;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BuildMetadata buildMetadata = (BuildMetadata) o;
return Objects.equals(invocationId, buildMetadata.invocationId)
&& Objects.equals(startedOn, buildMetadata.startedOn)
&& Objects.equals(finishedOn, buildMetadata.finishedOn);
}

@Override
public int hashCode() {
return Objects.hash(
invocationId, startedOn, finishedOn);
}
}
93 changes: 93 additions & 0 deletions src/main/java/io/github/intoto/slsa/models/v1/Builder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.github.intoto.slsa.models.v1;

import jakarta.validation.constraints.NotBlank;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* The build platform, or builder for short, represents the transitive closure of all the entities
* that are, by necessity, trusted to faithfully run the build and record the provenance. This
* includes not only the software but the hardware and people involved in running the service. For
* example, a particular instance of Tekton could be a build platform, while Tekton itself is not.
* For more info, see Build model.
*
* <p>The id MUST reflect the trust base that consumers care about. How detailed to be is a
* judgement call. For example, GitHub Actions supports both GitHub-hosted runners and self-hosted
* runners. The GitHub-hosted runner might be a single identity because it’s all GitHub from the
* consumer’s perspective. Meanwhile, each self-hosted runner might have its own identity because
* not all runners are trusted by all consumers.
*
* <p>Consumers MUST accept only specific signer-builder pairs. For example, “GitHub” can sign
* provenance for the “GitHub Actions” builder, and “Google” can sign provenance for the “Google
* Cloud Build” builder, but “GitHub” cannot sign for the “Google Cloud Build” builder.
*
* <p>Design rationale: The builder is distinct from the signer in order to support the case where
* one signer generates attestations for more than one builder, as in the GitHub Actions example
* above. The field is REQUIRED, even if it is implicit from the signer, to aid readability and
* debugging. It is an object to allow additional fields in the future, in case one URI is not
* sufficient.
*/
public class Builder {

/**
* URI indicating the builder’s identity. (<a
* href="https://github.com/in-toto/attestation/blob/main/spec/field_types.md#TypeURI">TypeURI</a>)
*/
@NotBlank(message = "builder Id must not be empty or blank")
private String id;

/**
* Dependencies used by the orchestrator that are not run within the workload and that do not
* affect the build, but might affect the provenance generation or security guarantees.
*/
private List<ResourceDescriptor> builderDependencies;

/**
* Map of names of components of the build platform to their version.
*/
private Map<String, String> version;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public List<ResourceDescriptor> getBuilderDependencies() {
return builderDependencies;
}

public void setBuilderDependencies(
List<ResourceDescriptor> builderDependencies) {
this.builderDependencies = builderDependencies;
}

public Map<String, String> getVersion() {
return version;
}

public void setVersion(Map<String, String> version) {
this.version = version;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
io.github.intoto.slsa.models.v1.Builder builder = (io.github.intoto.slsa.models.v1.Builder) o;
return id.equals(builder.id) && Objects.equals(builderDependencies, builder.builderDependencies)
&& Objects.equals(version, builder.version);
}

@Override
public int hashCode() {
return Objects.hash(id, version);
}
}
63 changes: 63 additions & 0 deletions src/main/java/io/github/intoto/slsa/models/v1/Provenance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.github.intoto.slsa.models.v1;

import io.github.intoto.models.Predicate;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.Objects;

public class Provenance extends Predicate {

/**
* The input to the build. The accuracy and completeness are implied by runDetails.builder.id.
*/
@Valid
@NotNull(message = "buildDefinition must not be null")
private BuildDefinition buildDefinition;

/**
* Details specific to this particular execution of the build.
*/
@Valid
@NotNull(message = "runDetails must not be null")
private RunDetails runDetails;

public BuildDefinition getBuildDefinition() {
return buildDefinition;
}

public void setBuildDefinition(BuildDefinition buildDefinition) {
this.buildDefinition = buildDefinition;
}

public RunDetails getRunDetails() {
return runDetails;
}

public void setRunDetails(RunDetails runDetails) {
this.runDetails = runDetails;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Provenance provenance = (Provenance) o;
return Objects.equals(buildDefinition, provenance.buildDefinition)
&& Objects.equals(runDetails, provenance.runDetails);
}

@Override
public int hashCode() {
return Objects.hash(
buildDefinition, runDetails);
}

@Override
public String getPredicateType() {
return "https://slsa.dev/provenance/v1";
}
}
Loading

0 comments on commit c9934f0

Please sign in to comment.