Carry a candidate module's named paths, so the builder's fetch for a candidate names them (issue 1758, ADR 0499 §2, the builder lane's request)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A candidate's module carries the git objects of its named paths at the preview (novox/hq ADR 0499 clause 2), so the
|
||||
// builder's fetch request for a candidate names them; an older candidate decodes without them, and a path that is not
|
||||
// clean and relative, or names no object, is refused.
|
||||
func TestACandidatesModuleCarriesItsNamedPaths(t *testing.T) {
|
||||
c := sampleCandidate()
|
||||
paths := map[string]string{"src": strings.Repeat("a", 40), "package.json": strings.Repeat("b", 40)}
|
||||
c.Pulls[0].Fps = map[string]CandidateModule{"mesh-mail": {FP2: SourcePrefix2 + strings.Repeat("1", 64),
|
||||
Manifest: strings.Repeat("2", 64), Paths: paths}}
|
||||
c.FPSet = FingerprintSet(c.Pulls)
|
||||
data, err := EncodeCandidate(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
back, err := DecodeCandidate(data)
|
||||
if err != nil || back.Pulls[0].Fps["mesh-mail"].Paths["src"] != paths["src"] {
|
||||
t.Fatalf("decoded %+v, %v", back.Pulls[0].Fps, err)
|
||||
}
|
||||
old := sampleCandidate()
|
||||
old.Pulls[0].Fps = map[string]CandidateModule{"mesh-mail": {FP2: SourcePrefix2 + strings.Repeat("1", 64)}}
|
||||
old.FPSet = FingerprintSet(old.Pulls)
|
||||
if data, err := EncodeCandidate(old); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if b, err := DecodeCandidate(data); err != nil || b.Pulls[0].Fps["mesh-mail"].Paths != nil {
|
||||
t.Fatalf("an older candidate: %+v, %v", b, err)
|
||||
}
|
||||
for _, bad := range []map[string]string{{"../x": "a"}, {"/src": "a"}, {"": "a"}, {"src": ""}} {
|
||||
c.Pulls[0].Fps = map[string]CandidateModule{"mesh-mail": {FP2: SourcePrefix2 + strings.Repeat("1", 64), Paths: bad}}
|
||||
c.FPSet = FingerprintSet(c.Pulls)
|
||||
if _, err := EncodeCandidate(c); err == nil {
|
||||
t.Errorf("%v was accepted", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-1
@@ -277,6 +277,9 @@ type CandidateModule struct {
|
||||
FP2 string `json:"fp2,omitempty"`
|
||||
None2 string `json:"none2,omitempty"`
|
||||
Manifest string `json:"manifest,omitempty"`
|
||||
// Paths are, of a module whose every artifact names its paths, each named path's git object id at the preview
|
||||
// (novox/hq ADR 0499 clause 2), so the builder's fetch request for the candidate names them. Absent otherwise.
|
||||
Paths map[string]string `json:"paths,omitempty"`
|
||||
}
|
||||
|
||||
func (m CandidateModule) check() error {
|
||||
@@ -286,6 +289,9 @@ func (m CandidateModule) check() error {
|
||||
case m.FP2 == "" && m.None2 == "":
|
||||
return fmt.Errorf("delivery: a module has neither fp2 nor none2")
|
||||
}
|
||||
if err := checkPathObjects(m.Paths); err != nil {
|
||||
return err
|
||||
}
|
||||
return checkNewForm(m.FP2, m.Manifest)
|
||||
}
|
||||
|
||||
@@ -357,7 +363,7 @@ func (c Candidate) check() error {
|
||||
if err := m.check(); err != nil {
|
||||
return fmt.Errorf("delivery: the candidate's module %q: %w", module, err)
|
||||
}
|
||||
if before, ok := seen[module]; ok && before != m {
|
||||
if before, ok := seen[module]; ok && !reflect.DeepEqual(before, m) {
|
||||
return fmt.Errorf("delivery: two pull requests of the candidate give the module %q different fingerprints", module)
|
||||
}
|
||||
seen[module] = m
|
||||
@@ -425,6 +431,19 @@ type KeptInputs2 struct {
|
||||
Paths map[string]string `json:"paths,omitempty"`
|
||||
}
|
||||
|
||||
// checkPathObjects refuses a named path that is not clean and relative to the module's directory, or names no object.
|
||||
func checkPathObjects(paths map[string]string) error {
|
||||
for p, object := range paths {
|
||||
if p == "" || p != path.Clean(p) || strings.HasPrefix(p, "/") || p == ".." || strings.HasPrefix(p, "../") {
|
||||
return fmt.Errorf("delivery: the named path %q is not a clean path inside the module's directory", p)
|
||||
}
|
||||
if object == "" {
|
||||
return fmt.Errorf("delivery: the named path %q names no git object", p)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkNamed refuses kept named paths that do not compute to the kept tree with the module's manifest digest.
|
||||
func checkNamed(tree, manifest string, paths map[string]string, of string) error {
|
||||
if len(paths) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user