103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
// 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)))
|
|
}
|