forked from security/hakurei
This should hopefully provide good separation between the artifact curing backend implementation and the (still work in progress) language. Making the IR parseable also guarantees uniqueness of the representation. Signed-off-by: Ophestra <cat@gensokyo.uk>
162 lines
4.8 KiB
Go
162 lines
4.8 KiB
Go
package pkg_test
|
|
|
|
import (
|
|
"crypto/sha512"
|
|
"io"
|
|
"net/http"
|
|
"reflect"
|
|
"testing"
|
|
"testing/fstest"
|
|
"unique"
|
|
"unsafe"
|
|
|
|
"hakurei.app/container/check"
|
|
"hakurei.app/internal/pkg"
|
|
)
|
|
|
|
func TestHTTPGet(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const testdata = "\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69"
|
|
|
|
testdataChecksum := func() unique.Handle[pkg.Checksum] {
|
|
h := sha512.New384()
|
|
h.Write([]byte(testdata))
|
|
return unique.Make(pkg.Checksum(h.Sum(nil)))
|
|
}()
|
|
|
|
var transport http.Transport
|
|
client := http.Client{Transport: &transport}
|
|
transport.RegisterProtocol("file", http.NewFileTransportFS(fstest.MapFS{
|
|
"testdata": {Data: []byte(testdata), Mode: 0400},
|
|
}))
|
|
|
|
checkWithCache(t, []cacheTestCase{
|
|
{"direct", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
var r pkg.RContext
|
|
rCacheVal := reflect.ValueOf(&r).Elem().FieldByName("cache")
|
|
reflect.NewAt(
|
|
rCacheVal.Type(),
|
|
unsafe.Pointer(rCacheVal.UnsafeAddr()),
|
|
).Elem().Set(reflect.ValueOf(c))
|
|
|
|
f := pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///testdata",
|
|
testdataChecksum.Value(),
|
|
)
|
|
var got []byte
|
|
if rc, err := f.Cure(&r); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if got, err = io.ReadAll(rc); err != nil {
|
|
t.Fatalf("ReadAll: error = %v", err)
|
|
} else if string(got) != testdata {
|
|
t.Fatalf("Cure: %x, want %x", got, testdata)
|
|
} else if err = rc.Close(); err != nil {
|
|
t.Fatalf("Close: error = %v", err)
|
|
}
|
|
|
|
// check direct validation
|
|
f = pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///testdata",
|
|
pkg.Checksum{},
|
|
)
|
|
wantErrMismatch := &pkg.ChecksumMismatchError{
|
|
Got: testdataChecksum.Value(),
|
|
}
|
|
if rc, err := f.Cure(&r); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if got, err = io.ReadAll(rc); err != nil {
|
|
t.Fatalf("ReadAll: error = %v", err)
|
|
} else if string(got) != testdata {
|
|
t.Fatalf("Cure: %x, want %x", got, testdata)
|
|
} else if err = rc.Close(); !reflect.DeepEqual(err, wantErrMismatch) {
|
|
t.Fatalf("Close: error = %#v, want %#v", err, wantErrMismatch)
|
|
}
|
|
|
|
// check fallback validation
|
|
if rc, err := f.Cure(&r); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if err = rc.Close(); !reflect.DeepEqual(err, wantErrMismatch) {
|
|
t.Fatalf("Close: error = %#v, want %#v", err, wantErrMismatch)
|
|
}
|
|
|
|
// check direct response error
|
|
f = pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///nonexistent",
|
|
pkg.Checksum{},
|
|
)
|
|
wantErrNotFound := pkg.ResponseStatusError(http.StatusNotFound)
|
|
if _, err := f.Cure(&r); !reflect.DeepEqual(err, wantErrNotFound) {
|
|
t.Fatalf("Cure: error = %#v, want %#v", err, wantErrNotFound)
|
|
}
|
|
}, pkg.MustDecode("E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C")},
|
|
|
|
{"cure", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
var r pkg.RContext
|
|
rCacheVal := reflect.ValueOf(&r).Elem().FieldByName("cache")
|
|
reflect.NewAt(
|
|
rCacheVal.Type(),
|
|
unsafe.Pointer(rCacheVal.UnsafeAddr()),
|
|
).Elem().Set(reflect.ValueOf(c))
|
|
|
|
f := pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///testdata",
|
|
testdataChecksum.Value(),
|
|
)
|
|
wantPathname := base.Append(
|
|
"identifier",
|
|
"oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_",
|
|
)
|
|
if pathname, checksum, err := c.Cure(f); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if !pathname.Is(wantPathname) {
|
|
t.Fatalf("Cure: %q, want %q", pathname, wantPathname)
|
|
} else if checksum != testdataChecksum {
|
|
t.Fatalf("Cure: %x, want %x", checksum.Value(), testdataChecksum.Value())
|
|
}
|
|
|
|
var got []byte
|
|
if rc, err := f.Cure(&r); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if got, err = io.ReadAll(rc); err != nil {
|
|
t.Fatalf("ReadAll: error = %v", err)
|
|
} else if string(got) != testdata {
|
|
t.Fatalf("Cure: %x, want %x", got, testdata)
|
|
} else if err = rc.Close(); err != nil {
|
|
t.Fatalf("Close: error = %v", err)
|
|
}
|
|
|
|
// check load from cache
|
|
f = pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///testdata",
|
|
testdataChecksum.Value(),
|
|
)
|
|
if rc, err := f.Cure(&r); err != nil {
|
|
t.Fatalf("Cure: error = %v", err)
|
|
} else if got, err = io.ReadAll(rc); err != nil {
|
|
t.Fatalf("ReadAll: error = %v", err)
|
|
} else if string(got) != testdata {
|
|
t.Fatalf("Cure: %x, want %x", got, testdata)
|
|
} else if err = rc.Close(); err != nil {
|
|
t.Fatalf("Close: error = %v", err)
|
|
}
|
|
|
|
// check error passthrough
|
|
f = pkg.NewHTTPGet(
|
|
&client,
|
|
"file:///nonexistent",
|
|
pkg.Checksum{},
|
|
)
|
|
wantErrNotFound := pkg.ResponseStatusError(http.StatusNotFound)
|
|
if _, _, err := c.Cure(f); !reflect.DeepEqual(err, wantErrNotFound) {
|
|
t.Fatalf("Pathname: error = %#v, want %#v", err, wantErrNotFound)
|
|
}
|
|
}, pkg.MustDecode("L_0RFHpr9JUS4Zp14rz2dESSRvfLzpvqsLhR1-YjQt8hYlmEdVl7vI3_-v8UNPKs")},
|
|
})
|
|
}
|