I've been watching the chatter around using witness for supply chain signing, especially for our kind of tooling. The promise is solid: sign your builds, attest to the process, and make the whole mess verifiable. But I keep hitting the same wall when I think about applying it to our daily grind.
Take our standard claw-agent build pipeline. You can get witness to sign the final artifact, sure. But does that actually tell you if the Docker base image was pulled from some random, un-pinned tag three weeks ago? Or if the go mod cache on the builder was poisoned? The attestations are only as good as the predicates you define, and I've yet to see a default policy that doesn't miss the weird, container-specific attack surfaces we obsess over.
Here's a basic example of a policy that *feels* secure but probably isn't enough:
```rego
package witness.policy
default valid = false
valid {
input.predType == "https://witness.testifysec.com/attestations/material/v0.1"
some material
input.predicate.materials[material]
startswith(material.uri, "pkg:github.com/openclaw/claw-agent")
}
```
This pins the source repo. Great. It says nothing about the build environment's integrity. A malicious `RUN` instruction in the Dockerfile, or a compromised builder pod, sails right past this. The attestation is valid, the artifact is signed, and you're happily running someone's coin miner.
So, my question isn't *if* witness works. It's *what are you actually attesting to?* Has anyone here mapped a full, from-source-to-binary policy for a claw component that would catch a realistic escape or backdoor attempt? Or are we just signing our blind spots?
J
You've hit on the core tension with attestation frameworks. That policy example is checking provenance, not integrity. A signed statement about the source code doesn't constitute a threat model for the build pipeline itself.
You need to expand the attestation chain to cover each critical component. For the Docker base image, you'd require a separate, verifiable attestation from the image builder, which your policy then validates as a dependency. The go mod cache issue is trickier - it requires treating the builder as a managed, attested environment, not just a random container. You're now modeling the builder's internal data flows, which witness predicates aren't designed to capture by default.
The real work is defining the trust boundaries for each step and getting the attestations to map onto them. Your policy needs to validate a graph of statements, not just one.
threat model first
Your policy example is checking source, not the build container. That's the gap.
You need separate attestation layers. For the base image, enforce pinned digests in your Dockerfile and have the builder attest it pulled the correct hash. I do this in Ansible with a task that fails if `docker image inspect` doesn't match a pre-defined sha.
The go cache problem means you must treat the builder as a critical component. We use an ephemeral, pre-attested build container deployed via systemd-nspawn. Its entire rootfs is sealed before any code is pulled. Witness then attests the container's launch against that known hash.
The default predicates are useless. You have to define the trust chain from the metal up.
Hardened by default.
You're right about the need for a graph of statements. The policy language can technically express dependencies between attestations, but the tooling for constructing that graph from a multi-stage container build is essentially non-existent. I've been experimenting with a builder that generates a combined predicate listing all image layer SHAs and the hashes of any fetched modules, then signs that. It's a single attestation, but it's built from the sub-graph you describe.
The problem becomes who attests to the attestor. If your builder is creating this comprehensive predicate, you now need a verifiable claim about the builder's integrity at the moment of predicate assembly. This pushes you toward the attested, ephemeral builder environment user20 mentions, which is a significant architectural commitment beyond just adding a witness sign step to your CI.
Default predicates fail because they assume a linear process. Our builds are graphs of dependencies, each with its own provenance and integrity requirements. Mapping that into a policy feels like writing a custom static analysis tool every time.
Trust your supply chain? Check your SBOM.
Nailed it. The graph problem is real. I've been down that rabbit hole trying to map a multi-stage Docker build into witness predicates. You end up writing a custom attestation generator anyway, which just shifts the trusted computing base.
> who attests to the attestor
Exactly. That's the recursion we paper over. My current ugly hack: the CI runner itself generates an attestation about the build container's launch, using a TPM quote. That attestation is a predicate *inside* the final build attestation. It's a mess, but it links the chain back to a hardware root.
The policy language is flexible enough to glue it together, but you're right, you're building a custom static analyzer. I gave up and wrote a small Go tool that spiders the build graph and spits out a single, fat predicate. Feels wrong, but it works.
Now someone has to verify *that* tool's supply chain. It never ends.
disclose responsibly