package main // The recipe of the Node build module (novox/hq ADR 0405 §7, ADR 0469 §4, ADR 0477 §1-§3; issues 1488, 1572): the // recipe's own version, and the recipe version, a hash of that and the bytes of the lock file that names the // TypeScript toolchain. The module names no Node version: it builds with the installed nodejs and npm, reports the // version installed to the toolchains state, and refuses only when node cannot be run (module.go). import ( "crypto/sha256" "encoding/hex" "fmt" "os" ) // RecipeSteps is the recipe's own version: changed whenever the steps of fetch, test or build change in a way that // can change what they produce (ADR 0405 §7). It is one of the two values the recipe version hashes. const RecipeSteps = "1" // Recipe is every value that makes up the recipe version. type Recipe struct { // Steps is RecipeSteps. Steps string // Lock is the hex sha256 of the bytes of toolchain/package-lock.json (LockHash). Lock string } // LockHash is the text a lock file's bytes stand for in the recipe version. func LockHash(lock []byte) string { sum := sha256.Sum256(lock) return hex.EncodeToString(sum[:]) } // ReadRecipe is the recipe of this build of the module with the lock file read from path. A missing lock is an // error: with no lock there is no toolchain to name. func ReadRecipe(lockPath string) (Recipe, error) { raw, err := os.ReadFile(lockPath) if err != nil { return Recipe{}, fmt.Errorf("the toolchain's lock file cannot be read: %w", err) } return Recipe{Steps: RecipeSteps, Lock: LockHash(raw)}, nil } // Version is the recipe version: a hash of the recipe's own version and the lock file's hash, never a Node version // (ADR 0477 §3): the toolchain enters each fingerprint once, as the version the build nodes agree on. A change of // either moves it and with it every fingerprint that holds it (ADR 0405 §7, ADR 0465 §2). The // fields are named in the hashed text, so no two recipes share a text. func (r Recipe) Version() string { h := sha256.New() for _, f := range [][2]string{{"steps", r.Steps}, {"lock", r.Lock}} { h.Write([]byte(f[0] + "=" + f[1] + "\n")) } return hex.EncodeToString(h.Sum(nil))[:16] }