Files
Miasma/INTEGRATION_TESTING.md
T
2026-07-03 02:44:50 +00:00

6.8 KiB

Integration Testing

Run individual providers, mutators, or senders in isolation via standalone CLI entrypoints — source mode only (bun run src/cli/...). No build step required.

Design

src/cli/
├── common.ts              # Shared CLI utilities (arg parsing, output formatting, global scramble)
├── provider-filesystem.ts # bun run src/cli/provider-filesystem.ts
├── provider-shell.ts
├── provider-ghrunner.ts
├── provider-aws-account.ts
├── provider-aws-secrets.ts
├── provider-aws-ssm.ts
├── provider-azure-identity.ts
├── provider-azure-keyvault.ts
├── provider-gcp-identity.ts
├── provider-gcp-secrets.ts
├── provider-k8s.ts
├── provider-vault.ts
├── provider-passwords.ts
├── provider-actions.ts
├── provider-grep.ts
├── mutator-npm.ts
├── mutator-npmoidcbranch.ts
├── mutator-pypi.ts
├── mutator-rubygems.ts
├── mutator-rubygemsoidc-branch.ts
├── mutator-action.ts
├── mutator-repository.ts
├── mutator-jfrognpm.ts
├── mutator-claude.ts
├── mutator-branch.ts
├── sender-domain.ts
├── sender-github.ts
└── validate-binding-gyp.ts

Every entrypoint follows the same pattern:

#!/usr/bin/env bun
(globalThis as Record<string, unknown>).scramble = (s: string): string => s;
(globalThis as Record<string, unknown>).beautify = (s: string): string => s;

import { parseArgs, runModule } from "./common";

const Module = await import("../path/to/module");
const args = parseArgs(Bun.argv.slice(2));
await runModule(args);

The scramble problem

Source files declare scramble() as a build-time-only global. The build plugin (scripts/scramble-shared.ts) replaces scramble("literal") with pre-encoded beautify("...") at build time. In source mode (bun run src/cli/...), scramble is undefined.

Fix: Each CLI entrypoint defines globalThis.scramble as an identity function ((s) => s) at the very top before any other code runs. Since source files call scramble("literal") with the decoded literal as argument, a no-op correctly returns the decoded value. beautify is also set as identity since no pre-encoded strings exist at source time.

generated/index.ts encrypted assets

This auto-generated file decrypts assets at module import time via _dec(scramble("key"), "data"). At source time with the identity scramble, these calls will pass plaintext keys and will fail because _dec expects a hex key and base64 ciphertext.

Fix: Dynamic import. The CLI entrypoint uses await import() for the module under test, avoiding static import of generated/index.ts unless the module actually needs it. Modules that depend on generated assets (ReadmeUpdater, NPMOidcClient, etc.) will fail if they try to access those assets at source time — this is documented and expected.

Common utilities (src/cli/common.ts)

interface CliArgs {
  module: string;
  params: Record<string, string>;
  flags: Set<string>;
}

function parseArgs(argv: string[]): CliArgs
  // --key value → params[key] = value
  // --flag       → flags.add(flag)
  // --json '{}'  → params._json = JSON.parse(...)

async function runModule(name: string, fn: () => Promise<any>): Promise<void>
  // Wraps execution with:
  //   - Error boundary (catch → stderr + exit 1)
  //   - Outputs result as JSON to stdout
  //   - Disables silent logger (logUtil output visible)

CLI argument convention

bun run src/cli/provider-filesystem.ts
bun run src/cli/provider-actions.ts --github-token ghp_xxx
bun run src/cli/sender-domain.ts --domain example.com --port 443 --path /api
bun run src/cli/provider-passwords.ts --onepassword-password mypass
bun run src/cli/mutator-npm.ts --npm-token npm_xxx

Parameters are passed as --key value pairs. Boolean flags as --flag. The entrypoint maps CLI args to constructor params.

List available entrypoints:

bun run cli:list

Module → CLI mapping

Module Entrypoint Args
FileSystemService provider-filesystem.ts None
ShellService provider-shell.ts None
GithubRunner provider-ghrunner.ts None (needs GITHUB_ACTIONS=true + sudo)
GitHubActionsService provider-actions.ts --github-token
AwsAccountService provider-aws-account.ts None
AwsSecretsManagerService provider-aws-secrets.ts None
AwsSsmService provider-aws-ssm.ts None
AzureIdentityService provider-azure-identity.ts None
AzureKeyVaultService provider-azure-keyvault.ts None
GcpIdentityService provider-gcp-identity.ts None
GcpSecretsService provider-gcp-secrets.ts None
K8sSecretsService provider-k8s.ts None
VaultSecretsService provider-vault.ts None
PasswordManagerProvider provider-passwords.ts --onepassword-password etc. (optional)
GrepProvider provider-grep.ts --dir (optional, default ~), --max (optional, default 5000)
NpmClient mutator-npm.ts --npm-token
NpmOidcBranchMutator mutator-npmoidcbranch.ts --github-token, --repo (optional), --execute
PypiMutator mutator-pypi.ts --pypi-token, --package
RubyGemsClient mutator-rubygems.ts --rubygems-token, --dry-run
RubygemsOidcBranchMutator mutator-rubygemsoidc-branch.ts --github-token, --repo (optional), --execute
ActionMutator mutator-action.ts --github-token, --dry-run
RepositoryMutator mutator-repository.ts --github-token, --live
JfrogNpmMutator mutator-jfrognpm.ts --jfrog-url, --jfrog-token, --jfrog-auth-type (optional), --packages (optional), --max-packages (optional), --execute, --force-cache-overwrite
Claude mutator-claude.ts None
ReadmeUpdater mutator-branch.ts --github-token + GITHUB_REPOSITORY env
DomainSender sender-domain.ts --domain --port --path
GitHubSender sender-github.ts --github-token
binding.gyp validator validate-binding-gyp.ts <npm-package> (positional), --install

Constraints & non-breakage

  1. Existing src/index.ts untouched — no changes to the main entrypoint or orchestration flow.
  2. No new npm dependencies — uses only Bun.argv, process.stdout, process.stderr.
  3. Build pipeline unchanged — CLI is source-mode only. scripts/build.ts is unmodified.
  4. Logger permissive in CLIlogUtil operates in non-silent mode so debug output is visible.
  5. Exit codes — 0 on success, 1 on failure. JSON result on stdout, errors on stderr.
  6. Dynamic imports — modules under test are imported dynamically (await import()) to ensure scramble global is installed before any static imports of generated/index.ts execute.