feat(backend): enforce user-owned sessions
This commit is contained in:
@@ -5,6 +5,7 @@ import { SessionBridge } from "../bridge/session-bridge.js";
|
||||
import type { ThtRunner } from "../tht/tht-runner.js";
|
||||
import { buildPiChildEnv, canonicalPiProvider } from "./provider-credentials.js";
|
||||
import { secretValue } from "../config/secret-bundle.js";
|
||||
import { principalEnvironment, type PrincipalContext } from "../auth/principal.js";
|
||||
|
||||
export interface SessionRuntime {
|
||||
rpc: RpcClient;
|
||||
@@ -19,6 +20,7 @@ export interface RuntimeOptions {
|
||||
author?: string;
|
||||
question?: string;
|
||||
mode?: "new" | "resume";
|
||||
principal?: PrincipalContext;
|
||||
}
|
||||
|
||||
/** Injectable child-process boundary; callbacks may ignore arguments in simpler tests. */
|
||||
@@ -31,21 +33,21 @@ type SpawnFn = (
|
||||
export class PiProcessManager {
|
||||
private runtimes = new Map<string, SessionRuntime>();
|
||||
private spawnFn: (
|
||||
sessionId: string, author: string, provider: string | undefined,
|
||||
sessionId: string, author: string, provider: string | undefined, principal?: PrincipalContext,
|
||||
) => ChildProcessWithoutNullStreams;
|
||||
|
||||
constructor(private cfg: AppConfig, opts?: { spawnFn?: SpawnFn }) {
|
||||
if (opts?.spawnFn) {
|
||||
this.spawnFn = (sessionId, author, provider) =>
|
||||
this.spawnPi(opts.spawnFn!, sessionId, author, provider);
|
||||
this.spawnFn = (sessionId, author, provider, principal) =>
|
||||
this.spawnPi(opts.spawnFn!, sessionId, author, provider, principal);
|
||||
} else {
|
||||
this.spawnFn = (sessionId, author, provider) =>
|
||||
this.spawnPi(nodeSpawn, sessionId, author, provider);
|
||||
this.spawnFn = (sessionId, author, provider, principal) =>
|
||||
this.spawnPi(nodeSpawn, sessionId, author, provider, principal);
|
||||
}
|
||||
}
|
||||
|
||||
private spawnPi(
|
||||
spawnFn: SpawnFn, sessionId: string, author: string, provider: string | undefined,
|
||||
spawnFn: SpawnFn, sessionId: string, author: string, provider: string | undefined, principal?: PrincipalContext,
|
||||
): ChildProcessWithoutNullStreams {
|
||||
const env = buildPiChildEnv({
|
||||
provider,
|
||||
@@ -53,6 +55,7 @@ export class PiProcessManager {
|
||||
credentialFile: this.cfg.modelApiKeyFile,
|
||||
additions: { THT_SESSION: sessionId, THT_AUTHOR: author },
|
||||
});
|
||||
if (principal) Object.assign(env, principalEnvironment(principal));
|
||||
// The Thoth gate executes the deterministic `tht` CLI as a Pi tool. Give only
|
||||
// this managed session process the adapter values already loaded by the core
|
||||
// entrypoint; the generic provider helper continues to scrub them by default.
|
||||
@@ -95,7 +98,7 @@ export class PiProcessManager {
|
||||
}
|
||||
const author = o.author ?? "dev@local";
|
||||
const provider = canonicalPiProvider(o.provider ?? this.cfg.defaults.provider);
|
||||
const child = this.spawnFn(sessionId, author, provider);
|
||||
const child = this.spawnFn(sessionId, author, provider, o.principal);
|
||||
let rt: SessionRuntime | undefined;
|
||||
try {
|
||||
const rpc = new RpcClient(child);
|
||||
|
||||
Reference in New Issue
Block a user