@gatedpath/preflight 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +189 -0
  3. package/dist/bip39-words.d.ts +1 -0
  4. package/dist/bip39-words.js +132 -0
  5. package/dist/checks/admin.d.ts +24 -0
  6. package/dist/checks/admin.js +81 -0
  7. package/dist/checks/balance.d.ts +3 -0
  8. package/dist/checks/balance.js +39 -0
  9. package/dist/checks/chain-id.d.ts +2 -0
  10. package/dist/checks/chain-id.js +11 -0
  11. package/dist/checks/compiler.d.ts +5 -0
  12. package/dist/checks/compiler.js +20 -0
  13. package/dist/checks/deployer.d.ts +14 -0
  14. package/dist/checks/deployer.js +53 -0
  15. package/dist/checks/git-secrets.d.ts +14 -0
  16. package/dist/checks/git-secrets.js +91 -0
  17. package/dist/checks/slither.d.ts +11 -0
  18. package/dist/checks/slither.js +119 -0
  19. package/dist/cli.d.ts +8 -0
  20. package/dist/cli.js +131 -0
  21. package/dist/config.d.ts +25 -0
  22. package/dist/config.js +197 -0
  23. package/dist/doctor-cli.d.ts +9 -0
  24. package/dist/doctor-cli.js +76 -0
  25. package/dist/doctor.d.ts +60 -0
  26. package/dist/doctor.js +251 -0
  27. package/dist/dotenv.d.ts +7 -0
  28. package/dist/dotenv.js +28 -0
  29. package/dist/gas-cli.d.ts +8 -0
  30. package/dist/gas-cli.js +100 -0
  31. package/dist/gas.d.ts +110 -0
  32. package/dist/gas.js +221 -0
  33. package/dist/index.d.ts +28 -0
  34. package/dist/index.js +20 -0
  35. package/dist/proc.d.ts +14 -0
  36. package/dist/proc.js +28 -0
  37. package/dist/redbelly.d.ts +2 -0
  38. package/dist/redbelly.js +40 -0
  39. package/dist/run.d.ts +9 -0
  40. package/dist/run.js +106 -0
  41. package/dist/secrets.d.ts +18 -0
  42. package/dist/secrets.js +89 -0
  43. package/dist/ship-cli.d.ts +8 -0
  44. package/dist/ship-cli.js +128 -0
  45. package/dist/ship.d.ts +108 -0
  46. package/dist/ship.js +383 -0
  47. package/dist/suites.d.ts +26 -0
  48. package/dist/suites.js +53 -0
  49. package/dist/types.d.ts +58 -0
  50. package/dist/types.js +3 -0
  51. package/dist/well-known.d.ts +2 -0
  52. package/dist/well-known.js +21 -0
  53. package/package.json +50 -0
package/dist/suites.js ADDED
@@ -0,0 +1,53 @@
1
+ // The five-state suites: test contracts under test/ that inherit GatedTest from @gatedpath/receptor-mock.
2
+ // Shared by `ship` here and by the MCP server's five_state_tests and status.
3
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ export function findGatedSuites(project, testDir = 'test') {
6
+ const dir = join(project, testDir);
7
+ if (!existsSync(dir))
8
+ return [];
9
+ const names = [];
10
+ const walk = (d) => {
11
+ for (const entry of readdirSync(d, { withFileTypes: true })) {
12
+ const p = join(d, entry.name);
13
+ if (entry.isDirectory())
14
+ walk(p);
15
+ else if (entry.name.endsWith('.t.sol')) {
16
+ const text = readFileSync(p, 'utf8');
17
+ for (const m of text.matchAll(/\bcontract\s+([A-Za-z0-9_]+)\s+is\s+([^{]*)\bGatedTest\b/g))
18
+ names.push(m[1]);
19
+ }
20
+ }
21
+ };
22
+ walk(dir);
23
+ return names;
24
+ }
25
+ /** Counts a `forge test --json` result against the suites that inherit GatedTest. */
26
+ export function summariseTests(parsed, gatedSuites) {
27
+ let passed = 0;
28
+ let failed = 0;
29
+ let skipped = 0;
30
+ const perSuite = new Map();
31
+ const failures = [];
32
+ for (const [suitePath, v] of Object.entries(parsed)) {
33
+ const name = suitePath.split(':').pop() ?? suitePath;
34
+ const s = perSuite.get(name) ?? { passed: 0, failed: 0 };
35
+ for (const [test, r] of Object.entries(v.test_results ?? {})) {
36
+ if (r.status === 'Success') {
37
+ passed++;
38
+ s.passed++;
39
+ }
40
+ else if (r.status === 'Failure') {
41
+ failed++;
42
+ s.failed++;
43
+ failures.push({ suite: name, test, reason: r.reason ?? null });
44
+ }
45
+ else
46
+ skipped++;
47
+ }
48
+ perSuite.set(name, s);
49
+ }
50
+ const suites = gatedSuites.map((name) => ({ name, ...(perSuite.get(name) ?? { passed: 0, failed: 0 }) }));
51
+ const fiveState = gatedSuites.length > 0 && suites.every((s) => s.failed === 0 && s.passed > 0);
52
+ return { passed, failed, skipped, suites, fiveState, failures };
53
+ }
@@ -0,0 +1,58 @@
1
+ export type CheckStatus = 'pass' | 'fail' | 'warn' | 'skip';
2
+ export type CheckId = 'chain-id' | 'deployer-verified' | 'admin-safe' | 'compiler-pins' | 'git-secrets' | 'balance' | 'slither-report';
3
+ export interface CheckResult {
4
+ readonly id: CheckId;
5
+ readonly status: CheckStatus;
6
+ /** One sentence. Printed after the status on the terminal and copied into the JSON. */
7
+ readonly reason: string;
8
+ /** Machine-readable detail. Never contains a secret. */
9
+ readonly data?: Record<string, unknown>;
10
+ }
11
+ export interface PreflightOptions {
12
+ /** Project directory holding foundry.toml or hardhat.config.*. Default: cwd. */
13
+ project?: string;
14
+ /** Foundry profile or Hardhat network name to read. Default: Foundry `default`, Hardhat: the network whose chainId matches. */
15
+ profile?: string;
16
+ /** Target chain. Default: whatever the RPC reports, checked against config. */
17
+ chain?: 151 | 153;
18
+ /** JSON-RPC URL. Default: the governors endpoint for `chain`. */
19
+ rpc?: string;
20
+ /** Foundry keystore account name; resolved with `cast wallet address --account`. */
21
+ account?: string;
22
+ /** Deployer address for a read-only run. */
23
+ address?: string;
24
+ /** Admin or owner address the deployed contracts will hand control to. */
25
+ admin?: string;
26
+ /** Gas the deployment is expected to burn. Default 3,000,000. */
27
+ gas?: number | bigint;
28
+ /** Slither report path. Default: reports/slither.json or reports/slither.md under the project. */
29
+ slitherReport?: string;
30
+ /** Check ids to skip. */
31
+ skip?: readonly CheckId[];
32
+ /** Registry, permission and price feed overrides for local chains. Tests use these. */
33
+ registry?: string;
34
+ /** Working directory for `cast`. Default: project. */
35
+ env?: NodeJS.ProcessEnv;
36
+ }
37
+ export interface PreflightReport {
38
+ readonly tool: 'redbelly-preflight';
39
+ readonly version: string;
40
+ readonly generatedAt: string;
41
+ readonly project: string;
42
+ readonly config: {
43
+ kind: 'foundry' | 'hardhat' | 'none';
44
+ file: string | null;
45
+ profile: string | null;
46
+ };
47
+ readonly chain: {
48
+ expected: number | null;
49
+ reported: number | null;
50
+ rpc: string;
51
+ network: 'mainnet' | 'testnet' | 'unknown';
52
+ };
53
+ readonly deployer: string | null;
54
+ readonly admin: string | null;
55
+ readonly checks: readonly CheckResult[];
56
+ /** True when no check failed. Warnings and skips do not clear a fail and do not cause one. */
57
+ readonly ok: boolean;
58
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Shared shapes. A check never throws for a "no" answer; it returns a result with a status
2
+ // and one sentence saying why. Only a bug throws.
3
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const WELL_KNOWN_DEV_ACCOUNTS: readonly string[];
2
+ export declare function isWellKnownDevAccount(address: string): boolean;
@@ -0,0 +1,21 @@
1
+ // The ten accounts every anvil and Hardhat node starts with, whose private keys are printed
2
+ // on every start and sit in every tutorial. RESEARCH.md question 30 (2026-09-12) found that
3
+ // accounts 0 and 1 pass permission.isAllowed on both Redbelly networks, so a deploy from one
4
+ // of them would succeed under an identity nobody here controls. Pre-flight warns on any of
5
+ // the ten. The list is checked in the tests against a spawned anvil's eth_accounts.
6
+ export const WELL_KNOWN_DEV_ACCOUNTS = [
7
+ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
8
+ '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
9
+ '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
10
+ '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
11
+ '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',
12
+ '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
13
+ '0x976EA74026E726554dB657fA54763abd0C3a0aa9',
14
+ '0x14dC79964da2C08b23698B3D3cc7Ca32193d9955',
15
+ '0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f',
16
+ '0xa0Ee7A142d267C1f36714E4a8F75612F20a79720',
17
+ ];
18
+ export function isWellKnownDevAccount(address) {
19
+ const a = address.toLowerCase();
20
+ return WELL_KNOWN_DEV_ACCOUNTS.some((w) => w.toLowerCase() === a);
21
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@gatedpath/preflight",
3
+ "version": "0.1.0",
4
+ "description": "Pre-flight checks before deploying to Redbelly Network (151 mainnet, 153 testnet): chain ID, deployer verification, Safe admin, compiler pins, secrets in git history, RBNT balance, Slither report.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/tshirtdropper/redbelly-development-tool.git",
9
+ "directory": "packages/preflight"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "type": "module",
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "bin": {
28
+ "redbelly-preflight": "./dist/cli.js",
29
+ "redbelly-doctor": "./dist/doctor-cli.js",
30
+ "redbelly": "./dist/redbelly.js"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "scripts": {
37
+ "build": "node scripts/ensure-deps-built.mjs && tsc -p tsconfig.json && node -e \"for (const f of ['cli.js','doctor-cli.js','redbelly.js']) require('fs').chmodSync('dist/'+f,0o755)\"",
38
+ "test": "npm run build && node --test --test-reporter=spec --test-concurrency=1 test/unit.test.mjs test/preflight.test.mjs test/doctor.test.mjs test/gas.test.mjs test/ship.test.mjs",
39
+ "test:live": "npm run build && node --test --test-reporter=spec test/live.test.mjs",
40
+ "prepack": "npm run build"
41
+ },
42
+ "dependencies": {
43
+ "@gatedpath/agent-rules": "0.1.0",
44
+ "@gatedpath/chains": "0.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.20.2",
48
+ "typescript": "^5.9.3"
49
+ }
50
+ }