171 lines
5.1 KiB
Go
171 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Keep this list independent of sourceHash so additions to its production source
|
|
// inventory require an explicit fixture update rather than being silently lost.
|
|
var siteInputSourceDirs = []string{
|
|
"art", "tools/artstudio", "anim", "asset", "contracts", "core", "engine", "format", "gpu",
|
|
"modules/render2d", "modules/particles", "platform", "render", "save", "scene", "schema", "script", "vfs",
|
|
}
|
|
|
|
func siteInputSourceFixture(t *testing.T) string {
|
|
t.Helper()
|
|
root := t.TempDir()
|
|
for _, name := range siteInputSourceDirs {
|
|
dir := filepath.Join(root, name)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "input.go"), []byte("source for "+name), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for _, name := range []string{"go.mod", "go.sum"} {
|
|
if err := os.WriteFile(filepath.Join(root, name), []byte("source for "+name), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return root
|
|
}
|
|
|
|
func TestProductionSiteInputRequiresPinnedRelease(t *testing.T) {
|
|
const app = "https://aeditor.akarpov.ru"
|
|
const docs = "https://aego.akarpov.ru"
|
|
commit := strings.Repeat("a", 40)
|
|
root := siteInputSourceFixture(t)
|
|
source, err := sourceHash(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type request struct {
|
|
sha, commit, app, docs string
|
|
change func(string, *buildManifest)
|
|
}
|
|
tests := map[string]request{
|
|
"valid": {},
|
|
"missing hash": {sha: "missing"},
|
|
"wrong hash": {sha: strings.Repeat("0", 64)},
|
|
"short commit": {commit: "abcd"},
|
|
"wrong commit": {commit: strings.Repeat("b", 40)},
|
|
"wrong app origin": {app: "https://unexpected.example"},
|
|
"wrong docs origin": {docs: "https://unexpected.example"},
|
|
"snapshot": {change: func(_ string, m *buildManifest) { m.Release = false }},
|
|
"extra parent origin": {change: func(_ string, m *buildManifest) {
|
|
m.DocsOrigins = append(m.DocsOrigins, "https://unexpected.example")
|
|
}},
|
|
"wrong source": {change: func(_ string, m *buildManifest) { m.SourceSHA256 = strings.Repeat("1", 64) }},
|
|
"tampered asset": {change: func(dir string, _ *buildManifest) {
|
|
if err := os.WriteFile(filepath.Join(dir, "index.html"), []byte("tampered"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}},
|
|
}
|
|
for name, req := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
dir, m, _ := fixtureArtifact(t, "site-input")
|
|
m.Release, m.Commit, m.SourceSHA256 = true, commit, source
|
|
m.AppOrigin, m.DocsOrigins = app, []string{docs, app}
|
|
if req.change != nil {
|
|
req.change(dir, &m)
|
|
}
|
|
manifest := jsonBytes(m)
|
|
if err := os.WriteFile(filepath.Join(dir, "manifest.json"), manifest, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sha := digest(manifest)
|
|
if req.sha != "" {
|
|
sha = req.sha
|
|
if sha == "missing" {
|
|
sha = ""
|
|
}
|
|
}
|
|
wantCommit, wantApp, wantDocs := commit, app, docs
|
|
if req.commit != "" {
|
|
wantCommit = req.commit
|
|
}
|
|
if req.app != "" {
|
|
wantApp = req.app
|
|
}
|
|
if req.docs != "" {
|
|
wantDocs = req.docs
|
|
}
|
|
_, _, err := verifySiteInput(dir, root, sha, wantCommit, wantApp, wantDocs)
|
|
if (err == nil) != (name == "valid") {
|
|
t.Fatalf("verification error = %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSiteInputSourceFixtureIsHashed(t *testing.T) {
|
|
inputs := []string{"go.mod", "go.sum"}
|
|
for _, dir := range siteInputSourceDirs {
|
|
inputs = append(inputs, filepath.Join(dir, "input.go"))
|
|
}
|
|
for _, name := range inputs {
|
|
t.Run(name, func(t *testing.T) {
|
|
root := siteInputSourceFixture(t)
|
|
before, err := sourceHash(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, name), []byte("modified "+name), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
after, err := sourceHash(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if before == after {
|
|
t.Fatalf("sourceHash ignored %s", name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProductionSiteInputRejectsChangedSource(t *testing.T) {
|
|
const app = "https://aeditor.akarpov.ru"
|
|
const docs = "https://aego.akarpov.ru"
|
|
commit := strings.Repeat("a", 40)
|
|
root := siteInputSourceFixture(t)
|
|
source, err := sourceHash(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir, m, _ := fixtureArtifact(t, "changed-site-source")
|
|
m.Release, m.Commit, m.SourceSHA256 = true, commit, source
|
|
m.AppOrigin, m.DocsOrigins = app, []string{docs, app}
|
|
manifest := jsonBytes(m)
|
|
if err := os.WriteFile(filepath.Join(dir, "manifest.json"), manifest, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, name := range siteInputSourceDirs {
|
|
t.Run(name, func(t *testing.T) {
|
|
path := filepath.Join(root, name, "input.go")
|
|
original, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if err := os.WriteFile(path, original, 0644); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
if err := os.WriteFile(path, []byte("changed"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, _, err = verifySiteInput(dir, root, digest(manifest), commit, app, docs)
|
|
if err == nil || !strings.Contains(err.Error(), "site source subset differs from the artifact") {
|
|
t.Fatalf("changed %s accepted or wrong failure: %v", name, err)
|
|
}
|
|
})
|
|
}
|
|
}
|