fix(startup): record first-presentation provenance
- commit
- e4b5a976154ba4286272cc67f72babeae8452b03
- author
- brice · · 2026-07-14 08:47 UTC
- committer
- brice · · 2026-07-14 09:35 UTC
- parent
- 04b52b5
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +18 -3
M internal/logging/first_presentation_collector_test.go +7 -0
| @@ -52,6 +52,13 @@ func TestFirstPresentationCollectorSanitizesMachineLocalValues(t *testing.T) { | |||
| 52 | 52 | for _, forbidden := range []string{"/home/", temp, "alice", "machine_path", `"time"`} { | |
| 53 | 53 | require.NotContainsf(t, artifacts.String(), forbidden, "committed artifact leaked %q", forbidden) | |
| 54 | 54 | } | |
| 55 | + | for _, required := range []string{ | |
| 56 | + | `"measured_source_revision"`, | |
| 57 | + | `"tag": "v0.8.4"`, | |
| 58 | + | `"revision": "f217ece342dea3ef2a3f98671fcd16a39ad0037d"`, | |
| 59 | + | } { | |
| 60 | + | require.Contains(t, artifacts.String(), required) | |
| 61 | + | } | |
| 55 | 62 | } | |
| 56 | 63 | ||
| 57 | 64 | func TestFirstPresentationCollectorRejectsInconsistentTiming(t *testing.T) { | |
| @@ -52,6 +52,13 @@ func TestFirstPresentationCollectorSanitizesMachineLocalValues(t *testing.T) { | |||||
| 52 | for _, forbidden := range []string{"/home/", temp, "alice", "machine_path", `"time"`} { | 52 | for _, forbidden := range []string{"/home/", temp, "alice", "machine_path", `"time"`} { | ||
| 53 | require.NotContainsf(t, artifacts.String(), forbidden, "committed artifact leaked %q", forbidden) | 53 | require.NotContainsf(t, artifacts.String(), forbidden, "committed artifact leaked %q", forbidden) | ||
| 54 | } | 54 | } | ||
| 55 | + | for _, required := range []string{ | |||
| 56 | + | `"measured_source_revision"`, | |||
| 57 | + | `"tag": "v0.8.4"`, | |||
| 58 | + | `"revision": "f217ece342dea3ef2a3f98671fcd16a39ad0037d"`, | |||
| 59 | + | } { | |||
| 60 | + | require.Contains(t, artifacts.String(), required) | |||
| 61 | + | } | |||
| 55 | } | 62 | } | ||
| 56 | 63 | ||||
| 57 | func TestFirstPresentationCollectorRejectsInconsistentTiming(t *testing.T) { | 64 | func TestFirstPresentationCollectorRejectsInconsistentTiming(t *testing.T) { | ||
M scripts/collect_first_presentation.sh +11 -3
| @@ -9,10 +9,17 @@ readonly timeout_seconds="${DUMBER_FIRST_PRESENTATION_TIMEOUT_SECONDS:-45}" | |||
| 9 | 9 | readonly runtime="${DUMBER_CEF_DIR:-$HOME/.local/share/cef-147-runtime}" | |
| 10 | 10 | readonly binary="${DUMBER_FIRST_PRESENTATION_BIN:-$PWD/dist/dumber}" | |
| 11 | 11 | readonly output="${DUMBER_FIRST_PRESENTATION_OUTPUT:-$PWD/phase1/first-presentation}" | |
| 12 | + | readonly upstream_module="github.com/bnema/purego-cef2gtk" | |
| 13 | + | readonly upstream_tag="v0.8.4" | |
| 14 | + | readonly upstream_revision="f217ece342dea3ef2a3f98671fcd16a39ad0037d" | |
| 12 | 15 | ||
| 13 | 16 | [[ -x "$binary" ]] || { echo "first-presentation: executable not found: $binary" >&2; exit 2; } | |
| 14 | 17 | [[ -d "$runtime" ]] || { echo "first-presentation: CEF runtime not found: $runtime" >&2; exit 2; } | |
| 15 | 18 | [[ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] || { echo "first-presentation: a current Wayland/X11 display is required" >&2; exit 2; } | |
| 19 | + | [[ "$(go list -m -f '{{.Version}}' "$upstream_module")" == "$upstream_tag" ]] || { | |
| 20 | + | echo "first-presentation: expected $upstream_module@$upstream_tag" >&2 | |
| 21 | + | exit 2 | |
| 22 | + | } | |
| 16 | 23 | ||
| 17 | 24 | rm -rf "$output" | |
| 18 | 25 | mkdir -p "$output" | |
| @@ -20,9 +27,9 @@ mkdir -p "$output" | |||
| 20 | 27 | # outside the committed artifact directory and always remove them. | |
| 21 | 28 | work_root="$(mktemp -d "${TMPDIR:-/tmp}/dumber-first-presentation.XXXXXX")" | |
| 22 | 29 | trap 'rm -rf "$work_root"' EXIT | |
| 23 | - | python3 - "$output/metadata.json" "$binary" "$timeout_seconds" <<'PY' | |
| 30 | + | python3 - "$output/metadata.json" "$binary" "$timeout_seconds" "$upstream_module" "$upstream_tag" "$upstream_revision" <<'PY' | |
| 24 | 31 | import hashlib, json, os, subprocess, sys | |
| 25 | - | path, binary, timeout = sys.argv[1:] | |
| 32 | + | path, binary, timeout, upstream_module, upstream_tag, upstream_revision = sys.argv[1:] | |
| 26 | 33 | with open(binary, "rb") as candidate: | |
| 27 | 34 | binary_sha256 = hashlib.file_digest(candidate, "sha256").hexdigest() | |
| 28 | 35 | json.dump({ | |
| @@ -30,7 +37,8 @@ json.dump({ | |||
| 30 | 37 | "runtime": {"label": "cef", "version": os.environ.get("DUMBER_CEF_RUNTIME_VERSION", "147")}, | |
| 31 | 38 | "binary": {"label": "dumber", "sha256": binary_sha256}, | |
| 32 | 39 | "timeout_seconds": int(timeout), | |
| 33 | - | "git_revision": subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip(), | |
| 40 | + | "measured_source_revision": subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip(), | |
| 41 | + | "upstream": {"module": upstream_module, "tag": upstream_tag, "revision": upstream_revision}, | |
| 34 | 42 | "fixed_environment": {"DUMBER_RENDER_STACK": "vulkan-dmabuf", "PUREGO_CEF2GTK_BACKEND": "gdk-dmabuf", "GSK_RENDERER": "vulkan"} | |
| 35 | 43 | }, open(path, "w"), indent=2, sort_keys=True) | |
| 36 | 44 | PY | |
| @@ -9,10 +9,17 @@ readonly timeout_seconds="${DUMBER_FIRST_PRESENTATION_TIMEOUT_SECONDS:-45}" | |||||
| 9 | readonly runtime="${DUMBER_CEF_DIR:-$HOME/.local/share/cef-147-runtime}" | 9 | readonly runtime="${DUMBER_CEF_DIR:-$HOME/.local/share/cef-147-runtime}" | ||
| 10 | readonly binary="${DUMBER_FIRST_PRESENTATION_BIN:-$PWD/dist/dumber}" | 10 | readonly binary="${DUMBER_FIRST_PRESENTATION_BIN:-$PWD/dist/dumber}" | ||
| 11 | readonly output="${DUMBER_FIRST_PRESENTATION_OUTPUT:-$PWD/phase1/first-presentation}" | 11 | readonly output="${DUMBER_FIRST_PRESENTATION_OUTPUT:-$PWD/phase1/first-presentation}" | ||
| 12 | + | readonly upstream_module="github.com/bnema/purego-cef2gtk" | |||
| 13 | + | readonly upstream_tag="v0.8.4" | |||
| 14 | + | readonly upstream_revision="f217ece342dea3ef2a3f98671fcd16a39ad0037d" | |||
| 12 | 15 | ||||
| 13 | [[ -x "$binary" ]] || { echo "first-presentation: executable not found: $binary" >&2; exit 2; } | 16 | [[ -x "$binary" ]] || { echo "first-presentation: executable not found: $binary" >&2; exit 2; } | ||
| 14 | [[ -d "$runtime" ]] || { echo "first-presentation: CEF runtime not found: $runtime" >&2; exit 2; } | 17 | [[ -d "$runtime" ]] || { echo "first-presentation: CEF runtime not found: $runtime" >&2; exit 2; } | ||
| 15 | [[ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] || { echo "first-presentation: a current Wayland/X11 display is required" >&2; exit 2; } | 18 | [[ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] || { echo "first-presentation: a current Wayland/X11 display is required" >&2; exit 2; } | ||
| 19 | + | [[ "$(go list -m -f '{{.Version}}' "$upstream_module")" == "$upstream_tag" ]] || { | |||
| 20 | + | echo "first-presentation: expected $upstream_module@$upstream_tag" >&2 | |||
| 21 | + | exit 2 | |||
| 22 | + | } | |||
| 16 | 23 | ||||
| 17 | rm -rf "$output" | 24 | rm -rf "$output" | ||
| 18 | mkdir -p "$output" | 25 | mkdir -p "$output" | ||
| @@ -20,9 +27,9 @@ mkdir -p "$output" | |||||
| 20 | # outside the committed artifact directory and always remove them. | 27 | # outside the committed artifact directory and always remove them. | ||
| 21 | work_root="$(mktemp -d "${TMPDIR:-/tmp}/dumber-first-presentation.XXXXXX")" | 28 | work_root="$(mktemp -d "${TMPDIR:-/tmp}/dumber-first-presentation.XXXXXX")" | ||
| 22 | trap 'rm -rf "$work_root"' EXIT | 29 | trap 'rm -rf "$work_root"' EXIT | ||
| 23 | - | python3 - "$output/metadata.json" "$binary" "$timeout_seconds" <<'PY' | 30 | + | python3 - "$output/metadata.json" "$binary" "$timeout_seconds" "$upstream_module" "$upstream_tag" "$upstream_revision" <<'PY' |
| 24 | import hashlib, json, os, subprocess, sys | 31 | import hashlib, json, os, subprocess, sys | ||
| 25 | - | path, binary, timeout = sys.argv[1:] | 32 | + | path, binary, timeout, upstream_module, upstream_tag, upstream_revision = sys.argv[1:] |
| 26 | with open(binary, "rb") as candidate: | 33 | with open(binary, "rb") as candidate: | ||
| 27 | binary_sha256 = hashlib.file_digest(candidate, "sha256").hexdigest() | 34 | binary_sha256 = hashlib.file_digest(candidate, "sha256").hexdigest() | ||
| 28 | json.dump({ | 35 | json.dump({ | ||
| @@ -30,7 +37,8 @@ json.dump({ | |||||
| 30 | "runtime": {"label": "cef", "version": os.environ.get("DUMBER_CEF_RUNTIME_VERSION", "147")}, | 37 | "runtime": {"label": "cef", "version": os.environ.get("DUMBER_CEF_RUNTIME_VERSION", "147")}, | ||
| 31 | "binary": {"label": "dumber", "sha256": binary_sha256}, | 38 | "binary": {"label": "dumber", "sha256": binary_sha256}, | ||
| 32 | "timeout_seconds": int(timeout), | 39 | "timeout_seconds": int(timeout), | ||
| 33 | - | "git_revision": subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip(), | 40 | + | "measured_source_revision": subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip(), |
| 41 | + | "upstream": {"module": upstream_module, "tag": upstream_tag, "revision": upstream_revision}, | |||
| 34 | "fixed_environment": {"DUMBER_RENDER_STACK": "vulkan-dmabuf", "PUREGO_CEF2GTK_BACKEND": "gdk-dmabuf", "GSK_RENDERER": "vulkan"} | 42 | "fixed_environment": {"DUMBER_RENDER_STACK": "vulkan-dmabuf", "PUREGO_CEF2GTK_BACKEND": "gdk-dmabuf", "GSK_RENDERER": "vulkan"} | ||
| 35 | }, open(path, "w"), indent=2, sort_keys=True) | 43 | }, open(path, "w"), indent=2, sort_keys=True) | ||
| 36 | PY | 44 | PY | ||