test(#804): reproduce unknown installer argument
This commit is contained in:
54
docs/scratchpads/804-install-unknown-flags.md
Normal file
54
docs/scratchpads/804-install-unknown-flags.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Issue #804 — fail closed on unknown installer arguments
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Implement Part 1 of Gitea issue #804 only: `tools/install.sh` must reject every unrecognized flag or argument with an actionable STDERR error and nonzero exit before installation starts.
|
||||||
|
|
||||||
|
## Scope and constraints
|
||||||
|
|
||||||
|
- Preserve all currently recognized options and behavior, including `-y` and `--ref <branch>`.
|
||||||
|
- No positional arguments are currently accepted by the parser.
|
||||||
|
- Do not add `--next`, `MOSAIC_NEXT`, prerelease routing, or any Part 2 behavior.
|
||||||
|
- TDD is mandatory: add and observe a failing process-level regression test before changing `tools/install.sh`.
|
||||||
|
- Worker lifecycle ends after branch push, PR creation, and coordinator notification; do not merge or close #804.
|
||||||
|
- Existing launcher-owned changes in `.mosaic/orchestrator/mission.json` and `.mosaic/orchestrator/session.lock` are out of scope and must not be committed.
|
||||||
|
|
||||||
|
## Requirements and acceptance criteria
|
||||||
|
|
||||||
|
- Unknown input names the offending argument on STDERR.
|
||||||
|
- STDERR includes a short installer usage hint.
|
||||||
|
- Exit status is nonzero.
|
||||||
|
- The installer does not invoke npm or otherwise proceed into installation.
|
||||||
|
- Existing recognized flags remain unchanged.
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
1. Add a process-level Vitest regression using the installer test location under `packages/mosaic/src/commands/`.
|
||||||
|
2. Run the focused test and record the expected RED failure.
|
||||||
|
3. Commit the RED test as `test(#804): ...`.
|
||||||
|
4. Replace the parser catch-all with a fail-closed STDERR error and usage hint.
|
||||||
|
5. Update concise installer-facing documentation without introducing prerelease behavior.
|
||||||
|
6. Run focused tests, shell syntax validation, package tests, lint, typecheck, and format checks.
|
||||||
|
7. Run independent review tooling and remediate findings.
|
||||||
|
8. Commit as `fix(#804): ...`, queue-guard, push, open a PR containing `Closes #804.`, notify the coordinator, and exit.
|
||||||
|
|
||||||
|
## Budget
|
||||||
|
|
||||||
|
- No explicit token cap supplied.
|
||||||
|
- Working estimate: 8K tokens; narrow two-file behavior/test change plus concise docs and delivery gates.
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
|
||||||
|
- 2026-07-17: Loaded mission state, issue #804, delivery/QA/documentation rails, and relevant TDD/Vitest/pnpm/Gitea skills.
|
||||||
|
- 2026-07-17: Confirmed the parser has no legitimate positional arguments and currently drops all unmatched input via `*) shift ;;`.
|
||||||
|
- 2026-07-17: Installed locked workspace dependencies with a worktree-local pnpm store; no lockfile changes.
|
||||||
|
- 2026-07-17: Added the process-level unknown-argument regression with an isolated `$HOME` and npm shim.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- RED: `pnpm --filter @mosaicstack/mosaic exec vitest run src/commands/install-arguments.spec.ts` — expected failure: installer exited `0` instead of nonzero at the exit-status assertion; confirms the test reproduces the silent-drop defect before production changes.
|
||||||
|
|
||||||
|
## Risks and blockers
|
||||||
|
|
||||||
|
- Part 2 remains owner-gated under #805 and is intentionally excluded.
|
||||||
|
- Test harness must isolate `$HOME` and shim npm so the pre-fix installer cannot mutate operator state or contact the registry.
|
||||||
41
packages/mosaic/src/commands/install-arguments.spec.ts
Normal file
41
packages/mosaic/src/commands/install-arguments.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import { existsSync } from 'node:fs';
|
||||||
|
import { chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||||
|
import { tmpdir } from 'node:os';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const INSTALLER_PATH = fileURLToPath(new URL('../../../../tools/install.sh', import.meta.url));
|
||||||
|
|
||||||
|
describe('installer arguments', () => {
|
||||||
|
it('rejects an unknown argument before installation starts', async () => {
|
||||||
|
const home = await mkdtemp(join(tmpdir(), 'mosaic-installer-args-'));
|
||||||
|
const bin = join(home, 'bin');
|
||||||
|
const npmMarker = join(home, 'npm-called');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mkdir(bin);
|
||||||
|
const npmShim = join(bin, 'npm');
|
||||||
|
await writeFile(npmShim, `#!/bin/sh\n: > "${npmMarker}"\n`);
|
||||||
|
await chmod(npmShim, 0o755);
|
||||||
|
|
||||||
|
const result = spawnSync('bash', [INSTALLER_PATH, '--cli', '--bogus'], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
HOME: home,
|
||||||
|
MOSAIC_NO_COLOR: '1',
|
||||||
|
PATH: `${bin}:${process.env.PATH ?? ''}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.status).not.toBe(0);
|
||||||
|
expect(result.stderr).toContain('Unknown argument: --bogus');
|
||||||
|
expect(result.stderr).toMatch(/Usage: .*install\.sh/);
|
||||||
|
expect(existsSync(npmMarker)).toBe(false);
|
||||||
|
} finally {
|
||||||
|
await rm(home, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user