CI/CD evidence
GitHub Actions artifacts: useful evidence without false trust
A GitHub Actions artifact preserves files from a workflow run for later inspection or another job. It can carry a test report or release candidate, but its existence does not mean the test passed or the candidate is safe to execute. Record the producing revision, run and attempt, job, artifact identity and digest, then verify the expected source and result before a trusted job consumes it. Provenance attestations can strengthen origin checks; deployment still needs target-side proof.
Decide whether the file is evidence or a reusable input
A workflow artifact is a file or collection of files produced during a run and retained after the job finishes. Test reports, screenshots, build outputs, and logs are natural examples. GitHub distinguishes artifacts from dependency caches: a cache makes repeatable setup faster, while an artifact preserves a result for viewing or transfer between jobs. A release candidate may be handed from a build job to a later release job, but the transfer alone does not approve the candidate. Keep the artifact's producer, job conclusion, and intended consumer in the same record.
This distinction matters for an agent reading CI results. A failed test job may upload a report precisely because it failed. Seeing report.xml in the run's artifact list proves that a file was uploaded; it does not prove that the report contains passing tests, that all tests ran, or that the required check is green. Conversely, a successful check does not tell you which particular binary was uploaded unless the workflow ties the output to the same revision and job. An agent should inspect the run outcome and the file contents, then report the failure or success with the exact source revision.
Use a cache for reconstructible downloads or intermediate inputs that can be discarded. Use an artifact when someone must inspect a result after the run or a downstream job must consume the produced bytes. Neither storage mechanism creates trust by itself. A cache hit is not a release artifact; an artifact download is not a test verdict. The producer's event and trust level travel with the file, even when the download happens in a new job with stronger permissions.
Sources: Workflow artifacts — GitHub Docs · Dependency caching — GitHub Docs
Keep an artifact ledger across handoff
Imagine a synthetic run that builds candidate A from revision H2. The first attempt fails during tests but uploads a diagnostic report; the second attempt passes and uploads a candidate bundle. A release job later downloads an item named candidate. If the ledger records only the name, the team cannot tell which attempt produced the bytes or whether the release consumed the passing candidate. Give each candidate a stable identity beyond its friendly name: source SHA, run ID, attempt, producer job, environment, artifact ID, digest, and retained-until date. Then record the target revision observed after release.
| Evidence field | Diagnostic report | Release candidate |
|---|---|---|
| Source and run | H2, run R17, attempt 1 | H2, run R17, attempt 2 |
| Producer and origin | test job, trusted push event | build job, trusted push event |
| Job conclusion | failed; report uploaded for diagnosis | passed required build and tests |
| Artifact identity and digest | report artifact ID plus recorded digest | candidate artifact ID plus recorded digest |
| Retention and environment | review until retention expiry, no deploy authority | release handoff to reviewed environment |
| Target proof | none; diagnostic only | compare consumed digest and target live revision after delivery |
The ledger is an original operating example, not a claim about any customer or GitHub run. It helps answer two different questions. Which bytes did the release job consume? Which revision did the destination actually serve? The first requires an artifact identity and an integrity check. The second requires deployment evidence from the target. If either value is absent, mark that part unresolved. A green build on H2 cannot prove production serves H2, and a live H2 label cannot by itself prove which archived candidate was used.
Choose a retention period that covers your debugging and release review window, then read the repository and organization settings that govern it. GitHub documents default retention and configurable limits that differ by repository type and managing policy. An artifact can expire or be deleted, taking away the ability to inspect it later. Preserve longer-term release records in an approved durable system when policy requires them. Do not assume a copied artifact URL will remain available indefinitely or that everyone with a link can read a private repository's artifact.
Sources: actions/upload-artifact README — GitHub · Downloading workflow artifacts — GitHub Docs · Managing GitHub Actions settings for a repository — GitHub Docs
Use names for routing and IDs for identity
A descriptive artifact name helps humans find the output, but name alone is a weak handoff key. The current upload-artifact action returns an artifact ID and a digest on successful upload. Its documentation says artifact names must be unique within the relevant run; matrix jobs trying to upload to the same name can conflict. Give matrix outputs a distinct name that includes the dimension that changes the bytes, then collect or select them explicitly. If a workflow uses overwrite, GitHub's upload action deletes the prior artifact and creates a new ID. Any ledger still pointing at the old ID is stale.
The upload action also has behavior that affects evidence quality. Its default when no files match is to warn rather than fail, so a green job may not contain the report an operator expected unless the workflow checks for it. Hidden files are excluded by default in the current action; turning inclusion on requires reviewing the path for credentials and other sensitive files. Review the action inputs used in the repository rather than assuming a wildcard captured every intended result. An artifact that is missing a file can be perfectly intact as an archive while still being incomplete evidence.
The download action can compare the downloaded artifact digest with the upload digest. GitHub's artifact tutorial says a mismatch produces a warning in the run UI and logs. A warning is a signal to stop and investigate, not an automatic release block you can assume exists. A digest match means these bytes match the recorded upload digest; it does not establish that the producing workflow was trusted, that the build used approved inputs, or that the software is safe. Bind digest verification to a separately checked producer identity and policy.
Sources: actions/upload-artifact README — GitHub · Store and share data with workflow artifacts — GitHub Docs
Do not promote untrusted artifacts into privileged code
A fork pull request can produce an artifact under a lower-trust event. Downloading that artifact in a later workflow with release secrets does not change its origin. A compressed archive can carry scripts, package metadata, or paths that become active when extracted or executed. GitHub's security guidance warns that privileged workflows fetching and running untrusted pull request code or artifacts can cross the same boundary as a dangerous checkout. Treat the fork artifact as untrusted data; inspect it in an isolated environment without release authority, and rebuild a release candidate from a trusted revision after review.
Repository artifact visibility is another boundary. GitHub says a signed-in person with repository read access can download workflow artifacts. That means test dumps and screenshots are not a private vault within the repository. Scrub secrets, personal data, and environment files before upload, and check the actual paths selected by the action. An organization with many readers should not place a production credential in a report merely because the workflow log would mask it. The stored file has its own access and retention rules.
If release jobs hand candidates between workflows, require a trusted producer event, an expected revision, a passing required verification result, and a specific artifact identity before consumption. Validate the archive contents and destination paths before extraction, and do not execute a file solely because its name matches candidate. If the producer and consumer have different privileges, the boundary check belongs at consumption time. An agent may summarize the lower-trust report, but that report should not be a command source for the privileged release job.
Sources: Secure use reference — GitHub Docs · Downloading workflow artifacts — GitHub Docs · Workflow artifacts — GitHub Docs
Use attestations for origin, then still check behavior
Where artifact attestations are available and configured, they can give a cryptographically verifiable statement about where and how an artifact was built. GitHub describes provenance information including the associated workflow, repository, environment, commit SHA, and triggering event. Generating an attestation is only the producer side; the consuming side must verify it and compare the reported identity with the policy expected for that release. A valid signature from a different repository or an unapproved workflow is not sufficient merely because verification succeeded cryptographically.
Define the expected repository and signer workflow, then require the correct source revision or branch and environment conditions for the candidate. GitHub's verification guidance includes options to constrain the signer repository and workflow when reusable workflows build the artifact. The policy should also account for the actual artifact digest, so the verified statement is about the bytes being consumed. These checks establish a chain from approved source and workflow to the downloaded candidate. They do not prove that tests passed unless the run's required results are checked separately.
GitHub explicitly cautions that an attestation is not a guarantee that software is secure. The same principle applies to an ordinary SHA-256 digest: it helps detect change relative to a recorded value, but an attacker can supply both malicious bytes and a matching digest if the record itself is not trusted. Complete the decision with policy, test results, content review where needed, and the target's observed live revision after deployment. That is the difference between preserving evidence and treating a convenient archive as a release verdict.
Sources: Artifact attestations — GitHub Docs · Using artifact attestations and reusable workflows — GitHub Docs · actions/upload-artifact README — GitHub
Sources and verification
- Workflow artifacts — GitHub Docs
GitHub describes artifacts as persisted workflow outputs for inspection and job-to-job transfer, distinct from dependency caches. Verified .
- Dependency caching — GitHub Docs
GitHub distinguishes reconstructible performance caches from artifacts retained for viewing or handoff. Verified .
- actions/upload-artifact README — GitHub
The official action documents artifact ID and digest outputs, no-file warnings, hidden-file defaults, matrix name collisions, overwrite creating a new ID, and retention inputs. Verified .
- Downloading workflow artifacts — GitHub Docs
GitHub documents signed-in repository read access, download behavior, and artifact expiration. Verified .
- Managing GitHub Actions settings for a repository — GitHub Docs
GitHub documents configurable artifact and log retention by repository type and managing organization or enterprise policy. Verified .
- Store and share data with workflow artifacts — GitHub Docs
GitHub documents digest calculation on artifact download and a warning, rather than automatic job failure, for mismatches. Verified .
- Secure use reference — GitHub Docs
GitHub warns against privileged workflows executing untrusted pull request code or artifacts and recommends protecting secret-bearing contexts. Verified .
- Artifact attestations — GitHub Docs
GitHub describes signed provenance fields, the need to verify attestations, and the limit that attestation does not guarantee security. Verified .
- Using artifact attestations and reusable workflows — GitHub Docs
GitHub documents constraining attestation verification by signer repository and workflow when reusable workflows build artifacts. Verified .