mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
feat(memory): resolve gateway profile principals
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
recheckMemoryIdentityBinding,
|
||||
recheckMemoryIdentityBindingRecipient,
|
||||
resolveMemoryIdentityBindingFromAdmission,
|
||||
resolveMemoryPrincipalForUserProfile,
|
||||
} from "./memory-identity.js";
|
||||
import {
|
||||
closeOpenClawStateDatabaseForTest,
|
||||
@@ -162,6 +163,31 @@ describe("memory identity binding", () => {
|
||||
).toEqual({ kind: "unbound" });
|
||||
});
|
||||
|
||||
it("resolves only the active memory principal for the current Gateway profile head", () => {
|
||||
const { env, profileId } = fixture();
|
||||
expect(
|
||||
resolveMemoryPrincipalForUserProfile({ userProfileId: profileId, options: { env } }),
|
||||
).toBeUndefined();
|
||||
|
||||
const binding = adminLinkAdmittedMemoryIdentity({
|
||||
admission: admitted("telegram", "default", "sender-profile-principal"),
|
||||
authenticatedOperatorProfileId: profileId,
|
||||
authenticatedOperatorScopes: ["operator.admin"],
|
||||
options: { env },
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveMemoryPrincipalForUserProfile({ userProfileId: profileId, options: { env } }),
|
||||
).toEqual({
|
||||
principalId: binding.principalId,
|
||||
kind: "user",
|
||||
revision: expect.any(String),
|
||||
});
|
||||
expect(
|
||||
resolveMemoryPrincipalForUserProfile({ userProfileId: "unknown-profile", options: { env } }),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("fails closed when a damaged shared database contains conflicting active bindings", () => {
|
||||
const { env, profileId } = fixture();
|
||||
const binding = adminLinkAdmittedMemoryIdentity({
|
||||
|
||||
@@ -266,6 +266,36 @@ export function recheckMemoryOperationalPrincipal(params: {
|
||||
return row ? toPrincipal(row) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the Gateway-authenticated profile to its active memory principal.
|
||||
* Control-plane callers must derive this here instead of accepting a principal
|
||||
* identifier from RPC or CLI input.
|
||||
*/
|
||||
export function resolveMemoryPrincipalForUserProfile(params: {
|
||||
userProfileId: string;
|
||||
options?: OpenClawStateDatabaseOptions;
|
||||
}): MemoryPrincipal | undefined {
|
||||
const options = params.options ?? {};
|
||||
const userProfileId = resolveUserProfileId(
|
||||
requireText(params.userProfileId, "userProfileId"),
|
||||
options,
|
||||
);
|
||||
if (!userProfileId) {
|
||||
return undefined;
|
||||
}
|
||||
ensureMemoryIdentitySchema(options);
|
||||
const row = openOpenClawStateDatabase(options)
|
||||
.db.prepare(
|
||||
`SELECT principal_id, principal_kind, revision
|
||||
FROM memory_principals
|
||||
WHERE user_profile_id = ? AND principal_kind = 'user' AND state = 'active'`,
|
||||
)
|
||||
.get(userProfileId) as
|
||||
| { principal_id: string; principal_kind: string; revision: string }
|
||||
| undefined;
|
||||
return row ? toPrincipal(row) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The only binding writer. Pairing admission supplies a one-use opaque proof;
|
||||
* a separately authenticated Gateway profile supplies the operator identity.
|
||||
|
||||
Reference in New Issue
Block a user