Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions pkg/attestation/crafter/materials/oci_image_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2025 The Chainloop Authors.
// Copyright 2025-2026 The Chainloop Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -74,7 +74,6 @@ func TestOCIImageCraft_Layout(t *testing.T) {
testCases := []struct {
name string
layoutPath string
wantErr string
wantDigest string
wantName string
wantTag string
Expand All @@ -97,11 +96,6 @@ func TestOCIImageCraft_Layout(t *testing.T) {
wantName: "oci-layout:v1.51.0",
wantDigest: "sha256:a5303ef28a4bd9b6e06aa92c07831dd151ac64172695971226bdba4a11fc1b88",
},
{
name: "non-existent path",
layoutPath: "/non/existent/path",
wantErr: "UNAUTHORIZED",
},
}

for _, tc := range testCases {
Expand All @@ -115,11 +109,6 @@ func TestOCIImageCraft_Layout(t *testing.T) {
require.NoError(t, err)

got, err := craftedMaterial(crafter.Craft(context.TODO(), tc.layoutPath))
if tc.wantErr != "" {
assert.ErrorContains(t, err, tc.wantErr)
return
}

require.NoError(t, err)
assert.Equal(t, contractAPI.CraftingSchema_Material_CONTAINER_IMAGE.String(), got.MaterialType.String())

Expand All @@ -139,6 +128,33 @@ func TestOCIImageCraft_Layout(t *testing.T) {
}
}

// TestOCIImageCraft_UnresolvableRemoteReference covers the path where the input
// is neither an OCI layout directory nor a pullable image, so Craft resolves it
// as a remote reference. It runs against an in-memory registry on loopback
// instead of Docker Hub, so the failure is deterministic and needs no external
// network.
func TestOCIImageCraft_UnresolvableRemoteReference(t *testing.T) {
server := httptest.NewServer(registry.New(registry.Logger(log.New(io.Discard, "", 0))))
defer server.Close()

u, err := url.Parse(server.URL)
require.NoError(t, err)

schema := &contractAPI.CraftingSchema_Material{
Name: "test",
Type: contractAPI.CraftingSchema_Material_CONTAINER_IMAGE,
}
l := zerolog.Nop()
crafter, err := materials.NewOCIImageCrafter(schema, authn.DefaultKeychain, &l)
require.NoError(t, err)

// The repository was never pushed, so the registry answers with a not-found
// error instead of serving a manifest.
_, err = craftedMaterial(crafter.Craft(context.TODO(), fmt.Sprintf("%s/does-not-exist:latest", u.Host)))
require.Error(t, err)
assert.ErrorContains(t, err, "NAME_UNKNOWN")
}

func TestOCIImageCraft_LayoutWithDigestSelector(t *testing.T) {
testCases := []struct {
name string
Expand Down
27 changes: 27 additions & 0 deletions pkg/policies/engine/rego/httpsend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,33 @@ violations contains resp.error.message if {
assert.NotContains(t, result.Violations[0].Violation, "is not allowed")
}

// TestRego_AllowedHostIsReachable proves that a host on the allow-list is
// actually reached by http.send, using a loopback httptest server instead of a
// live external host. PublicTargetsOnly is not set, so netguard does not block
// the loopback target (see evalContext).
func TestRego_AllowedHostIsReachable(t *testing.T) {
var hits int
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
hits++
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

serverURL, err := url.Parse(srv.URL)
require.NoError(t, err)

policy := &engine.Policy{
Name: "allowed-host",
Source: fmt.Appendf(nil, httpSendPolicyTemplate, fmt.Sprintf(`{"method": "GET", "url": %q}`, srv.URL)),
}

// OPA matches the allowed host without its port.
r := NewEngine(engine.WithAllowedHostnames(serverURL.Hostname()))
_, err = r.Verify(context.TODO(), policy, []byte(`{}`), nil)
require.NoError(t, err)
assert.Equal(t, 1, hits)
}

func TestRego_HTTPSendPublicTargetsOnly(t *testing.T) {
// httptest listens on the loopback interface, so it stands in for any
// destination that is not publicly routable.
Expand Down
49 changes: 12 additions & 37 deletions pkg/policies/engine/rego/rego_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,44 +325,19 @@ func TestRego_WithRestrictiveMode(t *testing.T) {
assert.Error(t, err)
assert.Contains(t, err.Error(), "eval_builtin_error: http.send: disallowed host: github.com")
})
}

t.Run("allowed network requests from defaults", func(t *testing.T) {
regoContent, err := os.ReadFile("testfiles/restricted_mode_networking_allowed_host.rego")
require.NoError(t, err)

r := NewEngine()
policy := &engine.Policy{
Name: "policy",
Source: regoContent,
}

_, err = r.Verify(context.TODO(), policy, []byte(`{}`), nil)
assert.NoError(t, err)
})

t.Run("allowed network requests from defaults plus custom domains", func(t *testing.T) {
defaultHosts, err := os.ReadFile("testfiles/restricted_mode_networking_allowed_host.rego")
require.NoError(t, err)
customHosts, err := os.ReadFile("testfiles/restrictive_mode_networking.rego")
require.NoError(t, err)

r := NewEngine(engine.WithAllowedHostnames("github.com"))
policy := &engine.Policy{
Name: "policy",
Source: defaultHosts,
}

_, err = r.Verify(context.TODO(), policy, []byte(`{}`), nil)
assert.NoError(t, err)

policy = &engine.Policy{
Name: "policy",
Source: customHosts,
}

_, err = r.Verify(context.TODO(), policy, []byte(`{}`), nil)
assert.NoError(t, err)
})
// TestRego_AllowedHostnames asserts the host allow-list membership without any
// network: that the defaults are present and that WithAllowedHostnames appends
// to them rather than replacing them. Whether an allowed host is actually
// reachable is covered hermetically by TestRego_AllowedHostIsReachable.
func TestRego_AllowedHostnames(t *testing.T) {
base := NewEngine().Capabilities().AllowNet
assert.Contains(t, base, "www.chainloop.dev")
assert.Contains(t, base, "www.cisa.gov")

withCustom := NewEngine(engine.WithAllowedHostnames("github.com")).Capabilities().AllowNet
assert.Subset(t, withCustom, []string{"www.chainloop.dev", "www.cisa.gov", "github.com"})
}

func TestRego_WithPermissiveMode(t *testing.T) {
Expand Down

This file was deleted.

Loading