find tea by absolute path, not by name
PM2 hands the sidecar a login-less PATH that excludes ~/.local/bin, which is exactly where the platform installs a release binary. So `tea whoami` failed with "the token may be wrong, or tea is not installed" on a machine where tea was sitting in the owner's home and working perfectly from a shell. Third time today the same trap: the probe in os-deps, then the agent's env, now this. Anything the platform installs to ~/.local/bin has to be found deliberately, because nothing the platform spawns inherits a PATH that includes it. Resolved per call rather than cached, so an install that adds it mid-run is picked up instead of a cached "missing" outliving the thing that fixed it.
This commit is contained in:
+16
-2
@@ -35,6 +35,20 @@ export type TeaLogin = { name: string; url: string; user: string | null; hasToke
|
|||||||
/** The owner IS this process, so no escalation — and no sudo prompt on a machine that has no sudo. */
|
/** The owner IS this process, so no escalation — and no sudo prompt on a machine that has no sudo. */
|
||||||
const isOwnerUser = (osUser: string | null): boolean => !osUser || osUser === process.env.USER;
|
const isOwnerUser = (osUser: string | null): boolean => !osUser || osUser === process.env.USER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `tea`, by absolute path.
|
||||||
|
*
|
||||||
|
* NOT by bare name. PM2 hands this sidecar a login-less PATH that does not include `~/.local/bin`, which
|
||||||
|
* is precisely where the platform installs a release binary — so `tea whoami` failed with "not
|
||||||
|
* installed" on a machine where `tea` was sitting in the owner's home and working perfectly from a
|
||||||
|
* shell. The same trap caught the agent's PATH an hour earlier.
|
||||||
|
*
|
||||||
|
* Resolved once per call rather than cached: an install can add it while this process is running, and a
|
||||||
|
* cached "missing" would outlive the thing that fixed it.
|
||||||
|
*/
|
||||||
|
const teaBinary = (): string =>
|
||||||
|
Bun.which('tea', { PATH: `${join(homedir(), '.local', 'bin')}:${process.env.PATH ?? ''}` }) ?? 'tea';
|
||||||
|
|
||||||
const configPathFor = (home: string): string => join(home, '.config', 'tea', 'config.yml');
|
const configPathFor = (home: string): string => join(home, '.config', 'tea', 'config.yml');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,7 +134,7 @@ export async function writeTeaLogin(
|
|||||||
token: string,
|
token: string,
|
||||||
): Promise<{ ok: boolean; error?: string }> {
|
): Promise<{ ok: boolean; error?: string }> {
|
||||||
const osUser = await osUserFor(userId);
|
const osUser = await osUserFor(userId);
|
||||||
const command = ['tea', 'login', 'add', '--name', LOGIN_NAME, '--url', instanceUrl, '--token', token];
|
const command = [teaBinary(), 'login', 'add', '--name', LOGIN_NAME, '--url', instanceUrl, '--token', token];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const proc = isOwnerUser(osUser)
|
const proc = isOwnerUser(osUser)
|
||||||
@@ -154,7 +168,7 @@ export async function writeTeaLogin(
|
|||||||
*/
|
*/
|
||||||
export async function testTeaLogin(userId: number): Promise<{ ok: boolean; user?: string; error?: string }> {
|
export async function testTeaLogin(userId: number): Promise<{ ok: boolean; user?: string; error?: string }> {
|
||||||
const osUser = await osUserFor(userId);
|
const osUser = await osUserFor(userId);
|
||||||
const out = await asUser(osUser, ['tea', 'whoami']);
|
const out = await asUser(osUser, [teaBinary(), 'whoami']);
|
||||||
if (out === null) {
|
if (out === null) {
|
||||||
return { ok: false, error: 'tea could not authenticate — the token may be wrong, or tea is not installed' };
|
return { ok: false, error: 'tea could not authenticate — the token may be wrong, or tea is not installed' };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user