feat: script for getting key material (#4829)

### Description

Corresponding info on how to use this efficiently, PSA will follow
https://www.notion.so/hyperlanexyz/Runbook-83c755f2652943289cf98cd1309487a8?pvs=4#1366d35200d68056b827e9e6115f3ea2

- Prints the private key in a subshell but not in a normal tty
- Intended to encourage healthier key habits that don't write keys to
the filesystem, as described in the first step of
https://discord.com/channels/935678348330434570/1296491706417549413/1301158531667595265

### Drive-by changes

- groups some key related scripts

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->
pull/4873/head
Trevor Porter 1 week ago committed by GitHub
parent 0cd65c5715
commit 85dc14d827
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 12
      typescript/infra/scripts/agent-utils.ts
  2. 10
      typescript/infra/scripts/agents/utils.ts
  3. 5
      typescript/infra/scripts/keys/create-keys.ts
  4. 5
      typescript/infra/scripts/keys/delete-keys.ts
  5. 7
      typescript/infra/scripts/keys/get-key-addresses.ts
  6. 38
      typescript/infra/scripts/keys/get-key.ts
  7. 9
      typescript/infra/scripts/keys/get-owner-ica.ts
  8. 2
      typescript/infra/scripts/keys/rotate-key.ts
  9. 2
      typescript/infra/scripts/keys/update-key.ts

@ -191,9 +191,8 @@ export function withProtocol<T>(args: Argv<T>) {
export function withAgentRole<T>(args: Argv<T>) {
return args
.describe('role', 'agent roles')
.array('role')
.coerce('role', (role: string[]): Role[] => role.map(assertRole))
.describe('role', 'agent role')
.coerce('role', (role: string): Role => assertRole(role))
.demandOption('role')
.alias('r', 'role');
}
@ -206,11 +205,16 @@ export function withAgentRoles<T>(args: Argv<T>) {
.coerce('roles', (role: string[]): Role[] => role.map(assertRole))
.choices('roles', Object.values(Role))
// Ensure roles are unique
.coerce('roles', (roles: string[]) => Array.from(new Set(roles)))
.coerce('roles', (roles: Role[]) => Array.from(new Set(roles)))
.alias('r', 'roles')
.alias('role', 'roles')
);
}
export function withAgentRolesRequired<T>(args: Argv<T>) {
return withAgentRoles(args).demandOption('roles');
}
export function withKeyRoleAndChain<T>(args: Argv<T>) {
return args
.describe('role', 'key role')

@ -11,7 +11,7 @@ import { HelmCommand } from '../../src/utils/helm.js';
import {
assertCorrectKubeContext,
getArgs,
withAgentRole,
withAgentRolesRequired,
withChains,
withContext,
} from '../agent-utils.js';
@ -70,21 +70,23 @@ export class AgentCli {
protected async init() {
if (this.initialized) return;
const argv = await withChains(withAgentRole(withContext(getArgs())))
const argv = await withChains(
withAgentRolesRequired(withContext(getArgs())),
)
.describe('dry-run', 'Run through the steps without making any changes')
.boolean('dry-run').argv;
if (
argv.chains &&
argv.chains.length > 0 &&
!argv.role.includes(Role.Validator)
!argv.roles.includes(Role.Validator)
) {
console.warn('Chain argument applies to validator role only. Ignoring.');
}
const { envConfig, agentConfig } = await getConfigsBasedOnArgs(argv);
await assertCorrectKubeContext(envConfig);
this.roles = argv.role;
this.roles = argv.roles;
this.envConfig = envConfig;
this.agentConfig = agentConfig;
this.dryRun = argv.dryRun || false;

@ -1,6 +1,5 @@
import { createAgentKeysIfNotExists } from '../src/agents/key-utils.js';
import { getAgentConfigsBasedOnArgs } from './agent-utils.js';
import { createAgentKeysIfNotExists } from '../../src/agents/key-utils.js';
import { getAgentConfigsBasedOnArgs } from '../agent-utils.js';
async function main() {
const { agentConfig } = await getAgentConfigsBasedOnArgs();

@ -1,6 +1,5 @@
import { deleteAgentKeys } from '../src/agents/key-utils.js';
import { getAgentConfigsBasedOnArgs } from './agent-utils.js';
import { deleteAgentKeys } from '../../src/agents/key-utils.js';
import { getAgentConfigsBasedOnArgs } from '../agent-utils.js';
async function main() {
const { agentConfig } = await getAgentConfigsBasedOnArgs();

@ -1,7 +1,6 @@
import { getAllCloudAgentKeys } from '../src/agents/key-utils.js';
import { getArgs, withContext, withProtocol } from './agent-utils.js';
import { getConfigsBasedOnArgs } from './core-utils.js';
import { getAllCloudAgentKeys } from '../../src/agents/key-utils.js';
import { getArgs, withContext, withProtocol } from '../agent-utils.js';
import { getConfigsBasedOnArgs } from '../core-utils.js';
async function main() {
const argv = await withProtocol(withContext(getArgs())).argv;

@ -0,0 +1,38 @@
import { getCloudAgentKey } from '../../src/agents/key-utils.js';
import {
getArgs,
withAgentRole,
withContext,
withProtocol,
} from '../agent-utils.js';
import { getConfigsBasedOnArgs } from '../core-utils.js';
async function main() {
const argv = await withAgentRole(withContext(getArgs())).argv;
const { agentConfig } = await getConfigsBasedOnArgs(argv);
// As a (very rudimentary) security precaution, we don't print the private key directly to
// the console if this script is ran directly.
// We only write the private key to the console if it is not a tty, e.g. if
// this is being called in a subshell or piped to another command.
//
// E.g. this will print the private key:
// $ echo `yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer`
// or this too:
// $ echo $(yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer)
// and even this:
// $ yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer | cat
//
// But this will not print the private key directly to the shell:
// $ yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer
if (process.stdout.isTTY) {
console.log('<omitted in tty, use in subshell>');
} else {
const key = getCloudAgentKey(agentConfig, argv.role);
await key.fetch();
console.log(key.privateKey);
}
}
main().catch(console.error);

@ -1,11 +1,10 @@
import { AccountConfig, InterchainAccount } from '@hyperlane-xyz/sdk';
import { Address, eqAddress, isZeroishAddress } from '@hyperlane-xyz/utils';
import { chainsToSkip } from '../src/config/chain.js';
import { isEthereumProtocolChain } from '../src/utils/utils.js';
import { getArgs as getEnvArgs, withChains } from './agent-utils.js';
import { getEnvironmentConfig, getHyperlaneCore } from './core-utils.js';
import { chainsToSkip } from '../../src/config/chain.js';
import { isEthereumProtocolChain } from '../../src/utils/utils.js';
import { getArgs as getEnvArgs, withChains } from '../agent-utils.js';
import { getEnvironmentConfig, getHyperlaneCore } from '../core-utils.js';
function getArgs() {
return withChains(getEnvArgs())

@ -3,7 +3,7 @@ import {
getArgs,
withContext,
withKeyRoleAndChain,
} from './agent-utils.js';
} from '../agent-utils.js';
async function rotateKey() {
const argv = await withContext(withKeyRoleAndChain(getArgs())).argv;

@ -3,7 +3,7 @@ import {
getArgs,
withContext,
withKeyRoleAndChain,
} from './agent-utils.js';
} from '../agent-utils.js';
async function rotateKey() {
const argv = await withKeyRoleAndChain(withContext(getArgs())).argv;
Loading…
Cancel
Save