Chainguard Checks: When Can CI Results Be Reused?

黎 浩然/ 16 10 月, 2026/ 大语言模型/LARGELANGUAGEMODEL/LLM, 教程/TUTORIAL, 计算机/COMPUTER/ 0 comments

A passing CI result can be reused only when it still describes the code, checks, and environment that the merge gate is about to accept. A valid signature addresses authenticity and integrity. It does not make an old result apply to new code, and it does not establish that the tests were sufficient.

Contents
  1. What the launch moves earlier
  2. The missing question is often: what was tested?
  3. Separate authenticity, matching, and acceptance
  4. Five local assertions expose the difference
  5. An environment needs more than a language-version label
  6. Choose rejection rules before removing CI work
  7. Sources and backfill note

Chainguard Checks moves CI feedback into the development loop. The interesting engineering question is what must remain true between a successful check and the eventual merge. The example below separates those conditions with five executable assertions. 中文版.

What the launch moves earlier

Google News surfaced the October 15 Trend Hunter report. The original Chainguard announcement, dated October 14, introduced Checks in Beta: developers or agents can invoke CI checks before committing, using warm isolated microVMs and receiving signed verdicts.

The useful change is earlier execution feedback within an edit–check–repair loop. A model reviewing code is different from an execution system reporting what actually ran. The announcement also describes configurable merge gates for reusing passing verdicts. That is not evidence that every repository already skips repeat CI automatically, nor an independent latency or cost benchmark.

1
Freeze tested source
Include actual changes
2
Run specified checks
Record environment and result
3
Authenticate the report
Protect its contents
4
Match at the merge gate
Apply acceptance policy
Original flow: a check result can be reused only while its subject and acceptance policy still match.

The missing question is often: what was tested?

Suppose an agent checks workspace A and receives a pass. It then changes a boundary condition, producing workspace B. If the interface remembers only the last successful result, B can inherit A’s green status. The signature on A’s report may be entirely valid; reusing it for B is still wrong.

A result therefore needs a defined subject. A Git commit identifier alone may be insufficient for a pre-commit check, which operates on uncommitted changes. Test configuration, generated inputs, and dependency lockfiles may also matter. Define what enters the source snapshot, how file modes and symlinks are represented, and how external dependencies are fixed. For example, hashing committed files while actually testing an uncommitted patch binds the report to a different version from the executed one. A strong digest cannot repair a poorly defined input boundary.

The teaching protocol below hashes source, check suite, and environment separately, then authenticates a report containing those digests. This is an original simplified design, not a description of Chainguard’s actual attestation fields; the announcement does not establish its complete payload schema.

Separate authenticity, matching, and acceptance

Authenticity asks whether a trusted execution side produced the report without alteration. Matching asks whether its source, suite, and environment correspond to the required inputs. Acceptance asks which checks must pass and how skipped, timed-out, or empty test runs are handled. A green icon compresses these into one display, but the verifier still needs separate decisions.

The Sigstore verification reference distinguishes signature verification from checking claims in the payload and illustrates identity and issuer restrictions. It is a useful reference for that distinction, not evidence that Checks uses this article’s protocol or that adopting Sigstore supplies a repository’s testing policy.

A compact rule is: accept = trusted producer AND intact content AND matching subject AND satisfied check policy. The conjunction matters. Evidence for one term cannot be borrowed to fill in another term that was never evaluated.

1
Authentic + matching subject
Evaluate the check policy
2
Authentic + changed source
Reject reuse
3
Authentic + zero tests
Reject under the example policy
4
Modified report
Reject on integrity
Original decision diagram: successful authentication alone does not authorize reuse or establish adequate testing.

Five local assertions expose the difference

This Python example uses only the standard library. HMAC avoids a separate signing dependency, but it is shared-key message authentication rather than a public-key signature: anyone holding its verification secret can also create authentication tags. It illustrates binding, and should not be distributed to agents as a production signing architecture. The ephemeral demonstration key is generated afresh and never printed.

# Teaching protocol only: not a Chainguard attestation format.
import hashlib, hmac, json, secrets

def encode(value):
    return json.dumps(value,sort_keys=True,separators=(",",":"),
                      ensure_ascii=True).encode("ascii")

def digest(value):
    return hashlib.sha256(encode(value)).hexdigest()

key = secrets.token_bytes(32)  # ephemeral demo key; never printed
expected = {"source": digest({"main.py": "print(1)\n"}),
            "suite": digest(["unit-v3", "integration-v2"]),
            "environment": digest({"image": "fictional-image-v1"})}
report = dict(expected, passed=True, tests=12)
def tag(report):
    return hmac.new(key,encode(report),hashlib.sha256).hexdigest()

def accept(report, signature, expected):
    if not hmac.compare_digest(tag(report),signature):
        return False
    if any(report.get(k)!=v for k,v in expected.items()):
        return False
    return report.get("passed") is True and type(report.get("tests")) is int \
        and report["tests"]>0

signature = tag(report)
assert accept(report,signature,expected)
changed = dict(expected,source=digest({"main.py": "print(2)\n"}))
assert not accept(report,signature,changed) # authentic, wrong source
assert not accept(dict(report,tests=120),signature,expected) # tampered
empty = dict(report,tests=0)
assert not accept(empty,tag(empty),expected) # authentic, inadequate
wrong_suite = dict(expected,suite=digest(["unit-v3"]))
assert not accept(report,signature,wrong_suite)
print("5 receipt checks passed")

The code was executed locally and all five checks passed. It accepts the matching report and rejects changed source, modified report contents, an authenticated zero-test result, and a changed required suite. This validates the example function, not the Checks service or a project’s test coverage.

An environment needs more than a language-version label

An environment digest should identify a description the execution side can actually reconstruct or resolve. “Python 3” does not specify patch version, system libraries, architecture, or dependencies. A mutable image tag does not necessarily resolve to the same bytes twice. The fictional-image-v1 value in the code is deliberately a placeholder; a real integration needs immutable content identifiers and versioned configuration.

The suite needs an independent policy boundary too. If an agent replaces the test entry point with a script that always succeeds, a correctly authenticated result may accurately report that script’s success. The gate must decide who may approve changes to test definitions and which required checks candidate code cannot remove. Authenticating an execution is different from approving the standard it executed.

The earlier Bazel cache article concerns missing inputs in an action key. Here the consumer is a merge gate, and the reused object is a check result. Both problems become easier to reason about after the dependency boundary is explicit, but a cache hit and a valid signed verdict are different pieces of evidence.

Choose rejection rules before removing CI work

Start with existing CI as a baseline. Record the tested snapshot, required-suite version, environment, execution identity, and result states. During an initial observation phase, compare the new acceptance decision with the existing pipeline. Investigate discrepancies before eliminating repeated jobs. Deliberately edit an uncommitted file, replace a check definition, and change the runtime environment during that phase; confirm that the old result is rejected in each case. An extra run is easier to diagnose than an incorrectly reused pass.

Time adds another policy dimension. External services, vulnerability rules, or the intended merge base can change while source bytes remain unchanged. Decide which dependencies allow reuse, how long results remain useful, and when the merged tree must be checked again. A signature does not answer those questions.

The zero-test condition is only a teaching floor. Twelve executed tests do not imply twelve covered requirements, and a critical regression may have no assertion at all. Take one real green result and ask which inputs it binds, who can change the suite, and what the gate actually accepted. Missing answers call for better evidence before more aggressive CI reuse.

Sources and backfill note

The discovery trail is the Google News listing of the October 15 report, followed by the October 14 official announcement. The Sigstore reference supports the verification distinction. Both diagrams and the protocol example are original teaching material. Backfilled on October 16, retaining the planned 16:00 Beijing article date; the news sources were public before that slot.

If these checks help identify a CI result that is authentic but wrongly reused, voluntary support through the section below is welcome.

Support

If the explanations or examples helped you solve a problem or save time, you’re welcome to support this site with a voluntary tip.

WeChat support QR code; click to enlarge
WeChat
Alipay support QR code; click to enlarge
Alipay
Buy Me a Coffee; support this site
Buy Me a Coffee

Click a QR code to enlarge. More options: support page。

Share this Post

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

*
*