Files
seaweedFS/weed/iam/integration/role_store_test.go
Chris Lu 1261e93ef2 fix: comprehensive go vet error fixes and add CI enforcement (#7861)
* fix: use keyed fields in struct literals

- Replace unsafe reflect.StringHeader/SliceHeader with safe unsafe.String/Slice (weed/query/sqltypes/unsafe.go)
- Add field names to Type_ScalarType struct literals (weed/mq/schema/schema_builder.go)
- Add Duration field name to FlexibleDuration struct literals across test files
- Add field names to bson.D struct literals (weed/filer/mongodb/mongodb_store_kv.go)

Fixes go vet warnings about unkeyed struct literals.

* fix: remove unreachable code

- Remove unreachable return statements after infinite for loops
- Remove unreachable code after if/else blocks where all paths return
- Simplify recursive logic by removing unnecessary for loop (inode_to_path.go)
- Fix Type_ScalarType literal to use enum value directly (schema_builder.go)
- Call onCompletionFn on stream error (subscribe_session.go)

Files fixed:
- weed/query/sqltypes/unsafe.go
- weed/mq/schema/schema_builder.go
- weed/mq/client/sub_client/connect_to_sub_coordinator.go
- weed/filer/redis3/ItemList.go
- weed/mq/client/agent_client/subscribe_session.go
- weed/mq/broker/broker_grpc_pub_balancer.go
- weed/mount/inode_to_path.go
- weed/util/skiplist/name_list.go

* fix: avoid copying lock values in protobuf messages

- Use proto.Merge() instead of direct assignment to avoid copying sync.Mutex in S3ApiConfiguration (iamapi_server.go)
- Add explicit comments noting that channel-received values are already copies before taking addresses (volume_grpc_client_to_master.go)

The protobuf messages contain sync.Mutex fields from the message state, which should not be copied.
Using proto.Merge() properly merges messages without copying the embedded mutex.

* fix: correct byte array size for uint32 bit shift operations

The generateAccountId() function only needs 4 bytes to create a uint32 value.
Changed from allocating 8 bytes to 4 bytes to match the actual usage.

This fixes go vet warning about shifting 8-bit values (bytes) by more than 8 bits.

* fix: ensure context cancellation on all error paths

In broker_client_subscribe.go, ensure subscriberCancel() is called on all error return paths:
- When stream creation fails
- When partition assignment fails
- When sending initialization message fails

This prevents context leaks when an error occurs during subscriber creation.

* fix: ensure subscriberCancel called for CreateFreshSubscriber stream.Send error

Ensure subscriberCancel() is called when stream.Send fails in CreateFreshSubscriber.

* ci: add go vet step to prevent future lint regressions

- Add go vet step to GitHub Actions workflow
- Filter known protobuf lock warnings (MessageState sync.Mutex)
  These are expected in generated protobuf code and are safe
- Prevents accumulation of go vet errors in future PRs
- Step runs before build to catch issues early

* fix: resolve remaining syntax and logic errors in vet fixes

- Fixed syntax errors in filer_sync.go caused by missing closing braces
- Added missing closing brace for if block and function
- Synchronized fixes to match previous commits on branch

* fix: add missing return statements to daemon functions

- Add 'return false' after infinite loops in filer_backup.go and filer_meta_backup.go
- Satisfies declared bool return type signatures
- Maintains consistency with other daemon functions (runMaster, runFilerSynchronize, runWorker)
- While unreachable, explicitly declares the return satisfies function signature contract

* fix: add nil check for onCompletionFn in SubscribeMessageRecord

- Check if onCompletionFn is not nil before calling it
- Prevents potential panic if nil function is passed
- Matches pattern used in other callback functions

* docs: clarify unreachable return statements in daemon functions

- Add comments documenting that return statements satisfy function signature
- Explains that these returns follow infinite loops and are unreachable
- Improves code clarity for future maintainers
2025-12-23 14:48:50 -08:00

128 lines
3.7 KiB
Go

package integration
import (
"context"
"testing"
"time"
"github.com/seaweedfs/seaweedfs/weed/iam/policy"
"github.com/seaweedfs/seaweedfs/weed/iam/sts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMemoryRoleStore(t *testing.T) {
ctx := context.Background()
store := NewMemoryRoleStore()
// Test storing a role
roleDef := &RoleDefinition{
RoleName: "TestRole",
RoleArn: "arn:aws:iam::role/TestRole",
Description: "Test role for unit testing",
AttachedPolicies: []string{"TestPolicy"},
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Action: []string{"sts:AssumeRoleWithWebIdentity"},
Principal: map[string]interface{}{
"Federated": "test-provider",
},
},
},
},
}
err := store.StoreRole(ctx, "", "TestRole", roleDef)
require.NoError(t, err)
// Test retrieving the role
retrievedRole, err := store.GetRole(ctx, "", "TestRole")
require.NoError(t, err)
assert.Equal(t, "TestRole", retrievedRole.RoleName)
assert.Equal(t, "arn:aws:iam::role/TestRole", retrievedRole.RoleArn)
assert.Equal(t, "Test role for unit testing", retrievedRole.Description)
assert.Equal(t, []string{"TestPolicy"}, retrievedRole.AttachedPolicies)
// Test listing roles
roles, err := store.ListRoles(ctx, "")
require.NoError(t, err)
assert.Contains(t, roles, "TestRole")
// Test deleting the role
err = store.DeleteRole(ctx, "", "TestRole")
require.NoError(t, err)
// Verify role is deleted
_, err = store.GetRole(ctx, "", "TestRole")
assert.Error(t, err)
}
func TestRoleStoreConfiguration(t *testing.T) {
// Test memory role store creation
memoryStore, err := NewMemoryRoleStore(), error(nil)
require.NoError(t, err)
assert.NotNil(t, memoryStore)
// Test filer role store creation without filerAddress in config
filerStore2, err := NewFilerRoleStore(map[string]interface{}{
// filerAddress not required in config
"basePath": "/test/roles",
}, nil)
assert.NoError(t, err)
assert.NotNil(t, filerStore2)
// Test filer role store creation with valid config
filerStore, err := NewFilerRoleStore(map[string]interface{}{
"filerAddress": "localhost:8888",
"basePath": "/test/roles",
}, nil)
require.NoError(t, err)
assert.NotNil(t, filerStore)
}
func TestDistributedIAMManagerWithRoleStore(t *testing.T) {
ctx := context.Background()
// Create IAM manager with role store configuration
config := &IAMConfig{
STS: &sts.STSConfig{
TokenDuration: sts.FlexibleDuration{Duration: time.Duration(3600) * time.Second},
MaxSessionLength: sts.FlexibleDuration{Duration: time.Duration(43200) * time.Second},
Issuer: "test-issuer",
SigningKey: []byte("test-signing-key-32-characters-long"),
},
Policy: &policy.PolicyEngineConfig{
DefaultEffect: "Deny",
StoreType: "memory",
},
Roles: &RoleStoreConfig{
StoreType: "memory",
},
}
iamManager := NewIAMManager()
err := iamManager.Initialize(config, func() string {
return "localhost:8888" // Mock filer address for testing
})
require.NoError(t, err)
// Test creating a role
roleDef := &RoleDefinition{
RoleName: "DistributedTestRole",
RoleArn: "arn:aws:iam::role/DistributedTestRole",
Description: "Test role for distributed IAM",
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
}
err = iamManager.CreateRole(ctx, "", "DistributedTestRole", roleDef)
require.NoError(t, err)
// Test that role is accessible through the IAM manager
// Note: We can't directly test GetRole as it's not exposed,
// but we can test through IsActionAllowed which internally uses the role store
assert.True(t, iamManager.initialized)
}