Files
Agent-System-Backend/internal/app/resource_authz_v2_test.go
T
weichen f1302ed5b3 Enable canonical versioned Go module consumption
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
2026-10-13 15:47:16 +00:00

74 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package app
// EXT-8b 资源级授权槽位测试(U9 首切片):
// 1. V2 未注册 → AuthorizeResource 回落 V1(owner×project 兼容现行);
// 2. V2 注册 → 按查询六要素咨询;受信字段缺失(actor/action/type/id 空)=拒绝;
// 3. V2 返回 error = 拒绝(fail-closed);
// 4. 首注册者生效(后来者忽略);
// 5. compiledRegistry 的 V2 注册被拒(声明式无宿主回调)。
import (
"errors"
"testing"
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/pkg/extension"
)
func TestAuthorizeResourceV2FallbackAndQuery(t *testing.T) {
var a projectAuthz
// 未注册任何适配器 → 拒绝。
if ok, err := a.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u1", Action: "download", ResourceType: "artifact", ResourceID: "a1",
Owner: "u2", ProjectID: "p1"}); ok || err != nil {
t.Fatalf("未注册应拒绝, got %v %v", ok, err)
}
// 仅 V1:回落 owner×project 布尔。
a.set("p1", func(owner string, projectID string) (bool, error) { return true, nil })
if ok, _ := a.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u1", Action: "download", ResourceType: "artifact", ResourceID: "a1",
Owner: "u2", ProjectID: "p1"}); !ok {
t.Fatal("V1 允许时回落应放行")
}
// V1 路径要求 owner/project 非空。
if ok, _ := a.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u1", Action: "download", ResourceType: "artifact", ResourceID: "a1"}); ok {
t.Fatal("V1 回落在无项目私域应拒绝")
}
// 注册 V2 → 按六要素咨询。
a.setV2("p1", func(q extension.ResourceAuthzQuery) (bool, error) {
return q.Actor == "u1" && q.Action == "download" && q.ResourceType == "artifact" &&
q.ResourceID == "a1" && q.Owner == "u2" && q.ProjectID == "p1", nil
})
if ok, _ := a.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u1", Action: "download", ResourceType: "artifact", ResourceID: "a1",
Owner: "u2", ProjectID: "p1"}); !ok {
t.Fatal("V2 六要素齐备应放行")
}
// 六要素缺一(action 空)=拒绝(不可判定)。
if ok, _ := a.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u1", ResourceType: "artifact", ResourceID: "a1", Owner: "u2", ProjectID: "p1"}); ok {
t.Fatal("受信字段缺失应拒绝")
}
// V2 出错=拒绝(fail-closed)。
a2 := projectAuthz{}
a2.setV2("p1", func(extension.ResourceAuthzQuery) (bool, error) { return false, errors.New("boom") })
if ok, err := a2.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u", Action: "read", ResourceType: "x", ResourceID: "1"}); ok || err == nil {
t.Fatal("V2 error 应拒绝")
}
// 首注册者生效。
a3 := projectAuthz{}
a3.setV2("first", func(extension.ResourceAuthzQuery) (bool, error) { return true, nil })
a3.setV2("second", func(extension.ResourceAuthzQuery) (bool, error) { return false, nil })
if ok, _ := a3.AuthorizeResource(extension.ResourceAuthzQuery{
Actor: "u", Action: "read", ResourceType: "x", ResourceID: "1"}); !ok {
t.Fatal("首个 V2 注册者应生效")
}
}
func TestCompiledRegistryRejectsV2(t *testing.T) {
r := compiledRegistry{}
if err := r.RegisterResourceAuthorizerV2(func(extension.ResourceAuthzQuery) (bool, error) { return true, nil }); err == nil {
t.Fatal("声明式扩展不得注册资源级授权回调(fail-closed)")
}
}