Continuum Academy · Chapter 01
From source code to delivered software: where is the evidence?
A supplier delivers payment-service-4.7.2.tar.gz. You retain the archive, its version and its SHA-256 digest. A few weeks later, someone asks: “Can you demonstrate that this archive was built from the approved source code?” Let’s open the delivery folder and work out what would let us answer.
1 — A delivered file does not carry its history with it
The archive is there. You can copy it, inspect its contents and perhaps run the program inside. You have an output of a build: a software artifact. It could equally be an executable, an installation package or a container image.
Its name suggests version 4.7.2 of a payment service. That does not establish its origin. A different archive could be given exactly the same name. A version file inside adds a clue, but someone had to write that information. It is still something to examine.
To trace a path from approved code to this particular archive, several questions need answers:
- Which repository supplied the source? Which commit, meaning the specific recorded revision of the code?
- Which builder, the system producing the software, ran the job? Which build process did it follow?
- Which dependencies and environment were involved?
- Who makes these claims? Has the statement been altered? Can it be checked independently of the system that produced it?
A file with a history to establish
The archive’s name does not answer questions about its origin.
Three sets of questions surround the file: which sources were used, how the build ran, and who or what stands behind the claim.
A link to a successful build may help recover those answers. But what remains for the recipient if access expires or the logs are deleted? Even with the link, how can they establish that the archive on their disk is the one that build produced? Start with that smaller question.
2 — Start with its digest
We want to compare the received content with a reference. SHA-256 performs a calculation over the file’s bytes and produces a fixed-length value: its digest, also called a hash or fingerprint.
SHA256(payment-service-4.7.2.tar.gz)
→ 3a16...9f21
Digests in this chapter are fictional and shortened for readability. A full SHA-256 digest has 64 hexadecimal characters. The dots are not a value that can be used for an actual verification.
A hash answers the question: is this the same content?
Calculate the received copy’s digest and compare it with the reference. Different values mean different contents. With SHA-256 used correctly, matching values let you recognise the expected content in practice. The filename is not part of a digest calculated over the file’s bytes.
Same name, different content
Comparing digests can reveal a change in the bytes. Values are fictional and shortened.
The reference remains 3a16...9f21. In this illustration, the modified archive produces 7b04...e812: the contents differ even though the name is unchanged. This tells us nothing about their origin.
In the sequence, the file keeps its name but one byte changes. Its digest becomes 7b04...e812: the comparison fails. Renaming the intact archive would have had the opposite outcome: a different name, but the same digest.
We still do not know which code produced those bytes. There is another limit: if someone replaces both the archive and the digest published beside it, their comparison may pass. The calculation cannot select a trustworthy reference on our behalf.
3 — We need a claim
Now ask the supplier: “What was this file built from?” Their answer might be: “This artifact was produced from the payment-service repository, at the approved revision, by our build system.”
That answer is a claim. Keep it in a document outside the archive, which the recipient can read without executing the software. We will call this declaration a statement.
For a tool to check it, replace vague phrases with precise values. “The approved version” becomes an identifiable revision. “This file” becomes content identified by a digest. The document should let us ask questions that can be answered by comparing values.
We are building an attestation: a document carrying a claim about an identified artifact. It can be signed to authenticate that claim. A structured document, however polished, does not yet establish who wrote it or whether its account is accurate.
The need comes before the format. We want to retain a precise claim, connect it to the right file, and give the recipient a way to examine it after the delivery has left the supplier’s system.
4 — Identify the artifact precisely
First, write the part that says which file the statement concerns:
{
"subject": [{
"name": "payment-service-4.7.2.tar.gz",
"digest": {
"sha256": "3a16...9f21"
}
}]
}
This JSON fragment is an incomplete teaching example with a shortened digest. It is not a complete attestation to submit to a verification tool.
subject contains the list of artifacts the claim applies to. We have one archive, but a single build could produce several files. name helps a reader recognise the one they are looking for. digest associates an algorithm, here sha256, with the expected digest value.
The name makes the document readable; the digest enables content comparison. If your file is now named delivery.tar.gz, its bytes can still match the declared subject. Conversely, the expected filename accompanied by a different digest indicates different content.
We now have a first checkable connection: “this claim concerns this content.” It does not yet explain the build. An authentic statement about a different archive would not answer the question we started with.
5 — Describe how it was built
Add the information that would help us trace the supplier’s work. This illustrative record is not intended to reproduce a standard’s schema:
| Recorded information | Illustrative value | Question it addresses |
|---|---|---|
| Source repository | https://git.example.org/payments/payment-service |
Where are the declared sources? |
| Commit | 7d34a8b4e1f98c2040e9844ab754ae068943bb16 |
Which exact revision? |
| Builder | payments-release-builder |
Which system produced the software? |
| Build process | release/build.yml, at that revision |
Which instructions were used? |
| Output | The archive with digest 3a16...9f21 |
Which content came out of the build? |
Connect the output to its build
The statement retains a connection between the sources, the work performed and the resulting artifact.
Source and commit → build → artifact → statement. The document connects the archive’s digest to the declared repository, commit, builder and process. This relationship still needs to be authenticated and evaluated.
The record connects inputs, an execution and an output. The commit identifies a revision; it does not establish that anyone approved it. The recipient still needs an approval record concerning that same revision.
Dependencies and the environment matter too. Two builds of the same commit can produce different files if the compiler or a downloaded library changes. A dependency lockfile and a precise environment version may help explain the difference.
The useful question is therefore more specific than “is there a document?” Ask what it actually recorded. If a dependency is missing, its identity remains unknown in this delivery record. If the document names a script, you need to be able to locate the declared version of that script. Neither an absent field nor a familiar filename should silently count as a successful check.
6 — Who stands behind the claim?
We can read the account of the build. We still need to check whether it is associated with the expected issuer and whether it has changed. That is where a digital signature comes in.
The signer uses a private key, kept secret, to sign the content defined by the signature format. The recipient uses the corresponding public key to check the signature. They do not need the private key and should not receive it.
Verify a signature, evaluate a claim
The private key is used to sign. The public key lets the recipient check the signature.
Statement → signature using the private key → verification using the public key. A valid signature protects the signed content and links it to a key; accepting that key requires a trust model. SIGNED ≠ TRUE: a signature does not guarantee a claim’s truth.
A valid signature establishes a cryptographic connection between the signed content and a key, subject to the assumptions of the mechanism being used. It makes changes to that content detectable. It does not confirm that the events described actually happened.
SIGNED ≠ TRUE.
Someone must still decide which keys to accept, for which purposes and under which conditions. Those rules form a trust model. A key included in the delivery folder is not automatically the expected supplier’s key. Its approval, period of use and available revocation information need separate consideration.
Consider two changes. Replacing the commit in the signed document can cause signature verification to fail. Changing only the archive can leave the signature on the untouched document valid; it is the digest comparison that fails. These checks answer different questions, and both connections matter to the delivery.
7 — From a claim to provenance
Return to the document. It identifies a file and describes the sources, system and process said to have produced it. This information about production is called provenance.
Provenance describes verifiable information about how a software artifact was produced.
“Verifiable” does not mean every event can be observed again. The recipient can check the signature, the connection to the file and whether the declared values meet their expectations. The reliability of the recording process remains an assumption to examine.
SLSA Provenance provides a shared format for some of this information. Instead of inventing a different record for every supplier, tools can exchange structured descriptions of builds. Using that format does not, by itself, demonstrate a SLSA level. A later chapter will examine the standard in more detail.
8 — Where does in-toto fit?
We have built a claim before choosing an exchange format. The in-toto attestation framework provides a structure called a Statement. For now, focus on three elements:
| Field | Role in our example |
|---|---|
subject |
Identifies the archive by its digest. |
predicateType |
Indicates what kind of claim the document contains. |
predicate |
Carries the information specific to that claim, here the build details. |
The in-toto Statement and its signature are separate layers. Recognising these fields in JSON does not amount to verifying a signature. Chapter 03 will examine how the parts fit together. The existing in-toto guide is a supplementary reference on exchanging receipts.
9 — What can we now verify?
Our delivery folder holds more than an archive with a name. Each addition answers a particular question:
| Available material | What it contributes to verification |
|---|---|
| Artifact alone | Content to inspect, with little origin information established by the file itself. |
| Artifact + reference hash | A comparison of content identity and integrity, provided the reference is reliable. |
| Artifact + attestation | A structured claim identifying the content it concerns. |
| Attestation + signature | A claim that can be checked cryptographically within a trust model. |
| Provenance | Structured build information to compare with the recipient’s expectations. |
Return to the request: “Was this archive built from the approved code?” We need to compare its digest with the declared subject, verify the signature with an accepted key, and compare the declared commit with the approved commit. We also need a reason to trust the system that recorded the build.
A useful result might read: “digest matches; signature valid; commit differs from the approved revision.” The first two checks passed, but the delivery does not meet the requirement. Verification is more than obtaining a green check mark.
These operations can run without access to the build system if the necessary documents, files and trust material have been retained. Operational independence does not make the supplier’s record infallible. A useful report names the checks that ran and keeps unresolved questions visible.
10 — What have we NOT proved?
Even with matching digests, a valid signature and the expected commit, we have not automatically proved:
- The absence of vulnerabilities. Approved code can still contain a flaw.
- An uncompromised builder. A compromised system can record a misleading account of production.
- The absolute truth of the declared information. A signature protects a claim; it does not witness the events on our behalf.
- Safe dependencies. Knowing a library’s identity does not establish that it is secure.
- Regulatory compliance. That depends on requirements and evidence this document may not cover.
- An inherently trustworthy signer. Accepting their key is a decision, not an automatic consequence of a cryptographic calculation.
Cryptography can make a claim verifiable. It does not turn a claim into truth.
The scope of the result must remain explicit: which file, which statement, which key, which expectations and which checks? “The checks defined for this delivery passed” is a conclusion someone else can examine. It does not mean “this software is safe in every context.”
11 — Where does Continuum Attest fit?
Continuum Attest automates recording build steps and digests of declared inputs and outputs in a receipt. Signing is enabled explicitly. The receipt can be retained and transferred with a delivery, then verified by the recipient using approved keys and the files required for their chosen checks.
Declared scope remains important: a receipt does not automatically cover every file a build might read. The native format also has its own hashing rules; our simplified SHA-256 example is not a complete description of those rules. The CLI reference and receipt format document the precise behaviour and practical use.
For further reading, Trust is not evidence is a complementary article outside the Academy learning path. Reading it is not a prerequisite for continuing.
12 — Key takeaways
The artifact provides the content; its hash lets us compare it. A statement expresses a claim, an attestation connects it to a subject, and a signature lets us check its integrity and connection to a key. Provenance describes production. Verification examines those connections against explicit expectations, without turning a signed claim into absolute truth.