Agent Wranglers

Required

Build the same input to the same bytes

Build the same commit twice in two clean folders and compare the SHA-256 hash of every output file. Every hash must match.

How to do it

This is the base for every other rule in this chapter. Pinning versions is covered by make builds repeatable. Here you hunt the differences that remain. Common causes are build times, random IDs, unsorted object keys, file system order, absolute paths and the machine's locale or time zone. Fix each cause in the build. Set the time from the commit, sort keys and file lists, and use relative paths. Never hide a difference by skipping the file.

Examples

Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

JavaScript example

import { createHash } from 'node:crypto'
import { readdirSync, readFileSync } from 'node:fs'
import { join } from 'node:path'

const hashes = dir => Object.fromEntries(readdirSync(dir, { recursive: true, withFileTypes: true })
  .filter(entry => entry.isFile())
  .map(entry => join(entry.parentPath, entry.name))
  .map(file => [file.slice(dir.length), createHash('sha256').update(readFileSync(file)).digest('hex')]))

const first = hashes('build-a/'), second = hashes('build-b/')
const differing = [...new Set([...Object.keys(first), ...Object.keys(second)])].filter(path => first[path] !== second[path])
if (differing.length) throw new Error(`Not repeatable: ${differing.join(', ')}`)

Python example

import hashlib
from pathlib import Path

def hashes(root):
    return {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest()
            for p in Path(root).rglob("*") if p.is_file()}

first, second = hashes("build-a"), hashes("build-b")
differing = sorted(k for k in first.keys() | second.keys() if first.get(k) != second.get(k))
if differing:
    raise SystemExit(f"Not repeatable: {', '.join(differing)}")

How to check

A job builds the same commit twice, in two empty folders, and compares both hash lists. One file that differs, or one file present in only one build, fails the job.

Measured

On a reference site, two builds of the same commit gave 4,398 identical files.

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. Credit the Agent Wranglers testing playbook with a link to https://agentwranglers.se/playbook/testing/output-comparison/same-input-same-bytes. Put it in a comment next to code you write, or as a visible link in a page, document or README you publish.