189 lines
7.0 KiB
Bash
Executable File
189 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repository_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
|
|
guard="$repository_root/tools/require-base-config.sh"
|
|
terminal_url=https://terminal.invalid/rpc
|
|
public_url=https://public.invalid/rpc
|
|
account=demo-account
|
|
sender=0x1111111111111111111111111111111111111111
|
|
recipient=0x2222222222222222222222222222222222222222
|
|
|
|
run_guard() {
|
|
local mode=${1-deploy}
|
|
shift || true
|
|
env -i PATH="$PATH" \
|
|
BASE_SEPOLIA_RPC_URL="$terminal_url" \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL="$public_url" \
|
|
BASE_SEPOLIA_ACCOUNT="$account" \
|
|
BASE_SEPOLIA_SENDER="$sender" \
|
|
BASE_SEPOLIA_RECIPIENT="$recipient" \
|
|
"$@" bash "$guard" "$mode"
|
|
}
|
|
|
|
assert_no_config_values() {
|
|
local output=$1
|
|
shift
|
|
local value
|
|
for value in "$terminal_url" "$public_url" "$account" "$sender" "$recipient" "$@"; do
|
|
[[ -n $value ]] || continue
|
|
if [[ $output == *"$value"* ]]; then
|
|
echo "configuration guard leaked a configured value" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
expect_rejected() {
|
|
local assignment=$1
|
|
local output
|
|
if output=$(run_guard deploy "$assignment" 2>&1); then
|
|
echo "configuration guard accepted invalid fixture: ${assignment%%=*}" >&2
|
|
exit 1
|
|
fi
|
|
assert_no_config_values "$output" "${assignment#*=}"
|
|
}
|
|
|
|
for mode in deploy upgrade transfer; do
|
|
output=$(run_guard "$mode" 2>&1)
|
|
[[ -z $output ]] || { echo "configuration guard produced output for valid fixtures" >&2; exit 1; }
|
|
done
|
|
|
|
for assignment in \
|
|
BASE_SEPOLIA_RPC_URL= \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL= \
|
|
BASE_SEPOLIA_ACCOUNT= \
|
|
BASE_SEPOLIA_SENDER= \
|
|
BASE_SEPOLIA_RECIPIENT= \
|
|
BASE_SEPOLIA_ACCOUNT='bad account' \
|
|
BASE_SEPOLIA_SENDER=0x1234 \
|
|
BASE_SEPOLIA_RECIPIENT=0x0000000000000000000000000000000000000000 \
|
|
BASE_SEPOLIA_RECIPIENT="$sender" \
|
|
BASE_SEPOLIA_RPC_URL=http://terminal.invalid \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL=http://public.invalid \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL=https://user@public.invalid \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL='https://public.invalid/?api_key=fixture' \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL='https://public.invalid/?token=fixture'; do
|
|
expect_rejected "$assignment"
|
|
done
|
|
|
|
private_key_name=PRIVATE_$(printf KEY)
|
|
mnemonic_name=MNEM$(printf ONIC)
|
|
fake_key=0x$(printf 'a%.0s' {1..64})
|
|
output=$(
|
|
env -i PATH="$PATH" "$private_key_name=$fake_key" "$mnemonic_name=fixture words only" \
|
|
bash "$guard" deploy 2>&1 || true
|
|
)
|
|
if [[ $output != *BASE_SEPOLIA_RPC_URL* ]]; then
|
|
echo "configuration guard unexpectedly accepted a raw-key or mnemonic fallback" >&2
|
|
exit 1
|
|
fi
|
|
assert_no_config_values "$output"
|
|
|
|
dry_run=$(
|
|
make -n -C "$repository_root" deploy-base-sepolia \
|
|
BASE_SEPOLIA_RPC_URL=https://terminal.invalid \
|
|
BASE_SEPOLIA_PUBLIC_RPC_URL=https://public.invalid \
|
|
BASE_SEPOLIA_ACCOUNT=demo \
|
|
BASE_SEPOLIA_SENDER=0x1111111111111111111111111111111111111111 \
|
|
BASE_SEPOLIA_RECIPIENT=0x2222222222222222222222222222222222222222
|
|
)
|
|
[[ $dry_run == *'--account "demo"'* ]] || { echo "Base dry run omitted --account" >&2; exit 1; }
|
|
[[ $dry_run == *'--sender "0x1111111111111111111111111111111111111111"'* ]] || \
|
|
{ echo "Base dry run omitted --sender" >&2; exit 1; }
|
|
[[ $dry_run == *'--slow'* ]] || { echo "Base dry run omitted --slow" >&2; exit 1; }
|
|
if [[ ${dry_run,,} == *private-key* || ${dry_run,,} == *mnemonic* ]]; then
|
|
echo "Base dry run exposed a raw signing option" >&2
|
|
exit 1
|
|
fi
|
|
|
|
node --input-type=module - "$repository_root" <<'NODE'
|
|
import assert from "node:assert/strict";
|
|
import { access, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
const repositoryRoot = process.argv[2];
|
|
const { archiveManifest, selectManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/select-manifest.mjs")));
|
|
const { publishManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/publish-web-manifest.mjs")));
|
|
const root = await mkdtemp(join(tmpdir(), "uups-base-config-"));
|
|
const deployments = join(root, "deployments");
|
|
const webManifest = join(root, "web/public/deployment.json");
|
|
const owner = "0x1111111111111111111111111111111111111111";
|
|
const recipient = "0x2222222222222222222222222222222222222222";
|
|
const base = {
|
|
schemaVersion: 1,
|
|
network: "baseSepolia",
|
|
chainId: 84532,
|
|
deploymentBlock: 99,
|
|
rpcUrl: "https://public.invalid/rpc",
|
|
explorerBaseUrl: "https://sepolia.basescan.org",
|
|
token: "0x3333333333333333333333333333333333333333",
|
|
proxy: "0x4444444444444444444444444444444444444444",
|
|
implementation: "0x5555555555555555555555555555555555555555",
|
|
owner,
|
|
actors: [
|
|
{ label: "Presenter", address: owner },
|
|
{ label: "Recipient", address: recipient },
|
|
],
|
|
};
|
|
const anvil = {
|
|
...base,
|
|
network: "anvil",
|
|
chainId: 31337,
|
|
rpcUrl: "http://127.0.0.1:8545",
|
|
explorerBaseUrl: undefined,
|
|
actors: [
|
|
{ label: "owner", address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" },
|
|
{ label: "Alice", address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" },
|
|
{ label: "Bob", address: "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" },
|
|
],
|
|
owner: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
};
|
|
delete anvil.explorerBaseUrl;
|
|
|
|
try {
|
|
await mkdir(deployments, { recursive: true });
|
|
await writeFile(join(deployments, "base-sepolia.json"), `${JSON.stringify(base)}\n`);
|
|
await writeFile(join(deployments, "anvil.json"), `${JSON.stringify(anvil)}\n`);
|
|
await selectManifest({ root, network: "baseSepolia" });
|
|
const activeBefore = await readFile(join(deployments, "active.json"));
|
|
const anvilBefore = await readFile(join(deployments, "anvil.json"));
|
|
const published = await publishManifest({
|
|
activePath: join(deployments, "active.json"),
|
|
outputPath: webManifest,
|
|
});
|
|
assert.equal(published.rpcUrl, "https://public.invalid/rpc");
|
|
assert.equal(published.explorerBaseUrl, "https://sepolia.basescan.org");
|
|
assert.equal((await readFile(webManifest, "utf8")).includes("terminal.invalid"), false);
|
|
for (const invalid of [
|
|
{ ...base, rpcUrl: "http://public.invalid/rpc" },
|
|
{ ...base, explorerBaseUrl: "https://example.invalid" },
|
|
]) {
|
|
await writeFile(join(deployments, "active.json"), `${JSON.stringify(invalid)}\n`);
|
|
await assert.rejects(
|
|
() => publishManifest({ activePath: join(deployments, "active.json"), outputPath: webManifest }),
|
|
/HTTPS|BaseScan/,
|
|
);
|
|
}
|
|
await writeFile(join(deployments, "active.json"), activeBefore);
|
|
|
|
const archived = await archiveManifest({
|
|
root,
|
|
network: "baseSepolia",
|
|
now: new Date("2026-08-21T12:34:56.789Z"),
|
|
});
|
|
assert.equal(archived.path, join(deployments, "base-sepolia.20260821T123456789Z.json"));
|
|
await access(archived.path);
|
|
await assert.rejects(() => access(join(deployments, "base-sepolia.json")));
|
|
assert.deepEqual(await readFile(join(deployments, "active.json")), activeBefore);
|
|
assert.deepEqual(await readFile(join(deployments, "anvil.json")), anvilBefore);
|
|
await assert.rejects(() => archiveManifest({ root, network: "anvil" }), /baseSepolia/);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
NODE
|
|
|
|
echo "Base configuration and manifest filesystem tests passed"
|