Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements. Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate. Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable. Refs: Versioned dependencies U1/U3; feature/dependency-workspace
90 lines
3.1 KiB
Go
90 lines
3.1 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
|
|
core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git"
|
|
)
|
|
|
|
// 协作存储 U3 切片 2(KTD13):动作授权矩阵。未配置的动作默认拒绝;
|
|
// 旧只读 EXT-8 适配器只保留 read 能力;action-aware 适配器注册后权威。
|
|
|
|
func newMatrixServer(t *testing.T) *Server {
|
|
t.Helper()
|
|
s := &Server{}
|
|
t.Cleanup(func() {})
|
|
return s
|
|
}
|
|
|
|
// 无任何适配器:全部动作拒绝(默认拒绝;与 EXT-8 未注册时读取 NotFound 同基调)。
|
|
func TestActionMatrixDefaultDeny(t *testing.T) {
|
|
s := newMatrixServer(t)
|
|
for _, a := range []ProjectAction{ProjectRead, ProjectEdit, ProjectApprove, ProjectExecute, ProjectAdmin} {
|
|
if s.authorizeProjectAction("alice", "p1", a) {
|
|
t.Fatalf("未注册适配器时 %s 应默认拒绝", a)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 旧只读适配器:read 放行、其余动作不得自动获得写入能力(KTD13 兼容语义)。
|
|
func TestActionMatrixLegacyAdapterReadOnly(t *testing.T) {
|
|
s := newMatrixServer(t)
|
|
s.SetProjectAuthorizer(func(owner string, projectID core.ID) (bool, error) {
|
|
return owner == "alice", nil
|
|
})
|
|
if !s.authorizeProjectAction("alice", "p1", ProjectRead) {
|
|
t.Fatal("alice read 应放行(旧适配器)")
|
|
}
|
|
for _, a := range []ProjectAction{ProjectEdit, ProjectApprove, ProjectExecute, ProjectAdmin} {
|
|
if s.authorizeProjectAction("alice", "p1", a) {
|
|
t.Fatalf("旧只读适配器不得自动获得 %s 能力", a)
|
|
}
|
|
}
|
|
// 他人(动作越权):read 同样拒绝。
|
|
if s.authorizeProjectAction("bob", "p1", ProjectRead) {
|
|
t.Fatal("bob 越权 read 应拒绝")
|
|
}
|
|
}
|
|
|
|
// action-aware 适配器:注册后权威(read 与显式配置的动作放行,未配置动作
|
|
// 默认拒绝;出错 fail-closed)。
|
|
func TestActionMatrixActionAwareAuthoritative(t *testing.T) {
|
|
s := newMatrixServer(t)
|
|
// 同时注册旧适配器:action-aware 存在时不得回落旧适配器(权威唯一)。
|
|
s.SetProjectAuthorizer(func(owner string, projectID core.ID) (bool, error) {
|
|
return true, nil
|
|
})
|
|
s.SetProjectActionAuthorizer(func(owner string, projectID core.ID, action ProjectAction) (bool, error) {
|
|
switch action {
|
|
case ProjectRead, ProjectEdit:
|
|
return owner == "alice", nil
|
|
default:
|
|
return false, nil // approve/execute/admin 未授予
|
|
}
|
|
})
|
|
if !s.authorizeProjectAction("alice", "p1", ProjectRead) || !s.authorizeProjectAction("alice", "p1", ProjectEdit) {
|
|
t.Fatal("alice read/edit 应放行")
|
|
}
|
|
for _, a := range []ProjectAction{ProjectApprove, ProjectExecute, ProjectAdmin} {
|
|
if s.authorizeProjectAction("alice", "p1", a) {
|
|
t.Fatalf("未授予的 %s 应默认拒绝", a)
|
|
}
|
|
}
|
|
if s.authorizeProjectAction("bob", "p1", ProjectEdit) {
|
|
t.Fatal("bob 越权 edit 应拒绝")
|
|
}
|
|
// 适配器出错:fail-closed(错误不区分,避免泄露存在性)。
|
|
s.SetProjectActionAuthorizer(func(owner string, projectID core.ID, action ProjectAction) (bool, error) {
|
|
return false, errBoom
|
|
})
|
|
if s.authorizeProjectAction("alice", "p1", ProjectRead) {
|
|
t.Fatal("适配器出错应 fail-closed")
|
|
}
|
|
}
|
|
|
|
var errBoom = &boomErr{}
|
|
|
|
type boomErr struct{}
|
|
|
|
func (*boomErr) Error() string { return "boom" }
|