Artifact Signing, Checksums and Integrity for Releases
AI generated
CI/CD
.yml
GitLab · CI/CD · Security · Release Integrity
Artifact Signing,
Checksums and Integrity for Releases

A release artifact that has been altered without anyone noticing is more dangerous than a build that visibly fails. SHA256 checksums, GPG signatures and automated verification steps in the GitLab pipeline close this silent attack surface for Magento deployments.

12 min read SHA256 · GPG · SLSA · Checksums · Verify Job GitLab CI · Magento 2 · Supply Chain Security

1. Why artifact integrity is a real risk

On its way from the pipeline to the production server, a release artifact passes through several stations: GitLab storage, network transfer, temporary directories on the server. At any of these stations, an unnoticed change can theoretically occur, whether through errors, supply chain attacks, or a faulty transfer process. A corrupted or tampered artifact that gets deployed without verification is more dangerous than a failed build, because it produces no visible error.

For Magento shops, this risk is concrete: vendor/ contains PHP libraries that run directly in production. If a library was altered between build and deploy, that malicious code executes with every request. Supply chain attacks against npm and Composer packages are no longer theoretical, they happen in reality. The countermeasure is not paranoia but a simple technical control: SHA256 checksums that are generated in the build job and verified before deployment.

2. Checksums: SHA256 and how they are generated

A checksum is a cryptographic hash of a file that changes even if only a single byte of the file changes. SHA256 is the current standard: MD5 and SHA1 are no longer sufficient for integrity checks because collisions are theoretically possible. A SHA256 hash is 64 characters long and unique to the exact contents of the file. On Linux systems sha256sum is used, on macOS shasum -a 256.

For a release artifact, the hash is calculated right after creation and stored in a separate file. The convention is a .sha256 file next to the artifact: release-v1.2.3.tar.gz and release-v1.2.3.tar.gz.sha256. Both files are stored as GitLab artifacts. Before deployment, the deployment job reads the .sha256 file, calculates the hash of the actual artifact, and compares the two values. If they match, integrity is confirmed. If they do not match, the pipeline aborts immediately.

package:release:
  stage: package
  dependencies:
    - build:magento
    - build:frontend
  script:
    # Create timestamped release archive
    - export RELEASE_TAG="${CI_COMMIT_TAG:-${CI_COMMIT_SHORT_SHA}}"
    - tar -czf "release-${RELEASE_TAG}.tar.gz" vendor/ generated/ app/ pub/static/
    # Generate SHA256 checksum, stored alongside the archive
    - sha256sum "release-${RELEASE_TAG}.tar.gz" > "release-${RELEASE_TAG}.tar.gz.sha256"
    # Display checksum for pipeline log transparency
    - cat "release-${RELEASE_TAG}.tar.gz.sha256"
    - echo "RELEASE_TAG=${RELEASE_TAG}" >> release.env
  artifacts:
    name: "release-${CI_COMMIT_SHORT_SHA}"
    paths:
      - release-*.tar.gz
      - release-*.tar.gz.sha256
      - release.env
    reports:
      dotenv: release.env
    expire_in: 14 days

3. Generating checksums automatically in the pipeline

The checksum step must be part of the package job, not a step added afterward. Only when the hash and the artifact are produced in the same job is it guaranteed that the hash actually describes the artifact that was built, and not a later, possibly altered version. The checksum file is listed alongside the artifact in artifacts.paths and therefore shares its lifecycle.

For multiple artifacts, a shared SHA256SUMS file following Linux convention is recommended: all hashes in one file, one hash per line, with the file name. This file can be verified with a single command: sha256sum -c SHA256SUMS. This checks all artifacts at once and outputs either OK or an error for each file. In GitLab CI, an error at this step automatically causes a job failure and stops the pipeline, which is exactly the desired behavior.

4. Verifying checksums before deployment

Verification must happen as an explicit step in the deploy job or as a separate verify job before deployment. The flow is always the same: download the artifact and the checksum file, calculate the hash of the artifact, compare it with the stored hash. Only on a match does the deployment continue. This step takes seconds but prevents corrupted or tampered packages from being deployed.

An important point: the checksum file itself must also be protected. If an attacker can replace both the artifact and the checksum file, the protection becomes worthless. This is where GPG signing comes in: the checksum file is signed with a private key known only to the CI system. Before deployment, the signature is verified with the public key. This way, no unnoticed manipulation can take place, neither on the artifact nor on the checksum.

5. GPG signing for release packages

GPG (GNU Privacy Guard) enables cryptographic signatures that prove an artifact originates from a specific source and has not been changed since signing. In a GitLab CI context, a GPG key pair is generated, the private key is stored as a protected CI/CD variable, and the public key is made available to all deployments. The build job signs the release package, the deploy job verifies the signature before unpacking it.

The setup requires a one-time effort: generate the key pair, store the private key base64-encoded as a GitLab variable, import the public key on the deployment server. In day-to-day operation, signing and verification happen fully automatically. For Magento shops that operate in regulated environments or have specific compliance requirements, GPG signing is not an optional measure but a documented security feature of the deployment process.

sign:release:
  stage: package
  dependencies:
    - package:release
  script:
    # Import GPG private key from CI variable (base64-encoded)
    - echo "${GPG_PRIVATE_KEY}" | base64 -d | gpg --batch --import
    # Sign the release archive, creates .asc detached signature
    - gpg --batch --yes --armor --detach-sign
        --local-user "${GPG_KEY_ID}"
        release-*.tar.gz
    # Verify signature immediately to confirm signing worked
    - gpg --verify release-*.tar.gz.asc release-*.tar.gz
  artifacts:
    paths:
      - release-*.tar.gz.asc
    expire_in: 14 days

verify:signature:
  stage: verify
  dependencies:
    - package:release
    - sign:release
  script:
    # Import public key on verification side
    - echo "${GPG_PUBLIC_KEY}" | gpg --batch --import
    # Verify GPG signature before any deployment step
    - gpg --verify release-*.tar.gz.asc release-*.tar.gz
    - echo "Signature verified, safe to deploy"

6. GitLab Release API and checksum attachments

GitLab offers a Release API that can automatically create a release entry with attached assets for every Git tag. Checksum files can be attached as release assets and stay permanently linked to the tag, even after the CI artifact has expired. This is especially useful for long-term traceability: which version was deployed, and what is the hash of the deployed package?

The GitLab Release CLI or the API makes it possible to attach checksum files as links. In the simplest case, the SHA256SUMS file is stored in S3-compatible object storage and the URL is attached to the GitLab release. For internal deployments without an external storage solution, it is enough to attach the checksum file as a downloadable asset on the GitLab release. What matters is the consequence: every tagged release has a documented, verifiable checksum.

7. SLSA and provenance: where does the artifact come from?

SLSA (Supply chain Levels for Software Artifacts) is a framework that describes the conditions under which an artifact was built. The core idea is provenance: a machine-readable document that records which commit served as the input, which pipeline ran the build, and which runner was used. GitLab supports provenance generation through the generate_provenance mechanism for releases.

For Magento deployments, reaching SLSA Level 1 only requires documenting the build environment: Git commit SHA, pipeline ID, runner ID, timestamp and artifact hash. This information can be generated as a JSON file in the package job and stored as an artifact. This makes every production state traceable back to an exact Git commit, a basic prerequisite for incident response and compliance evidence in regulated industries.

8. Composer integrity and composer.lock as the foundation

The foundation of all PHP-side integrity checks is the composer.lock file. For every package it fixes the exact version and the SHA hash of the downloaded file. composer install with a valid composer.lock automatically verifies that the installed packages exactly match the expected hashes. This protects against compromised package mirrors and downgrade attacks on Composer packages.

In the GitLab CI build job, composer.lock must therefore always be committed, and composer install (not composer update) must be used. An additional check: composer validate --strict checks whether composer.json and composer.lock are consistent. Using composer install --no-dev in the build job ensures that no development dependencies end up in the production artifact, eliminating yet another attack surface.

9. Comparison: without vs. with integrity assurance

The following table shows which risks exist without integrity checks and how each measure addresses them.

Measure Without measure With measure Effort
SHA256 checksum Transfer errors go unnoticed Corruption is caught before deployment Minimal (1 line)
GPG signature Tampering in storage is possible Origin is cryptographically proven Medium (key setup)
composer.lock Package versions drift Fixed, verified package hashes Minimal (always commit)
Provenance document No proof of build origin Full traceability Medium (JSON generation)
Verify job in the pipeline Deployment runs without checks Pipeline stops on mismatch Minimal (separate job)

The table makes it clear: the first three measures, SHA256 checksums, committing composer.lock, and a verify job, require minimal effort and cover the most common risks. GPG signing and provenance documents are useful for higher security requirements or regulated environments, but they are not a basic requirement for a secure deployment process.

10. Summary

Artifact signing, checksums and integrity checks are not exaggerated security measures, but the logical consequence of the fact that release artifacts flow through external systems. SHA256 checksums are generated in the package job and verified before deployment. GPG signatures cryptographically prove the origin of the package. The composer.lock file ensures that all PHP dependencies are installed with fixed versions and verified hashes. Provenance documents provide traceability for compliance and incident response.

The overall effort for basic integrity assurance is small: one additional checksum step in the package job and one verify job before deployment. These two additions turn a deployment process that relies on hope into one that relies on verification. For Magento shops handling customer data and payment processing, that difference is not trivial.

Artifact Integrity for Magento: The Essentials at a Glance

SHA256 in the package job

sha256sum release.tar.gz > release.tar.gz.sha256 right after archive creation. Store both files as artifacts.

Verify before deploy

sha256sum -c release.tar.gz.sha256 as a required step before every deployment. Pipeline fails on mismatch.

Commit composer.lock

Never exclude composer.lock in .gitignore. Always composer install, never composer update in the build job.

GPG for higher requirements

A detached signature (.asc) next to the artifact cryptographically secures its origin. One-time setup, fully automatic afterward.

11. FAQ: Artifact Signing and Checksums in GitLab

1Why is MD5 no longer enough?
MD5 is vulnerable to collisions: two different files can have the same hash. SHA256 has no known practical collisions.
2How to keep a GPG key secure in GitLab?
Store it base64-encoded as a protected, masked CI/CD variable. Only available in pipelines on protected branches.
3GPG, or are checksums enough?
For most deployments SHA256 checksums are enough. GPG makes sense for higher compliance requirements.
4Is SLSA needed for Magento?
Level 1 (provenance document) is useful for compliance evidence. Higher levels are optional for standard Magento shops.
5Does composer.lock protect against all attacks?
No, it protects against version drift, not against compromised registry packages under the same version. Use private mirrors for critical packages.
6How long to keep a checksum file?
At least as long as the artifact. For tagged releases: keep it permanently as a release asset in GitLab.
7What happens on a failed checksum?
The verify job fails, deployment is not started. Pipeline is marked as failed, team is notified.
8Create a checksum after the fact?
Provides no security: the hash must be generated in the same job as the artifact, otherwise it proves nothing about it being unchanged.
9Verify an artifact on the production server?
sha256sum -c release.tar.gz.sha256 after the transfer. On mismatch, abort immediately and trigger a new build.
10GitLab native integrity features?
GitLab internally stores SHA256 hashes. The Release API allows checksum files as assets. GPG signing requires a custom CI implementation.