Files
xinmi/internal/application/service/knowledgebase_version_access_test.go
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

110 lines
4.8 KiB
Go

package service
import (
"context"
"testing"
"github.com/Tencent/WeKnora/internal/accesspolicy"
"github.com/Tencent/WeKnora/internal/knowledgeversion"
"github.com/Tencent/WeKnora/internal/types"
"github.com/Tencent/WeKnora/internal/types/interfaces"
"github.com/stretchr/testify/require"
)
type versionAccessKBRepository struct {
interfaces.KnowledgeBaseRepository
bases map[string]*types.KnowledgeBase
}
func (r versionAccessKBRepository) GetKnowledgeBaseByID(_ context.Context, id string) (*types.KnowledgeBase, error) {
return r.bases[id], nil
}
func (r versionAccessKBRepository) GetKnowledgeBaseByIDs(_ context.Context, ids []string) ([]*types.KnowledgeBase, error) {
result := make([]*types.KnowledgeBase, 0, len(ids))
for _, id := range ids {
result = append(result, r.bases[id])
}
return result, nil
}
func TestKnowledgeBaseVersionStateAccessIsolation(t *testing.T) {
owner := context.WithValue(context.Background(), types.TenantIDContextKey, uint64(7))
owner = context.WithValue(owner, types.UserIDContextKey, "owner")
owner = context.WithValue(owner, types.TenantRoleContextKey, types.TenantRoleContributor)
owner = accesspolicy.WithSnapshot(owner, &accesspolicy.Snapshot{Restricted: true, Permissions: map[string]bool{"knowledge.read": true}})
for _, state := range []string{"copying", "snapshot"} {
for _, actor := range []struct {
name string
ctx context.Context
allowed bool
}{
{"owner", owner, false},
{"workspace_admin", context.WithValue(owner, types.TenantRoleContextKey, types.TenantRoleAdmin), false},
{"system_admin", context.WithValue(owner, types.SystemAdminContextKey, true), false},
{"cross_workspace", context.WithValue(owner, types.TenantIDContextKey, uint64(8)), false},
{"worker", knowledgeversion.WithWorker(owner), true},
} {
t.Run(state+"/"+actor.name, func(t *testing.T) {
staging := &types.KnowledgeBase{ID: "staging", TenantID: 7, CreatorID: "owner", VersionState: state}
ready := &types.KnowledgeBase{ID: "ready", TenantID: 7, CreatorID: "owner"}
svc := &knowledgeBaseService{repo: versionAccessKBRepository{bases: map[string]*types.KnowledgeBase{staging.ID: staging, ready.ID: ready}}}
require.Equal(t, actor.allowed, knowledgeBaseReadable(actor.ctx, staging))
require.True(t, knowledgeBaseReadable(actor.ctx, ready))
for _, get := range []func(context.Context, string) (*types.KnowledgeBase, error){svc.GetKnowledgeBaseByID, svc.GetKnowledgeBaseByIDOnly} {
kb, err := get(actor.ctx, staging.ID)
if actor.allowed {
require.NoError(t, err)
require.Equal(t, staging.ID, kb.ID)
} else {
require.ErrorContains(t, err, "没有此知识库")
require.Nil(t, kb)
}
}
listed, err := svc.GetKnowledgeBasesByIDsOnly(actor.ctx, []string{staging.ID, ready.ID})
require.NoError(t, err)
if actor.allowed {
require.Len(t, listed, 2)
} else {
require.Len(t, listed, 1)
require.Equal(t, ready.ID, listed[0].ID)
}
})
}
}
}
func TestKnowledgeBaseRequiresExplicitSharing(t *testing.T) {
base := context.WithValue(context.Background(), types.TenantIDContextKey, uint64(7))
base = context.WithValue(base, types.UserIDContextKey, "other-user")
base = context.WithValue(base, types.TenantRoleContextKey, types.TenantRoleContributor)
kb := &types.KnowledgeBase{ID: "private-kb", TenantID: 7, CreatorID: "owner"}
for _, tt := range []struct {
name string
owner string
role types.TenantRole
snapshot *accesspolicy.Snapshot
allowed bool
}{
{"unmanaged_private", "other-user", types.TenantRoleContributor, &accesspolicy.Snapshot{}, false},
{"owner", "owner", types.TenantRoleContributor, &accesspolicy.Snapshot{}, true},
{"workspace_admin", "admin", types.TenantRoleAdmin, &accesspolicy.Snapshot{}, true},
{"published", "other-user", types.TenantRoleContributor, &accesspolicy.Snapshot{Publications: map[string]bool{"knowledge:private-kb": true}}, true},
{"granted", "other-user", types.TenantRoleContributor, &accesspolicy.Snapshot{Grants: map[string]bool{"knowledge:private-kb": true}}, true},
{"revoked", "other-user", types.TenantRoleContributor, &accesspolicy.Snapshot{Publications: map[string]bool{"knowledge:private-kb": false}}, false},
{"module_denied", "owner", types.TenantRoleContributor, &accesspolicy.Snapshot{Restricted: true}, false},
{"background", "other-user", types.TenantRoleContributor, nil, true},
} {
t.Run(tt.name, func(t *testing.T) {
ctx := context.WithValue(base, types.UserIDContextKey, tt.owner)
ctx = context.WithValue(ctx, types.TenantRoleContextKey, tt.role)
if tt.snapshot != nil {
ctx = accesspolicy.WithSnapshot(ctx, tt.snapshot)
}
require.Equal(t, tt.allowed, knowledgeBaseReadable(ctx, kb))
listed := filterReadableKnowledgeBases(ctx, []*types.KnowledgeBase{kb})
require.Equal(t, tt.allowed, len(listed) == 1)
})
}
}