// Reference-only Moby saveConfig/CreateID oracle. The generator supplies the // source-pinned Config/V1Image declarations; this never imports Hub code. package main import ( "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "os" "reflect" ) type blob struct { Name string `json:"name"` Payload string `json:"payloadBase64"` } type result struct { Dialect string `json:"dialect"` Config json.RawMessage `json:"config"` Blobs []blob `json:"blobs"` } func sum(data []byte) string { return fmt.Sprintf("%x", sha256.Sum256(data)) } func encoded(value any) []byte { data, err := json.Marshal(value) if err != nil { panic(err) } return data } func derive[T any](dialect string, raw json.RawMessage) result { var image struct { RootFS struct { DiffIDs []string `json:"diff_ids"` } `json:"rootfs"` } if err := json.Unmarshal(raw, &image); err != nil { panic(err) } // Image.Parent shadows V1Image.Parent in Moby; these golden inputs do not // depend on an old builder's parent field. var original T if err := json.Unmarshal(raw, &original); err != nil { panic(err) } chain, parent := "", "" output := result{Dialect: dialect, Config: raw, Blobs: []blob{}} for index, diff := range image.RootFS.DiffIDs { if chain == "" { chain = diff } else { chain = "sha256:" + sum([]byte(chain+" "+diff)) } var legacy T if index == len(image.RootFS.DiffIDs)-1 { legacy = original } else { if err := json.Unmarshal([]byte(`{"created":"1970-01-01T00:00:00Z"}`), &legacy); err != nil { panic(err) } } reflected := reflect.ValueOf(&legacy).Elem() reflected.FieldByName("ID").SetString("") var preimage map[string]json.RawMessage if err := json.Unmarshal(encoded(legacy), &preimage); err != nil { panic(err) } preimage["layer_id"] = encoded(chain) if parent != "" { preimage["parent"] = encoded("sha256:" + parent) } identity := sum(encoded(preimage)) reflected.FieldByName("ID").SetString(identity) if parent != "" { reflected.FieldByName("Parent").SetString(parent) } reflected.FieldByName("OS").SetString("linux") payload := encoded(legacy) output.Blobs = append(output.Blobs, blob{ Name: "blobs/sha256/" + sum(payload), Payload: base64.StdEncoding.EncodeToString(payload), }) parent = identity } return output } func main() { data, err := os.ReadFile(os.Args[1]) if err != nil { panic(err) } var inputs []json.RawMessage if err := json.Unmarshal(data, &inputs); err != nil { panic(err) } outputs := []result{} for _, input := range inputs { outputs = append(outputs, derive[OldV1]("onbuild_null", input)) outputs = append(outputs, derive[NewV1]("onbuild_omitempty", input)) } fmt.Println(string(encoded(outputs))) }