Skip to content

Commit 83cee97

Browse files
committed
ci: add manual @bitgo-beta SDK bump workflow
1 parent e1c6019 commit 83cee97

6 files changed

Lines changed: 211 additions & 5 deletions

File tree

.github/workflows/bump-sdk.yaml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Bump @bitgo-beta SDK Dependencies
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: write
8+
pull-requests: write
9+
10+
jobs:
11+
bump-sdk:
12+
name: Bump SDK deps and open PR
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
ref: master
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '22.1.0'
24+
cache: 'npm'
25+
26+
- name: Install current dependencies
27+
run: npm ci
28+
29+
- name: Bump @bitgo-beta versions
30+
run: npm run bump-versions
31+
32+
- name: Regenerate lockfile
33+
run: npm install --package-lock-only
34+
35+
- name: Install updated dependencies
36+
run: npm ci
37+
38+
- name: Lint
39+
run: npm run lint
40+
41+
- name: Build
42+
run: npm run build
43+
44+
- name: Generate test SSL certificates
45+
run: npm run generate-test-ssl
46+
47+
- name: Test
48+
run: npm test
49+
env:
50+
NODE_OPTIONS: '--max-old-space-size=4096'
51+
MASTER_BITGO_EXPRESS_KEYPATH: ./demo.key
52+
MASTER_BITGO_EXPRESS_CRTPATH: ./demo.crt
53+
MTLS_ENABLED: true
54+
MTLS_REQUEST_CERT: true
55+
MTLS_REJECT_UNAUTHORIZED: false
56+
KEY_PROVIDER_URL: 'https://localhost:3000/'
57+
58+
- name: Check for changes
59+
id: changes
60+
run: |
61+
if git diff --quiet HEAD -- package.json package-lock.json; then
62+
echo "changed=false" >> $GITHUB_OUTPUT
63+
else
64+
echo "changed=true" >> $GITHUB_OUTPUT
65+
fi
66+
67+
- name: Commit and push branch
68+
id: push-branch
69+
if: steps.changes.outputs.changed == 'true'
70+
run: |
71+
DATE=$(date +'%Y-%m-%d')
72+
BRANCH="chore/bump-bitgo-beta-$(date +'%Y%m%d-%H%M')"
73+
git config user.name "github-actions[bot]"
74+
git config user.email "github-actions[bot]@users.noreply.github.com"
75+
git checkout -b "$BRANCH"
76+
git add package.json package-lock.json
77+
git commit -m "chore: bump @bitgo-beta dependencies ${DATE}"
78+
git push origin "$BRANCH"
79+
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
80+
echo "date=$DATE" >> $GITHUB_OUTPUT
81+
82+
- name: Open draft PR
83+
if: steps.changes.outputs.changed == 'true'
84+
run: |
85+
gh pr create \
86+
--title "chore: bump @bitgo-beta dependencies ${{ steps.push-branch.outputs.date }}" \
87+
--body "Automated weekly bump of \`@bitgo-beta/*\` dependencies.
88+
89+
Build and tests passed on this branch before opening." \
90+
--base master \
91+
--head "${{ steps.push-branch.outputs.branch }}" \
92+
--draft
93+
env:
94+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

src/__tests__/api/master/accelerate.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
3434
type: 'independent',
3535
};
3636

37+
const mockBitgoKeychain = {
38+
id: 'bitgo-key-id',
39+
pub: 'xpub661MyMwAqRbcH7HSwqXjBxRr2imXfTnCTLBiSHqFMb8FGnXtKEmYYrakVg1YBR6mY8gQwUfq9P',
40+
type: 'independent',
41+
};
42+
43+
function nockAllKeychains(accessToken: string) {
44+
return [
45+
nock(bitgoApiUrl)
46+
.get(`/api/v2/${coin}/key/user-key-id`)
47+
.matchHeader('authorization', `Bearer ${accessToken}`)
48+
.reply(200, mockUserKeychain),
49+
nock(bitgoApiUrl)
50+
.get(`/api/v2/${coin}/key/backup-key-id`)
51+
.matchHeader('authorization', `Bearer ${accessToken}`)
52+
.reply(200, mockBackupKeychain),
53+
nock(bitgoApiUrl)
54+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
55+
.matchHeader('authorization', `Bearer ${accessToken}`)
56+
.reply(200, mockBitgoKeychain),
57+
];
58+
}
59+
3760
before(() => {
3861
nock.disableNetConnect();
3962
nock.enableNetConnect('127.0.0.1');
@@ -73,6 +96,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
7396
.matchHeader('authorization', `Bearer ${accessToken}`)
7497
.reply(200, mockUserKeychain);
7598

99+
const allKeychainNocks = nockAllKeychains(accessToken);
100+
76101
const accelerateTransactionStub = sinon
77102
.stub(Wallet.prototype, 'accelerateTransaction')
78103
.resolves({
@@ -101,6 +126,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
101126

102127
walletGetNock.done();
103128
keychainGetNock.done();
129+
allKeychainNocks.forEach((n) => n.done());
104130
sinon.assert.calledOnce(accelerateTransactionStub);
105131

106132
const callArgs = accelerateTransactionStub.firstCall.args[0];
@@ -122,6 +148,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
122148
.matchHeader('authorization', `Bearer ${accessToken}`)
123149
.reply(200, mockBackupKeychain);
124150

151+
const allKeychainNocks = nockAllKeychains(accessToken);
152+
125153
const accelerateTransactionStub = sinon
126154
.stub(Wallet.prototype, 'accelerateTransaction')
127155
.resolves({
@@ -148,6 +176,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
148176

149177
walletGetNock.done();
150178
keychainGetNock.done();
179+
allKeychainNocks.forEach((n) => n.done());
151180
sinon.assert.calledOnce(accelerateTransactionStub);
152181
});
153182

@@ -162,6 +191,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
162191
.matchHeader('authorization', `Bearer ${accessToken}`)
163192
.reply(200, mockUserKeychain);
164193

194+
const allKeychainNocks = nockAllKeychains(accessToken);
195+
165196
const accelerateTransactionStub = sinon
166197
.stub(Wallet.prototype, 'accelerateTransaction')
167198
.resolves({
@@ -190,6 +221,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
190221

191222
walletGetNock.done();
192223
keychainGetNock.done();
224+
allKeychainNocks.forEach((n) => n.done());
193225
sinon.assert.calledOnce(accelerateTransactionStub);
194226
});
195227

@@ -329,6 +361,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
329361
.matchHeader('authorization', `Bearer ${accessToken}`)
330362
.reply(200, mockUserKeychain);
331363

364+
const allKeychainNocks = nockAllKeychains(accessToken);
365+
332366
const accelerateTransactionStub = sinon
333367
.stub(Wallet.prototype, 'accelerateTransaction')
334368
.rejects(new Error('Insufficient funds for acceleration'));
@@ -350,6 +384,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/accelerate', () => {
350384

351385
walletGetNock.done();
352386
keychainGetNock.done();
387+
allKeychainNocks.forEach((n) => n.done());
353388
sinon.assert.calledOnce(accelerateTransactionStub);
354389
});
355390

src/__tests__/api/master/consolidateUnspents.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
3434
type: 'independent',
3535
};
3636

37+
const mockBitgoKeychain = {
38+
id: 'bitgo-key-id',
39+
pub: 'xpub661MyMwAqRbcH7HSwqXjBxRr2imXfTnCTLBiSHqFMb8FGnXtKEmYYrakVg1YBR6mY8gQwUfq9P',
40+
type: 'independent',
41+
};
42+
43+
function nockAllKeychains(accessToken: string) {
44+
return [
45+
nock(bitgoApiUrl)
46+
.get(`/api/v2/${coin}/key/user-key-id`)
47+
.matchHeader('authorization', `Bearer ${accessToken}`)
48+
.reply(200, mockUserKeychain),
49+
nock(bitgoApiUrl)
50+
.get(`/api/v2/${coin}/key/backup-key-id`)
51+
.matchHeader('authorization', `Bearer ${accessToken}`)
52+
.reply(200, mockBackupKeychain),
53+
nock(bitgoApiUrl)
54+
.get(`/api/v2/${coin}/key/bitgo-key-id`)
55+
.matchHeader('authorization', `Bearer ${accessToken}`)
56+
.reply(200, mockBitgoKeychain),
57+
];
58+
}
59+
3760
before(() => {
3861
nock.disableNetConnect();
3962
nock.enableNetConnect('127.0.0.1');
@@ -73,6 +96,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
7396
.matchHeader('authorization', `Bearer ${accessToken}`)
7497
.reply(200, mockUserKeychain);
7598

99+
const allKeychainNocks = nockAllKeychains(accessToken);
100+
76101
const mockResult = {
77102
transfer: {
78103
entries: [
@@ -119,6 +144,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
119144

120145
walletGetNock.done();
121146
keychainGetNock.done();
147+
allKeychainNocks.forEach((n) => n.done());
122148
sinon.assert.calledOnce(consolidateUnspentsStub);
123149

124150
const callArgs = consolidateUnspentsStub.firstCall.args[0];
@@ -140,6 +166,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
140166
.matchHeader('authorization', `Bearer ${accessToken}`)
141167
.reply(200, mockBackupKeychain);
142168

169+
const allKeychainNocks = nockAllKeychains(accessToken);
170+
143171
const mockResult = {
144172
txid: 'backup-consolidation-tx-id',
145173
tx: '01000000000102backup...',
@@ -169,6 +197,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
169197

170198
walletGetNock.done();
171199
keychainGetNock.done();
200+
allKeychainNocks.forEach((n) => n.done());
172201
sinon.assert.calledOnce(consolidateUnspentsStub);
173202
});
174203

@@ -183,6 +212,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
183212
.matchHeader('authorization', `Bearer ${accessToken}`)
184213
.reply(200, mockUserKeychain);
185214

215+
const allKeychainNocks = nockAllKeychains(accessToken);
216+
186217
const mockArrayResult = [
187218
{
188219
transfer: {
@@ -232,6 +263,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
232263

233264
walletGetNock.done();
234265
keychainGetNock.done();
266+
allKeychainNocks.forEach((n) => n.done());
235267
sinon.assert.calledOnce(consolidateUnspentsStub);
236268
});
237269

@@ -246,6 +278,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
246278
.matchHeader('authorization', `Bearer ${accessToken}`)
247279
.reply(200, mockUserKeychain);
248280

281+
const allKeychainNocks = nockAllKeychains(accessToken);
282+
249283
const mockArrayResult = [
250284
{
251285
txid: 'first-tx-id',
@@ -284,6 +318,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
284318

285319
walletGetNock.done();
286320
keychainGetNock.done();
321+
allKeychainNocks.forEach((n) => n.done());
287322
sinon.assert.calledOnce(consolidateUnspentsStub);
288323
});
289324

@@ -298,6 +333,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
298333
.matchHeader('authorization', `Bearer ${accessToken}`)
299334
.reply(200, mockUserKeychain);
300335

336+
const allKeychainNocks = nockAllKeychains(accessToken);
337+
301338
const mockResult = {
302339
txid: 'full-params-consolidation-tx-id',
303340
tx: '01000000000102full...',
@@ -338,6 +375,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
338375

339376
walletGetNock.done();
340377
keychainGetNock.done();
378+
allKeychainNocks.forEach((n) => n.done());
341379
sinon.assert.calledOnce(consolidateUnspentsStub);
342380
});
343381

@@ -477,6 +515,8 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
477515
.matchHeader('authorization', `Bearer ${accessToken}`)
478516
.reply(200, mockUserKeychain);
479517

518+
const allKeychainNocks = nockAllKeychains(accessToken);
519+
480520
const consolidateUnspentsStub = sinon
481521
.stub(Wallet.prototype, 'consolidateUnspents')
482522
.rejects(new Error('No unspents available for consolidation'));
@@ -497,6 +537,7 @@ describe('POST /api/v1/:coin/advancedwallet/:walletId/consolidateunspents', () =
497537

498538
walletGetNock.done();
499539
keychainGetNock.done();
540+
allKeychainNocks.forEach((n) => n.done());
500541
sinon.assert.calledOnce(consolidateUnspentsStub);
501542
});
502543

src/masterBitgoExpress/handlers/handleAccelerate.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { RequestTracer, KeyIndices } from '@bitgo-beta/sdk-core';
22
import logger from '../../shared/logger';
33
import { MasterApiSpecRouteRequest } from '../routers/masterBitGoExpressApiSpec';
4-
import { getWalletAndSigningKeychain, makeCustomSigningFunction } from './utils/utils';
4+
import {
5+
getWalletAndSigningKeychain,
6+
getWalletPubs,
7+
makeCustomSigningFunction,
8+
} from './utils/utils';
59

610
export async function handleAccelerate(
711
req: MasterApiSpecRouteRequest<'v1.wallet.accelerate', 'post'>,
@@ -13,7 +17,7 @@ export async function handleAccelerate(
1317
const walletId = req.params.walletId;
1418
const coin = req.params.coin;
1519

16-
const { wallet, signingKeychain } = await getWalletAndSigningKeychain({
20+
const { baseCoin, wallet, signingKeychain } = await getWalletAndSigningKeychain({
1721
bitgo,
1822
coin,
1923
walletId,
@@ -22,12 +26,15 @@ export async function handleAccelerate(
2226
KeyIndices,
2327
});
2428

29+
const walletPubs = await getWalletPubs({ baseCoin, wallet, KeyIndices });
30+
2531
try {
2632
// Create custom signing function that delegates to EBE
2733
const customSigningFunction = makeCustomSigningFunction({
2834
awmClient,
2935
source: params.source,
3036
pub: signingKeychain.pub!,
37+
walletPubs,
3138
});
3239

3340
// Prepare acceleration parameters

0 commit comments

Comments
 (0)