orchard/pkg/resource/v1/host_dir_policy_test.go

176 lines
5.2 KiB
Go

package v1_test
import (
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
"github.com/stretchr/testify/require"
"testing"
)
func TestNewHostDirPolicyFromString(t *testing.T) {
policy, err := v1.NewHostDirPolicyFromString("/Users/ci/src:ro")
require.NoError(t, err)
require.EqualValues(t, v1.HostDirPolicy{
PathPrefix: "/Users/ci/src",
ReadOnly: true,
}, policy)
_, err = v1.NewHostDirPolicyFromString("/Users/ci/src:ro:something")
require.Error(t, err)
_, err = v1.NewHostDirPolicyFromString("/Users/ci/src:rw")
require.Error(t, err)
}
func TestHostDirPolicyValidate(t *testing.T) {
policy := &v1.HostDirPolicy{PathPrefix: "/Users/ci/src"}
// Valid uses
require.True(t, policy.Validate("/Users/ci/src", true))
require.True(t, policy.Validate("/Users/ci/src/", true))
require.True(t, policy.Validate("/Users/ci/src/website", true))
// Invalid uses
require.False(t, policy.Validate("/Users/ci/", true))
require.False(t, policy.Validate("/Users", true))
require.False(t, policy.Validate("/tmp", true))
require.False(t, policy.Validate("/", true))
// No path traversal, even within the path prefix
require.False(t, policy.Validate("/Users/ci/src/website/../../../../../../etc/passwd", true))
require.False(t, policy.Validate("/Users/ci/src/website/..", true))
require.False(t, policy.Validate("/Users/ci/src/..", true))
require.False(t, policy.Validate("/Users/ci/..", true))
require.False(t, policy.Validate("/Users/..", true))
require.False(t, policy.Validate("/..", true))
}
func TestHostDirPolicyValidatePathBoundary(t *testing.T) {
const (
localPathPrefix = "/src/"
githubURLPrefix = "https://github.com"
)
testCases := []struct {
name string
pathPrefix string
path string
allowed bool
}{
{
name: "local policy allows its exact path",
pathPrefix: localPathPrefix,
path: "/src",
allowed: true,
},
{
name: "local policy allows descendants",
pathPrefix: localPathPrefix,
path: "/src/project",
allowed: true,
},
{
name: "local policy without trailing slash rejects sibling sharing its prefix",
pathPrefix: "/src",
path: "/src-private",
allowed: false,
},
{
name: "local policy rejects sibling sharing its prefix",
pathPrefix: localPathPrefix,
path: "/src-private",
allowed: false,
},
{
name: "local root policy allows descendants",
pathPrefix: "/",
path: "/src/project",
allowed: true,
},
{
name: "local root policy rejects remote URLs",
pathPrefix: "/",
path: "https://github.com/archive.tar.gz",
allowed: false,
},
{
name: "URL policy allows its exact host",
pathPrefix: githubURLPrefix + "/",
path: githubURLPrefix,
allowed: true,
},
{
name: "URL policy allows paths on its host",
pathPrefix: githubURLPrefix,
path: "https://github.com/actions/archive.tar.gz",
allowed: true,
},
{
name: "URL policy rejects lookalike host",
pathPrefix: githubURLPrefix,
path: "https://github.com.attacker.com/archive.tar.gz",
allowed: false,
},
{
name: "URL policy with trailing slash rejects lookalike host",
pathPrefix: githubURLPrefix + "/",
path: "https://github.com.attacker.com/archive.tar.gz",
allowed: false,
},
{
name: "URL policy rejects host concealed by userinfo",
pathPrefix: githubURLPrefix,
path: "https://github.com@attacker.example/archive.tar.gz",
allowed: false,
},
{
name: "URL path policy allows descendants",
pathPrefix: "https://github.com/actions",
path: "https://github.com/actions/runner/archive.tar.gz",
allowed: true,
},
{
name: "URL path policy rejects sibling sharing its prefix",
pathPrefix: "https://github.com/actions",
path: "https://github.com/actions-private/archive.tar.gz",
allowed: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
policy := v1.HostDirPolicy{PathPrefix: testCase.pathPrefix, ReadOnly: false}
require.Equal(t, testCase.allowed, policy.Validate(testCase.path, false))
})
}
}
func TestHostDirPolicyValidateReadOnly(t *testing.T) {
policy := &v1.HostDirPolicy{PathPrefix: "/Users/ci/src", ReadOnly: true}
const desiredPath = "/Users/ci/src/website"
// Only read-only is allowed
require.True(t, policy.Validate(desiredPath, true))
require.False(t, policy.Validate(desiredPath, false))
}
func TestHostDirPolicyString(t *testing.T) {
policyRw := &v1.HostDirPolicy{PathPrefix: "/Users/ci/src"}
require.EqualValues(t, "/Users/ci/src", policyRw.String())
policyRo := &v1.HostDirPolicy{PathPrefix: "/Users/ci/src", ReadOnly: true}
require.EqualValues(t, "/Users/ci/src:ro", policyRo.String())
}
func TestHTTPHostDirPolicyString(t *testing.T) {
policy, err := v1.NewHostDirPolicyFromString("https://github.com/actions/runner/releases/download")
require.NoError(t, err)
require.EqualValues(t, v1.HostDirPolicy{
PathPrefix: "https://github.com/actions/runner/releases/download",
ReadOnly: false,
}, policy)
//nolint: lll
require.True(t, policy.Validate("https://github.com/actions/runner/releases/download/v2.309.0/actions-runner-osx-arm64-2.309.0.tar.gz", false))
}