Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d955971
feat(e2e): add update-snap-binary CLI script for downloading snap tar…
chrisleewilcox Apr 23, 2026
247f3e4
feat(e2e): add local snap binary tarballs for all 21 flask test snaps
chrisleewilcox Apr 23, 2026
2adb389
feat(e2e): add snap binary mock functions for local tarball serving
chrisleewilcox Apr 23, 2026
8c7efec
feat(e2e): add snap binary mocks to ethereum-provider and multichain-…
chrisleewilcox Apr 23, 2026
e4efe20
feat(e2e): add testSpecificMock with snap binary mocks to 20 flask specs
chrisleewilcox Apr 23, 2026
b6f9bc0
feat(e2e): add snap binary mocks for multi-snap RPC test
chrisleewilcox Apr 23, 2026
bb2a9c0
feat(e2e): remove npm URI allowlist bypass from MockServerE2E
chrisleewilcox Apr 23, 2026
2f4c52a
fix(e2e): address review — gitattributes, inline helper, headers check
chrisleewilcox Apr 23, 2026
e56372e
fix(e2e): restore npm URI allowlist bypass for snap proxy leaks
chrisleewilcox Apr 23, 2026
53875d7
fix(scripts): sanitize input and guard output paths in update-snap-bi…
chrisleewilcox Apr 23, 2026
f2ef5e4
ci: retrigger CI checks
chrisleewilcox Apr 24, 2026
a457e00
fix(e2e): import getDecodedProxiedURL from shared helper instead of d…
chrisleewilcox Apr 24, 2026
31774b9
Merge branch 'main' into MMQA-1366-snap-local-binaries
chrisleewilcox Apr 30, 2026
38f7282
Merge remote-tracking branch 'origin/main' into MMQA-1366-snap-local-…
Copilot May 15, 2026
90806bb
test(e2e): patch react-native-blob-util for snap tarball mocking
chrisleewilcox May 15, 2026
81512e9
Revert "test(e2e): patch react-native-blob-util for snap tarball mock…
chrisleewilcox May 15, 2026
d9a4ae6
test(e2e): route snap tarball downloads through MockServerE2E proxy
chrisleewilcox May 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"feature-flags:sync": "ts-node tests/feature-flags/sync-production-flags.ts",
"feature-flags:sync:check": "ts-node tests/feature-flags/sync-production-flags.ts --check",
"feature-flags:sync:update": "ts-node tests/feature-flags/sync-production-flags.ts --update",
"update-snap-binary": "ts-node --transpile-only scripts/update-snap-binary.ts",
"worktree:create": "yarn ts-node --transpile-only scripts/worktree-create.ts",
"worktree:remove": "yarn ts-node --transpile-only scripts/worktree-remove.ts",
"a:start": "scripts/perps/agentic/start-metro.sh",
Expand Down
110 changes: 110 additions & 0 deletions scripts/update-snap-binary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { existsSync, readdirSync, unlinkSync, mkdirSync, writeFileSync } from 'fs';
import { resolve, join, basename } from 'path';
import { valid } from 'semver';

const SNAP_BINARIES_DIR = resolve(
__dirname,
'../tests/api-mocking/mock-response-data/snaps/snap-binaries-and-headers',
);

const RELEVANT_HEADERS = [
'accept-ranges',
'content-length',
'content-type',
'etag',
'vary',
];

function parseArgs(): { snapName: string; version: string } {
const arg = process.argv[2];
if (!arg || !arg.startsWith('--')) {
console.error('Usage: yarn update-snap-binary --<snap-name>@<version>');
console.error('Example: yarn update-snap-binary --bip32-example-snap@2.3.0');
process.exit(1);
}

const nameVersion = arg.slice(2);
const atIndex = nameVersion.lastIndexOf('@');
if (atIndex <= 0) {
console.error(`Invalid format: ${nameVersion}. Expected <name>@<version>`);
process.exit(1);
}

const snapName = nameVersion.slice(0, atIndex);
const version = nameVersion.slice(atIndex + 1);

if (!valid(version)) {
console.error(`Invalid semver version: ${version}`);
process.exit(1);
}

return { snapName, version };
}

function deleteOldSnapFiles(snapName: string): void {
if (!existsSync(SNAP_BINARIES_DIR)) return;
const files = readdirSync(SNAP_BINARIES_DIR);
for (const file of files) {
if (file.startsWith(`${snapName}@`)) {
const filePath = join(SNAP_BINARIES_DIR, file);
unlinkSync(filePath);
console.log(`Deleted old file: ${file}`);
}
}
}

async function downloadSnapBinary(
snapName: string,
version: string,
): Promise<void> {
const scopedName = `@metamask/${snapName}`;
const tarballUrl = `https://registry.npmjs.org/${scopedName}/-/${snapName}-${version}.tgz`;

console.log(`Downloading ${scopedName}@${version} from ${tarballUrl}`);

const response = await fetch(tarballUrl);
if (!response.ok) {
throw new Error(
`Failed to download: ${response.status} ${response.statusText}`,
);
}

if (!existsSync(SNAP_BINARIES_DIR)) {
mkdirSync(SNAP_BINARIES_DIR, { recursive: true });
}

deleteOldSnapFiles(snapName);

const buffer = Buffer.from(await response.arrayBuffer());
const binaryPath = join(
SNAP_BINARIES_DIR,
`${snapName}@${version}.txt`,
);
writeFileSync(binaryPath, buffer);

Check warning

Code scanning / CodeQL

Network data written to file Medium

Write to file system depends on
Untrusted data
.
Comment thread
chrisleewilcox marked this conversation as resolved.
Dismissed
console.log(`Saved binary: ${basename(binaryPath)}`);

const headers: Record<string, string> = {};
for (const headerName of RELEVANT_HEADERS) {
const value = response.headers.get(headerName);
if (value) {
headers[headerName] = value;
}
}
const headersPath = join(
SNAP_BINARIES_DIR,
`${snapName}@${version}-headers.json`,
);
writeFileSync(headersPath, JSON.stringify(headers, null, 2));
console.log(`Saved headers: ${basename(headersPath)}`);
}

async function main(): Promise<void> {
const { snapName, version } = parseArgs();
await downloadSnapBinary(snapName, version);
console.log('Done.');
}

main().catch((error) => {
console.error(error);
process.exit(1);
});
6 changes: 0 additions & 6 deletions tests/api-mocking/MockServerE2E.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,6 @@ const isUrlAllowed = (url: string): boolean => {
return true;
}

// Malformed npm: package URIs that leak through the snap proxy
// e.g. https://https//npm:@metamask/... or npm:@metamask/...
if (/^(?:https?:\/\/.*)?npm[:@]@?metamask\//.test(url)) {
return true;
}

const parsedUrl = new URL(url);
const hostname = parsedUrl.hostname;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "12336",
"content-type": "application/octet-stream",
"etag": "\"6089ae64c9d548802d1cb3cefc4a4366\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "72040",
"content-type": "application/octet-stream",
"etag": "\"f6aefd54643480c1b753fa4244a537cf\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "78008",
"content-type": "application/octet-stream",
"etag": "\"2868a47b39a090ac18044548fb6fa37e\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "11873",
"content-type": "application/octet-stream",
"etag": "\"84e43175ffad7735148282c566b2a933\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "14697",
"content-type": "application/octet-stream",
"etag": "\"19f44e9e1a7ae62f4d036c5b76d585b7\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "14985",
"content-type": "application/octet-stream",
"etag": "\"2ba3e0bc12c6102b0b8364df36d35fee\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "7097",
"content-type": "application/octet-stream",
"etag": "\"0f020a896a5e7e71490980948e215922\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "40830",
"content-type": "application/octet-stream",
"etag": "\"f7162b1783325693be06cf33e22a2046\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "28663",
"content-type": "application/octet-stream",
"etag": "\"8d2d41cb8f2f7e7218f4224f6729486d\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "12290",
"content-type": "application/octet-stream",
"etag": "\"8135e843e047041b4bc331ff81490d1f\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "17406",
"content-type": "application/octet-stream",
"etag": "\"53d8d18e3a90eafc45e6b99fa3963f0d\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "41673",
"content-type": "application/octet-stream",
"etag": "\"fb3226cb55d721daedda5e5701863529\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "12621",
"content-type": "application/octet-stream",
"etag": "\"d83c6bec2ed39981ad7f84b36d055564\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "11962",
"content-type": "application/octet-stream",
"etag": "\"c618ad778d68fb7bb01568a3f79755ad\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "7557",
"content-type": "application/octet-stream",
"etag": "\"f9b3d3ba2d306efe4add6062ae879d87\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "13369",
"content-type": "application/octet-stream",
"etag": "\"ebf53ab08e421cb48ca87a46a36453f4\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "42251",
"content-type": "application/octet-stream",
"etag": "\"a653b90d4181b08d66589fa3ff193d8c\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "7213",
"content-type": "application/octet-stream",
"etag": "\"46c1c1d932d24ba1f8525db185d6e082\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "13022",
"content-type": "application/octet-stream",
"etag": "\"e69e583dbe6d354859b6adf0a5255a33\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "11617",
"content-type": "application/octet-stream",
"etag": "\"680cc54c481db6ee835d31c4803b29b8\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accept-ranges": "bytes",
"content-length": "13547",
"content-type": "application/octet-stream",
"etag": "\"d97d99aecc904046e68bd9bc1a73f1b0\"",
"vary": "Accept-Encoding"
}
Binary file not shown.
Loading
Loading