Merge pull request 'Land IAM U4 role policy authority across the composition' (#619) from feature/iam-u4-role-authority into main
ci / svc-realcombo (push) Successful in 2m30s
ci / test (push) Successful in 7m23s
ci / test-pg (push) Successful in 8m24s

This commit was merged in pull request #619.
This commit is contained in:
2026-10-18 15:51:48 +00:00
9 changed files with 1692 additions and 5 deletions
+3
View File
@@ -45,6 +45,7 @@ jobs:
"modules/ui": "Agent-System-UI", "modules/ui": "Agent-System-UI",
"modules/documents": "Agent-System-Documents", "modules/documents": "Agent-System-Documents",
"deps/agent-system-core": "Agent-System-Core", "deps/agent-system-core": "Agent-System-Core",
"deps/agent-document-renderer": "Agent-Document-Renderer",
"deps/development-guidelines": "Development-Guidelines", "deps/development-guidelines": "Development-Guidelines",
"deps/agent-native": "Agent-Native", "deps/agent-native": "Agent-Native",
"deps/agent-squad": "Agent-Squad", "deps/agent-squad": "Agent-Squad",
@@ -228,6 +229,7 @@ jobs:
"modules/ui": "Agent-System-UI", "modules/ui": "Agent-System-UI",
"modules/documents": "Agent-System-Documents", "modules/documents": "Agent-System-Documents",
"deps/agent-system-core": "Agent-System-Core", "deps/agent-system-core": "Agent-System-Core",
"deps/agent-document-renderer": "Agent-Document-Renderer",
"deps/development-guidelines": "Development-Guidelines", "deps/development-guidelines": "Development-Guidelines",
"deps/agent-native": "Agent-Native", "deps/agent-native": "Agent-Native",
"deps/agent-squad": "Agent-Squad", "deps/agent-squad": "Agent-Squad",
@@ -524,6 +526,7 @@ jobs:
"modules/ui": "Agent-System-UI", "modules/ui": "Agent-System-UI",
"modules/documents": "Agent-System-Documents", "modules/documents": "Agent-System-Documents",
"deps/agent-system-core": "Agent-System-Core", "deps/agent-system-core": "Agent-System-Core",
"deps/agent-document-renderer": "Agent-Document-Renderer",
"deps/development-guidelines": "Development-Guidelines", "deps/development-guidelines": "Development-Guidelines",
"deps/agent-native": "Agent-Native", "deps/agent-native": "Agent-Native",
"deps/agent-squad": "Agent-Squad", "deps/agent-squad": "Agent-Squad",
+3
View File
@@ -37,3 +37,6 @@
[submodule "deps/development-manager"] [submodule "deps/development-manager"]
path = deps/development-manager path = deps/development-manager
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Manager.git url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Manager.git
[submodule "deps/agent-document-renderer"]
path = deps/agent-document-renderer
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Document-Renderer.git
File diff suppressed because one or more lines are too long
+10 -1
View File
@@ -1,4 +1,5 @@
[ [
"backend/app backend/authz",
"backend/app backend/blobstore", "backend/app backend/blobstore",
"backend/app backend/bus", "backend/app backend/bus",
"backend/app backend/cardsvc", "backend/app backend/cardsvc",
@@ -14,6 +15,7 @@
"backend/app backend/pgbus", "backend/app backend/pgbus",
"backend/app backend/plugins", "backend/app backend/plugins",
"backend/app backend/profiles", "backend/app backend/profiles",
"backend/app backend/projectcontext",
"backend/app backend/projectscope", "backend/app backend/projectscope",
"backend/app backend/prompts", "backend/app backend/prompts",
"backend/app backend/rag", "backend/app backend/rag",
@@ -28,6 +30,7 @@
"backend/app backend/surfacesvc", "backend/app backend/surfacesvc",
"backend/app backend/tools", "backend/app backend/tools",
"backend/app backend/workflow", "backend/app backend/workflow",
"backend/authz backend/store",
"backend/cardsvc backend/store", "backend/cardsvc backend/store",
"backend/ctxasm backend/vision", "backend/ctxasm backend/vision",
"backend/hostapi backend/store", "backend/hostapi backend/store",
@@ -48,9 +51,11 @@
"backend/route backend/intentgate", "backend/route backend/intentgate",
"backend/runmgr backend/bus", "backend/runmgr backend/bus",
"backend/runmgr backend/cardsvc", "backend/runmgr backend/cardsvc",
"backend/runmgr backend/docgen",
"backend/runmgr backend/ingest", "backend/runmgr backend/ingest",
"backend/runmgr backend/intentgate", "backend/runmgr backend/intentgate",
"backend/runmgr backend/profiles", "backend/runmgr backend/profiles",
"backend/runmgr backend/projectcontext",
"backend/runmgr backend/route", "backend/runmgr backend/route",
"backend/runmgr backend/runtime", "backend/runmgr backend/runtime",
"backend/runmgr backend/settings", "backend/runmgr backend/settings",
@@ -58,13 +63,14 @@
"backend/runmgr backend/tools", "backend/runmgr backend/tools",
"backend/runmgr backend/workflow", "backend/runmgr backend/workflow",
"backend/runtime backend/ctxasm", "backend/runtime backend/ctxasm",
"backend/runtime backend/docgen", "backend/runtime backend/projectcontext",
"backend/runtime backend/prompts", "backend/runtime backend/prompts",
"backend/runtime backend/quality", "backend/runtime backend/quality",
"backend/runtime backend/squadadapter", "backend/runtime backend/squadadapter",
"backend/runtime backend/wfcompile", "backend/runtime backend/wfcompile",
"backend/runtime backend/vision", "backend/runtime backend/vision",
"backend/runtime backend/workflow", "backend/runtime backend/workflow",
"backend/server backend/authz",
"backend/server backend/cardsvc", "backend/server backend/cardsvc",
"backend/server backend/cmdbus", "backend/server backend/cmdbus",
"backend/server backend/execenv", "backend/server backend/execenv",
@@ -84,10 +90,13 @@
"backend/server backend/workflow", "backend/server backend/workflow",
"backend/settings backend/store", "backend/settings backend/store",
"backend/squadadapter backend/quality", "backend/squadadapter backend/quality",
"backend/store backend/authz",
"backend/store backend/blobstore", "backend/store backend/blobstore",
"backend/surfacesvc backend/store", "backend/surfacesvc backend/store",
"backend/tools backend/docgen",
"backend/tools backend/execenv", "backend/tools backend/execenv",
"backend/tools backend/quality", "backend/tools backend/quality",
"backend/wfcompile backend/projectcontext",
"backend/wfcompile backend/tools", "backend/wfcompile backend/tools",
"backend/wfcompile backend/workflow", "backend/wfcompile backend/workflow",
"frontend/app frontend/components", "frontend/app frontend/components",
@@ -41,6 +41,7 @@ import (
const ( const (
aliceOwner = "mi_alice" aliceOwner = "mi_alice"
alicePass = "mi-alice-pass-1" alicePass = "mi-alice-pass-1"
rootPass = "mi-root-pass-1"
httpWait = 15 * time.Second httpWait = 15 * time.Second
) )
@@ -455,7 +456,7 @@ func (e *env) killNine(t *testing.T, inst *instance) {
func (e *env) loginAlice(t *testing.T) *userClient { func (e *env) loginAlice(t *testing.T) *userClient {
t.Helper() t.Helper()
// 空库先引导首个管理员(本地 pending 创建要求库内已有用户),再建 alice。 // 空库先引导首个管理员(本地 pending 创建要求库内已有用户),再建 alice。
// 两步都签发一次性凭据,独占落临时 JSON 后即弃。 // 两步都签发一次性凭据,独占落临时 JSON;mi-root 的凭据随后用于初始化其账号。
rootCred := filepath.Join(t.TempDir(), "root-cred.json") rootCred := filepath.Join(t.TempDir(), "root-cred.json")
e.cliIn(t, e.a.dataDir, "user", "bootstrap-admin", "--dsn", e.dbDSN, "--owner", "mi-root", "--out-file", rootCred) e.cliIn(t, e.a.dataDir, "user", "bootstrap-admin", "--dsn", e.dbDSN, "--owner", "mi-root", "--out-file", rootCred)
activation := filepath.Join(t.TempDir(), "activation.json") activation := filepath.Join(t.TempDir(), "activation.json")
@@ -475,6 +476,8 @@ func (e *env) loginAlice(t *testing.T) *userClient {
}, nil) }, nil)
apiKey := e.cliOut(t, "apikey", "create", "--dsn", e.dbDSN, "--owner", aliceOwner, "--name", "mi-acceptance") apiKey := e.cliOut(t, "apikey", "create", "--dsn", e.dbDSN, "--owner", aliceOwner, "--name", "mi-acceptance")
// IAM U4 把建项目改为系统动作 project.create:由引导管理员经真实 API 授予 alice。
e.grantAliceProjectCreate(t, rootCred)
uc := &userClient{ uc := &userClient{
api: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}}, api: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}},
apiB: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}}, apiB: &http.Client{Timeout: httpWait, Transport: bearerRT{key: apiKey}},
@@ -486,6 +489,68 @@ func (e *env) loginAlice(t *testing.T) *userClient {
return uc return uc
} }
// grantAliceProjectCreate 以 mi-root 身份经 admin API 为 alice 追加系统授权
// project.create(保留其已有授权;PUT 为整体替换,按 authorityEpoch 乐观并发)。
// bootstrap-admin 只签发一次性凭据,mi-root 未初始化前不能发 API key,故先照
// alice 的方式 redeem 并设 rootPass。
func (e *env) grantAliceProjectCreate(t *testing.T, rootCred string) {
t.Helper()
raw, err := os.ReadFile(rootCred)
if err != nil {
t.Fatal(err)
}
rootSecret := strings.TrimSpace(string(raw))
if rootSecret == "" {
t.Fatal("bootstrap-admin credential file is empty")
}
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatal(err)
}
sess := &http.Client{Timeout: httpWait, Jar: jar}
e.do(t, sess, "POST", "/api/auth/login-key/redeem", map[string]any{
"key": rootSecret,
}, nil)
e.do(t, sess, "POST", "/api/auth/password", map[string]any{
"next": rootPass,
}, nil)
rootKey := e.cliOut(t, "apikey", "create", "--dsn", e.dbDSN, "--owner", "mi-root", "--name", "mi-acceptance-root")
root := &http.Client{Timeout: httpWait, Transport: bearerRT{key: rootKey}}
var users []struct {
UserID string `json:"userId"`
Owner string `json:"owner"`
}
e.do(t, root, "GET", "/api/admin/users", nil, &users)
userID := ""
for _, u := range users {
if u.Owner == aliceOwner {
userID = u.UserID
}
}
if userID == "" {
t.Fatalf("user %s not found in /api/admin/users", aliceOwner)
}
var grants struct {
Actions []string `json:"actions"`
AuthorityEpoch int64 `json:"authorityEpoch"`
}
e.do(t, root, "GET", "/api/admin/users/"+userID+"/system-grants", nil, &grants)
actions := grants.Actions
has := false
for _, a := range actions {
has = has || a == "project.create"
}
if !has {
actions = append(actions, "project.create")
}
e.do(t, root, "PUT", "/api/admin/users/"+userID+"/system-grants", map[string]any{
"expectedAuthorityEpoch": grants.AuthorityEpoch,
"idempotencyKey": "mi-alice-project-create",
"actions": actions,
}, nil)
}
// bearerRT 为所有请求附加 Authorization: Bearer <key>。 // bearerRT 为所有请求附加 Authorization: Bearer <key>。
type bearerRT struct{ key string } type bearerRT struct{ key string }