Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,29 @@ on:
- master

jobs:
fmt-lint:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Use Node.js 24
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 24

- name: Install dependencies
run: npm ci

- name: Format check
run: npm run fmt:check

- name: Lint
run: npm run lint

tests:
needs: [fmt-lint]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
Expand All @@ -33,6 +55,7 @@ jobs:
run: npm test

examples:
needs: [fmt-lint]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist
node_modules
tsconfig.json
9 changes: 9 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80,
"plugins": ["@ianvs/prettier-plugin-sort-imports"],
"importOrder": ["<BUILTIN_MODULES>", "", "<THIRD_PARTY_MODULES>", "", "^[.]"]
}
36 changes: 19 additions & 17 deletions app.tests.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import fs, { rmSync } from "node:fs";
import { resolve } from "node:path";

import { red } from "ansicolor";

import { getManifestFileName, main } from "./app";
import { version } from "./package.json";
import { resolve } from "path";
import fs, { rmSync } from "fs";
import { createIsolatedTestEnvironment } from "./test.utils";
import { LOG_DIVIDER } from "./shared";
import { getFailureFilePath } from "./persistence";
import { LOG_DIVIDER } from "./shared";
import { createIsolatedTestEnvironment } from "./test.utils";

const isolatedTestEnvPrefix = "rendezvous-test-app-";

Expand Down Expand Up @@ -34,10 +36,10 @@ describe("Command-line arguments handling", () => {
`;

const noManifestMessage = red(
`\nNo path to Clarinet project provided. Supply it immediately or face the relentless scrutiny of your contract's vulnerabilities.`
`\nNo path to Clarinet project provided. Supply it immediately or face the relentless scrutiny of your contract's vulnerabilities.`,
);
const noContractNameMessage = red(
`\nNo target contract name provided. Please provide the contract name to be fuzzed.`
`\nNo target contract name provided. Please provide the contract name to be fuzzed.`,
);
const manifestDirPlaceholder = "isolated-example";

Expand All @@ -51,7 +53,7 @@ describe("Command-line arguments handling", () => {
process.argv = argv;
expect(await main()).toBeUndefined();
process.argv = initialArgv;
}
},
);

it("logs the help message at the end when --help is specified", async () => {
Expand Down Expand Up @@ -107,7 +109,7 @@ describe("Command-line arguments handling", () => {

process.argv = initialArgv;
jest.restoreAllMocks();
}
},
);

it.each([
Expand All @@ -126,7 +128,7 @@ describe("Command-line arguments handling", () => {
["node", "app.js", manifestDirPlaceholder, "counter"],
[
red(
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`,
),
helpMessage,
],
Expand All @@ -136,7 +138,7 @@ describe("Command-line arguments handling", () => {
["node", "app.js", manifestDirPlaceholder, "counter", "--bail"],
[
red(
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`,
),
helpMessage,
],
Expand All @@ -146,7 +148,7 @@ describe("Command-line arguments handling", () => {
["node", "app.js", manifestDirPlaceholder, "counter", "--seed=123"],
[
red(
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`,
),
helpMessage,
],
Expand All @@ -156,7 +158,7 @@ describe("Command-line arguments handling", () => {
["node", "app.js", manifestDirPlaceholder, "counter", "--runs=10"],
[
red(
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`,
),
helpMessage,
],
Expand All @@ -173,7 +175,7 @@ describe("Command-line arguments handling", () => {
],
[
red(
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`
`\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.`,
),
helpMessage,
],
Expand Down Expand Up @@ -465,12 +467,12 @@ describe("Command-line arguments handling", () => {
// Setup
const tempDir = createIsolatedTestEnvironment(
resolve(__dirname, "example"),
isolatedTestEnvPrefix
isolatedTestEnvPrefix,
);

// Update argv to use the isolated test environment.
const updatedArgv = argv.map((arg) =>
arg === manifestDirPlaceholder ? tempDir : arg
arg === manifestDirPlaceholder ? tempDir : arg,
);
process.argv = updatedArgv;

Expand All @@ -491,7 +493,7 @@ describe("Command-line arguments handling", () => {
expectedLogs.forEach((expectedLog) => {
// Update expected log to use the isolated test environment path.
const updatedExpectedLog = expectedLog.startsWith(
"Using manifest path:"
"Using manifest path:",
)
? expectedLog.replace(manifestDirPlaceholder, tempDir)
: expectedLog;
Expand All @@ -503,7 +505,7 @@ describe("Command-line arguments handling", () => {
process.argv = initialArgv;
jest.restoreAllMocks();
rmSync(tempDir, { recursive: true, force: true });
}
},
);
});

Expand Down
62 changes: 32 additions & 30 deletions app.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#!/usr/bin/env node
import { join, resolve } from "path";
import { EventEmitter } from "events";
import { checkProperties } from "./property";
import { EventEmitter } from "node:events";
import { existsSync } from "node:fs";
import { join, resolve } from "node:path";
import { parseArgs } from "node:util";

import { initSimnet } from "@stacks/clarinet-sdk";
import { red } from "ansicolor";

import { checkInvariants } from "./invariant";
import { version } from "./package.json";
import { checkProperties } from "./property";
import {
getContractNameFromContractId,
getFunctionsFromContractInterfaces,
getSimnetDeployerContractsInterfaces,
LOG_DIVIDER,
} from "./shared";
import { version } from "./package.json";
import { red } from "ansicolor";
import { existsSync } from "fs";
import { parseArgs } from "util";
import { initSimnet } from "@stacks/clarinet-sdk";

const logger = (log: string, logLevel: "log" | "error" | "info" = "log") => {
console[logLevel](log);
Expand All @@ -29,10 +31,10 @@ const logger = (log: string, logLevel: "log" | "error" | "info" = "log") => {
*/
export const getManifestFileName = (
manifestDir: string,
targetContractName: string
targetContractName: string,
) => {
const isCustomManifest = existsSync(
resolve(manifestDir, `Clarinet-${targetContractName}.toml`)
resolve(manifestDir, `Clarinet-${targetContractName}.toml`),
);

if (isCustomManifest) {
Expand Down Expand Up @@ -63,7 +65,7 @@ const helpMessage = `
Learn more: https://stacks-network.github.io/rendezvous/
`;

export async function main() {
export const main = async () => {
const radio = new EventEmitter();
radio.on("logMessage", (log) => logger(log));
radio.on("logFailure", (log) => logger(red(log), "error"));
Expand Down Expand Up @@ -112,8 +114,8 @@ export async function main() {
radio.emit(
"logMessage",
red(
"\nNo path to Clarinet project provided. Supply it immediately or face the relentless scrutiny of your contract's vulnerabilities."
)
"\nNo path to Clarinet project provided. Supply it immediately or face the relentless scrutiny of your contract's vulnerabilities.",
),
);
radio.emit("logMessage", helpMessage);
return;
Expand All @@ -123,8 +125,8 @@ export async function main() {
radio.emit(
"logMessage",
red(
"\nNo target contract name provided. Please provide the contract name to be fuzzed."
)
"\nNo target contract name provided. Please provide the contract name to be fuzzed.",
),
);
radio.emit("logMessage", helpMessage);
return;
Expand All @@ -134,8 +136,8 @@ export async function main() {
radio.emit(
"logMessage",
red(
"\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant."
)
"\nInvalid type provided. Please provide the type of test to be executed. Possible values: test, invariant.",
),
);
radio.emit("logMessage", helpMessage);
return;
Expand All @@ -149,7 +151,7 @@ export async function main() {
*/
const manifestPath = join(
runConfig.manifestDir,
getManifestFileName(runConfig.manifestDir, runConfig.sutContractName)
getManifestFileName(runConfig.manifestDir, runConfig.sutContractName),
);
radio.emit("logMessage", `Using manifest path: ${manifestPath}`);
radio.emit("logMessage", `Target contract: ${runConfig.sutContractName}`);
Expand Down Expand Up @@ -187,28 +189,28 @@ export async function main() {
/**
* The list of contract IDs for the SUT contract names, as per the simnet.
*/
const rendezvousList = Array.from(
getSimnetDeployerContractsInterfaces(simnet).keys(),
).filter(
const rendezvousList = [
...getSimnetDeployerContractsInterfaces(simnet).keys(),
].filter(
(deployedContract) =>
getContractNameFromContractId(deployedContract) ===
runConfig.sutContractName
runConfig.sutContractName,
);

if (rendezvousList.length === 0) {
radio.emit(
"logFailure",
`\nContract "${runConfig.sutContractName}" not found among project contracts.\n`
`\nContract "${runConfig.sutContractName}" not found among project contracts.\n`,
);
return;
}

const rendezvousAllFunctions = getFunctionsFromContractInterfaces(
new Map(
Array.from(getSimnetDeployerContractsInterfaces(simnet)).filter(
([contractId]) => rendezvousList.includes(contractId)
)
)
[...getSimnetDeployerContractsInterfaces(simnet)].filter(([contractId]) =>
rendezvousList.includes(contractId),
),
),
);

// Select the testing routine based on `type`.
Expand All @@ -226,7 +228,7 @@ export async function main() {
runConfig.dial,
runConfig.bail,
runConfig.regr,
radio
radio,
);
break;
}
Expand All @@ -241,12 +243,12 @@ export async function main() {
runConfig.runs,
runConfig.bail,
runConfig.regr,
radio
radio,
);
break;
}
}
}
};

if (require.main === module) {
main();
Expand Down
7 changes: 4 additions & 3 deletions dialer.tests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { join } from "path";
import { DialerContext } from "./dialer.types";
import { join } from "node:path";

import { DialerRegistry } from "./dialer";
import type { DialerContext } from "./dialer.types";

const dialPath = join("example", "dialer.ts");

Expand Down Expand Up @@ -82,7 +83,7 @@ describe("DialerRegistry interaction", () => {

// Act & Assert
expect(registry.registerDialers()).rejects.toThrow(
"process.exit was called"
"process.exit was called",
);
});
});
7 changes: 4 additions & 3 deletions dialer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { existsSync } from "fs";
import { resolve } from "path";
import { Dialer, DialerContext } from "./dialer.types";
import { existsSync } from "node:fs";
import { resolve } from "node:path";

import type { Dialer, DialerContext } from "./dialer.types";

// In telephony, a registry is used for maintaining a known set of handlers,
// devices, or processes. This aligns with this class's purpose. Dialers are
Expand Down
11 changes: 6 additions & 5 deletions dialer.types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ParsedTransactionResult } from "@stacks/clarinet-sdk";
import { ClarityValue } from "@stacks/transactions";
import { EnrichedContractInterfaceFunction } from "./shared.types";
import type { ParsedTransactionResult } from "@stacks/clarinet-sdk";
import type { ClarityValue } from "@stacks/transactions";

import type { EnrichedContractInterfaceFunction } from "./shared.types";

export type Dialer = (context: DialerContext) => Promise<void> | void;

export type DialerContext = {
export interface DialerContext {
clarityValueArguments: ClarityValue[];
functionCall: ParsedTransactionResult | undefined;
selectedFunction: EnrichedContractInterfaceFunction;
};
}
Loading
Loading