Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile sansshell on windows. #233

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# We checksum this data in tests so we need the content to be
# identical across operating systems.
services/localfile/server/testdata/sum.data text eol=lf
37 changes: 28 additions & 9 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ on:
- v*
pull_request:
schedule:
- cron: '7 3 * * *'
- cron: "7 3 * * *"
jobs:
pre-commit:
name: Pre commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: 'go.mod'
- uses: actions/setup-python@v3
- uses: pre-commit/[email protected]
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: "go.mod"
- uses: actions/setup-python@v3
- uses: pre-commit/[email protected]
test:
name: Unit tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: 'go.mod'
go-version-file: "go.mod"
- name: Install tools
run: |
sudo apt-get update
Expand All @@ -37,4 +37,23 @@ jobs:
- name: integration tests
run: ./testing/integrate.sh
shell: bash

test-macos:
name: Test on macos
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: "go.mod"
- name: unit tests
run: go test ./...
test-windows:
name: Test on windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: "go.mod"
- name: unit tests
run: go test ./...
31 changes: 8 additions & 23 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ package sansshell.authz
default allow = false

allow {
input.type = "LocalFile.ReadActionRequest"
input.message.file.filename = "/etc/hosts"
}
allow {
input.type = "LocalFile.ReadActionRequest"
input.message.file.filename = "/no-such-filename-for-sansshell-unittest"
input.type = "LocalFile.ReadActionRequest"
input.message.file.filename in [
"/etc/hosts",
"/no-such-filename-for-sansshell-unittest",
"C:\\Windows\\win.ini",
"C:\\no-such-filename-for-sansshell-unittest",
]
}
`
)
Expand Down Expand Up @@ -138,23 +139,7 @@ func TestRead(t *testing.T) {
testutil.FatalOnErr("Failed to dial bufnet", err, t)
t.Cleanup(func() { conn.Close() })

for _, tc := range []struct {
filename string
err string
}{
{
filename: "/etc/hosts",
err: "",
},
{
filename: "/no-such-filename-for-sansshell-unittest",
err: "no such file or directory",
},
{
filename: "/permission-denied-filename-for-sansshell-unittest",
err: "PermissionDenied",
},
} {
for _, tc := range readFileTestCases {
tc := tc
t.Run(tc.filename, func(t *testing.T) {
client := lfpb.NewLocalFileClient(conn)
Expand Down
21 changes: 21 additions & 0 deletions server/server_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build unix

package server

var readFileTestCases = []struct {
filename string
err string
}{
{
filename: "/etc/hosts",
err: "",
},
{
filename: "/no-such-filename-for-sansshell-unittest",
err: "no such file or directory",
},
{
filename: "/permission-denied-filename-for-sansshell-unittest",
err: "PermissionDenied",
},
}
21 changes: 21 additions & 0 deletions server/server_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build windows

package server

var readFileTestCases = []struct {
filename string
err string
}{
{
filename: "C:\\Windows\\win.ini",
err: "",
},
{
filename: "C:\\no-such-filename-for-sansshell-unittest",
err: "The system cannot find the file specified",
},
{
filename: "/permission-denied-filename-for-sansshell-unittest",
err: "PermissionDenied",
},
}
2 changes: 2 additions & 0 deletions services/fdb/server/conf_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build unix

/* Copyright (c) 2019 Snowflake Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the
Expand Down
2 changes: 2 additions & 0 deletions services/fdb/server/fdbcli_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build unix

/* Copyright (c) 2019 Snowflake Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the
Expand Down
2 changes: 2 additions & 0 deletions services/fdb/server/server_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build unix

/* Copyright (c) 2019 Snowflake Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the
Expand Down
24 changes: 13 additions & 11 deletions services/localfile/server/localfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"os"
"os/user"
"path/filepath"
"runtime"
"strconv"
"time"

Expand All @@ -43,8 +44,6 @@ import (
"github.com/Snowflake-Labs/sansshell/services/util"
"github.com/Snowflake-Labs/sansshell/telemetry/metrics"

"golang.org/x/sys/unix"

"github.com/go-logr/logr"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
Expand All @@ -57,7 +56,7 @@ var (
AbsolutePathError = status.Error(codes.InvalidArgument, "filename path must be absolute and clean")

// For testing since otherwise tests have to run as root for these.
chown = unix.Chown
chown = os.Chown
changeImmutableOS = changeImmutable

// ReadTimeout is how long tail should wait on a given poll call
Expand Down Expand Up @@ -95,7 +94,7 @@ var (

// This encompasses the permission plus the setuid/gid/sticky bits one
// can set on a file/directory.
const modeMask = uint32(fs.ModePerm | fs.ModeSticky | fs.ModeSetuid | fs.ModeSetgid)
const modeMask = fs.ModePerm | fs.ModeSticky | fs.ModeSetuid | fs.ModeSetgid

// server is used to implement the gRPC server
type server struct{}
Expand Down Expand Up @@ -320,6 +319,9 @@ func setupOutput(a *pb.FileAttributes) (*os.File, *immutableState, error) {
// to accidentally leave this in another otherwise default state.
// Except we don't trigger immutable now or we won't be able to write to it.
immutable, err := validateAndSetAttrs(f.Name(), a.Attributes, false)
if err != nil {
f.Close()
}
return f, immutable, err
}

Expand Down Expand Up @@ -577,7 +579,7 @@ type immutableState struct {
func validateAndSetAttrs(filename string, attrs []*pb.FileAttribute, doImmutable bool) (*immutableState, error) {
uid, gid := int(-1), int(-1)
setMode, setImmutable, immutable := false, false, false
mode := uint32(0)
mode := fs.FileMode(0)

for _, attr := range attrs {
switch a := attr.Value.(type) {
Expand Down Expand Up @@ -621,7 +623,7 @@ func validateAndSetAttrs(filename string, attrs []*pb.FileAttribute, doImmutable
if setMode {
return nil, status.Error(codes.InvalidArgument, "cannot set mode more than once")
}
mode = a.Mode
mode = fs.FileMode(a.Mode)
setMode = true
case *pb.FileAttribute_Immutable:
if setImmutable {
Expand All @@ -632,14 +634,14 @@ func validateAndSetAttrs(filename string, attrs []*pb.FileAttribute, doImmutable
}
}

if uid != -1 || gid != -1 {
if (uid != -1 || gid != -1) && runtime.GOOS != "windows" {
if err := chown(filename, uid, gid); err != nil {
return nil, status.Errorf(codes.Internal, "error from chown: %v", err)
}
}

if setMode {
if err := unix.Chmod(filename, mode&modeMask); err != nil {
if err := os.Chmod(filename, mode&modeMask); err != nil {
return nil, status.Errorf(codes.Internal, "error from chmod: %v", err)
}
}
Expand Down Expand Up @@ -687,7 +689,7 @@ func (s *server) Rm(ctx context.Context, req *pb.RmRequest) (*emptypb.Empty, err
recorder.CounterOrLog(ctx, localfileRmFailureCounter, 1, attribute.String("reason", "invalid_path"))
return nil, err
}
err := unix.Unlink(req.Filename)
err := osAgnosticRm(req.Filename)
if err != nil {
recorder.CounterOrLog(ctx, localfileRmFailureCounter, 1, attribute.String("reason", "unlink_err"))
return nil, status.Errorf(codes.Internal, "unlink error: %v", err)
Expand All @@ -703,7 +705,7 @@ func (s *server) Rmdir(ctx context.Context, req *pb.RmdirRequest) (*emptypb.Empt
recorder.CounterOrLog(ctx, localfileRmDirFailureCounter, 1, attribute.String("reason", "invalid_path"))
return nil, err
}
err := unix.Rmdir(req.Directory)
err := osAgnosticRmdir(req.Directory)
if err != nil {
recorder.CounterOrLog(ctx, localfileRmDirFailureCounter, 1, attribute.String("reason", "rmdir_err"))
return nil, status.Errorf(codes.Internal, "rmdir error: %v", err)
Expand All @@ -723,7 +725,7 @@ func (s *server) Rename(ctx context.Context, req *pb.RenameRequest) (*emptypb.Em
recorder.CounterOrLog(ctx, localfileRenameFailureCounter, 1, attribute.String("reason", "invalid_dst_path"))
return nil, err
}
err := unix.Rename(req.OriginalName, req.DestinationName)
err := os.Rename(req.OriginalName, req.DestinationName)
if err != nil {
recorder.CounterOrLog(ctx, localfileRenameFailureCounter, 1, attribute.String("reason", "rename_err"))
return nil, status.Errorf(codes.Internal, "rename error: %v", err)
Expand Down
14 changes: 8 additions & 6 deletions services/localfile/server/localfile_default.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build !(linux || darwin)
// +build !linux,!darwin
//go:build !(linux || darwin || windows)
// +build !linux,!darwin,!windows

/* Copyright (c) 2019 Snowflake Inc. All rights reserved.

Expand Down Expand Up @@ -32,9 +32,11 @@ import (
pb "github.com/Snowflake-Labs/sansshell/services/localfile"
)

// osStat is the platform agnostic version which uses basic os.Stat.
var osStat = defaultOsStat

// defaultOsStat is the platform agnostic version which uses basic os.Stat.
// As a result immutable bits cannot be returned.
func osStat(path string, useLstat bool) (*pb.StatReply, error) {
func defaultOsStat(path string, useLstat bool) (*pb.StatReply, error) {
var stat fs.FileInfo
var err error
if useLstat {
Expand Down Expand Up @@ -83,14 +85,14 @@ func dataPrep(f *os.File) (interface{}, func(), error) {
// stream and then return no matter what (assuming the file was already
// at EOF).
func dataReady(_ interface{}, stream pb.LocalFile_ReadServer) error {
// We sleep for READ_TIMEOUT_SEC between calls as there's no good
// We sleep for ReadTimeout between calls as there's no good
// way to poll on a file. Once it reaches EOF it's always readable
// (you just get EOF). We have to poll like this so we can check
// the context state and return if it's canclled.
if stream.Context().Err() != nil {
return stream.Context().Err()
}
time.Sleep(READ_TIMEOUT_SEC * time.Second)
time.Sleep(ReadTimeout * time.Second)
// Time to try again.
return nil
}
Loading