Files
apophis-fastify/src/cli/commands/init/scaffolds/index.ts
T

371 lines
11 KiB
TypeScript
Raw Normal View History

/**
* S3: Init command scaffold templates
* Each preset returns a config object and file contents for the init command.
*/
import type { ApophisConfig, PresetDefinition, ProfileDefinition, EnvironmentPolicy } from '../../../core/types.js';
export interface ScaffoldResult {
config: ApophisConfig;
readmeContent: string;
}
// ─────────────────────────────────────────────────────────────────────────────
// safe-ci: Minimal CI-safe preset (default)
// ─────────────────────────────────────────────────────────────────────────────
export function safeCiScaffold(): ScaffoldResult {
const preset: PresetDefinition = {
name: 'safe-ci',
timeout: 5000,
parallel: false,
chaos: false,
observe: false,
};
const profile: ProfileDefinition = {
name: 'quick',
mode: 'verify',
preset: 'safe-ci',
routes: ['POST /users'],
};
const envLocal: EnvironmentPolicy = {
name: 'local',
allowVerify: true,
allowObserve: true,
allowQualify: false,
allowChaos: false,
allowBlocking: true,
requireSink: false,
};
const config: ApophisConfig = {
mode: 'verify',
profiles: { quick: profile },
presets: { 'safe-ci': preset },
environments: { local: envLocal },
};
const readmeContent = `
# APOPHIS Setup — safe-ci preset
This project was scaffolded with \`apophis init --preset safe-ci\`.
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Add behavioral contracts to your route schemas using \`x-ensures\`.
3. Run: apophis verify --profile quick
## What This Preset Does
- Runs only behavioral contracts (not schema-only routes).
- No chaos, no observe, no stateful testing.
- Safe for CI pipelines.
- Timeout: 5s per route.
## Example Behavioral Contract
Add this inside your route schema to check that a created resource is retrievable:
\`\`\`javascript
"x-ensures": [
"response_code(GET /users/{response_body(this).id}) == 200"
]
\`\`\`
If \`apophis verify\` says "No behavioral contracts found", it means your routes have schemas but no \`x-ensures\` or \`x-requires\` clauses. Add at least one clause per route you want to verify.
## Next Steps
- Add more routes to the \`routes\` array in your profile.
- Try \`apophis init --preset platform-observe\` for production readiness.
- Try \`apophis init --preset protocol-lab\` for multi-step flows.
`;
return { config, readmeContent };
}
// ─────────────────────────────────────────────────────────────────────────────
// platform-observe: Production-ready with observe mode
// ─────────────────────────────────────────────────────────────────────────────
export function platformObserveScaffold(): ScaffoldResult {
const preset: PresetDefinition = {
name: 'platform-observe',
timeout: 10000,
parallel: true,
chaos: false,
observe: true,
};
const profile: ProfileDefinition = {
name: 'staging-observe',
mode: 'observe',
preset: 'platform-observe',
routes: [],
};
const envStaging: EnvironmentPolicy = {
name: 'staging',
allowVerify: true,
allowObserve: true,
allowQualify: true,
allowChaos: false,
allowBlocking: false,
requireSink: true,
};
const envProduction: EnvironmentPolicy = {
name: 'production',
allowVerify: true,
allowObserve: true,
allowQualify: false,
allowChaos: false,
allowBlocking: false,
requireSink: true,
};
const config: ApophisConfig = {
mode: 'observe',
profile: 'staging-observe',
profiles: { 'staging-observe': profile },
presets: { 'platform-observe': preset },
environments: {
staging: envStaging,
production: envProduction,
},
};
const readmeContent = `
# APOPHIS Setup — platform-observe preset
This project was scaffolded with \`apophis init --preset platform-observe\`.
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Configure your reporting sink (see environments.staging.requireSink).
3. Run: apophis observe --profile staging-observe
## What This Preset Does
- Enables observe mode for production readiness checks.
- Validates non-blocking semantics and sink configuration.
- Parallel execution for faster feedback.
- Requires sink config in staging/production.
## Safety
- Observe mode is non-blocking by default.
- Production requires explicit policy to enable blocking.
- Chaos is disabled in this preset.
## Next Steps
- Add a sink configuration to your environment policy.
- Run \`apophis doctor\` to validate the full setup.
`;
return { config, readmeContent };
}
// ─────────────────────────────────────────────────────────────────────────────
// llm-safe: Minimal preset for LLM-generated codebases
// ─────────────────────────────────────────────────────────────────────────────
export function llmSafeScaffold(): ScaffoldResult {
const preset: PresetDefinition = {
name: 'llm-safe',
timeout: 3000,
parallel: false,
chaos: false,
observe: false,
};
const profile: ProfileDefinition = {
name: 'llm-check',
mode: 'verify',
preset: 'llm-safe',
routes: [],
};
const envLocal: EnvironmentPolicy = {
name: 'local',
allowVerify: true,
allowObserve: false,
allowQualify: false,
allowChaos: false,
allowBlocking: false,
requireSink: false,
};
const config: ApophisConfig = {
mode: 'verify',
profile: 'llm-check',
profiles: { 'llm-check': profile },
presets: { 'llm-safe': preset },
environments: { local: envLocal },
};
const readmeContent = `
# APOPHIS Setup — llm-safe preset
This project was scaffolded with \`apophis init --preset llm-safe\`.
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Add behavioral contracts to your route schemas using \`x-ensures\`.
3. Run: apophis verify --profile llm-check
## What This Preset Does
- Ultra-minimal preset for LLM-generated codebases.
- 3s timeout per route (fast feedback).
- No observe, no qualify, no chaos — verify only.
- Conservative defaults to avoid surprising failures.
## Example Behavioral Contract
Add this inside your route schema to check that a created resource is retrievable:
\`\`\`javascript
"x-ensures": [
"response_code(GET /users/{response_body(this).id}) == 200"
]
\`\`\`
If \`apophis verify\` says "No behavioral contracts found", it means your routes have schemas but no \`x-ensures\` or \`x-requires\` clauses. Add at least one clause per route you want to verify.
## Next Steps
- Add routes to the \`routes\` array once you have behavioral contracts.
- Run \`apophis doctor\` to check for missing dependencies.
`;
return { config, readmeContent };
}
// ─────────────────────────────────────────────────────────────────────────────
// protocol-lab: Multi-step flow and stateful testing
// ─────────────────────────────────────────────────────────────────────────────
export function protocolLabScaffold(): ScaffoldResult {
const preset: PresetDefinition = {
name: 'protocol-lab',
timeout: 15000,
parallel: false,
chaos: true,
observe: false,
};
const profile: ProfileDefinition = {
name: 'oauth-nightly',
mode: 'qualify',
preset: 'protocol-lab',
routes: [],
seed: 42,
};
const envLocal: EnvironmentPolicy = {
name: 'local',
allowVerify: true,
allowObserve: true,
allowQualify: true,
allowChaos: true,
allowBlocking: true,
requireSink: false,
};
const envTest: EnvironmentPolicy = {
name: 'test',
allowVerify: true,
allowObserve: true,
allowQualify: true,
allowChaos: true,
allowBlocking: true,
requireSink: false,
};
const config: ApophisConfig = {
mode: 'qualify',
profile: 'oauth-nightly',
profiles: { 'oauth-nightly': profile },
presets: { 'protocol-lab': preset },
environments: {
local: envLocal,
test: envTest,
},
};
const readmeContent = `
# APOPHIS Setup — protocol-lab preset
This project was scaffolded with \`apophis init --preset protocol-lab\`.
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Define multi-step flows in your route schemas.
3. Run: apophis qualify --profile oauth-nightly --seed 42
## What This Preset Does
- Enables qualify mode for stateful and scenario testing.
- Chaos engineering enabled (local/test only).
- Deep depth for thorough exploration.
- 15s timeout per route.
## Safety
- Chaos is blocked in production by default.
- Use \`apophis doctor\` to validate environment safety before qualifying.
## Machine Output in CI
Qualify can produce large output. In CI, use machine-readable formats and filter events:
- \`--format json\` emits a single stable JSON artifact (good for small-to-medium runs).
- \`--format ndjson\` emits one event per line (good for streaming parsers).
- Use \`--quiet\` to suppress human progress text.
- Pipe ndjson to \`jq\` or a custom filter to extract only failures:
\`\`\`bash
apophis qualify --profile oauth-nightly --format ndjson | jq 'select(.type == "route.failed")'
\`\`\`
- For very large runs, consider writing artifacts to a directory and parsing the JSON file instead of stdout:
\`\`\`bash
apophis qualify --profile oauth-nightly --format json --artifact-dir reports/apophis
\`\`\`
## Next Steps
- Define scenario sequences in your config.
- Add route allowlists for chaos if needed.
- Run \`apophis replay --artifact <path>\` to debug failures.
`;
return { config, readmeContent };
}
// ─────────────────────────────────────────────────────────────────────────────
// Preset registry
// ─────────────────────────────────────────────────────────────────────────────
export const PRESETS: Record<string, () => ScaffoldResult> = {
'safe-ci': safeCiScaffold,
'platform-observe': platformObserveScaffold,
'llm-safe': llmSafeScaffold,
'protocol-lab': protocolLabScaffold,
};
export function getPresetNames(): string[] {
return Object.keys(PRESETS);
}
export function getScaffoldForPreset(preset: string): ScaffoldResult | null {
const fn = PRESETS[preset];
return fn ? fn() : null;
}