Files
server-deploy/internal/installplan/lock.go
T

69 lines
2.4 KiB
Go

package installplan
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"regexp"
"strings"
)
type Lock struct {
ProtocolVersion int `json:"protocolVersion"`
Repository string `json:"repository"`
Suite string `json:"suite"`
Architecture string `json:"architecture"`
ReleaseDigest string `json:"releaseDigest"`
Packages []Package `json:"packages"`
}
type Package struct {
Name string `json:"name"`
Version string `json:"version"`
Filename string `json:"filename"`
Digest string `json:"digest"`
Size uint64 `json:"size"`
}
var versionPattern = regexp.MustCompile(`^(?:[0-9]+:)?[0-9][0-9A-Za-z.+~-]*$`)
var digestPattern = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`)
var required = []string{"docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin"}
// Validate checks a caller-supplied lock against a fixed source policy. This is
// NOT repository signature validation or evidence these artifacts exist.
func Validate(lock Lock, suite, architecture string) (string, error) {
reject := errors.New("invalid Docker package lock")
if lock.ProtocolVersion != 1 || lock.Repository != "https://download.docker.com/linux/ubuntu" || lock.Suite != suite || lock.Architecture != architecture {
return "", reject
}
if (suite != "jammy" && suite != "noble" && suite != "resolute") || (architecture != "amd64" && architecture != "arm64") || !digestPattern.MatchString(lock.ReleaseDigest) || len(lock.Packages) != len(required) {
return "", reject
}
versions := map[string]string{}
for _, p := range lock.Packages {
allowed := false
for _, name := range required {
if p.Name == name {
allowed = true
}
}
if !allowed || versions[p.Name] != "" || len(p.Version) > 128 || !versionPattern.MatchString(p.Version) || !digestPattern.MatchString(p.Digest) || p.Size == 0 || p.Size > 512<<20 {
return "", reject
}
fileVersion := p.Version
if _, after, ok := strings.Cut(fileVersion, ":"); ok {
fileVersion = after
}
if p.Filename != "dists/"+suite+"/pool/stable/"+architecture+"/"+p.Name+"_"+fileVersion+"_"+architecture+".deb" {
return "", reject
}
versions[p.Name] = p.Version
}
if versions["docker-ce"] != versions["docker-ce-cli"] {
return "", reject
}
raw, _ := json.Marshal(lock)
sum := sha256.Sum256(raw)
return "sha256:" + hex.EncodeToString(sum[:]), nil
}