Keep each artifact's named paths in the modules value, so the checker needs no manifest to see a change touch them (issue 1758, ADR 0499, lead decision L8)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The indexer's modules value carries each artifact's named paths (novox/hq ADR 0499; the lead's decision L8 of R4e):
|
||||
// the checker tells from it whether a change touches lib's paths without reading a manifest. An older value has none.
|
||||
func TestAModulesValueCarriesEachArtifactsNamedPaths(t *testing.T) {
|
||||
m := Module{FP2: SourcePrefix2 + strings.Repeat("a", 64), Repository: "novox/mesh-sdk", Commit: "c",
|
||||
ArtifactPaths: map[string][]string{"lib": {"package-lock.json", "package.json", "src", "test", "tsconfig.json"}}}
|
||||
data, err := EncodeModule(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(data), `"paths":{"lib":[`) {
|
||||
t.Fatalf("the value carries no paths: %s", data)
|
||||
}
|
||||
back, err := DecodeModule(data)
|
||||
if err != nil || len(back.ArtifactPaths["lib"]) != 5 || back.ArtifactPaths["lib"][2] != "src" {
|
||||
t.Fatalf("decoded %+v, %v", back.ArtifactPaths, err)
|
||||
}
|
||||
if old, err := DecodeModule([]byte(`{"v":1,"fp":"src1:x","repository":"a/b","commit":"c"}`)); err != nil || old.ArtifactPaths != nil {
|
||||
t.Fatalf("an older value: %+v, %v", old, err)
|
||||
}
|
||||
for _, bad := range []map[string][]string{{"": {"src"}}, {"lib": {}}, {"lib": {"../x"}}, {"lib": {""}}} {
|
||||
m.ArtifactPaths = bad
|
||||
if _, err := EncodeModule(m); err == nil {
|
||||
t.Errorf("%v was accepted", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -399,6 +400,11 @@ type Module struct {
|
||||
// builds the fingerprint only with these. Empty when FP2 is empty or the module has no toolchain; a value written
|
||||
// before has none (issue 1615).
|
||||
Toolchains map[string]ToolchainUsed `json:"toolchains,omitempty"`
|
||||
// ArtifactPaths are, of each artifact that names the paths it is built from, those paths as its manifest names
|
||||
// them, by artifact (novox/hq ADR 0499 clause 1): the indexer fills them from each catalogue.Artifact.Paths it reads,
|
||||
// so the checker tells whether a change touches an artifact's build source without reading a manifest (the lead's
|
||||
// decision L8 of R4e). Absent for an artifact that names none, and in a value written before.
|
||||
ArtifactPaths map[string][]string `json:"paths,omitempty"`
|
||||
}
|
||||
|
||||
// RootPath is Module.Path of a module whose manifest is its repository's root.
|
||||
@@ -459,6 +465,16 @@ func (m Module) check() error {
|
||||
if m.Inputs2 != nil && m.Manifest == "" {
|
||||
return fmt.Errorf("delivery: a module keeps new-form inputs but has no manifest digest")
|
||||
}
|
||||
for artifact, paths := range m.ArtifactPaths {
|
||||
if artifact == "" || len(paths) == 0 {
|
||||
return fmt.Errorf("delivery: the module's named paths of the artifact %q are empty or name no artifact", artifact)
|
||||
}
|
||||
for _, p := range paths {
|
||||
if p == "" || p != path.Clean(p) || strings.HasPrefix(p, "/") || p == ".." || strings.HasPrefix(p, "../") {
|
||||
return fmt.Errorf("delivery: the artifact %q names the path %q, not a clean path inside the module's directory", artifact, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
if m.Inputs2 != nil {
|
||||
if err := checkNamed(m.Inputs2.Tree, m.Manifest, m.Inputs2.Paths, "the module's kept inputs"); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user