Skip to content

Commit

Permalink
feat: agoric deploy --allow-unsafe-plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Sep 16, 2020
1 parent 94e7016 commit d2a545e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 55 deletions.
74 changes: 73 additions & 1 deletion packages/agoric-cli/lib/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { E, makeCapTP } from '@agoric/captp';
import { makePromiseKit } from '@agoric/promise-kit';
import bundleSource from '@agoric/bundle-source';
import path from 'path';
import inquirer from 'inquirer';

import { getAccessToken } from './open';

Expand All @@ -20,10 +21,29 @@ import { getAccessToken } from './open';

const RETRY_DELAY_MS = 1000;

const PATH_SEP_RE = new RegExp(`${path.sep}`, 'g');

export default async function deployMain(progname, rawArgs, powers, opts) {
const { anylogger, makeWebSocket } = powers;
const { anylogger, fs, makeWebSocket } = powers;
const console = anylogger('agoric:deploy');

const allowUnsafePlugins = opts.allowUnsafePlugins;
if (allowUnsafePlugins) {
const { yesReally } = await inquirer.prompt([
{
name: 'yesReally',
message: `Enable unsafe (unconfined) plugins for this deployment? Type 'yes' if you are sure:`,
default: 'no',
},
]);
if (yesReally !== 'yes') {
console.error(
`Aborting (if you wish to continue unsafely, you must type 'yes' exactly)!`,
);
process.exit(1);
}
}

const args = rawArgs.slice(1);
const provide = opts.provide
.split(',')
Expand Down Expand Up @@ -134,12 +154,63 @@ export default async function deployMain(progname, rawArgs, powers, opts) {
// Take a new copy, since the chain objects have been added to bootstrap.
bootP = getBootstrap();

const pluginManager = await E.G(E.G(bootP).local).plugin.catch(_ => {});
const pluginDir = await E(pluginManager)
.getPluginDir()
.catch(_ => {});

if (allowUnsafePlugins && !pluginDir) {
throw Error(
`Installing unsafe plugins disabled; no pluginDir detected`,
);
}

for (const arg of args) {
const moduleFile = path.resolve(process.cwd(), arg);
const pathResolve = (...resArgs) =>
path.resolve(path.dirname(moduleFile), ...resArgs);
console.warn('running', moduleFile);

let installUnsafePlugin;
if (!allowUnsafePlugins) {
installUnsafePlugin = async plugin => {
throw Error(
`Installing unsafe plugin ${JSON.stringify(
pathResolve(plugin),
)} disabled; maybe you meant '--allow-unsafe-plugins'?`,
);
};
} else {
installUnsafePlugin = async plugin => {
try {
const absPath = pathResolve(plugin);
const pluginName = absPath.replace(PATH_SEP_RE, '_');
const pluginFile = path.resolve(pluginDir, pluginName);

// Just create a little redirector for that path.
console.warn(
`Installing unsafe plugin ${JSON.stringify(absPath)}`,
);
const content = `\
// ${pluginFile}
// AUTOMATICALLY GENERATED BY ${JSON.stringify(
[progname, ...rawArgs].join(' '),
)}
export { bootPlugin } from ${JSON.stringify(absPath)};
`;
await fs.writeFile(pluginFile, content);

// Return the bootstrap object for this plugin.
console.info(`Loading plugin ${JSON.stringify(pluginFile)}`);
return E.G(E(pluginManager).load(pluginName)).bootstrap;
} catch (e) {
throw Error(
`Cannot install unsafe plugin: ${(e && e.stack) || e}`,
);
}
};
}

// use a dynamic import to load the deploy script, it is unconfined
// eslint-disable-next-line import/no-dynamic-require,global-require
const mainNS = require(pathResolve(moduleFile));
Expand All @@ -152,6 +223,7 @@ export default async function deployMain(progname, rawArgs, powers, opts) {
await main(bootP, {
bundleSource: file => bundleSource(pathResolve(file)),
pathResolve,
installUnsafePlugin,
});
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/agoric-cli/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ const main = async (progname, rawArgs, powers) => {
program
.command('deploy [script...]')
.description('run a deployment script against the local Agoric VM')
.option(
'--allow-unsafe-plugins',
'CAREFUL: allow the deploy script full control over the Agoric VM',
false,
)
.option(
'--hostport <host:port>',
'host and port to connect to VM',
Expand Down
56 changes: 6 additions & 50 deletions packages/agoric-cli/lib/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const HOST_PORT = process.env.HOST_PORT || PORT;
const CHAIN_PORT = process.env.CHAIN_PORT || 26657;

export default async function startMain(progname, rawArgs, powers, opts) {
const { anylogger, fs, spawn, os, process } = powers;
const { anylogger, fs, spawn, process } = powers;
const log = anylogger('agoric:start');

const pspawnEnv = { ...process.env };
Expand Down Expand Up @@ -109,11 +109,9 @@ export default async function startMain(progname, rawArgs, powers, opts) {
};

let agSolo;
let agSetupSolo;
let agServer;
if (opts.sdk) {
agSolo = path.resolve(__dirname, '../../cosmic-swingset/bin/ag-solo');
agSetupSolo = path.resolve(__dirname, '../../cosmic-swingset/setup-solo');
} else {
agSolo = `${process.cwd()}/node_modules/@agoric/cosmic-swingset/bin/ag-solo`;
}
Expand Down Expand Up @@ -512,55 +510,13 @@ export default async function startMain(progname, rawArgs, powers, opts) {
return setupRun();
}

async function startTestnetSdk(profileName, startArgs) {
const virtEnv = path.resolve(
`_agstate/agoric-servers/ve3-${os.platform()}-${os.arch()}`,
);
if (!(await exists(`${virtEnv}/bin/pip`))) {
const exitStatus = await pspawn('python3', ['-mvenv', virtEnv], {
cwd: agSetupSolo,
});
if (exitStatus) {
return exitStatus;
}
}

const pipRun = (...bonusArgs) =>
pspawn(`${virtEnv}/bin/pip`, bonusArgs, {
cwd: agSetupSolo,
});

if (!(await exists(`${virtEnv}/bin/wheel`))) {
const exitStatus = await pipRun('install', 'wheel');
if (exitStatus) {
return exitStatus;
}
}

if (!(await exists(`${virtEnv}/bin/ag-setup-solo`))) {
const exitStatus = await pipRun('install', `--editable`, '.');
if (exitStatus) {
return exitStatus;
}
}

async function startTestnetSdk(_profileName, startArgs) {
const setupRun = (...bonusArgs) =>
pspawn(
`${virtEnv}/bin/ag-setup-solo`,
[`--webport=${PORT}`, ...bonusArgs, ...startArgs],
{
env: { ...pspawnEnv, AG_SOLO_BASEDIR: agServer },
},
);

if (!(await exists(agServer))) {
const exitStatus = await setupRun('--no-restart');
if (exitStatus) {
return exitStatus;
}
}
pspawn(agSolo, [`--webport=${PORT}`, ...bonusArgs, ...startArgs], {
env: { ...pspawnEnv, AG_SOLO_BASEDIR: agServer },
});

return setupRun();
return setupRun('setup');
}

const profiles = {
Expand Down
1 change: 1 addition & 0 deletions packages/agoric-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"commander": "^5.0.0",
"deterministic-json": "^1.0.5",
"esm": "^3.2.25",
"inquirer": "^6.3.1",
"opener": "^1.5.2",
"ws": "^7.2.0"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/cosmic-swingset/lib/ag-solo/chain-cosmos-sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ const HELPER = 'ag-cosmos-helper';
const SUPPORT_ADDRESS =
'@agoric.support#testnet on Keybase (https://keybase.io)';

const adviseProvision = myAddr =>
const adviseEgress = myAddr =>
`\
Send:
!faucet provision ${myAddr}
!faucet add-egress ${myAddr}
to ${SUPPORT_ADDRESS}`;

Expand Down Expand Up @@ -289,7 +289,7 @@ export async function connectToChain(
if (!r.stdout) {
console.error(`\
=============
${chainID} chain does not yet know of address ${myAddr}${adviseProvision(
${chainID} chain does not yet know of address ${myAddr}${adviseEgress(
myAddr,
)}
=============
Expand Down
4 changes: 3 additions & 1 deletion packages/cosmic-swingset/lib/ag-solo/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ let swingSetRunning = false;

const fsWrite = promisify(fs.write);
const fsClose = promisify(fs.close);
const mkdir = promisify(fs.mkdir);
const rename = promisify(fs.rename);
const unlink = promisify(fs.unlink);
const symlink = promisify(fs.symlink);
const unlink = promisify(fs.unlink);

async function atomicReplaceFile(filename, contents) {
const info = await new Promise((resolve, reject) => {
Expand Down Expand Up @@ -97,6 +98,7 @@ async function buildSwingset(
});

const pluginDir = path.resolve('./plugins');
await mkdir(pluginDir, { recursive: true });
const pluginsPrefix = `${pluginDir}${path.sep}`;
const pluginRequire = mod => {
// Ensure they can't traverse out of the plugins prefix.
Expand Down

0 comments on commit d2a545e

Please sign in to comment.