|
| 1 | +#!/usr/bin/env bash |
| 2 | +# validate_and_sign.sh |
| 3 | +# |
| 4 | +# Validates a guide YAML file against the CUE schema and, on success, embeds a |
| 5 | +# SHA256 hash of the validated content into the file as the 'cue.verified' field. |
| 6 | +# Running this script a second time on an already-signed file is safe: the |
| 7 | +# existing 'cue.verified' field is stripped before hashing so the hash is stable. |
| 8 | +# |
| 9 | +# Usage: |
| 10 | +# ./validate_and_sign.sh <guide.yml> |
| 11 | +# |
| 12 | +# Example: |
| 13 | +# ./validate_and_sign.sh guide_competition_1_0_source.yml |
| 14 | +# |
| 15 | +# Requirements: cue, yq (go-yq), sha256sum |
| 16 | +# Install via the accompanying shell.nix: nix-shell |
| 17 | + |
| 18 | +set -euo pipefail |
| 19 | + |
| 20 | +FILE="${1:?Usage: validate_and_sign.sh <guide.yml>}" |
| 21 | +SCHEMA="$(dirname "$0")/excelguide_schema.cue" |
| 22 | + |
| 23 | +# --------------------------------------------------------------------------- # |
| 24 | +# Sanity checks |
| 25 | +# --------------------------------------------------------------------------- # |
| 26 | + |
| 27 | +if [ ! -f "$FILE" ]; then |
| 28 | + echo "Error: file not found: $FILE" >&2 |
| 29 | + exit 1 |
| 30 | +fi |
| 31 | + |
| 32 | +if [ ! -f "$SCHEMA" ]; then |
| 33 | + echo "Error: schema not found: $SCHEMA" >&2 |
| 34 | + exit 1 |
| 35 | +fi |
| 36 | + |
| 37 | +for cmd in cue yq sha256sum; do |
| 38 | + if ! command -v "$cmd" &>/dev/null; then |
| 39 | + echo "Error: required command not found: $cmd" >&2 |
| 40 | + echo " Start a nix-shell in this directory to get all dependencies." >&2 |
| 41 | + exit 1 |
| 42 | + fi |
| 43 | +done |
| 44 | + |
| 45 | +# --------------------------------------------------------------------------- # |
| 46 | +# Prepare a stripped temporary copy (without any existing cue.verified field) |
| 47 | +# --------------------------------------------------------------------------- # |
| 48 | + |
| 49 | +TMPFILE=$(mktemp /tmp/guide_XXXXXX.yml) |
| 50 | +trap 'rm -f "$TMPFILE"' EXIT |
| 51 | + |
| 52 | +yq 'del(.["cue.verified"])' "$FILE" > "$TMPFILE" |
| 53 | + |
| 54 | +# --------------------------------------------------------------------------- # |
| 55 | +# CUE validation |
| 56 | +# --------------------------------------------------------------------------- # |
| 57 | + |
| 58 | +echo "Validating ${FILE} ..." |
| 59 | + |
| 60 | +if ! cue vet -c "$SCHEMA" "$TMPFILE"; then |
| 61 | + echo "" |
| 62 | + echo "CUE validation FAILED — 'cue.verified' was NOT embedded." >&2 |
| 63 | + exit 1 |
| 64 | +fi |
| 65 | + |
| 66 | +# --------------------------------------------------------------------------- # |
| 67 | +# Hash the yq-normalised content and embed it in the original file |
| 68 | +# |
| 69 | +# The hash is computed over the yq-normalised YAML (without cue.verified). |
| 70 | +# yq normalises whitespace, quoting style, and key order within scalars, |
| 71 | +# making the hash stable across cosmetic edits to the original file. |
| 72 | +# --------------------------------------------------------------------------- # |
| 73 | + |
| 74 | +HASH=$(sha256sum "$TMPFILE" | cut -d' ' -f1) |
| 75 | + |
| 76 | +yq -i ".\"cue.verified\" = \"sha256:${HASH}\"" "$FILE" |
| 77 | + |
| 78 | +echo "Validation passed." |
| 79 | +echo "Embedded: sha256:${HASH}" |
0 commit comments