| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- #!/usr/bin/env node
- 'use strict';
- const assert = require('assert/strict');
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- function writeEnv(filePath, values) {
- fs.writeFileSync(filePath, Object.entries(values).map(([key, value]) => `${key}=${value}`).join('\n') + '\n', 'utf8');
- }
- function envValue(filePath, key) {
- const content = fs.readFileSync(filePath, 'utf8');
- const match = content.match(new RegExp(`^${key}=(.*)$`, 'm'));
- return match ? match[1].trim() : undefined;
- }
- async function main() {
- const packageRoot = path.resolve(__dirname, '..');
- const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-credential-precedence-'));
- const previousCwd = process.cwd();
- const previousEnv = { ...process.env };
- let closeAgentWorkbenches = () => {};
- let otherCwd = '';
- try {
- process.env.HOME = fixtureRoot;
- process.env.USERPROFILE = fixtureRoot;
- process.env.QIWEI_PACKAGE_ROOT = fixtureRoot;
- process.env.QIWEI_WORKSPACE_ROOT = fixtureRoot;
- process.env.QIWEI_AUTH_TOKEN = 'startup-auth';
- process.env.QIWEI_UID = 'startup-uid';
- process.env.QIWEI_GUID = 'startup-guid';
- process.env.QIWEI_API_BASE = 'https://startup.example/api/qiwei';
- process.chdir(fixtureRoot);
- const envPath = path.join(fixtureRoot, '.env.local');
- writeEnv(envPath, {
- QIWEI_AUTH_TOKEN: 'file-auth-a',
- QIWEI_UID: 'file-uid-a',
- QIWEI_GUID: 'file-guid-a',
- QIWEI_API_BASE: 'https://file-a.example/api/qiwei',
- });
- const globalConfigDir = path.join(fixtureRoot, '.fmode');
- fs.mkdirSync(globalConfigDir, { recursive: true });
- fs.writeFileSync(path.join(globalConfigDir, 'config.json'), JSON.stringify({ sessionToken: 'global-auth' }), 'utf8');
- const credentials = require(path.join(packageRoot, 'mcp', 'src', 'core', 'credentials'));
- const { FmodeQiweiClient } = require(path.join(packageRoot, 'mcp', 'src', 'providers', 'fmode-agent-transport'));
- assert.equal(credentials.readQiweiAuthToken(), 'file-auth-a');
- assert.equal(credentials.readQiweiUid(), 'file-uid-a');
- assert.equal(credentials.readQiweiGuid({ uid: 'file-uid-a' }), 'file-guid-a');
- assert.equal(credentials.readQiweiApiBase(), 'https://file-a.example/api/qiwei');
- const dynamicClient = new FmodeQiweiClient({
- dynamicCredentials: true,
- authToken: 'cached-auth',
- uid: 'cached-uid',
- guid: 'cached-guid',
- apiBase: 'https://cached.example/api/qiwei',
- });
- assert.deepEqual(dynamicClient.context(), {
- token: 'file-auth-a',
- uid: 'file-uid-a',
- guid: 'file-guid-a',
- apiBase: 'https://file-a.example/api/qiwei',
- transportMode: 'fmode',
- upstreamToken: '',
- upstreamApiBase: 'https://manager.qiweapi.com/qiwe',
- });
- assert.equal(credentials.readQiweiAuthToken({ authToken: 'request-auth' }), 'request-auth');
- assert.equal(credentials.readQiweiUid({ uid: 'request-uid' }), 'request-uid');
- assert.equal(credentials.readQiweiGuid({ uid: 'request-uid', guid: 'request-guid' }), 'request-guid');
- assert.equal(credentials.readQiweiApiBase({ apiBase: 'https://request.example/api/qiwei' }), 'https://request.example/api/qiwei');
- writeEnv(envPath, {
- QIWEI_AUTH_TOKEN: 'file-auth-b',
- QIWEI_UID: 'file-uid-b',
- QIWEI_GUID: 'file-guid-b',
- QIWEI_API_BASE: 'https://file-b.example/api/qiwei',
- });
- assert.equal(credentials.readQiweiAuthToken(), 'file-auth-b');
- assert.equal(credentials.readQiweiUid(), 'file-uid-b');
- assert.equal(credentials.readQiweiGuid({ uid: 'file-uid-b' }), 'file-guid-b');
- assert.equal(credentials.readQiweiGuid({ uid: 'different-uid' }), '');
- assert.equal(credentials.readQiweiApiBase(), 'https://file-b.example/api/qiwei');
- assert.equal(dynamicClient.context().token, 'file-auth-b');
- assert.equal(dynamicClient.context().uid, 'file-uid-b');
- assert.equal(dynamicClient.context().guid, 'file-guid-b');
- const agentService = require(path.join(packageRoot, 'mcp', 'src', 'dashboard', 'agent-service'));
- closeAgentWorkbenches = agentService.closeAgentWorkbenches;
- const loadedAgentConfig = agentService.__testing.loadAgentConfig();
- assert.equal(loadedAgentConfig.qiwei.authToken, 'file-auth-b');
- assert.equal(loadedAgentConfig.qiwei.uid, 'file-uid-b');
- assert.equal(loadedAgentConfig.qiwei.guid, 'file-guid-b');
- assert.equal(loadedAgentConfig.qiwei.apiBase, 'https://file-b.example/api/qiwei');
- const globalCredentialPath = credentials.CREDENTIALS_FILE;
- credentials.saveQiweiClientConfig({
- uid: 'file-uid-b',
- guid: 'file-guid-b',
- apiBase: 'https://file-b.example/api/qiwei',
- envRoot: fixtureRoot,
- });
- // Persistence must follow the configured package root even when a caller
- // (for example an MCP client) has changed the process working directory.
- otherCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-credential-cwd-'));
- process.chdir(otherCwd);
- credentials.saveQiweiClientConfig({
- uid: 'file-uid-b',
- guid: 'file-guid-b',
- apiBase: 'https://file-b.example/api/qiwei',
- });
- assert.equal(envValue(envPath, 'QIWEI_GUID'), 'file-guid-b');
- assert.equal(fs.existsSync(path.join(otherCwd, '.env.local')), false);
- process.chdir(fixtureRoot);
- assert.equal(fs.existsSync(globalCredentialPath), false, 'standalone package must not write ~/.claude credentials');
- const cleared = credentials.clearQiweiClientConfig({ uid: 'file-uid-b', envRoot: fixtureRoot });
- assert.equal(cleared.cleared, true);
- assert.equal(envValue(envPath, 'QIWEI_UID'), '');
- assert.equal(envValue(envPath, 'QIWEI_GUID'), '');
- assert.equal(credentials.readQiweiUid(), '');
- assert.equal(credentials.readQiweiGuid(), '');
- writeEnv(envPath, {
- QIWEI_AUTH_TOKEN: '',
- QIWEI_UID: '',
- QIWEI_GUID: '',
- QIWEI_API_BASE: '',
- });
- delete process.env.QIWEI_AUTH_TOKEN;
- delete process.env.QIWE_AUTH_TOKEN;
- delete process.env.FMODE_API_KEY;
- delete process.env.FMODE_API_TOKEN;
- delete process.env.NEWAPI_TOKEN;
- delete process.env.ANTHROPIC_AUTH_TOKEN;
- assert.equal(credentials.readQiweiAuthToken(), '', 'standalone package must ignore ~/.fmode/config.json');
- process.stdout.write(`${JSON.stringify({
- status: 'ok',
- checks: 28,
- coverage: [
- 'request_values_override_package_file',
- 'package_file_overrides_startup_environment',
- 'updated_package_file_is_visible_without_restart',
- 'long_lived_client_reloads_package_credentials',
- 'workbench_scope_uses_package_file_credentials',
- 'uid_guid_are_kept_on_the_same_account',
- 'host_fmode_config_is_ignored',
- 'standalone_package_does_not_write_global_credentials',
- 'standalone_account_removal_clears_package_file',
- ],
- }, null, 2)}\n`);
- } finally {
- closeAgentWorkbenches();
- process.chdir(previousCwd);
- for (const key of Object.keys(process.env)) {
- if (!(key in previousEnv)) delete process.env[key];
- }
- for (const [key, value] of Object.entries(previousEnv)) process.env[key] = value;
- fs.rmSync(fixtureRoot, { recursive: true, force: true });
- if (otherCwd) fs.rmSync(otherCwd, { recursive: true, force: true });
- }
- }
- main().catch(error => {
- process.stderr.write(`${error.stack || error.message}\n`);
- process.exitCode = 1;
- });
|