blob: b404ccecfe857c935d6859000b0140ba41ccfa35 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import type {
RemoteRuntimeHostProfile,
RuntimeHostProfileCatalog,
RuntimeHostProfileDocument,
} from '@maka/runtime-host/client';
import { parseRuntimeHostCommand } from '../runtime-host-cli.js';
import { runRuntimeHostProfileCommand } from '../runtime-host-profile-command.js';
const ROOT_ID = 'a'.repeat(64);
describe('Runtime Host profile CLI', () => {
test('parses profile management without accepting credential material on argv', () => {
assert.deepEqual(parseRuntimeHostCommand(['profile', 'list']), {
kind: 'runtime-host-profile-list',
});
assert.deepEqual(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'office',
'--name',
'Office',
'--tls-url',
'wss://runtime.example.com',
'--expected-root',
ROOT_ID,
'--credential-env',
'OFFICE_HOST_TOKEN',
]),
{
kind: 'runtime-host-profile-set',
id: 'office',
name: 'Office',
transport: { kind: 'tls', url: 'wss://runtime.example.com' },
expectedRootId: ROOT_ID,
credentialEnv: 'OFFICE_HOST_TOKEN',
},
);
assert.deepEqual(parseRuntimeHostCommand(['profile', 'remove', '--id', 'office']), {
kind: 'runtime-host-profile-remove',
id: 'office',
});
assert.deepEqual(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'lab',
'--name',
'Lab',
'--plaintext-url',
'ws://192.0.2.10:7443/runtime-host',
'--acknowledge-plaintext',
'--expected-root',
ROOT_ID,
]),
{
kind: 'runtime-host-profile-set',
id: 'lab',
name: 'Lab',
transport: {
kind: 'plaintext',
url: 'ws://192.0.2.10:7443/runtime-host',
acknowledgement: 'plaintext-bearer-v1',
},
expectedRootId: ROOT_ID,
},
);
assert.equal(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'peer-lab',
'--name',
'Peer Lab',
'--peer-id',
'12D3KooWPeer',
'--peer-route',
'/ip4/192.0.2.10/udp/4001/quic-v1',
'--expected-root',
ROOT_ID,
]).kind,
'error',
);
assert.equal(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'lab',
'--name',
'Lab',
'--plaintext-url',
'ws://192.0.2.10:7443/runtime-host',
'--expected-root',
ROOT_ID,
]).kind,
'error',
);
assert.deepEqual(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'ssh-lab',
'--name',
'SSH Lab',
'--ssh-destination',
'operator@example.com',
'--ssh-port',
'2222',
'--ssh-remote-port',
'7443',
'--expected-root',
ROOT_ID,
]),
{
kind: 'runtime-host-profile-set',
id: 'ssh-lab',
name: 'SSH Lab',
transport: {
kind: 'ssh',
destination: 'operator@example.com',
sshPort: 2222,
remotePort: 7443,
websocketPath: '/runtime-host',
},
expectedRootId: ROOT_ID,
},
);
assert.equal(
parseRuntimeHostCommand(['profile', 'set', '--credential', 'secret']).kind,
'error',
);
assert.deepEqual(
parseRuntimeHostCommand([
'profile',
'set',
'--id',
'wsl',
'--name',
'Ubuntu',
'--wsl-distribution',
'Ubuntu',
'--operator-path',
'/home/operator/.local/share/maka/operator',
'--expected-root',
ROOT_ID,
]),
{
kind: 'runtime-host-profile-set-environment',
id: 'wsl',
name: 'Ubuntu',
distribution: 'Ubuntu',
operator: {
kind: 'legacy_posix_executable',
executablePath: '/home/operator/.local/share/maka/operator',
},
expectedRootId: ROOT_ID,
},
);
});
test('passes the credential to the catalog without writing it to command output', async () => {
const state = createProfileCatalogCapture();
const output: string[] = [];
assert.equal(
await runRuntimeHostProfileCommand(
{
kind: 'set',
id: 'office',
name: 'Office',
transport: { kind: 'tls', url: 'wss://runtime.example.com' },
expectedRootId: ROOT_ID,
credentialEnv: 'OFFICE_HOST_TOKEN',
},
{
catalog: state.catalog,
env: { OFFICE_HOST_TOKEN: 'opaque-token' },
write: (value) => output.push(value),
},
),
0,
);
assert.equal(state.saved[0]?.credential, 'opaque-token');
assert.equal(output.join('').includes('opaque-token'), false);
assert.equal(JSON.stringify(state.saved[0]?.profile).includes('opaque-token'), false);
output.length = 0;
await runRuntimeHostProfileCommand(
{ kind: 'list' },
{
catalog: state.catalog,
env: {},
write: (value) => output.push(value),
},
);
assert.deepEqual(
(JSON.parse(output.join('')) as Array<{ id: string }>).map((profile) => profile.id),
['local', 'office'],
);
});
});
function createProfileCatalogCapture(): {
document: RuntimeHostProfileDocument;
catalog: RuntimeHostProfileCatalog;
saved: Array<{ profile: RemoteRuntimeHostProfile; credential?: string }>;
} {
const state: { document: RuntimeHostProfileDocument } = {
document: { schemaVersion: 5, profiles: [] },
};
const saved: Array<{ profile: RemoteRuntimeHostProfile; credential?: string }> = [];
const catalog: RuntimeHostProfileCatalog = {
read: async () => state.document,
resolve: async () => assert.fail('unexpected profile resolution'),
create: async () => assert.fail('unexpected profile creation'),
save: async (profile: RemoteRuntimeHostProfile, credential?: string) => {
saved.push({ profile, credential });
state.document = {
schemaVersion: 5,
profiles: [
...state.document.profiles.filter((candidate) => candidate.id !== profile.id),
profile,
],
};
return state.document;
},
remove: async () => assert.fail('unexpected profile removal'),
removeIfCurrent: async () => assert.fail('unexpected conditional profile removal'),
rebindIfCurrent: async () => assert.fail('unexpected conditional profile rebind'),
updateRemoteProfileIfCurrent: async () => assert.fail('unexpected conditional update'),
mutateRemoteProfileIfCurrent: async () => assert.fail('unexpected conditional mutation'),
readRemoteProfileIfCurrent: async () => assert.fail('unexpected conditional read'),
};
return {
get document() {
return state.document;
},
catalog,
saved,
};
}