Files
Miasma_Archive/INTEGRATION_TESTING.md
2026-06-13 09:36:13 -04:00

144 lines
6.8 KiB
Markdown

# 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:
```typescript
#!/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`)
```typescript
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 CLI**`logUtil` 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.