qa360 2.2.1 → 2.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +79 -0
- package/cli/dist/cli-minimal.d.ts +6 -0
- package/cli/dist/cli-minimal.js +36 -0
- package/cli/dist/commands/ai.d.ts +43 -0
- package/cli/dist/commands/ai.js +616 -0
- package/cli/dist/commands/ask.d.ts +94 -0
- package/cli/dist/commands/ask.js +582 -0
- package/cli/dist/commands/coverage.d.ts +8 -0
- package/cli/dist/commands/coverage.js +252 -0
- package/cli/dist/commands/crawl.d.ts +24 -0
- package/cli/dist/commands/crawl.js +121 -0
- package/cli/dist/commands/doctor.d.ts +54 -0
- package/cli/dist/commands/doctor.js +513 -0
- package/cli/dist/commands/examples.d.ts +33 -0
- package/cli/dist/commands/examples.js +193 -0
- package/cli/dist/commands/explain.d.ts +27 -0
- package/cli/dist/commands/explain.js +630 -0
- package/cli/dist/commands/flakiness.d.ts +73 -0
- package/cli/dist/commands/flakiness.js +435 -0
- package/cli/dist/commands/generate.d.ts +66 -0
- package/cli/dist/commands/generate.js +438 -0
- package/cli/dist/commands/history.d.ts +76 -0
- package/cli/dist/commands/history.js +755 -0
- package/cli/dist/commands/init.d.ts +106 -0
- package/cli/dist/commands/init.js +616 -0
- package/cli/dist/commands/monitor.d.ts +27 -0
- package/cli/dist/commands/monitor.js +225 -0
- package/cli/dist/commands/ollama.d.ts +40 -0
- package/cli/dist/commands/ollama.js +346 -0
- package/cli/dist/commands/pack.d.ts +70 -0
- package/cli/dist/commands/pack.js +413 -0
- package/cli/dist/commands/regression.d.ts +8 -0
- package/cli/dist/commands/regression.js +340 -0
- package/cli/dist/commands/repair.d.ts +26 -0
- package/cli/dist/commands/repair.js +307 -0
- package/cli/dist/commands/report.d.ts +62 -0
- package/cli/dist/commands/report.js +378 -0
- package/cli/dist/commands/retry.d.ts +43 -0
- package/cli/dist/commands/retry.js +275 -0
- package/cli/dist/commands/run.d.ts +41 -0
- package/cli/dist/commands/run.js +171 -0
- package/cli/dist/commands/scan.d.ts +5 -0
- package/cli/dist/commands/scan.js +155 -0
- package/cli/dist/commands/secrets.d.ts +58 -0
- package/cli/dist/commands/secrets.js +289 -0
- package/cli/dist/commands/serve.d.ts +13 -0
- package/cli/dist/commands/serve.js +156 -0
- package/cli/dist/commands/slo.d.ts +8 -0
- package/cli/dist/commands/slo.js +327 -0
- package/cli/dist/commands/verify.d.ts +32 -0
- package/cli/dist/commands/verify.js +278 -0
- package/cli/dist/core/adapters/gitleaks-secrets.d.ts +114 -0
- package/cli/dist/core/adapters/gitleaks-secrets.js +410 -0
- package/cli/dist/core/adapters/jest-adapter.d.ts +44 -0
- package/cli/dist/core/adapters/jest-adapter.js +261 -0
- package/cli/dist/core/adapters/k6-perf.d.ts +85 -0
- package/cli/dist/core/adapters/k6-perf.js +398 -0
- package/cli/dist/core/adapters/osv-deps.d.ts +123 -0
- package/cli/dist/core/adapters/osv-deps.js +372 -0
- package/cli/dist/core/adapters/playwright-native-adapter.d.ts +121 -0
- package/cli/dist/core/adapters/playwright-native-adapter.js +339 -0
- package/cli/dist/core/adapters/playwright-native-api.d.ts +183 -0
- package/cli/dist/core/adapters/playwright-native-api.js +465 -0
- package/cli/dist/core/adapters/playwright-ui.d.ts +197 -0
- package/cli/dist/core/adapters/playwright-ui.js +864 -0
- package/cli/dist/core/adapters/pytest-adapter.d.ts +49 -0
- package/cli/dist/core/adapters/pytest-adapter.js +324 -0
- package/cli/dist/core/adapters/semgrep-sast.d.ts +99 -0
- package/cli/dist/core/adapters/semgrep-sast.js +322 -0
- package/cli/dist/core/adapters/unit-test-types.d.ts +119 -0
- package/cli/dist/core/adapters/unit-test-types.js +6 -0
- package/cli/dist/core/adapters/vitest-adapter.d.ts +46 -0
- package/cli/dist/core/adapters/vitest-adapter.js +272 -0
- package/cli/dist/core/adapters/zap-dast.d.ts +133 -0
- package/cli/dist/core/adapters/zap-dast.js +424 -0
- package/cli/dist/core/ai/anthropic-provider.d.ts +50 -0
- package/cli/dist/core/ai/anthropic-provider.js +223 -0
- package/cli/dist/core/ai/deepseek-provider.d.ts +81 -0
- package/cli/dist/core/ai/deepseek-provider.js +266 -0
- package/cli/dist/core/ai/index.d.ts +60 -0
- package/cli/dist/core/ai/index.js +18 -0
- package/cli/dist/core/ai/llm-client.d.ts +45 -0
- package/cli/dist/core/ai/llm-client.js +7 -0
- package/cli/dist/core/ai/mock-provider.d.ts +49 -0
- package/cli/dist/core/ai/mock-provider.js +121 -0
- package/cli/dist/core/ai/ollama-provider.d.ts +78 -0
- package/cli/dist/core/ai/ollama-provider.js +216 -0
- package/cli/dist/core/ai/openai-provider.d.ts +48 -0
- package/cli/dist/core/ai/openai-provider.js +200 -0
- package/cli/dist/core/ai/provider-factory.d.ts +160 -0
- package/cli/dist/core/ai/provider-factory.js +269 -0
- package/cli/dist/core/artifacts/index.d.ts +6 -0
- package/cli/dist/core/artifacts/index.js +6 -0
- package/cli/dist/core/artifacts/ui-artifacts.d.ts +133 -0
- package/cli/dist/core/artifacts/ui-artifacts.js +304 -0
- package/cli/dist/core/assertions/engine.d.ts +51 -0
- package/cli/dist/core/assertions/engine.js +530 -0
- package/cli/dist/core/assertions/index.d.ts +11 -0
- package/cli/dist/core/assertions/index.js +11 -0
- package/cli/dist/core/assertions/types.d.ts +121 -0
- package/cli/dist/core/assertions/types.js +37 -0
- package/cli/dist/core/auth/api-key-provider.d.ts +16 -0
- package/cli/dist/core/auth/api-key-provider.js +63 -0
- package/cli/dist/core/auth/aws-iam-provider.d.ts +35 -0
- package/cli/dist/core/auth/aws-iam-provider.js +177 -0
- package/cli/dist/core/auth/azure-ad-provider.d.ts +15 -0
- package/cli/dist/core/auth/azure-ad-provider.js +99 -0
- package/cli/dist/core/auth/basic-auth-provider.d.ts +26 -0
- package/cli/dist/core/auth/basic-auth-provider.js +111 -0
- package/cli/dist/core/auth/gcp-adc-provider.d.ts +27 -0
- package/cli/dist/core/auth/gcp-adc-provider.js +126 -0
- package/cli/dist/core/auth/index.d.ts +238 -0
- package/cli/dist/core/auth/index.js +82 -0
- package/cli/dist/core/auth/jwt-provider.d.ts +19 -0
- package/cli/dist/core/auth/jwt-provider.js +160 -0
- package/cli/dist/core/auth/manager.d.ts +84 -0
- package/cli/dist/core/auth/manager.js +230 -0
- package/cli/dist/core/auth/oauth2-provider.d.ts +17 -0
- package/cli/dist/core/auth/oauth2-provider.js +114 -0
- package/cli/dist/core/auth/totp-provider.d.ts +31 -0
- package/cli/dist/core/auth/totp-provider.js +134 -0
- package/cli/dist/core/auth/ui-login-provider.d.ts +26 -0
- package/cli/dist/core/auth/ui-login-provider.js +198 -0
- package/cli/dist/core/cache/index.d.ts +7 -0
- package/cli/dist/core/cache/index.js +6 -0
- package/cli/dist/core/cache/lru-cache.d.ts +203 -0
- package/cli/dist/core/cache/lru-cache.js +397 -0
- package/cli/dist/core/coverage/analyzer.d.ts +101 -0
- package/cli/dist/core/coverage/analyzer.js +415 -0
- package/cli/dist/core/coverage/collector.d.ts +74 -0
- package/cli/dist/core/coverage/collector.js +459 -0
- package/cli/dist/core/coverage/config.d.ts +37 -0
- package/cli/dist/core/coverage/config.js +156 -0
- package/cli/dist/core/coverage/index.d.ts +11 -0
- package/cli/dist/core/coverage/index.js +15 -0
- package/cli/dist/core/coverage/types.d.ts +267 -0
- package/cli/dist/core/coverage/types.js +6 -0
- package/cli/dist/core/coverage/vault.d.ts +95 -0
- package/cli/dist/core/coverage/vault.js +405 -0
- package/cli/dist/core/crawler/index.d.ts +57 -0
- package/cli/dist/core/crawler/index.js +281 -0
- package/cli/dist/core/crawler/journey-generator.d.ts +49 -0
- package/cli/dist/core/crawler/journey-generator.js +412 -0
- package/cli/dist/core/crawler/page-analyzer.d.ts +88 -0
- package/cli/dist/core/crawler/page-analyzer.js +709 -0
- package/cli/dist/core/crawler/selector-generator.d.ts +34 -0
- package/cli/dist/core/crawler/selector-generator.js +309 -0
- package/cli/dist/core/crawler/types.d.ts +353 -0
- package/cli/dist/core/crawler/types.js +6 -0
- package/cli/dist/core/dashboard/assets.d.ts +6 -0
- package/cli/dist/core/dashboard/assets.js +690 -0
- package/cli/dist/core/dashboard/index.d.ts +6 -0
- package/cli/dist/core/dashboard/index.js +5 -0
- package/cli/dist/core/dashboard/server.d.ts +72 -0
- package/cli/dist/core/dashboard/server.js +354 -0
- package/cli/dist/core/dashboard/types.d.ts +70 -0
- package/cli/dist/core/dashboard/types.js +5 -0
- package/cli/dist/core/discoverer/index.d.ts +115 -0
- package/cli/dist/core/discoverer/index.js +250 -0
- package/cli/dist/core/fixtures/index.d.ts +8 -0
- package/cli/dist/core/fixtures/index.js +8 -0
- package/cli/dist/core/fixtures/loader.d.ts +65 -0
- package/cli/dist/core/fixtures/loader.js +161 -0
- package/cli/dist/core/fixtures/resolver.d.ts +79 -0
- package/cli/dist/core/fixtures/resolver.js +181 -0
- package/cli/dist/core/fixtures/types.d.ts +75 -0
- package/cli/dist/core/fixtures/types.js +30 -0
- package/cli/dist/core/flakiness/index.d.ts +228 -0
- package/cli/dist/core/flakiness/index.js +384 -0
- package/cli/dist/core/generation/code-formatter.d.ts +111 -0
- package/cli/dist/core/generation/code-formatter.js +307 -0
- package/cli/dist/core/generation/code-generator.d.ts +144 -0
- package/cli/dist/core/generation/code-generator.js +293 -0
- package/cli/dist/core/generation/crawler-pack-generator.d.ts +44 -0
- package/cli/dist/core/generation/crawler-pack-generator.js +245 -0
- package/cli/dist/core/generation/generator.d.ts +40 -0
- package/cli/dist/core/generation/generator.js +76 -0
- package/cli/dist/core/generation/index.d.ts +32 -0
- package/cli/dist/core/generation/index.js +30 -0
- package/cli/dist/core/generation/pack-generator.d.ts +107 -0
- package/cli/dist/core/generation/pack-generator.js +416 -0
- package/cli/dist/core/generation/prompt-builder.d.ts +132 -0
- package/cli/dist/core/generation/prompt-builder.js +672 -0
- package/cli/dist/core/generation/source-analyzer.d.ts +213 -0
- package/cli/dist/core/generation/source-analyzer.js +657 -0
- package/cli/dist/core/generation/test-optimizer.d.ts +117 -0
- package/cli/dist/core/generation/test-optimizer.js +328 -0
- package/cli/dist/core/generation/types.d.ts +214 -0
- package/cli/dist/core/generation/types.js +4 -0
- package/cli/dist/core/hooks/compose.d.ts +61 -0
- package/cli/dist/core/hooks/compose.js +225 -0
- package/cli/dist/core/hooks/runner.d.ts +68 -0
- package/cli/dist/core/hooks/runner.js +303 -0
- package/cli/dist/core/index.d.ts +110 -0
- package/cli/dist/core/index.js +99 -0
- package/cli/dist/core/pack/migrator.d.ts +51 -0
- package/cli/dist/core/pack/migrator.js +304 -0
- package/cli/dist/core/pack/validator.d.ts +42 -0
- package/cli/dist/core/pack/validator.js +330 -0
- package/cli/dist/core/pack-v2/index.d.ts +9 -0
- package/cli/dist/core/pack-v2/index.js +8 -0
- package/cli/dist/core/pack-v2/loader.d.ts +63 -0
- package/cli/dist/core/pack-v2/loader.js +292 -0
- package/cli/dist/core/pack-v2/migrator.d.ts +62 -0
- package/cli/dist/core/pack-v2/migrator.js +505 -0
- package/cli/dist/core/pack-v2/validator.d.ts +65 -0
- package/cli/dist/core/pack-v2/validator.js +629 -0
- package/cli/dist/core/parallel/index.d.ts +6 -0
- package/cli/dist/core/parallel/index.js +6 -0
- package/cli/dist/core/parallel/parallel-runner.d.ts +107 -0
- package/cli/dist/core/parallel/parallel-runner.js +192 -0
- package/cli/dist/core/pom/base-page.d.ts +237 -0
- package/cli/dist/core/pom/base-page.js +354 -0
- package/cli/dist/core/pom/index.d.ts +22 -0
- package/cli/dist/core/pom/index.js +23 -0
- package/cli/dist/core/pom/loader.d.ts +118 -0
- package/cli/dist/core/pom/loader.js +382 -0
- package/cli/dist/core/pom/types.d.ts +112 -0
- package/cli/dist/core/pom/types.js +9 -0
- package/cli/dist/core/proof/bundle.d.ts +137 -0
- package/cli/dist/core/proof/bundle.js +160 -0
- package/cli/dist/core/proof/canonicalize.d.ts +47 -0
- package/cli/dist/core/proof/canonicalize.js +105 -0
- package/cli/dist/core/proof/index.d.ts +13 -0
- package/cli/dist/core/proof/index.js +18 -0
- package/cli/dist/core/proof/schema.d.ts +217 -0
- package/cli/dist/core/proof/schema.js +263 -0
- package/cli/dist/core/proof/signer.d.ts +111 -0
- package/cli/dist/core/proof/signer.js +226 -0
- package/cli/dist/core/proof/verifier.d.ts +97 -0
- package/cli/dist/core/proof/verifier.js +308 -0
- package/cli/dist/core/regression/detector.d.ts +107 -0
- package/cli/dist/core/regression/detector.js +497 -0
- package/cli/dist/core/regression/index.d.ts +9 -0
- package/cli/dist/core/regression/index.js +11 -0
- package/cli/dist/core/regression/trend-analyzer.d.ts +102 -0
- package/cli/dist/core/regression/trend-analyzer.js +345 -0
- package/cli/dist/core/regression/types.d.ts +222 -0
- package/cli/dist/core/regression/types.js +7 -0
- package/cli/dist/core/regression/vault.d.ts +87 -0
- package/cli/dist/core/regression/vault.js +289 -0
- package/cli/dist/core/repair/engine/fixer.d.ts +24 -0
- package/cli/dist/core/repair/engine/fixer.js +226 -0
- package/cli/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
- package/cli/dist/core/repair/engine/suggestion-engine.js +187 -0
- package/cli/dist/core/repair/index.d.ts +10 -0
- package/cli/dist/core/repair/index.js +13 -0
- package/cli/dist/core/repair/repairer.d.ts +90 -0
- package/cli/dist/core/repair/repairer.js +284 -0
- package/cli/dist/core/repair/types.d.ts +91 -0
- package/cli/dist/core/repair/types.js +6 -0
- package/cli/dist/core/repair/utils/error-analyzer.d.ts +28 -0
- package/cli/dist/core/repair/utils/error-analyzer.js +264 -0
- package/cli/dist/core/reporting/html-reporter.d.ts +119 -0
- package/cli/dist/core/reporting/html-reporter.js +737 -0
- package/cli/dist/core/reporting/index.d.ts +6 -0
- package/cli/dist/core/reporting/index.js +6 -0
- package/cli/dist/core/retry/flakiness-integration.d.ts +60 -0
- package/cli/dist/core/retry/flakiness-integration.js +228 -0
- package/cli/dist/core/retry/index.d.ts +14 -0
- package/cli/dist/core/retry/index.js +16 -0
- package/cli/dist/core/retry/retry-engine.d.ts +80 -0
- package/cli/dist/core/retry/retry-engine.js +296 -0
- package/cli/dist/core/retry/types.d.ts +178 -0
- package/cli/dist/core/retry/types.js +52 -0
- package/cli/dist/core/retry/vault.d.ts +77 -0
- package/cli/dist/core/retry/vault.js +304 -0
- package/cli/dist/core/runner/e2e-helpers.d.ts +102 -0
- package/cli/dist/core/runner/e2e-helpers.js +153 -0
- package/cli/dist/core/runner/phase3-runner.d.ts +249 -0
- package/cli/dist/core/runner/phase3-runner.js +1323 -0
- package/cli/dist/core/schemas/pack.schema.json +236 -0
- package/cli/dist/core/secrets/crypto.d.ts +75 -0
- package/cli/dist/core/secrets/crypto.js +223 -0
- package/cli/dist/core/secrets/manager.d.ts +76 -0
- package/cli/dist/core/secrets/manager.js +219 -0
- package/cli/dist/core/security/redaction-patterns-extended.d.ts +27 -0
- package/cli/dist/core/security/redaction-patterns-extended.js +247 -0
- package/cli/dist/core/security/redactor.d.ts +71 -0
- package/cli/dist/core/security/redactor.js +279 -0
- package/cli/dist/core/self-healing/assertion-healer.d.ts +97 -0
- package/cli/dist/core/self-healing/assertion-healer.js +371 -0
- package/cli/dist/core/self-healing/engine.d.ts +122 -0
- package/cli/dist/core/self-healing/engine.js +538 -0
- package/cli/dist/core/self-healing/index.d.ts +10 -0
- package/cli/dist/core/self-healing/index.js +11 -0
- package/cli/dist/core/self-healing/selector-healer.d.ts +103 -0
- package/cli/dist/core/self-healing/selector-healer.js +372 -0
- package/cli/dist/core/self-healing/types.d.ts +152 -0
- package/cli/dist/core/self-healing/types.js +6 -0
- package/cli/dist/core/serve/diagnostics-collector.d.ts +32 -0
- package/cli/dist/core/serve/diagnostics-collector.js +149 -0
- package/cli/dist/core/serve/health-checker.d.ts +44 -0
- package/cli/dist/core/serve/health-checker.js +219 -0
- package/cli/dist/core/serve/index.d.ts +8 -0
- package/cli/dist/core/serve/index.js +8 -0
- package/cli/dist/core/serve/metrics-collector.d.ts +24 -0
- package/cli/dist/core/serve/metrics-collector.js +322 -0
- package/cli/dist/core/serve/process-manager.d.ts +36 -0
- package/cli/dist/core/serve/process-manager.js +213 -0
- package/cli/dist/core/serve/server.d.ts +36 -0
- package/cli/dist/core/serve/server.js +191 -0
- package/cli/dist/core/slo/config.d.ts +107 -0
- package/cli/dist/core/slo/config.js +360 -0
- package/cli/dist/core/slo/index.d.ts +11 -0
- package/cli/dist/core/slo/index.js +15 -0
- package/cli/dist/core/slo/sli-calculator.d.ts +92 -0
- package/cli/dist/core/slo/sli-calculator.js +364 -0
- package/cli/dist/core/slo/slo-tracker.d.ts +148 -0
- package/cli/dist/core/slo/slo-tracker.js +379 -0
- package/cli/dist/core/slo/types.d.ts +281 -0
- package/cli/dist/core/slo/types.js +7 -0
- package/cli/dist/core/slo/vault.d.ts +102 -0
- package/cli/dist/core/slo/vault.js +427 -0
- package/cli/dist/core/tui/index.d.ts +7 -0
- package/cli/dist/core/tui/index.js +6 -0
- package/cli/dist/core/tui/monitor.d.ts +92 -0
- package/cli/dist/core/tui/monitor.js +271 -0
- package/cli/dist/core/tui/renderer.d.ts +33 -0
- package/cli/dist/core/tui/renderer.js +218 -0
- package/cli/dist/core/tui/types.d.ts +63 -0
- package/cli/dist/core/tui/types.js +5 -0
- package/cli/dist/core/types/pack-v1.d.ts +251 -0
- package/cli/dist/core/types/pack-v1.js +5 -0
- package/cli/dist/core/types/pack-v2.d.ts +456 -0
- package/cli/dist/core/types/pack-v2.js +8 -0
- package/cli/dist/core/types/trust-score.d.ts +69 -0
- package/cli/dist/core/types/trust-score.js +191 -0
- package/cli/dist/core/vault/cas.d.ts +90 -0
- package/cli/dist/core/vault/cas.js +261 -0
- package/cli/dist/core/vault/index.d.ts +326 -0
- package/cli/dist/core/vault/index.js +1042 -0
- package/cli/dist/core/visual/index.d.ts +6 -0
- package/cli/dist/core/visual/index.js +6 -0
- package/cli/dist/core/visual/visual-regression.d.ts +113 -0
- package/cli/dist/core/visual/visual-regression.js +236 -0
- package/cli/dist/core/watch/index.d.ts +7 -0
- package/cli/dist/core/watch/index.js +6 -0
- package/cli/dist/core/watch/watch-mode.d.ts +213 -0
- package/cli/dist/core/watch/watch-mode.js +389 -0
- package/cli/dist/generators/index.d.ts +5 -0
- package/cli/dist/generators/index.js +5 -0
- package/cli/dist/generators/json-reporter.d.ts +10 -0
- package/cli/dist/generators/json-reporter.js +12 -0
- package/cli/dist/generators/test-generator.d.ts +18 -0
- package/cli/dist/generators/test-generator.js +78 -0
- package/cli/dist/index.d.ts +8 -0
- package/cli/dist/index.js +262 -0
- package/cli/dist/scanners/dom-scanner.d.ts +52 -0
- package/cli/dist/scanners/dom-scanner.js +296 -0
- package/cli/dist/scanners/index.d.ts +4 -0
- package/cli/dist/scanners/index.js +4 -0
- package/cli/dist/schemas/pack.schema.json +236 -0
- package/cli/dist/types/scan.d.ts +68 -0
- package/cli/dist/types/scan.js +4 -0
- package/cli/dist/utils/config.d.ts +35 -0
- package/cli/dist/utils/config.js +196 -0
- package/cli/package.json +1 -1
- package/package.json +26 -2
- package/.BETA_TESTING_FEEDBACK.md +0 -256
- package/.claude/settings.local.json +0 -154
- package/.editorconfig +0 -21
- package/.github/CODEOWNERS +0 -23
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -108
- package/.github/ISSUE_TEMPLATE/feedback_dx.yml +0 -121
- package/.github/dependabot.yml +0 -35
- package/.github/workflows/mcp-dx.yml +0 -106
- package/.github/workflows/release.yml +0 -26
- package/.github/workflows/test.yml +0 -93
- package/.nvmrc +0 -1
- package/.qa360/vault.db +0 -0
- package/.qa360/vault.db-shm +0 -0
- package/.qa360/vault.db-wal +0 -0
- package/.qa360-artifacts/.gitkeep +0 -0
- package/.qa360-artifacts/baselines/.gitkeep +0 -0
- package/.qa360-artifacts/cache/.gitkeep +0 -0
- package/.qa360-artifacts/reports/.gitkeep +0 -0
- package/.qa360-artifacts/screenshots/.gitkeep +0 -0
- package/.qa360-baselines/www_xyqo_ai.baseline.json +0 -33
- package/CODEOWNERS +0 -43
- package/NOVICE_USER_GUIDE.md +0 -272
- package/adapters/README.md +0 -46
- package/check-branches.sh +0 -32
- package/cli/.qa360/keys/ed25519.key +0 -1
- package/cli/.qa360/keys/ed25519.pub +0 -1
- package/cli/examples/README.md +0 -160
- package/cli/examples/accessibility.yml +0 -48
- package/cli/examples/api-basic.yml +0 -27
- package/cli/examples/complete.yml +0 -146
- package/cli/examples/crawler.yml +0 -38
- package/cli/examples/fullstack.yml +0 -78
- package/cli/examples/security.yml +0 -58
- package/cli/examples/ui-advanced.yml +0 -49
- package/cli/examples/ui-basic.yml +0 -24
- package/cli/scripts/bundle-for-npm.sh +0 -51
- package/cli/scripts/validate-package.js +0 -116
- package/cli/src/__tests__/commands/doctor.test.ts +0 -108
- package/cli/src/__tests__/index.test.ts +0 -15
- package/cli/src/cli-minimal.ts +0 -44
- package/cli/src/commands/__tests__/crawl.test.ts +0 -412
- package/cli/src/commands/__tests__/doctor-qa360-home.test.ts +0 -156
- package/cli/src/commands/__tests__/e2e-ui-tests.test.ts +0 -494
- package/cli/src/commands/__tests__/e2e.test.ts +0 -187
- package/cli/src/commands/__tests__/flakiness.test.ts +0 -528
- package/cli/src/commands/__tests__/generate.test.ts +0 -507
- package/cli/src/commands/__tests__/history.integration.test.ts +0 -358
- package/cli/src/commands/__tests__/history.test.ts +0 -433
- package/cli/src/commands/__tests__/monitor-realworld.test.ts +0 -199
- package/cli/src/commands/__tests__/monitor.test.ts +0 -81
- package/cli/src/commands/__tests__/ollama.test.ts +0 -529
- package/cli/src/commands/__tests__/repair.test.ts +0 -225
- package/cli/src/commands/__tests__/report.integration.test.ts +0 -167
- package/cli/src/commands/__tests__/report.test.ts +0 -294
- package/cli/src/commands/__tests__/report.vitest.ts +0 -288
- package/cli/src/commands/__tests__/retry.test.ts +0 -78
- package/cli/src/commands/__tests__/run.integration.test.ts +0 -240
- package/cli/src/commands/__tests__/run.test.ts +0 -346
- package/cli/src/commands/__tests__/run.vitest.ts +0 -301
- package/cli/src/commands/__tests__/secrets.test.ts +0 -114
- package/cli/src/commands/__tests__/serve.test.ts +0 -80
- package/cli/src/commands/__tests__/verify.test.ts +0 -103
- package/cli/src/commands/ai.ts +0 -702
- package/cli/src/commands/ask.ts +0 -678
- package/cli/src/commands/coverage.ts +0 -305
- package/cli/src/commands/crawl.ts +0 -155
- package/cli/src/commands/doctor.ts +0 -610
- package/cli/src/commands/examples.ts +0 -248
- package/cli/src/commands/explain.ts +0 -710
- package/cli/src/commands/flakiness.ts +0 -560
- package/cli/src/commands/generate.ts +0 -566
- package/cli/src/commands/history.ts +0 -914
- package/cli/src/commands/init.ts +0 -777
- package/cli/src/commands/monitor.ts +0 -270
- package/cli/src/commands/ollama.ts +0 -337
- package/cli/src/commands/pack.ts +0 -497
- package/cli/src/commands/regression.ts +0 -400
- package/cli/src/commands/repair.ts +0 -356
- package/cli/src/commands/report.ts +0 -463
- package/cli/src/commands/retry.ts +0 -380
- package/cli/src/commands/run.ts +0 -220
- package/cli/src/commands/scan.ts +0 -177
- package/cli/src/commands/secrets.ts +0 -340
- package/cli/src/commands/serve.ts +0 -194
- package/cli/src/commands/slo.ts +0 -387
- package/cli/src/commands/verify-temp-note.md +0 -11
- package/cli/src/commands/verify.ts +0 -322
- package/cli/src/generators/index.ts +0 -6
- package/cli/src/generators/json-reporter.ts +0 -15
- package/cli/src/generators/test-generator.ts +0 -90
- package/cli/src/index.ts +0 -289
- package/cli/src/scanners/dom-scanner.ts +0 -360
- package/cli/src/scanners/index.ts +0 -5
- package/cli/src/types/scan.ts +0 -84
- package/cli/src/utils/config.ts +0 -145
- package/cli/tsconfig.bundle.json +0 -12
- package/cli/tsconfig.json +0 -23
- package/cli/vitest.config.ts +0 -59
- package/core/src/__tests__/adapters-contract/adapters-contract.test.md +0 -156
- package/core/src/__tests__/index.test.ts +0 -31
- package/core/src/__tests__/integration/phase3.test.ts +0 -405
- package/core/src/__tests__/pack/validator.test.ts +0 -312
- package/core/src/__tests__/secrets/crypto.test.ts +0 -190
- package/core/src/__tests__/secrets/manager.test.ts +0 -316
- package/core/src/__tests__/security/redactor-phase3.test.ts +0 -233
- package/core/src/__tests__/serve/health-checker.test.ts +0 -155
- package/core/src/__tests__/serve/process-manager.test.ts +0 -213
- package/core/src/__tests__/serve/server.test.ts +0 -103
- package/core/src/__tests__/vault/cas.test.ts +0 -178
- package/core/src/__tests__/vault/vault.test.ts +0 -296
- package/core/src/adapters/__tests__/fixtures/jest-coverage.json +0 -8
- package/core/src/adapters/__tests__/fixtures/jest-results.json +0 -41
- package/core/src/adapters/__tests__/fixtures/pytest-junit.xml +0 -16
- package/core/src/adapters/__tests__/fixtures/vitest-coverage.json +0 -8
- package/core/src/adapters/__tests__/fixtures/vitest-results.json +0 -50
- package/core/src/adapters/__tests__/gitleaks-secrets.test.ts +0 -452
- package/core/src/adapters/__tests__/jest-adapter.test.ts +0 -276
- package/core/src/adapters/__tests__/k6-perf.test.ts +0 -538
- package/core/src/adapters/__tests__/osv-deps.test.ts +0 -471
- package/core/src/adapters/__tests__/playwright-native-api.test.ts +0 -792
- package/core/src/adapters/__tests__/playwright-ui-e2e.test.ts +0 -431
- package/core/src/adapters/__tests__/playwright-ui.test.ts +0 -1073
- package/core/src/adapters/__tests__/pytest-adapter.test.ts +0 -207
- package/core/src/adapters/__tests__/semgrep-sast.test.ts +0 -436
- package/core/src/adapters/__tests__/vitest-adapter.test.ts +0 -208
- package/core/src/adapters/__tests__/zap-dast.test.ts +0 -453
- package/core/src/adapters/gitleaks-secrets.ts +0 -521
- package/core/src/adapters/jest-adapter.ts +0 -306
- package/core/src/adapters/k6-perf.ts +0 -479
- package/core/src/adapters/osv-deps.ts +0 -467
- package/core/src/adapters/playwright-native-adapter.ts +0 -472
- package/core/src/adapters/playwright-native-api.ts +0 -619
- package/core/src/adapters/playwright-ui.ts +0 -1088
- package/core/src/adapters/pytest-adapter.ts +0 -472
- package/core/src/adapters/semgrep-sast.ts +0 -410
- package/core/src/adapters/unit-test-types.ts +0 -106
- package/core/src/adapters/vitest-adapter.ts +0 -295
- package/core/src/adapters/zap-dast.ts +0 -551
- package/core/src/ai/__tests__/deepseek-provider.test.ts +0 -586
- package/core/src/ai/__tests__/ollama-provider.test.ts +0 -641
- package/core/src/ai/anthropic-provider.ts +0 -262
- package/core/src/ai/deepseek-provider.ts +0 -315
- package/core/src/ai/index.ts +0 -87
- package/core/src/ai/llm-client.ts +0 -52
- package/core/src/ai/mock-provider.ts +0 -146
- package/core/src/ai/ollama-provider.ts +0 -269
- package/core/src/ai/openai-provider.ts +0 -240
- package/core/src/ai/provider-factory.ts +0 -408
- package/core/src/artifacts/README.md +0 -78
- package/core/src/artifacts/index.ts +0 -16
- package/core/src/artifacts/ui-artifacts.ts +0 -412
- package/core/src/assertions/__tests__/engine.test.ts +0 -360
- package/core/src/assertions/engine.ts +0 -577
- package/core/src/assertions/index.ts +0 -13
- package/core/src/assertions/types.ts +0 -229
- package/core/src/auth/__tests__/api-key-provider.test.ts +0 -282
- package/core/src/auth/__tests__/auth-manager.test.ts +0 -430
- package/core/src/auth/__tests__/basic-auth-provider.test.ts +0 -364
- package/core/src/auth/__tests__/cloud-providers.test.ts +0 -751
- package/core/src/auth/__tests__/jwt-provider.test.ts +0 -400
- package/core/src/auth/__tests__/oauth2-provider.test.ts +0 -383
- package/core/src/auth/__tests__/totp-provider.test.ts +0 -294
- package/core/src/auth/__tests__/ui-login-provider.test.ts +0 -323
- package/core/src/auth/api-key-provider.ts +0 -75
- package/core/src/auth/aws-iam-provider.ts +0 -212
- package/core/src/auth/azure-ad-provider.ts +0 -126
- package/core/src/auth/basic-auth-provider.ts +0 -133
- package/core/src/auth/gcp-adc-provider.ts +0 -146
- package/core/src/auth/index.ts +0 -342
- package/core/src/auth/jwt-provider.ts +0 -193
- package/core/src/auth/manager.ts +0 -281
- package/core/src/auth/oauth2-provider.ts +0 -141
- package/core/src/auth/totp-provider.ts +0 -163
- package/core/src/auth/ui-login-provider.ts +0 -242
- package/core/src/cache/__tests__/lru-cache.test.ts +0 -564
- package/core/src/cache/index.ts +0 -13
- package/core/src/cache/lru-cache.ts +0 -536
- package/core/src/crawler/__tests__/journey-generator.test.ts +0 -344
- package/core/src/crawler/__tests__/selector-generator.test.ts +0 -211
- package/core/src/crawler/index.ts +0 -335
- package/core/src/crawler/journey-generator.ts +0 -471
- package/core/src/crawler/page-analyzer.ts +0 -857
- package/core/src/crawler/selector-generator.ts +0 -280
- package/core/src/crawler/types.ts +0 -475
- package/core/src/dashboard/__tests__/real-world.test.ts +0 -430
- package/core/src/dashboard/__tests__/server.test.ts +0 -283
- package/core/src/dashboard/__tests__/types.test.ts +0 -208
- package/core/src/dashboard/assets.ts +0 -692
- package/core/src/dashboard/index.ts +0 -17
- package/core/src/dashboard/server.ts +0 -401
- package/core/src/dashboard/types.ts +0 -78
- package/core/src/discoverer/__tests__/test-discoverer.test.ts +0 -444
- package/core/src/discoverer/index.ts +0 -374
- package/core/src/fixtures/__tests__/loader.test.ts +0 -246
- package/core/src/fixtures/__tests__/resolver.test.ts +0 -334
- package/core/src/fixtures/index.ts +0 -9
- package/core/src/fixtures/loader.ts +0 -200
- package/core/src/fixtures/resolver.ts +0 -221
- package/core/src/fixtures/types.ts +0 -86
- package/core/src/flakiness/__tests__/flakiness.test.ts +0 -554
- package/core/src/flakiness/index.ts +0 -536
- package/core/src/generation/__tests__/code-formatter.test.ts +0 -170
- package/core/src/generation/__tests__/code-generator-contract.test.ts +0 -207
- package/core/src/generation/__tests__/code-generator.test.ts +0 -586
- package/core/src/generation/__tests__/crawler-pack-generator.test.ts +0 -479
- package/core/src/generation/__tests__/generation-e2e-b2bshop.test.ts +0 -718
- package/core/src/generation/__tests__/generation-integration.test.ts +0 -655
- package/core/src/generation/__tests__/pack-generator.test.ts +0 -408
- package/core/src/generation/__tests__/prompt-builder.test.ts +0 -200
- package/core/src/generation/__tests__/real-provider-integration.test.ts +0 -414
- package/core/src/generation/__tests__/source-analyzer.test.ts +0 -774
- package/core/src/generation/__tests__/test-optimizer.test.ts +0 -255
- package/core/src/generation/code-formatter.ts +0 -408
- package/core/src/generation/code-generator.ts +0 -470
- package/core/src/generation/crawler-pack-generator.ts +0 -289
- package/core/src/generation/generator.ts +0 -113
- package/core/src/generation/index.ts +0 -59
- package/core/src/generation/pack-generator.ts +0 -527
- package/core/src/generation/prompt-builder.ts +0 -772
- package/core/src/generation/source-analyzer.ts +0 -830
- package/core/src/generation/test-optimizer.ts +0 -474
- package/core/src/generation/types.ts +0 -217
- package/core/src/hooks/__tests__/compose.test.ts +0 -636
- package/core/src/hooks/__tests__/runner.test.ts +0 -478
- package/core/src/hooks/compose.ts +0 -268
- package/core/src/hooks/runner.ts +0 -364
- package/core/src/index.ts +0 -255
- package/core/src/pack/__tests__/migrator.test.ts +0 -594
- package/core/src/pack/__tests__/validator.test.ts +0 -759
- package/core/src/pack/migrator.ts +0 -353
- package/core/src/pack/validator.ts +0 -359
- package/core/src/pack-v2/__tests__/loader.test.ts +0 -533
- package/core/src/pack-v2/__tests__/migrator.test.ts +0 -455
- package/core/src/pack-v2/__tests__/validator.test.ts +0 -609
- package/core/src/pack-v2/index.ts +0 -41
- package/core/src/pack-v2/loader.ts +0 -358
- package/core/src/pack-v2/migrator.ts +0 -540
- package/core/src/pack-v2/validator.ts +0 -731
- package/core/src/parallel/README.md +0 -143
- package/core/src/parallel/index.ts +0 -16
- package/core/src/parallel/parallel-runner.ts +0 -282
- package/core/src/pom/__tests__/loader.test.ts +0 -378
- package/core/src/pom/base-page.ts +0 -425
- package/core/src/pom/index.ts +0 -45
- package/core/src/pom/loader.ts +0 -480
- package/core/src/pom/types.ts +0 -146
- package/core/src/proof/__tests__/proof-roundtrip.test.ts +0 -149
- package/core/src/proof/__tests__/schema-validation-manual.mjs +0 -211
- package/core/src/proof/__tests__/schema-validation.test.ts +0 -336
- package/core/src/proof/__tests__/signer.test.ts +0 -486
- package/core/src/proof/__tests__/temporal-regression.test.ts +0 -537
- package/core/src/proof/__tests__/verifier-advanced.test.ts +0 -588
- package/core/src/proof/__tests__/verifier.test.ts +0 -413
- package/core/src/proof/bundle.ts +0 -290
- package/core/src/proof/canonicalize.ts +0 -116
- package/core/src/proof/index.ts +0 -74
- package/core/src/proof/schema.ts +0 -285
- package/core/src/proof/signer.ts +0 -293
- package/core/src/proof/verifier.ts +0 -380
- package/core/src/regression/__tests__/detector.test.ts +0 -396
- package/core/src/regression/__tests__/trend-analyzer.test.ts +0 -300
- package/core/src/regression/detector.ts +0 -629
- package/core/src/regression/index.ts +0 -34
- package/core/src/regression/trend-analyzer.ts +0 -468
- package/core/src/regression/types.ts +0 -295
- package/core/src/regression/vault.ts +0 -419
- package/core/src/repair/__tests__/repairer.test.ts +0 -572
- package/core/src/repair/__tests__/types.test.ts +0 -302
- package/core/src/repair/engine/__tests__/fixer.test.ts +0 -482
- package/core/src/repair/engine/__tests__/suggestion-engine.test.ts +0 -395
- package/core/src/repair/engine/fixer.ts +0 -271
- package/core/src/repair/engine/suggestion-engine.ts +0 -234
- package/core/src/repair/index.ts +0 -53
- package/core/src/repair/repairer.ts +0 -376
- package/core/src/repair/types.ts +0 -119
- package/core/src/repair/utils/__tests__/error-analyzer.test.ts +0 -454
- package/core/src/repair/utils/error-analyzer.ts +0 -308
- package/core/src/reporting/README.md +0 -144
- package/core/src/reporting/html-reporter.ts +0 -835
- package/core/src/reporting/index.ts +0 -16
- package/core/src/retry/README.md +0 -192
- package/core/src/retry/__tests__/flakiness-integration.test.ts +0 -475
- package/core/src/retry/__tests__/retry-engine.test.ts +0 -424
- package/core/src/retry/flakiness-integration.ts +0 -267
- package/core/src/retry/index.ts +0 -48
- package/core/src/retry/retry-engine.ts +0 -368
- package/core/src/retry/types.ts +0 -208
- package/core/src/retry/vault.ts +0 -413
- package/core/src/runner/__tests__/flakiness-integration.test.ts +0 -566
- package/core/src/runner/__tests__/phase3-e2e-b2bshop.test.ts +0 -218
- package/core/src/runner/__tests__/phase3-e2e-reqres.test.ts +0 -199
- package/core/src/runner/__tests__/phase3-runner.test.ts +0 -1118
- package/core/src/runner/e2e-helpers.ts +0 -216
- package/core/src/runner/phase3-runner.ts +0 -1536
- package/core/src/schemas/gherkin-report.json +0 -122
- package/core/src/secrets/__tests__/crypto.test.ts +0 -180
- package/core/src/secrets/crypto.ts +0 -289
- package/core/src/secrets/manager.ts +0 -272
- package/core/src/security/__tests__/hardening.test.ts +0 -480
- package/core/src/security/redaction-patterns-extended.ts +0 -278
- package/core/src/security/redactor.ts +0 -326
- package/core/src/self-healing/assertion-healer.ts +0 -485
- package/core/src/self-healing/engine.ts +0 -626
- package/core/src/self-healing/index.ts +0 -33
- package/core/src/self-healing/selector-healer.ts +0 -488
- package/core/src/self-healing/types.ts +0 -193
- package/core/src/serve/diagnostics-collector.ts +0 -201
- package/core/src/serve/health-checker.ts +0 -274
- package/core/src/serve/index.ts +0 -9
- package/core/src/serve/metrics-collector.ts +0 -386
- package/core/src/serve/process-manager.ts +0 -265
- package/core/src/serve/server.ts +0 -230
- package/core/src/slo/config.ts +0 -408
- package/core/src/slo/index.ts +0 -68
- package/core/src/slo/sli-calculator.ts +0 -474
- package/core/src/slo/slo-tracker.ts +0 -481
- package/core/src/slo/types.ts +0 -408
- package/core/src/slo/vault.ts +0 -600
- package/core/src/tui/__tests__/monitor.test.ts +0 -336
- package/core/src/tui/__tests__/real-world.test.ts +0 -376
- package/core/src/tui/__tests__/renderer.test.ts +0 -201
- package/core/src/tui/__tests__/types.test.ts +0 -295
- package/core/src/tui/index.ts +0 -19
- package/core/src/tui/monitor.ts +0 -331
- package/core/src/tui/renderer.ts +0 -269
- package/core/src/tui/types.ts +0 -68
- package/core/src/types/pack-v1.ts +0 -305
- package/core/src/types/pack-v2.ts +0 -525
- package/core/src/types/trust-score.ts +0 -258
- package/core/src/vault/__tests__/flakiness-vault.test.ts +0 -562
- package/core/src/vault/__tests__/vault.test.ts +0 -259
- package/core/src/vault/cas.ts +0 -323
- package/core/src/vault/index.ts +0 -1361
- package/core/src/vault/schema.sql +0 -168
- package/core/src/visual/README.md +0 -185
- package/core/src/visual/index.ts +0 -14
- package/core/src/visual/visual-regression.ts +0 -347
- package/core/src/watch/__tests__/watch-mode.test.ts +0 -192
- package/core/src/watch/index.ts +0 -14
- package/core/src/watch/watch-mode.ts +0 -565
- package/core/tsconfig.json +0 -12
- package/core/vitest.config.ts +0 -52
- package/docs/ARCHITECTURE.md +0 -901
- package/docs/AUDIT-GLOBAL-DEC2025.md +0 -271
- package/docs/BETA_TESTING.md +0 -257
- package/docs/BETA_TESTING_PLAN.md +0 -727
- package/docs/CERTIFICATION-REPORT.md +0 -142
- package/docs/COMPLETE_AUDIT_REFACTORING.md +0 -965
- package/docs/DEVELOPMENT.md +0 -545
- package/docs/DEVELOPMENT_HISTORY.md +0 -345
- package/docs/LIMITATIONS.md +0 -176
- package/docs/MIGRATION.md +0 -303
- package/docs/OPTION_3_4_EXPLORATION.md +0 -1257
- package/docs/PHASE1_PERFORMANCE.md +0 -144
- package/docs/QA360_Cloud.postman_collection.json +0 -89
- package/docs/QA360_TESTING_PHILOSOPHY.md +0 -769
- package/docs/QA_TEST_PLAN.md +0 -727
- package/docs/README.md +0 -50
- package/docs/STATUS.md +0 -198
- package/docs/STRATEGIC_STUDY_GOOSE_INTEGRATION.md +0 -615
- package/docs/USER_GUIDE.md +0 -687
- package/docs/WORK-DONE-ADAPTER-TESTS.md +0 -136
- package/docs/adapters-security.md +0 -485
- package/docs/architecture-diagram.mmd +0 -168
- package/docs/archive/ARCH-01-DAY6-BUILD-FIXES.md +0 -396
- package/docs/archive/ARCH-01-DAY6-FINAL-STATUS.md +0 -324
- package/docs/archive/ARCH-01_MCP_MERGE_ANALYSIS.md +0 -644
- package/docs/archive/ARCH-01_NEXT_STEPS.md +0 -60
- package/docs/archive/BRANCH_PROTECTION.md +0 -183
- package/docs/archive/CI_LOCKDOWN_CHECKLIST.md +0 -222
- package/docs/archive/HANDOFF_TEST-01.md +0 -669
- package/docs/archive/LEGAL_READY_PLACEHOLDERS.md +0 -372
- package/docs/archive/NODE_UPGRADE_GUIDE.md +0 -188
- package/docs/archive/PHASE1_COMPLETION.md +0 -386
- package/docs/archive/PHASE2_COMPLETION.md +0 -404
- package/docs/archive/PHASE3_AND_4_FINAL.md +0 -360
- package/docs/archive/PHASE3_COMPLETE.md +0 -301
- package/docs/archive/PHASE3_STATUS.md +0 -255
- package/docs/archive/PRE-WEEK2-AUDIT.md +0 -364
- package/docs/archive/README.md +0 -16
- package/docs/archive/SCHEMA_AJV_2020_FIX.md +0 -245
- package/docs/archive/TEST-01_AUDIT_REPORT.md +0 -240
- package/docs/archive/TEST-01_COVERAGE_PLAN.md +0 -423
- package/docs/archive/obsolete-proposals/dom-element-discovery-mode.md +0 -250
- package/docs/archive/obsolete-proposals/qa360-comprehensive-test-plan.md +0 -1249
- package/docs/archive/obsolete-proposals/qa360-quick-start-guide.md +0 -298
- package/docs/archive/obsolete-proposals/technical-plan-dom-discovery.md +0 -870
- package/docs/budgets-advanced.md +0 -308
- package/docs/examples/history-export-gc.md +0 -285
- package/docs/examples/pack-v2-complete.yaml +0 -158
- package/docs/examples/pack-v2-quickstart.yaml +0 -24
- package/docs/examples/pack-v2-ui-login.yaml +0 -81
- package/docs/examples/qa360-report.json +0 -50
- package/docs/history.md +0 -565
- package/docs/hooks.md +0 -304
- package/docs/llm-providers.md +0 -512
- package/docs/mcp-server.md +0 -651
- package/docs/mcp-tools.md +0 -1131
- package/docs/pack-v1.md +0 -383
- package/docs/pack-v2.md +0 -558
- package/docs/page-objects.md +0 -366
- package/docs/proofs.md +0 -670
- package/docs/quickstart-5min.md +0 -257
- package/docs/readiness-ci.md +0 -654
- package/docs/rfc/README.md +0 -20
- package/docs/rfc/proof-bundle-v1.md +0 -787
- package/docs/secrets.md +0 -392
- package/docs/serve.md +0 -494
- package/docs/unit-test-adapters.md +0 -168
- package/docs/vault.md +0 -491
- package/e2e/qa360-e2e.test.ts +0 -696
- package/e2e/vitest.config.ts +0 -18
- package/examples/README.md +0 -50
- package/examples/ci/docker-compose-serve.yml +0 -375
- package/examples/ci/github-actions-serve.yml +0 -345
- package/examples/ci/gitlab-ci-serve.yml +0 -407
- package/examples/datasets/README.md +0 -101
- package/examples/datasets/b2bshop.ts +0 -155
- package/examples/datasets/index.ts +0 -57
- package/examples/datasets/reqres.ts +0 -195
- package/examples/fixtures-demo/fixtures/users.yml +0 -39
- package/examples/fixtures-demo/pack.yml +0 -71
- package/examples/future-api/README.md +0 -16
- package/examples/future-api/diag.js +0 -7
- package/examples/future-api/health.js +0 -4
- package/examples/future-api/packs.js +0 -13
- package/examples/future-api/runpack.js +0 -10
- package/examples/generation/README.md +0 -148
- package/examples/generation/pack-generator-example.js +0 -115
- package/examples/generation/source-analyzer-example.js +0 -115
- package/examples/httpbin/pack.yml +0 -59
- package/examples/load-testing/mcp-load.yml +0 -115
- package/examples/load-testing/mcp-stdio.yml +0 -95
- package/examples/mcp/claude-desktop-config.json +0 -33
- package/examples/mcp/claude-desktop.json +0 -16
- package/examples/mcp/conversation-sample.md +0 -131
- package/examples/mcp/demo-60s.md +0 -330
- package/examples/mcp/sample-conversation.jsonl +0 -21
- package/examples/mcp/vscode-settings.json +0 -22
- package/examples/pack-v2-complete.yml +0 -242
- package/examples/pack-v2-examples.md +0 -244
- package/examples/pack-v2-quickstart.yml +0 -55
- package/examples/packs-business/ecommerce-api.yml +0 -121
- package/examples/packs-business/saas-dashboard-ui.yml +0 -133
- package/examples/packs-conformance/compose-multi.yml +0 -174
- package/examples/packs-conformance/full.yml +0 -152
- package/examples/packs-conformance/heavy-artifacts.yml +0 -152
- package/examples/packs-conformance/minimal.yml +0 -71
- package/examples/packs-conformance/secrets-missing.yml +0 -97
- package/examples/packs-conformance/timeouts.yml +0 -77
- package/examples/pom-demo/README.md +0 -104
- package/examples/pom-demo/pack.yml +0 -60
- package/examples/pom-demo/pages/DashboardPage.page.ts +0 -73
- package/examples/pom-demo/pages/LoginPage.page.ts +0 -76
- package/examples/proofs/e2e-playwright-proof.json +0 -75
- package/examples/proofs/httpbin-proof.json +0 -69
- package/examples/proofs/multi-adapter-proof.json +0 -117
- package/examples/proofs/test-proof.json +0 -26
- package/examples/restful-api-dev/README.md +0 -102
- package/examples/restful-api-dev/restful-api-advanced.yml +0 -29
- package/examples/restful-api-dev/restful-api-basic.yml +0 -29
- package/examples/web-lite/.github/workflows/qa360-phase3.yml +0 -73
- package/examples/web-lite/api-mock/server.js +0 -258
- package/examples/web-lite/pack.yml +0 -71
- package/examples/web-lite/services.yml +0 -43
- package/examples/web-lite/web-content/healthz +0 -1
- package/examples/web-lite/web-content/index.html +0 -259
- package/packages/mcp/CHANGELOG.md +0 -109
- package/packages/mcp/IMPLEMENTATION_SUMMARY.md +0 -350
- package/packages/mcp/LICENSE +0 -21
- package/packages/mcp/QUICK_START.md +0 -291
- package/packages/mcp/README.md +0 -294
- package/packages/mcp/TELEMETRY.md +0 -220
- package/packages/mcp/package.json +0 -91
- package/packages/mcp/scripts/generate-sbom-fallback.cjs +0 -84
- package/packages/mcp/scripts/safe-postinstall.cjs +0 -32
- package/packages/mcp/src/__tests__/contract.test.ts +0 -902
- package/packages/mcp/src/cli/cli.ts +0 -137
- package/packages/mcp/src/cli/doctor.ts +0 -286
- package/packages/mcp/src/cli/fix.ts +0 -99
- package/packages/mcp/src/cli/init.ts +0 -233
- package/packages/mcp/src/cli/postinstall.ts +0 -14
- package/packages/mcp/src/cli/reset.ts +0 -44
- package/packages/mcp/src/cli/telemetry.ts +0 -166
- package/packages/mcp/src/cli/test-dx.ts +0 -94
- package/packages/mcp/src/cli/uninstall.ts +0 -80
- package/packages/mcp/src/cli/up.ts +0 -178
- package/packages/mcp/src/index.ts +0 -12
- package/packages/mcp/src/scripts/e2e-local.ts +0 -337
- package/packages/mcp/src/scripts/verify-settings.ts +0 -242
- package/packages/mcp/src/security/audit.ts +0 -244
- package/packages/mcp/src/security/manager.ts +0 -242
- package/packages/mcp/src/server/full-server.ts +0 -212
- package/packages/mcp/src/server/minimal-server.ts +0 -134
- package/packages/mcp/src/tools/history.ts +0 -388
- package/packages/mcp/src/tools/pack.ts +0 -449
- package/packages/mcp/src/tools/registry.ts +0 -638
- package/packages/mcp/src/tools/report.ts +0 -100
- package/packages/mcp/src/tools/run.ts +0 -268
- package/packages/mcp/src/tools/secrets.ts +0 -198
- package/packages/mcp/src/tools/serve.ts +0 -221
- package/packages/mcp/src/tools/triage.ts +0 -532
- package/packages/mcp/src/tools/types.ts +0 -26
- package/packages/mcp/src/tools/vault.ts +0 -164
- package/packages/mcp/src/tools/verify.ts +0 -166
- package/packages/mcp/src/types/index.ts +0 -311
- package/packages/mcp/src/types/mcp-stubs.ts +0 -83
- package/packages/mcp/tsconfig.json +0 -16
- package/playwright.config.ts +0 -20
- package/pnpm-workspace.yaml +0 -4
- package/run-test-and-push.sh +0 -20
- package/scripts/build-proof-cli.sh +0 -110
- package/scripts/ci/check-windows-paths.js +0 -92
- package/scripts/ci/invariants.sh +0 -124
- package/scripts/ci/make-final-bundle.js +0 -106
- package/scripts/ci/mcp-run-multipack.js +0 -305
- package/scripts/ci/run-pack-suite.sh +0 -103
- package/scripts/ci/run-phase7-final.sh +0 -190
- package/scripts/ci/slo-assert.js +0 -158
- package/scripts/ci/test-fault-tolerance.sh +0 -301
- package/scripts/install-mcp.sh +0 -66
- package/scripts/mcp-smoke.mjs +0 -27
- package/scripts/smoke.sh +0 -26
- package/scripts/stress-test.js +0 -288
- package/scripts/sync-version.mjs +0 -50
- package/scripts/validate-examples.mjs +0 -404
- package/scripts/validation/simple-pack-check.sh +0 -51
- package/scripts/validation/validate-universal-pack.mjs +0 -77
- package/scripts/verify-persistence.js +0 -127
- package/test-pack.yaml +0 -43
- package/test-results/.last-run.json +0 -4
- package/test-runner.mjs +0 -87
- package/tests/artifacts.spec.js +0 -147
- package/tests/contracts.spec.js +0 -239
- package/tests/e2e/assertions.test.mjs +0 -370
- package/tests/e2e/crawler.test.mjs +0 -451
- package/tests/e2e/playwright-plus-plus.test.mjs +0 -604
- package/tests/e2e/proof-bundle.test.mjs +0 -258
- package/tests/e2e/real-world/saucedemo.test.mjs +0 -714
- package/tests/e2e/real-world/the-internet-herokuapp.test.mjs +0 -760
- package/tests/e2e/ui-actions.test.mjs +0 -546
- package/tests/gherkin.e2e.spec.ts +0 -310
- package/tests/no-console-errors.spec.js +0 -136
- package/tests/pdf.spec.ts +0 -252
- package/tests/run-pack.spec.ts +0 -58
- package/tsconfig.base.json +0 -15
- package/tsconfig.build.json +0 -8
- package/tsconfig.json +0 -37
- package/tsconfig.test.json +0 -18
- package/typedoc.json +0 -37
- package/ui/README.md +0 -50
- package/verify-proof.mjs +0 -60
|
@@ -1,1536 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* QA360 Phase 3 Runner
|
|
3
|
-
* Orchestrates hooks, adapters, and proof generation
|
|
4
|
-
* Supports both Pack v1 and Pack v2 configurations
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
-
import { join, resolve } from 'path';
|
|
9
|
-
import { createHash } from 'crypto';
|
|
10
|
-
import chalk from 'chalk';
|
|
11
|
-
import { PackConfigV1 } from '../types/pack-v1.js';
|
|
12
|
-
import { PackConfigV2, AuthConfigV2, GateConfigV2 } from '../types/pack-v2.js';
|
|
13
|
-
import { HooksRunner } from '../hooks/runner.js';
|
|
14
|
-
import { PlaywrightNativeApiAdapter } from '../adapters/playwright-native-api.js';
|
|
15
|
-
import { PlaywrightUiAdapter } from '../adapters/playwright-ui.js';
|
|
16
|
-
import { K6PerfAdapter } from '../adapters/k6-perf.js';
|
|
17
|
-
import { SemgrepSastAdapter } from '../adapters/semgrep-sast.js';
|
|
18
|
-
// v2.2.0 Unit Test Adapters
|
|
19
|
-
import { VitestAdapter } from '../adapters/vitest-adapter.js';
|
|
20
|
-
import { JestAdapter } from '../adapters/jest-adapter.js';
|
|
21
|
-
import { PytestAdapter } from '../adapters/pytest-adapter.js';
|
|
22
|
-
// v2.2.0 Data Fixtures
|
|
23
|
-
import { FixtureLoader } from '../fixtures/loader.js';
|
|
24
|
-
import { FixtureResolver } from '../fixtures/resolver.js';
|
|
25
|
-
import { PageObjectLoader } from '../pom/loader.js';
|
|
26
|
-
import { SecurityRedactor } from '../security/redactor.js';
|
|
27
|
-
import { initializeKeys, sign, KeyPair } from '../proof/signer.js';
|
|
28
|
-
import { canonicalize } from '../proof/canonicalize.js';
|
|
29
|
-
import { EvidenceVault, RunRecord, GateRecord, FindingRecord } from '../vault/index.js';
|
|
30
|
-
import { AuthManager, AuthConfig, AuthCredentials } from '../auth/index.js';
|
|
31
|
-
import {
|
|
32
|
-
FlakinessDetector,
|
|
33
|
-
TestResult as FlakyTestResult,
|
|
34
|
-
FlakinessResult,
|
|
35
|
-
FlakinessCategory,
|
|
36
|
-
formatFlakinessScore,
|
|
37
|
-
generateTestId,
|
|
38
|
-
DEFAULT_FLAKINESS_OPTIONS
|
|
39
|
-
} from '../flakiness/index.js';
|
|
40
|
-
|
|
41
|
-
export type PackConfig = PackConfigV1 | PackConfigV2;
|
|
42
|
-
|
|
43
|
-
export interface Phase3RunnerOptions {
|
|
44
|
-
workingDir: string;
|
|
45
|
-
pack: PackConfig;
|
|
46
|
-
packDir?: string; // Directory containing the pack file (for resolving fixtures)
|
|
47
|
-
outputDir?: string;
|
|
48
|
-
/** Enable flakiness detection (runs tests N times consecutively) */
|
|
49
|
-
flakyDetect?: boolean;
|
|
50
|
-
/** Number of consecutive runs for flakiness detection (default: 3) */
|
|
51
|
-
flakyRuns?: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface GateResult {
|
|
55
|
-
gate: string;
|
|
56
|
-
success: boolean;
|
|
57
|
-
duration: number;
|
|
58
|
-
adapter: string;
|
|
59
|
-
results: any;
|
|
60
|
-
junit?: string;
|
|
61
|
-
error?: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface Phase3RunResult {
|
|
65
|
-
success: boolean;
|
|
66
|
-
pack: PackConfig;
|
|
67
|
-
duration: number;
|
|
68
|
-
gates: GateResult[];
|
|
69
|
-
hooks: {
|
|
70
|
-
beforeAll: any[];
|
|
71
|
-
beforeEach: any[];
|
|
72
|
-
afterEach: any[];
|
|
73
|
-
afterAll: any[];
|
|
74
|
-
};
|
|
75
|
-
summary: {
|
|
76
|
-
total: number;
|
|
77
|
-
passed: number;
|
|
78
|
-
failed: number;
|
|
79
|
-
trustScore: number;
|
|
80
|
-
};
|
|
81
|
-
/** Flakiness analysis results (if enabled) */
|
|
82
|
-
flakiness?: FlakinessResult[];
|
|
83
|
-
proofPath?: string;
|
|
84
|
-
/** Vault run ID for this execution */
|
|
85
|
-
runId?: string;
|
|
86
|
-
error?: string;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export class Phase3Runner {
|
|
90
|
-
private workingDir: string;
|
|
91
|
-
private pack: PackConfig;
|
|
92
|
-
private packDir: string; // Directory containing the pack file
|
|
93
|
-
private outputDir: string;
|
|
94
|
-
private redactor: SecurityRedactor;
|
|
95
|
-
private hooksRunner: HooksRunner;
|
|
96
|
-
private keyPair?: KeyPair;
|
|
97
|
-
private vault?: EvidenceVault;
|
|
98
|
-
private authManager: AuthManager;
|
|
99
|
-
private authCredentialsCache = new Map<string, AuthCredentials>();
|
|
100
|
-
private flakyDetect: boolean;
|
|
101
|
-
private flakyRuns: number;
|
|
102
|
-
private flakinessDetector: FlakinessDetector;
|
|
103
|
-
// v2.2.0 Data Fixtures & POM
|
|
104
|
-
private fixtureLoader?: FixtureLoader;
|
|
105
|
-
private fixtureResolver?: FixtureResolver;
|
|
106
|
-
private pageObjectLoader?: PageObjectLoader;
|
|
107
|
-
|
|
108
|
-
constructor(options: Phase3RunnerOptions) {
|
|
109
|
-
this.workingDir = options.workingDir;
|
|
110
|
-
this.pack = options.pack;
|
|
111
|
-
this.packDir = options.packDir || options.workingDir;
|
|
112
|
-
this.outputDir = options.outputDir || join(this.workingDir, '.qa360', 'runs');
|
|
113
|
-
this.redactor = SecurityRedactor.forLogs();
|
|
114
|
-
this.authManager = new AuthManager();
|
|
115
|
-
this.flakyDetect = options.flakyDetect || false;
|
|
116
|
-
this.flakyRuns = options.flakyRuns || DEFAULT_FLAKINESS_OPTIONS.consecutiveRuns;
|
|
117
|
-
this.flakinessDetector = new FlakinessDetector({
|
|
118
|
-
consecutiveRuns: this.flakyRuns,
|
|
119
|
-
minRuns: 2,
|
|
120
|
-
enablePatternDetection: true
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Initialize hooks runner (convert v2 hooks to v1 format if needed)
|
|
124
|
-
const hooks = this.isPackV2(options.pack)
|
|
125
|
-
? this.convertV2HooksToV1(options.pack.hooks)
|
|
126
|
-
: options.pack.hooks;
|
|
127
|
-
|
|
128
|
-
this.hooksRunner = new HooksRunner({
|
|
129
|
-
workingDir: this.workingDir,
|
|
130
|
-
hooks: hooks || {},
|
|
131
|
-
execution: this.isPackV2(options.pack) ? this.convertV2ExecutionToV1(options.pack.execution) : options.pack.execution,
|
|
132
|
-
redactor: this.redactor
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Register auth profiles from pack v2
|
|
136
|
-
if (this.isPackV2(options.pack) && options.pack.auth?.profiles) {
|
|
137
|
-
this.registerAuthProfiles(options.pack.auth.profiles);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Load data fixtures from pack v2
|
|
141
|
-
if (this.isPackV2(options.pack) && options.pack.fixtures && options.pack.fixtures.length > 0) {
|
|
142
|
-
this.initializeFixtures(options.pack.fixtures);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Initialize Page Object Model from pack v2
|
|
146
|
-
if (this.isPackV2(options.pack) && options.pack.pageObjects) {
|
|
147
|
-
this.initializePageObjects(options.pack.pageObjects);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Initialize Page Object Model from the pack configuration
|
|
153
|
-
*/
|
|
154
|
-
private initializePageObjects(config: { directory?: string; pattern?: string; baseUrl?: string }): void {
|
|
155
|
-
try {
|
|
156
|
-
const pomDir = config.directory ? resolve(this.packDir, config.directory) : this.packDir;
|
|
157
|
-
this.pageObjectLoader = new PageObjectLoader({ cwd: pomDir });
|
|
158
|
-
console.log(chalk.gray(` 📄 POM loader initialized for: ${pomDir}`));
|
|
159
|
-
} catch (error) {
|
|
160
|
-
console.log(chalk.yellow(`⚠️ Failed to initialize POM loader: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Load Page Objects before execution
|
|
166
|
-
*/
|
|
167
|
-
private async loadPageObjects(): Promise<void> {
|
|
168
|
-
if (!this.pageObjectLoader || !this.isPackV2(this.pack) || !this.pack.pageObjects) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
const pattern = this.pack.pageObjects.pattern || '**/*.page.{ts,js}';
|
|
174
|
-
const result = await this.pageObjectLoader.loadFromDirectory(this.packDir, { pattern });
|
|
175
|
-
console.log(chalk.green(` ✅ Page Objects loaded: ${result.pagesCount} pages`));
|
|
176
|
-
} catch (error) {
|
|
177
|
-
console.log(chalk.yellow(`⚠️ Failed to load page objects: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Initialize data fixtures from the pack configuration
|
|
183
|
-
*/
|
|
184
|
-
private initializeFixtures(fixturePaths: string[]): void {
|
|
185
|
-
try {
|
|
186
|
-
this.fixtureLoader = new FixtureLoader(this.packDir);
|
|
187
|
-
// Load fixtures synchronously - they're already validated
|
|
188
|
-
// We'll load them before execution starts
|
|
189
|
-
this.fixtureResolver = new FixtureResolver(this.fixtureLoader, this.packDir);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
console.log(chalk.yellow(`⚠️ Failed to initialize fixtures: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Load fixtures before execution
|
|
197
|
-
*/
|
|
198
|
-
private async loadFixtures(): Promise<void> {
|
|
199
|
-
if (!this.fixtureLoader || !this.isPackV2(this.pack) || !this.pack.fixtures) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
await this.fixtureLoader.load(this.pack.fixtures);
|
|
205
|
-
console.log(chalk.green(` ✅ Fixtures loaded: ${this.fixtureLoader.getFixtureNames().join(', ')}`));
|
|
206
|
-
} catch (error) {
|
|
207
|
-
console.log(chalk.yellow(`⚠️ Failed to load fixtures: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Resolve fixture references in a configuration object
|
|
213
|
-
*/
|
|
214
|
-
private resolveFixturesInConfig(config: any): any {
|
|
215
|
-
if (!this.fixtureResolver || !config) {
|
|
216
|
-
return config;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
const result = this.fixtureResolver.resolve(config, {
|
|
221
|
-
baseDir: this.workingDir,
|
|
222
|
-
keepUnresolved: false
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
if (result.hasFixtures) {
|
|
226
|
-
console.log(chalk.gray(` 🔧 Fixtures resolved in config`));
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return result.value;
|
|
230
|
-
} catch (error) {
|
|
231
|
-
console.log(chalk.yellow(`⚠️ Failed to resolve fixtures: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
232
|
-
return config;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Type guard to check if pack is v2
|
|
238
|
-
*/
|
|
239
|
-
private isPackV2(pack: PackConfig): pack is PackConfigV2 {
|
|
240
|
-
return (pack as PackConfigV2).version === 2;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Register authentication profiles from pack config
|
|
245
|
-
*/
|
|
246
|
-
private registerAuthProfiles(profiles: Record<string, any>): void {
|
|
247
|
-
for (const [name, profile] of Object.entries(profiles)) {
|
|
248
|
-
// Convert v2 auth profile to auth module format
|
|
249
|
-
const authConfig: AuthConfig = {
|
|
250
|
-
type: profile.type || 'none',
|
|
251
|
-
...profile.config
|
|
252
|
-
};
|
|
253
|
-
this.authManager.registerProfile(name, authConfig);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Get auth profile name for a specific gate
|
|
259
|
-
*/
|
|
260
|
-
private getAuthProfileForGate(gateName: string): string | undefined {
|
|
261
|
-
if (!this.isPackV2(this.pack) || !this.pack.auth) {
|
|
262
|
-
return undefined;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const authConfig = this.pack.auth as AuthConfigV2;
|
|
266
|
-
|
|
267
|
-
// Check if gate has specific auth override
|
|
268
|
-
const gateConfig = (this.pack.gates as Record<string, GateConfigV2>)[gateName];
|
|
269
|
-
if (gateConfig?.auth) {
|
|
270
|
-
return gateConfig.auth;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Use default based on gate type
|
|
274
|
-
if (gateName === 'api_smoke' || gateName === 'api') {
|
|
275
|
-
return authConfig.api;
|
|
276
|
-
}
|
|
277
|
-
if (gateName === 'ui' || gateName === 'a11y') {
|
|
278
|
-
return authConfig.ui;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return undefined;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Authenticate and get credentials for a gate
|
|
286
|
-
*/
|
|
287
|
-
private async getCredentialsForGate(gateName: string): Promise<AuthCredentials | undefined> {
|
|
288
|
-
const profileName = this.getAuthProfileForGate(gateName);
|
|
289
|
-
|
|
290
|
-
if (!profileName) {
|
|
291
|
-
return undefined;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Check cache first
|
|
295
|
-
if (this.authCredentialsCache.has(profileName)) {
|
|
296
|
-
return this.authCredentialsCache.get(profileName);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Authenticate
|
|
300
|
-
const result = await this.authManager.authenticate(profileName);
|
|
301
|
-
|
|
302
|
-
if (result.success && result.credentials) {
|
|
303
|
-
this.authCredentialsCache.set(profileName, result.credentials);
|
|
304
|
-
return result.credentials;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
console.log(chalk.yellow(` ⚠️ Auth failed for profile '${profileName}': ${result.error}`));
|
|
308
|
-
return undefined;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Convert v2 hooks to v1 format
|
|
313
|
-
*/
|
|
314
|
-
private convertV2HooksToV1(hooks?: any): any {
|
|
315
|
-
if (!hooks) return undefined;
|
|
316
|
-
|
|
317
|
-
// v2 hooks use { type, command, ... } format
|
|
318
|
-
// v1 hooks use { run, timeout } format
|
|
319
|
-
const converted: any = {
|
|
320
|
-
beforeAll: [],
|
|
321
|
-
afterAll: [],
|
|
322
|
-
beforeEach: [],
|
|
323
|
-
afterEach: []
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
for (const [phase, phaseHooks] of Object.entries(hooks)) {
|
|
327
|
-
if (Array.isArray(phaseHooks)) {
|
|
328
|
-
converted[phase] = (phaseHooks as any[]).map((h: any) => {
|
|
329
|
-
if (h.type === 'run' || h.type === 'script') {
|
|
330
|
-
return { run: h.command, timeout: h.timeout, cwd: h.cwd, env: h.env };
|
|
331
|
-
}
|
|
332
|
-
if (h.type === 'wait_on') {
|
|
333
|
-
return { run: `npx wait-on ${h.wait_for?.resource || h.command}`, timeout: h.timeout };
|
|
334
|
-
}
|
|
335
|
-
if (h.type === 'docker') {
|
|
336
|
-
return { run: `docker compose ${h.compose?.command || 'up -d'}`, timeout: h.timeout };
|
|
337
|
-
}
|
|
338
|
-
return h;
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return converted;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Convert v2 execution config to v1 format
|
|
348
|
-
*/
|
|
349
|
-
private convertV2ExecutionToV1(execution?: any): any {
|
|
350
|
-
if (!execution) return undefined;
|
|
351
|
-
|
|
352
|
-
return {
|
|
353
|
-
timeout: execution.default_timeout || execution.timeout,
|
|
354
|
-
max_retries: execution.default_retries || execution.retries,
|
|
355
|
-
on_failure: execution.on_failure || 'continue'
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Get gates array from pack (handles v1 and v2)
|
|
361
|
-
*/
|
|
362
|
-
private getGatesArray(): string[] {
|
|
363
|
-
if (this.isPackV2(this.pack)) {
|
|
364
|
-
return Object.keys(this.pack.gates).filter(gateName => {
|
|
365
|
-
const gateConfig = (this.pack.gates as Record<string, GateConfigV2>)[gateName];
|
|
366
|
-
return gateConfig?.enabled !== false;
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
return (this.pack as PackConfigV1).gates || [];
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Execute complete Phase 3 workflow
|
|
374
|
-
*/
|
|
375
|
-
async run(): Promise<Phase3RunResult> {
|
|
376
|
-
const startTime = Date.now();
|
|
377
|
-
|
|
378
|
-
const gatesArray = this.getGatesArray();
|
|
379
|
-
|
|
380
|
-
console.log(chalk.bold.blue(`\n🚀 QA360 Phase 3 Runner - ${this.pack.name}`));
|
|
381
|
-
console.log(chalk.gray(`Gates: ${gatesArray.join(', ')}`));
|
|
382
|
-
|
|
383
|
-
try {
|
|
384
|
-
// Ensure output directory exists
|
|
385
|
-
this.ensureOutputDir();
|
|
386
|
-
|
|
387
|
-
// Load data fixtures if configured
|
|
388
|
-
await this.loadFixtures();
|
|
389
|
-
|
|
390
|
-
// Load page objects if configured
|
|
391
|
-
await this.loadPageObjects();
|
|
392
|
-
|
|
393
|
-
// Initialize cryptographic keys
|
|
394
|
-
console.log(chalk.blue('\n🔑 Initializing Ed25519 keys...'));
|
|
395
|
-
this.keyPair = await initializeKeys();
|
|
396
|
-
console.log(chalk.green(' ✅ Keys ready'));
|
|
397
|
-
|
|
398
|
-
// Initialize Evidence Vault
|
|
399
|
-
console.log(chalk.blue('\n🗄️ Initializing Evidence Vault...'));
|
|
400
|
-
const vaultDir = join(this.workingDir, '.qa360');
|
|
401
|
-
this.vault = await EvidenceVault.open(vaultDir);
|
|
402
|
-
console.log(chalk.green(' ✅ Vault ready'));
|
|
403
|
-
|
|
404
|
-
// Execute beforeAll hooks
|
|
405
|
-
console.log(chalk.blue('\n🔗 Phase 1: Setup Hooks'));
|
|
406
|
-
const beforeAllResults = await this.hooksRunner.executeHooks('beforeAll');
|
|
407
|
-
|
|
408
|
-
// Check if setup failed and should stop
|
|
409
|
-
const setupFailed = beforeAllResults.some(r => !r.success);
|
|
410
|
-
if (setupFailed && this.pack.execution?.on_failure === 'stop') {
|
|
411
|
-
throw new Error('Setup hooks failed, stopping execution');
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// Execute gates
|
|
415
|
-
console.log(chalk.blue('\n🎯 Phase 2: Quality Gates'));
|
|
416
|
-
const gateResults: GateResult[] = [];
|
|
417
|
-
|
|
418
|
-
for (const gate of gatesArray) {
|
|
419
|
-
const gateResult = await this.executeGate(gate);
|
|
420
|
-
gateResults.push(gateResult);
|
|
421
|
-
|
|
422
|
-
// Check if gate failed and should stop
|
|
423
|
-
if (!gateResult.success && this.pack.execution?.on_failure === 'stop') {
|
|
424
|
-
console.log(chalk.yellow(`🛑 Gate ${gate} failed, stopping execution`));
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Flakiness Detection Phase (Vision 2.0)
|
|
430
|
-
let flakinessResults: FlakinessResult[] | undefined;
|
|
431
|
-
if (this.flakyDetect) {
|
|
432
|
-
console.log(chalk.blue(`\n🎲 Phase 2.5: Flakiness Detection (${this.flakyRuns} consecutive runs)`));
|
|
433
|
-
flakinessResults = await this.detectFlakiness(gateResults);
|
|
434
|
-
|
|
435
|
-
// Display flakiness summary
|
|
436
|
-
const unstableCount = flakinessResults.filter(f =>
|
|
437
|
-
f.category === FlakinessCategory.UNSTABLE || f.category === FlakinessCategory.SHAKY
|
|
438
|
-
).length;
|
|
439
|
-
|
|
440
|
-
if (unstableCount > 0) {
|
|
441
|
-
console.log(chalk.yellow(` ⚠️ ${unstableCount} test(s) show flaky behavior`));
|
|
442
|
-
} else {
|
|
443
|
-
console.log(chalk.green(' ✅ All tests stable - no flakiness detected'));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Execute afterAll hooks
|
|
448
|
-
console.log(chalk.blue('\n🔗 Phase 3: Cleanup Hooks'));
|
|
449
|
-
const afterAllResults = await this.hooksRunner.executeHooks('afterAll');
|
|
450
|
-
|
|
451
|
-
// Calculate results
|
|
452
|
-
const duration = Date.now() - startTime;
|
|
453
|
-
const summary = this.calculateSummary(gateResults);
|
|
454
|
-
const success = summary.failed === 0;
|
|
455
|
-
|
|
456
|
-
// Generate proof
|
|
457
|
-
console.log(chalk.blue('\n📋 Phase 4: Proof Generation'));
|
|
458
|
-
const proofPath = await this.generateProof({
|
|
459
|
-
success,
|
|
460
|
-
pack: this.pack,
|
|
461
|
-
duration,
|
|
462
|
-
gates: gateResults,
|
|
463
|
-
hooks: {
|
|
464
|
-
beforeAll: beforeAllResults,
|
|
465
|
-
beforeEach: [],
|
|
466
|
-
afterEach: [],
|
|
467
|
-
afterAll: afterAllResults
|
|
468
|
-
},
|
|
469
|
-
summary
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// Save to Evidence Vault
|
|
473
|
-
console.log(chalk.blue('\n💾 Phase 5: Evidence Storage'));
|
|
474
|
-
const proofRunId = proofPath.split('/').pop()?.replace('-proof.json', '') || 'unknown';
|
|
475
|
-
const vaultRunId = await this.saveToVault(proofRunId, {
|
|
476
|
-
success,
|
|
477
|
-
pack: this.pack,
|
|
478
|
-
duration,
|
|
479
|
-
gates: gateResults,
|
|
480
|
-
hooks: {
|
|
481
|
-
beforeAll: beforeAllResults,
|
|
482
|
-
beforeEach: [],
|
|
483
|
-
afterEach: [],
|
|
484
|
-
afterAll: afterAllResults
|
|
485
|
-
},
|
|
486
|
-
summary,
|
|
487
|
-
proofPath
|
|
488
|
-
}, proofPath, flakinessResults, startTime);
|
|
489
|
-
|
|
490
|
-
// Final summary
|
|
491
|
-
console.log(chalk.blue('\n📊 Execution Summary'));
|
|
492
|
-
console.log(` Duration: ${duration}ms`);
|
|
493
|
-
console.log(` Gates: ${summary.passed}/${summary.total} passed`);
|
|
494
|
-
console.log(` Trust Score: ${summary.trustScore}%`);
|
|
495
|
-
console.log(` Proof: ${proofPath}`);
|
|
496
|
-
|
|
497
|
-
// Display flakiness details if enabled
|
|
498
|
-
if (flakinessResults && flakinessResults.length > 0) {
|
|
499
|
-
console.log(chalk.blue('\n🎲 Flakiness Scores:'));
|
|
500
|
-
for (const f of flakinessResults) {
|
|
501
|
-
const scoreFormatted = formatFlakinessScore(f.score);
|
|
502
|
-
const categoryMeta = {
|
|
503
|
-
[FlakinessCategory.LEGENDARY]: { emoji: '🟢', color: chalk.green },
|
|
504
|
-
[FlakinessCategory.SOLID]: { emoji: '🟢', color: chalk.green },
|
|
505
|
-
[FlakinessCategory.GOOD]: { emoji: '🟡', color: chalk.yellow },
|
|
506
|
-
[FlakinessCategory.SHAKY]: { emoji: '🟠', color: chalk.hex('#F97316') },
|
|
507
|
-
[FlakinessCategory.UNSTABLE]: { emoji: '🔴', color: chalk.red }
|
|
508
|
-
}[f.category];
|
|
509
|
-
|
|
510
|
-
console.log(` ${categoryMeta.color(`${f.testName}: ${scoreFormatted}`)} (${f.successfulRuns}/${f.totalRuns} passes)`);
|
|
511
|
-
if (f.suggestedFix) {
|
|
512
|
-
console.log(chalk.gray(` 💡 ${f.suggestedFix}`));
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if (success) {
|
|
518
|
-
console.log(chalk.green('\n✅ All quality gates passed!'));
|
|
519
|
-
} else {
|
|
520
|
-
console.log(chalk.red(`\n❌ ${summary.failed} quality gate(s) failed`));
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
return {
|
|
524
|
-
success,
|
|
525
|
-
pack: this.pack,
|
|
526
|
-
duration,
|
|
527
|
-
gates: gateResults,
|
|
528
|
-
hooks: {
|
|
529
|
-
beforeAll: beforeAllResults,
|
|
530
|
-
beforeEach: [],
|
|
531
|
-
afterEach: [],
|
|
532
|
-
afterAll: afterAllResults
|
|
533
|
-
},
|
|
534
|
-
summary,
|
|
535
|
-
flakiness: flakinessResults,
|
|
536
|
-
proofPath,
|
|
537
|
-
runId: vaultRunId
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
} catch (error) {
|
|
541
|
-
const duration = Date.now() - startTime;
|
|
542
|
-
|
|
543
|
-
// Ensure cleanup even on error
|
|
544
|
-
try {
|
|
545
|
-
await this.hooksRunner.executeHooks('afterAll');
|
|
546
|
-
} catch {
|
|
547
|
-
// Ignore cleanup errors
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
return {
|
|
551
|
-
success: false,
|
|
552
|
-
pack: this.pack,
|
|
553
|
-
duration,
|
|
554
|
-
gates: [],
|
|
555
|
-
hooks: { beforeAll: [], beforeEach: [], afterEach: [], afterAll: [] },
|
|
556
|
-
summary: { total: 0, passed: 0, failed: 0, trustScore: 0 },
|
|
557
|
-
error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error')
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Execute a single quality gate
|
|
564
|
-
*/
|
|
565
|
-
private async executeGate(gate: string): Promise<GateResult> {
|
|
566
|
-
const startTime = Date.now();
|
|
567
|
-
|
|
568
|
-
console.log(chalk.cyan(`\n 🎯 Gate: ${gate}`));
|
|
569
|
-
|
|
570
|
-
try {
|
|
571
|
-
let result: any;
|
|
572
|
-
let adapter: string;
|
|
573
|
-
|
|
574
|
-
// Check if this is a v2 pack with dynamic gate configuration
|
|
575
|
-
if (this.isPackV2(this.pack)) {
|
|
576
|
-
const gateConfig = (this.pack.gates as Record<string, any>)[gate];
|
|
577
|
-
if (gateConfig) {
|
|
578
|
-
return await this.executeDynamicGate(gate, gateConfig);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Legacy v1 gates or predefined gates
|
|
583
|
-
switch (gate) {
|
|
584
|
-
case 'api_smoke':
|
|
585
|
-
adapter = 'playwright-native-api';
|
|
586
|
-
result = await this.runApiSmokeGate();
|
|
587
|
-
break;
|
|
588
|
-
|
|
589
|
-
case 'ui':
|
|
590
|
-
adapter = 'playwright-ui';
|
|
591
|
-
result = await this.runUiGate();
|
|
592
|
-
break;
|
|
593
|
-
|
|
594
|
-
case 'a11y':
|
|
595
|
-
adapter = 'playwright-ui';
|
|
596
|
-
result = await this.runA11yGate();
|
|
597
|
-
break;
|
|
598
|
-
|
|
599
|
-
case 'perf':
|
|
600
|
-
adapter = 'k6';
|
|
601
|
-
result = await this.runPerfGate();
|
|
602
|
-
break;
|
|
603
|
-
|
|
604
|
-
case 'sast':
|
|
605
|
-
adapter = 'semgrep';
|
|
606
|
-
result = await this.runSastGate();
|
|
607
|
-
break;
|
|
608
|
-
|
|
609
|
-
case 'dast':
|
|
610
|
-
adapter = 'zap';
|
|
611
|
-
result = await this.runDastGate();
|
|
612
|
-
break;
|
|
613
|
-
|
|
614
|
-
default:
|
|
615
|
-
throw new Error(`Unknown gate: ${gate}`);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
const duration = Date.now() - startTime;
|
|
619
|
-
|
|
620
|
-
if (result.success) {
|
|
621
|
-
console.log(chalk.green(` ✅ ${gate} passed (${duration}ms)`));
|
|
622
|
-
} else {
|
|
623
|
-
console.log(chalk.red(` ❌ ${gate} failed (${duration}ms)`));
|
|
624
|
-
if (result.error) {
|
|
625
|
-
console.log(chalk.red(` 🔍 ${result.error}`));
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
return {
|
|
630
|
-
gate,
|
|
631
|
-
success: result.success,
|
|
632
|
-
duration,
|
|
633
|
-
adapter,
|
|
634
|
-
results: result,
|
|
635
|
-
junit: result.junit,
|
|
636
|
-
error: result.error
|
|
637
|
-
};
|
|
638
|
-
|
|
639
|
-
} catch (error) {
|
|
640
|
-
const duration = Date.now() - startTime;
|
|
641
|
-
const errorMessage = this.redactor.redact(error instanceof Error ? error.message : 'Unknown error');
|
|
642
|
-
|
|
643
|
-
console.log(chalk.red(` 💥 ${gate} crashed (${duration}ms): ${errorMessage}`));
|
|
644
|
-
|
|
645
|
-
return {
|
|
646
|
-
gate,
|
|
647
|
-
success: false,
|
|
648
|
-
duration,
|
|
649
|
-
adapter: 'unknown',
|
|
650
|
-
results: null,
|
|
651
|
-
error: errorMessage
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Execute a dynamic v2 gate
|
|
658
|
-
*/
|
|
659
|
-
private async executeDynamicGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
660
|
-
const startTime = Date.now();
|
|
661
|
-
const adapterType = gateConfig.adapter || gateConfig.type;
|
|
662
|
-
|
|
663
|
-
if (!adapterType) {
|
|
664
|
-
throw new Error(`Gate '${gateName}' must specify an adapter`);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// Resolve fixtures in gate configuration
|
|
668
|
-
const resolvedGateConfig = this.resolveFixturesInConfig(gateConfig);
|
|
669
|
-
|
|
670
|
-
// Get auth credentials for this gate
|
|
671
|
-
const credentials = await this.getCredentialsForGate(gateName);
|
|
672
|
-
|
|
673
|
-
// Map adapter type to implementation
|
|
674
|
-
let result: GateResult;
|
|
675
|
-
switch (adapterType) {
|
|
676
|
-
case 'playwright-api':
|
|
677
|
-
result = await this.executePlaywrightApiGate(gateName, resolvedGateConfig, credentials);
|
|
678
|
-
break;
|
|
679
|
-
|
|
680
|
-
case 'playwright-ui':
|
|
681
|
-
result = await this.executePlaywrightUiGate(gateName, resolvedGateConfig, credentials);
|
|
682
|
-
break;
|
|
683
|
-
|
|
684
|
-
case 'k6':
|
|
685
|
-
case 'k6-perf':
|
|
686
|
-
result = await this.executeK6PerfGate(gateName, resolvedGateConfig);
|
|
687
|
-
break;
|
|
688
|
-
|
|
689
|
-
case 'semgrep':
|
|
690
|
-
case 'sast':
|
|
691
|
-
result = await this.executeSemgrepSastGate(gateName, resolvedGateConfig);
|
|
692
|
-
break;
|
|
693
|
-
|
|
694
|
-
// v2.2.0 Unit Test Adapters
|
|
695
|
-
case 'vitest':
|
|
696
|
-
result = await this.executeVitestGate(gateName, resolvedGateConfig);
|
|
697
|
-
break;
|
|
698
|
-
|
|
699
|
-
case 'jest':
|
|
700
|
-
result = await this.executeJestGate(gateName, resolvedGateConfig);
|
|
701
|
-
break;
|
|
702
|
-
|
|
703
|
-
case 'pytest':
|
|
704
|
-
result = await this.executePytestGate(gateName, resolvedGateConfig);
|
|
705
|
-
break;
|
|
706
|
-
|
|
707
|
-
default:
|
|
708
|
-
throw new Error(`Unsupported adapter: '${adapterType}' for gate '${gateName}'`);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
// Set duration
|
|
712
|
-
result.duration = Date.now() - startTime;
|
|
713
|
-
|
|
714
|
-
// Log result
|
|
715
|
-
if (result.success) {
|
|
716
|
-
console.log(chalk.green(` ✅ ${gateName} passed (${result.duration}ms)`));
|
|
717
|
-
} else {
|
|
718
|
-
console.log(chalk.red(` ❌ ${gateName} failed (${result.duration}ms)`));
|
|
719
|
-
if (result.error) {
|
|
720
|
-
console.log(chalk.red(` 🔍 ${result.error}`));
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
return result;
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Execute Playwright API gate with v2 config
|
|
729
|
-
* Uses PlaywrightNativeApiAdapter for zero-overhead HTTP testing
|
|
730
|
-
*/
|
|
731
|
-
private async executePlaywrightApiGate(gateName: string, gateConfig: any, credentials?: any): Promise<GateResult> {
|
|
732
|
-
const { PlaywrightNativeApiAdapter } = await import('../adapters/playwright-native-api.js');
|
|
733
|
-
const adapter = new PlaywrightNativeApiAdapter();
|
|
734
|
-
|
|
735
|
-
// Transform v2 config to adapter format
|
|
736
|
-
const gateConfigData = gateConfig.config || {};
|
|
737
|
-
const gateOptions = gateConfig.options || {};
|
|
738
|
-
|
|
739
|
-
const config = {
|
|
740
|
-
target: {
|
|
741
|
-
baseUrl: gateConfigData.baseUrl,
|
|
742
|
-
smoke: gateConfigData.smoke
|
|
743
|
-
},
|
|
744
|
-
budgets: gateConfigData.budgets,
|
|
745
|
-
timeout: gateOptions.timeout || gateConfigData.timeout,
|
|
746
|
-
retries: gateOptions.retries || gateConfigData.retries,
|
|
747
|
-
auth: credentials
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
const result = await adapter.runSmokeTests(config);
|
|
751
|
-
return {
|
|
752
|
-
gate: gateName,
|
|
753
|
-
success: result.success,
|
|
754
|
-
duration: 0, // Will be set by caller
|
|
755
|
-
adapter: 'playwright-native-api',
|
|
756
|
-
results: result,
|
|
757
|
-
junit: result.junit
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* Execute Playwright UI gate with v2 config
|
|
763
|
-
*/
|
|
764
|
-
private async executePlaywrightUiGate(gateName: string, gateConfig: any, credentials?: any): Promise<GateResult> {
|
|
765
|
-
const { PlaywrightUiAdapter } = await import('../adapters/playwright-ui.js');
|
|
766
|
-
const adapter = new PlaywrightUiAdapter();
|
|
767
|
-
|
|
768
|
-
// Transform v2 config to adapter format
|
|
769
|
-
// v2: { baseUrl, pages: [{ url: '/', expectedElements: [...] }] }
|
|
770
|
-
// adapter expects: { target: { baseUrl, pages: ['https://.../'] } }
|
|
771
|
-
const gateConfigData = gateConfig.config || {};
|
|
772
|
-
const gateOptions = gateConfig.options || {};
|
|
773
|
-
|
|
774
|
-
// Transform page objects to full URLs
|
|
775
|
-
// v2 pages format: [{ url: '/', expectedElements: [...] }] or ['/', '/about']
|
|
776
|
-
const rawPages = gateConfigData.pages;
|
|
777
|
-
let pages: string[] | undefined;
|
|
778
|
-
if (rawPages && Array.isArray(rawPages) && rawPages.length > 0) {
|
|
779
|
-
const baseUrl = gateConfigData.baseUrl || '';
|
|
780
|
-
pages = rawPages.map((p: any) => {
|
|
781
|
-
if (typeof p === 'string') {
|
|
782
|
-
// Already a URL string - make it absolute if relative
|
|
783
|
-
return p.startsWith('http') ? p : `${baseUrl.replace(/\/$/, '')}${p}`;
|
|
784
|
-
} else if (p && typeof p === 'object' && p.url) {
|
|
785
|
-
// Page object { url: '/', ... } - convert to full URL
|
|
786
|
-
const url = p.url;
|
|
787
|
-
return url.startsWith('http') ? url : `${baseUrl.replace(/\/$/, '')}${url}`;
|
|
788
|
-
}
|
|
789
|
-
return p;
|
|
790
|
-
});
|
|
791
|
-
} else if (gateConfigData.baseUrl) {
|
|
792
|
-
pages = [gateConfigData.baseUrl];
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
const config = {
|
|
796
|
-
target: {
|
|
797
|
-
baseUrl: gateConfigData.baseUrl,
|
|
798
|
-
pages: pages
|
|
799
|
-
},
|
|
800
|
-
budgets: gateConfigData.budgets,
|
|
801
|
-
timeout: gateOptions.timeout || gateConfigData.timeout,
|
|
802
|
-
auth: credentials,
|
|
803
|
-
// Playwright++ features
|
|
804
|
-
artifacts: gateConfigData.artifacts,
|
|
805
|
-
htmlReport: gateConfigData.htmlReport,
|
|
806
|
-
bail: gateConfigData.bail
|
|
807
|
-
};
|
|
808
|
-
|
|
809
|
-
const result = await adapter.runSmokeTests(config);
|
|
810
|
-
return {
|
|
811
|
-
gate: gateName,
|
|
812
|
-
success: result.success,
|
|
813
|
-
duration: 0, // Will be set by caller
|
|
814
|
-
adapter: 'playwright-ui',
|
|
815
|
-
results: result,
|
|
816
|
-
junit: result.junit
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* Execute K6 Performance gate with v2 config
|
|
822
|
-
*/
|
|
823
|
-
private async executeK6PerfGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
824
|
-
const { K6PerfAdapter } = await import('../adapters/k6-perf.js');
|
|
825
|
-
const adapter = new K6PerfAdapter(this.workingDir);
|
|
826
|
-
|
|
827
|
-
const config = {
|
|
828
|
-
baseUrl: gateConfig.config?.baseUrl,
|
|
829
|
-
...gateConfig.config
|
|
830
|
-
};
|
|
831
|
-
|
|
832
|
-
const result = await adapter.runPerfTest(config);
|
|
833
|
-
return {
|
|
834
|
-
gate: gateName,
|
|
835
|
-
success: result.success,
|
|
836
|
-
duration: 0,
|
|
837
|
-
adapter: 'k6',
|
|
838
|
-
results: result,
|
|
839
|
-
junit: result.junit
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
/**
|
|
844
|
-
* Execute Semgrep SAST gate with v2 config
|
|
845
|
-
*/
|
|
846
|
-
private async executeSemgrepSastGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
847
|
-
const { SemgrepSastAdapter } = await import('../adapters/semgrep-sast.js');
|
|
848
|
-
const adapter = new SemgrepSastAdapter();
|
|
849
|
-
|
|
850
|
-
const config = {
|
|
851
|
-
workingDir: this.workingDir,
|
|
852
|
-
...gateConfig.config
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
const result = await adapter.runSastScan(config);
|
|
856
|
-
return {
|
|
857
|
-
gate: gateName,
|
|
858
|
-
success: result.success,
|
|
859
|
-
duration: 0,
|
|
860
|
-
adapter: 'semgrep',
|
|
861
|
-
results: result,
|
|
862
|
-
junit: result.junit
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
/**
|
|
867
|
-
* Execute Vitest unit tests gate (v2.2.0)
|
|
868
|
-
*/
|
|
869
|
-
private async executeVitestGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
870
|
-
const adapter = new VitestAdapter(this.workingDir);
|
|
871
|
-
|
|
872
|
-
const config: any = {
|
|
873
|
-
cwd: this.workingDir,
|
|
874
|
-
...gateConfig.config
|
|
875
|
-
};
|
|
876
|
-
|
|
877
|
-
const result = await adapter.execute(config);
|
|
878
|
-
|
|
879
|
-
return {
|
|
880
|
-
gate: gateName,
|
|
881
|
-
success: result.success,
|
|
882
|
-
duration: result.duration,
|
|
883
|
-
adapter: 'vitest',
|
|
884
|
-
results: {
|
|
885
|
-
total: result.total,
|
|
886
|
-
passed: result.passed,
|
|
887
|
-
failed: result.failed,
|
|
888
|
-
skipped: result.skipped,
|
|
889
|
-
tests: result.tests.map(t => ({
|
|
890
|
-
name: t.name,
|
|
891
|
-
status: t.status,
|
|
892
|
-
duration: t.duration,
|
|
893
|
-
error: t.error
|
|
894
|
-
}))
|
|
895
|
-
},
|
|
896
|
-
junit: this.buildJunitFromVitest(result)
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* Execute Jest unit tests gate (v2.2.0)
|
|
902
|
-
*/
|
|
903
|
-
private async executeJestGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
904
|
-
const adapter = new JestAdapter(this.workingDir);
|
|
905
|
-
|
|
906
|
-
const config: any = {
|
|
907
|
-
cwd: this.workingDir,
|
|
908
|
-
...gateConfig.config
|
|
909
|
-
};
|
|
910
|
-
|
|
911
|
-
const result = await adapter.execute(config);
|
|
912
|
-
|
|
913
|
-
return {
|
|
914
|
-
gate: gateName,
|
|
915
|
-
success: result.success,
|
|
916
|
-
duration: result.duration,
|
|
917
|
-
adapter: 'jest',
|
|
918
|
-
results: {
|
|
919
|
-
total: result.total,
|
|
920
|
-
passed: result.passed,
|
|
921
|
-
failed: result.failed,
|
|
922
|
-
skipped: result.skipped + result.pending,
|
|
923
|
-
tests: result.tests.map(t => ({
|
|
924
|
-
name: t.name,
|
|
925
|
-
status: t.status,
|
|
926
|
-
duration: t.duration,
|
|
927
|
-
error: t.error
|
|
928
|
-
}))
|
|
929
|
-
},
|
|
930
|
-
junit: this.buildJunitFromJest(result)
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* Execute Pytest unit tests gate (v2.2.0)
|
|
936
|
-
*/
|
|
937
|
-
private async executePytestGate(gateName: string, gateConfig: any): Promise<GateResult> {
|
|
938
|
-
const adapter = new PytestAdapter(this.workingDir);
|
|
939
|
-
|
|
940
|
-
const config: any = {
|
|
941
|
-
cwd: this.workingDir,
|
|
942
|
-
...gateConfig.config
|
|
943
|
-
};
|
|
944
|
-
|
|
945
|
-
const result = await adapter.execute(config);
|
|
946
|
-
|
|
947
|
-
return {
|
|
948
|
-
gate: gateName,
|
|
949
|
-
success: result.success,
|
|
950
|
-
duration: result.duration,
|
|
951
|
-
adapter: 'pytest',
|
|
952
|
-
results: {
|
|
953
|
-
total: result.total,
|
|
954
|
-
passed: result.passed,
|
|
955
|
-
failed: result.failed,
|
|
956
|
-
skipped: result.skipped,
|
|
957
|
-
tests: result.tests.map(t => ({
|
|
958
|
-
name: t.name,
|
|
959
|
-
status: t.status,
|
|
960
|
-
duration: t.duration,
|
|
961
|
-
error: t.error
|
|
962
|
-
}))
|
|
963
|
-
},
|
|
964
|
-
junit: this.buildJunitFromPytest(result)
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* Build JUnit format from Vitest results
|
|
970
|
-
*/
|
|
971
|
-
private buildJunitFromVitest(result: any): any {
|
|
972
|
-
// Convert adapter result to JUnit-like format
|
|
973
|
-
return {
|
|
974
|
-
testsuites: [{
|
|
975
|
-
name: 'vitest',
|
|
976
|
-
tests: result.total,
|
|
977
|
-
failures: result.failed,
|
|
978
|
-
skipped: result.skipped,
|
|
979
|
-
time: result.duration / 1000,
|
|
980
|
-
testcases: result.tests.map((t: any) => ({
|
|
981
|
-
name: t.name,
|
|
982
|
-
classname: t.file,
|
|
983
|
-
time: t.duration / 1000,
|
|
984
|
-
failure: t.error ? { message: t.error } : undefined,
|
|
985
|
-
skipped: t.status === 'skipped' ? { message: 'Skipped' } : undefined
|
|
986
|
-
}))
|
|
987
|
-
}]
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* Build JUnit format from Jest results
|
|
993
|
-
*/
|
|
994
|
-
private buildJunitFromJest(result: any): any {
|
|
995
|
-
return {
|
|
996
|
-
testsuites: [{
|
|
997
|
-
name: 'jest',
|
|
998
|
-
tests: result.total,
|
|
999
|
-
failures: result.failed,
|
|
1000
|
-
skipped: result.pending,
|
|
1001
|
-
time: result.duration / 1000,
|
|
1002
|
-
testcases: result.tests.map((t: any) => ({
|
|
1003
|
-
name: t.name,
|
|
1004
|
-
time: t.duration / 1000,
|
|
1005
|
-
failure: t.error ? { message: t.error } : undefined,
|
|
1006
|
-
skipped: t.status === 'pending' || t.status === 'skipped' ? { message: 'Skipped' } : undefined
|
|
1007
|
-
}))
|
|
1008
|
-
}]
|
|
1009
|
-
};
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* Build JUnit format from Pytest results
|
|
1014
|
-
*/
|
|
1015
|
-
private buildJunitFromPytest(result: any): any {
|
|
1016
|
-
return {
|
|
1017
|
-
testsuites: [{
|
|
1018
|
-
name: 'pytest',
|
|
1019
|
-
tests: result.total,
|
|
1020
|
-
failures: result.failed,
|
|
1021
|
-
skipped: result.skipped,
|
|
1022
|
-
time: result.duration / 1000,
|
|
1023
|
-
testcases: result.tests.map((t: any) => ({
|
|
1024
|
-
name: t.name,
|
|
1025
|
-
classname: t.file,
|
|
1026
|
-
time: t.duration / 1000,
|
|
1027
|
-
failure: t.error ? { message: t.error } : undefined,
|
|
1028
|
-
skipped: t.status === 'skipped' ? { message: 'Skipped' } : undefined
|
|
1029
|
-
}))
|
|
1030
|
-
}]
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
/**
|
|
1035
|
-
* Run API smoke gate
|
|
1036
|
-
* Uses PlaywrightNativeApiAdapter for zero-overhead HTTP testing
|
|
1037
|
-
*/
|
|
1038
|
-
private async runApiSmokeGate() {
|
|
1039
|
-
const target = this.getTargetApi();
|
|
1040
|
-
if (!target) {
|
|
1041
|
-
throw new Error('API smoke gate requires targets.api configuration or gate config with baseUrl');
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
const credentials = await this.getCredentialsForGate('api_smoke');
|
|
1045
|
-
|
|
1046
|
-
const adapter = new PlaywrightNativeApiAdapter();
|
|
1047
|
-
return await adapter.runSmokeTests({
|
|
1048
|
-
target,
|
|
1049
|
-
budgets: this.getBudgets(),
|
|
1050
|
-
timeout: this.getExecutionTimeout() || 10000,
|
|
1051
|
-
retries: this.getExecutionRetries() || 1,
|
|
1052
|
-
auth: credentials
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
/**
|
|
1057
|
-
* Run UI gate (includes basic accessibility)
|
|
1058
|
-
*/
|
|
1059
|
-
private async runUiGate() {
|
|
1060
|
-
const target = this.getTargetWeb();
|
|
1061
|
-
if (!target) {
|
|
1062
|
-
throw new Error('UI gate requires targets.web configuration or gate config with baseUrl');
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
const credentials = await this.getCredentialsForGate('ui');
|
|
1066
|
-
|
|
1067
|
-
const adapter = new PlaywrightUiAdapter();
|
|
1068
|
-
return await adapter.runSmokeTests({
|
|
1069
|
-
target,
|
|
1070
|
-
budgets: this.getBudgets(),
|
|
1071
|
-
timeout: this.getExecutionTimeout() || 30000,
|
|
1072
|
-
auth: credentials
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
/**
|
|
1077
|
-
* Run A11y gate (focused accessibility testing)
|
|
1078
|
-
*/
|
|
1079
|
-
private async runA11yGate() {
|
|
1080
|
-
// Same as UI gate but focused on accessibility
|
|
1081
|
-
return await this.runUiGate();
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
/**
|
|
1085
|
-
* Run performance gate
|
|
1086
|
-
*/
|
|
1087
|
-
private async runPerfGate() {
|
|
1088
|
-
const baseUrl = (this.pack as PackConfigV1).targets?.web?.baseUrl || (this.pack as PackConfigV1).targets?.api?.baseUrl;
|
|
1089
|
-
if (!baseUrl) {
|
|
1090
|
-
throw new Error('Performance gate requires web or api target');
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
const adapter = new K6PerfAdapter(this.workingDir);
|
|
1094
|
-
return await adapter.runPerfTest({
|
|
1095
|
-
baseUrl,
|
|
1096
|
-
budgets: (this.pack as PackConfigV1).budgets,
|
|
1097
|
-
duration: '30s',
|
|
1098
|
-
vus: 5,
|
|
1099
|
-
timeout: 120000
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
/**
|
|
1104
|
-
* Run SAST gate
|
|
1105
|
-
*/
|
|
1106
|
-
private async runSastGate() {
|
|
1107
|
-
const adapter = new SemgrepSastAdapter();
|
|
1108
|
-
return await adapter.runSastScan({
|
|
1109
|
-
workingDir: this.workingDir,
|
|
1110
|
-
security: (this.pack as PackConfigV1).security,
|
|
1111
|
-
rules: ['auto'],
|
|
1112
|
-
paths: ['src/', 'lib/', '.'],
|
|
1113
|
-
timeout: 120000
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
/**
|
|
1118
|
-
* Run DAST gate (mock implementation)
|
|
1119
|
-
*/
|
|
1120
|
-
private async runDastGate() {
|
|
1121
|
-
// Mock DAST implementation for Phase 3
|
|
1122
|
-
console.log(chalk.yellow(' ⚠️ DAST gate: Mock implementation (ZAP integration in Phase 4)'));
|
|
1123
|
-
|
|
1124
|
-
return {
|
|
1125
|
-
success: true,
|
|
1126
|
-
findings: [],
|
|
1127
|
-
summary: { total: 0, high: 0, medium: 0, low: 0 },
|
|
1128
|
-
junit: `<?xml version="1.0" encoding="UTF-8"?>
|
|
1129
|
-
<testsuite name="DAST Mock" tests="1" failures="0" time="0">
|
|
1130
|
-
<testcase name="Mock DAST Scan" time="0"></testcase>
|
|
1131
|
-
</testsuite>`
|
|
1132
|
-
};
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
* Calculate execution summary
|
|
1137
|
-
*/
|
|
1138
|
-
private calculateSummary(gateResults: GateResult[]): Phase3RunResult['summary'] {
|
|
1139
|
-
const total = gateResults.length;
|
|
1140
|
-
const passed = gateResults.filter(g => g.success).length;
|
|
1141
|
-
const failed = total - passed;
|
|
1142
|
-
|
|
1143
|
-
// Calculate trust score (weighted by gate importance)
|
|
1144
|
-
const gateWeights: Record<string, number> = {
|
|
1145
|
-
'api_smoke': 20,
|
|
1146
|
-
'ui': 15,
|
|
1147
|
-
'perf': 15,
|
|
1148
|
-
'sast': 20,
|
|
1149
|
-
'dast': 20,
|
|
1150
|
-
'a11y': 10
|
|
1151
|
-
};
|
|
1152
|
-
|
|
1153
|
-
let totalWeight = 0;
|
|
1154
|
-
let passedWeight = 0;
|
|
1155
|
-
|
|
1156
|
-
for (const gate of gateResults) {
|
|
1157
|
-
const weight = gateWeights[gate.gate] || 10;
|
|
1158
|
-
totalWeight += weight;
|
|
1159
|
-
if (gate.success) {
|
|
1160
|
-
passedWeight += weight;
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
const trustScore = totalWeight > 0 ? Math.round((passedWeight / totalWeight) * 100) : 0;
|
|
1165
|
-
|
|
1166
|
-
return { total, passed, failed, trustScore };
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
/**
|
|
1170
|
-
* Generate cryptographically signed proof document
|
|
1171
|
-
*/
|
|
1172
|
-
private async generateProof(result: Phase3RunResult): Promise<string> {
|
|
1173
|
-
const timestamp = new Date().toISOString();
|
|
1174
|
-
const runId = `run-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1175
|
-
|
|
1176
|
-
// Build proof payload (without signature)
|
|
1177
|
-
const proofPayload = {
|
|
1178
|
-
version: '3.0.0',
|
|
1179
|
-
runId,
|
|
1180
|
-
timestamp,
|
|
1181
|
-
pack: {
|
|
1182
|
-
name: result.pack.name,
|
|
1183
|
-
version: result.pack.version,
|
|
1184
|
-
gates: result.pack.gates
|
|
1185
|
-
},
|
|
1186
|
-
execution: {
|
|
1187
|
-
duration: result.duration,
|
|
1188
|
-
success: result.success,
|
|
1189
|
-
trustScore: result.summary.trustScore
|
|
1190
|
-
},
|
|
1191
|
-
gates: result.gates.map(g => {
|
|
1192
|
-
const gateObj: any = {
|
|
1193
|
-
gate: g.gate,
|
|
1194
|
-
adapter: g.adapter,
|
|
1195
|
-
success: g.success,
|
|
1196
|
-
duration: g.duration
|
|
1197
|
-
};
|
|
1198
|
-
// Only include error if it exists (avoid undefined fields)
|
|
1199
|
-
if (g.error !== undefined) {
|
|
1200
|
-
gateObj.error = g.error;
|
|
1201
|
-
}
|
|
1202
|
-
return gateObj;
|
|
1203
|
-
}),
|
|
1204
|
-
hooks: {
|
|
1205
|
-
beforeAll: result.hooks.beforeAll.length,
|
|
1206
|
-
afterAll: result.hooks.afterAll.length
|
|
1207
|
-
}
|
|
1208
|
-
};
|
|
1209
|
-
|
|
1210
|
-
// Canonicalize the payload for signing (must match verification: canonical + newline)
|
|
1211
|
-
const canonicalPayload = canonicalize(proofPayload) + '\n';
|
|
1212
|
-
|
|
1213
|
-
// Sign with Ed25519
|
|
1214
|
-
let signatureValue: string;
|
|
1215
|
-
let algorithm: string;
|
|
1216
|
-
let publicKeyB64: string;
|
|
1217
|
-
|
|
1218
|
-
if (this.keyPair) {
|
|
1219
|
-
signatureValue = sign(canonicalPayload, this.keyPair.secretKey);
|
|
1220
|
-
algorithm = 'ed25519';
|
|
1221
|
-
publicKeyB64 = Buffer.from(this.keyPair.publicKey).toString('base64');
|
|
1222
|
-
console.log(chalk.green(' 🔏 Proof signed with Ed25519'));
|
|
1223
|
-
} else {
|
|
1224
|
-
signatureValue = `unsigned-${runId}`;
|
|
1225
|
-
algorithm = 'none';
|
|
1226
|
-
publicKeyB64 = '';
|
|
1227
|
-
console.log(chalk.yellow(' ⚠️ Proof unsigned (no keys available)'));
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
// Build complete proof with signature
|
|
1231
|
-
const proof = {
|
|
1232
|
-
...proofPayload,
|
|
1233
|
-
signature: {
|
|
1234
|
-
algorithm,
|
|
1235
|
-
publicKey: publicKeyB64,
|
|
1236
|
-
value: signatureValue,
|
|
1237
|
-
timestamp
|
|
1238
|
-
}
|
|
1239
|
-
};
|
|
1240
|
-
|
|
1241
|
-
// Save proof
|
|
1242
|
-
const proofPath = join(this.outputDir, `${runId}-proof.json`);
|
|
1243
|
-
writeFileSync(proofPath, JSON.stringify(proof, null, 2));
|
|
1244
|
-
|
|
1245
|
-
return proofPath;
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
/**
|
|
1249
|
-
* Save run results to Evidence Vault
|
|
1250
|
-
* @returns The vault run ID
|
|
1251
|
-
*/
|
|
1252
|
-
private async saveToVault(
|
|
1253
|
-
runId: string,
|
|
1254
|
-
result: Phase3RunResult,
|
|
1255
|
-
proofPath: string,
|
|
1256
|
-
flakinessResults?: FlakinessResult[],
|
|
1257
|
-
startTime?: number
|
|
1258
|
-
): Promise<string | undefined> {
|
|
1259
|
-
if (!this.vault) {
|
|
1260
|
-
console.log(chalk.yellow(' ⚠️ Vault not initialized, skipping storage'));
|
|
1261
|
-
return undefined;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
try {
|
|
1265
|
-
// Begin run in vault (returns actual runId used)
|
|
1266
|
-
// Use startTime if provided to correctly calculate duration
|
|
1267
|
-
const { runId: vaultRunId } = await this.vault.beginRun({
|
|
1268
|
-
pack_path: `${(this.pack as any).name || 'pack'}.yaml`,
|
|
1269
|
-
pack_hash: this.hashPack(result.pack),
|
|
1270
|
-
started_at: startTime // Use actual run start time for accurate duration
|
|
1271
|
-
});
|
|
1272
|
-
|
|
1273
|
-
// Finish run with final status
|
|
1274
|
-
await this.vault.finishRun(vaultRunId, {
|
|
1275
|
-
status: result.success ? 'passed' : 'failed',
|
|
1276
|
-
trust_score: result.summary.trustScore,
|
|
1277
|
-
signature: this.keyPair ? 'ed25519-signed' : undefined
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
// Record gate executions
|
|
1281
|
-
for (const gate of result.gates) {
|
|
1282
|
-
await this.vault.recordGate(vaultRunId, {
|
|
1283
|
-
name: gate.gate,
|
|
1284
|
-
status: gate.success ? 'passed' : 'failed',
|
|
1285
|
-
duration_ms: gate.duration,
|
|
1286
|
-
metrics_json: JSON.stringify(gate.results?.summary || {})
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
// Record finding if gate has error
|
|
1290
|
-
if (gate.error) {
|
|
1291
|
-
await this.vault.recordFinding(vaultRunId, {
|
|
1292
|
-
gate: gate.gate,
|
|
1293
|
-
severity: 'high',
|
|
1294
|
-
rule: 'gate-failure',
|
|
1295
|
-
message: gate.error
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
// Record flakiness results if available
|
|
1301
|
-
if (flakinessResults && flakinessResults.length > 0) {
|
|
1302
|
-
for (const flaky of flakinessResults) {
|
|
1303
|
-
// Record unstable/shaky tests as findings
|
|
1304
|
-
if (flaky.category === FlakinessCategory.UNSTABLE || flaky.category === FlakinessCategory.SHAKY) {
|
|
1305
|
-
await this.vault.recordFinding(vaultRunId, {
|
|
1306
|
-
gate: flaky.gate,
|
|
1307
|
-
severity: flaky.category === FlakinessCategory.UNSTABLE ? 'high' : 'medium',
|
|
1308
|
-
rule: 'flaky-test-detected',
|
|
1309
|
-
message: `Test "${flaky.testName}" is ${flaky.category}: ${flaky.score}% reliability (${flaky.successfulRuns}/${flaky.totalRuns} passes)`
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
console.log(chalk.green(` 💾 ${flakinessResults.length} flakiness analysis(es) saved`));
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
console.log(chalk.green(' 💾 Run saved to Evidence Vault'));
|
|
1317
|
-
return vaultRunId;
|
|
1318
|
-
|
|
1319
|
-
} catch (error) {
|
|
1320
|
-
console.log(chalk.yellow(` ⚠️ Failed to save to vault: ${error}`));
|
|
1321
|
-
return undefined;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
/**
|
|
1326
|
-
* Detect flakiness by running tests multiple times consecutively
|
|
1327
|
-
* @param gateResults Original gate results from first run
|
|
1328
|
-
* @returns Flakiness analysis results
|
|
1329
|
-
*/
|
|
1330
|
-
private async detectFlakiness(gateResults: GateResult[]): Promise<FlakinessResult[]> {
|
|
1331
|
-
const flakinessMap = new Map<string, FlakyTestResult[]>();
|
|
1332
|
-
const timestamp = Date.now();
|
|
1333
|
-
|
|
1334
|
-
// First, collect results from the initial run
|
|
1335
|
-
for (const gateResult of gateResults) {
|
|
1336
|
-
for (const [testId, testResult] of this.extractTestResults(gateResult, timestamp)) {
|
|
1337
|
-
if (!flakinessMap.has(testId)) {
|
|
1338
|
-
flakinessMap.set(testId, []);
|
|
1339
|
-
}
|
|
1340
|
-
flakinessMap.get(testId)!.push(testResult);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
// Run additional consecutive runs
|
|
1345
|
-
for (let run = 1; run < this.flakyRuns; run++) {
|
|
1346
|
-
console.log(chalk.gray(` 🔄 Consecutive run ${run + 1}/${this.flakyRuns}...`));
|
|
1347
|
-
|
|
1348
|
-
for (const gateResult of gateResults) {
|
|
1349
|
-
// Re-run all gates to detect flakiness
|
|
1350
|
-
try {
|
|
1351
|
-
const retryResult = await this.executeGate(gateResult.gate);
|
|
1352
|
-
|
|
1353
|
-
// Extract and store test results
|
|
1354
|
-
for (const [testId, testResult] of this.extractTestResults(retryResult, timestamp)) {
|
|
1355
|
-
if (!flakinessMap.has(testId)) {
|
|
1356
|
-
flakinessMap.set(testId, []);
|
|
1357
|
-
}
|
|
1358
|
-
flakinessMap.get(testId)!.push(testResult);
|
|
1359
|
-
}
|
|
1360
|
-
} catch (error) {
|
|
1361
|
-
console.log(chalk.yellow(` ⚠️ Failed to re-run ${gateResult.gate}: ${error}`));
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
// Analyze all collected results
|
|
1367
|
-
return this.flakinessDetector.analyzeAll(flakinessMap);
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* Extract test results from a gate result
|
|
1372
|
-
* Returns a map of testId to TestResult for flakiness tracking
|
|
1373
|
-
*/
|
|
1374
|
-
private extractTestResults(gateResult: GateResult, timestamp: number): Map<string, FlakyTestResult> {
|
|
1375
|
-
const results = new Map<string, FlakyTestResult>();
|
|
1376
|
-
|
|
1377
|
-
// Extract test results from adapter output
|
|
1378
|
-
const adapterResults = gateResult.results;
|
|
1379
|
-
|
|
1380
|
-
if (adapterResults?.results && Array.isArray(adapterResults.results)) {
|
|
1381
|
-
// Check for Playwright Native API adapter format
|
|
1382
|
-
const firstResult = adapterResults.results[0];
|
|
1383
|
-
|
|
1384
|
-
if (firstResult && 'endpoint' in firstResult && 'method' in firstResult) {
|
|
1385
|
-
// PlaywrightNativeApiAdapter format: { endpoint, method, status, success, error, ... }
|
|
1386
|
-
for (const test of adapterResults.results as Array<{endpoint: string; method: string; status: number; success: boolean; error?: string; responseTime?: number}>) {
|
|
1387
|
-
// Extract just the path from full URL for cleaner test names
|
|
1388
|
-
const url = new URL(test.endpoint);
|
|
1389
|
-
const path = url.pathname + url.search;
|
|
1390
|
-
const testName = `${test.method} ${path} -> ${test.status}`;
|
|
1391
|
-
const testId = generateTestId(testName, gateResult.gate);
|
|
1392
|
-
results.set(testId, {
|
|
1393
|
-
testId,
|
|
1394
|
-
testName,
|
|
1395
|
-
filePath: gateResult.gate,
|
|
1396
|
-
gate: gateResult.gate,
|
|
1397
|
-
success: test.success,
|
|
1398
|
-
durationMs: test.responseTime || 0,
|
|
1399
|
-
errorMessage: test.error,
|
|
1400
|
-
timestamp: timestamp + Math.random(), // Small offset for ordering
|
|
1401
|
-
environment: process.env.NODE_ENV || 'local'
|
|
1402
|
-
});
|
|
1403
|
-
}
|
|
1404
|
-
} else {
|
|
1405
|
-
// Generic adapter format with results array
|
|
1406
|
-
for (const test of adapterResults.results as Array<{name?: string; passed?: boolean; status?: string; duration?: number; error?: {message?: string; type?: string}}>) {
|
|
1407
|
-
const testName = test.name || gateResult.gate;
|
|
1408
|
-
const testId = generateTestId(testName, gateResult.gate);
|
|
1409
|
-
results.set(testId, {
|
|
1410
|
-
testId,
|
|
1411
|
-
testName,
|
|
1412
|
-
filePath: gateResult.gate,
|
|
1413
|
-
gate: gateResult.gate,
|
|
1414
|
-
success: test.passed || test.status === 'passed',
|
|
1415
|
-
durationMs: test.duration || 0,
|
|
1416
|
-
errorType: test.error?.type,
|
|
1417
|
-
errorMessage: test.error?.message,
|
|
1418
|
-
timestamp: timestamp + Math.random(),
|
|
1419
|
-
environment: process.env.NODE_ENV || 'local'
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
} else if (adapterResults?.summary) {
|
|
1424
|
-
// Generic adapter with summary only (no detailed results)
|
|
1425
|
-
const testId = generateTestId(gateResult.gate, gateResult.gate);
|
|
1426
|
-
results.set(testId, {
|
|
1427
|
-
testId,
|
|
1428
|
-
testName: gateResult.gate,
|
|
1429
|
-
filePath: gateResult.gate,
|
|
1430
|
-
gate: gateResult.gate,
|
|
1431
|
-
success: gateResult.success,
|
|
1432
|
-
durationMs: gateResult.duration,
|
|
1433
|
-
errorMessage: gateResult.error,
|
|
1434
|
-
timestamp,
|
|
1435
|
-
environment: process.env.NODE_ENV || 'local'
|
|
1436
|
-
});
|
|
1437
|
-
} else {
|
|
1438
|
-
// Fallback: create single test result from gate
|
|
1439
|
-
const testId = generateTestId(gateResult.gate, gateResult.gate);
|
|
1440
|
-
results.set(testId, {
|
|
1441
|
-
testId,
|
|
1442
|
-
testName: gateResult.gate,
|
|
1443
|
-
filePath: gateResult.gate,
|
|
1444
|
-
gate: gateResult.gate,
|
|
1445
|
-
success: gateResult.success,
|
|
1446
|
-
durationMs: gateResult.duration,
|
|
1447
|
-
errorMessage: gateResult.error,
|
|
1448
|
-
timestamp,
|
|
1449
|
-
environment: process.env.NODE_ENV || 'local'
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
return results;
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
/**
|
|
1457
|
-
* Generate hash of pack configuration
|
|
1458
|
-
*/
|
|
1459
|
-
private hashPack(pack: PackConfig): string {
|
|
1460
|
-
return createHash('sha256')
|
|
1461
|
-
.update(JSON.stringify(pack))
|
|
1462
|
-
.digest('hex')
|
|
1463
|
-
.substring(0, 16);
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
/**
|
|
1467
|
-
* Get API target (v1 or v2 format)
|
|
1468
|
-
*/
|
|
1469
|
-
private getTargetApi(): any {
|
|
1470
|
-
if (this.isPackV2(this.pack)) {
|
|
1471
|
-
// In v2, target is in the gate config
|
|
1472
|
-
const gateConfig = this.pack.gates['api_smoke'] || this.pack.gates['api'];
|
|
1473
|
-
if (gateConfig && (gateConfig as any).config?.baseUrl) {
|
|
1474
|
-
return (gateConfig as any).config;
|
|
1475
|
-
}
|
|
1476
|
-
return undefined;
|
|
1477
|
-
}
|
|
1478
|
-
return this.pack.targets?.api;
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* Get Web target (v1 or v2 format)
|
|
1483
|
-
*/
|
|
1484
|
-
private getTargetWeb(): any {
|
|
1485
|
-
if (this.isPackV2(this.pack)) {
|
|
1486
|
-
// In v2, target is in the gate config
|
|
1487
|
-
const gateConfig = this.pack.gates['ui'] || this.pack.gates['a11y'];
|
|
1488
|
-
if (gateConfig && (gateConfig as any).config?.baseUrl) {
|
|
1489
|
-
return (gateConfig as any).config;
|
|
1490
|
-
}
|
|
1491
|
-
return undefined;
|
|
1492
|
-
}
|
|
1493
|
-
return this.pack.targets?.web;
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
/**
|
|
1497
|
-
* Get budgets (v1 or v2 format)
|
|
1498
|
-
*/
|
|
1499
|
-
private getBudgets(): any {
|
|
1500
|
-
if (this.isPackV2(this.pack)) {
|
|
1501
|
-
// In v2, budgets can be in gate config or global
|
|
1502
|
-
// For now, return undefined - budgets are gate-specific in v2
|
|
1503
|
-
return undefined;
|
|
1504
|
-
}
|
|
1505
|
-
return this.pack.budgets;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
/**
|
|
1509
|
-
* Get execution timeout (v1 or v2 format)
|
|
1510
|
-
*/
|
|
1511
|
-
private getExecutionTimeout(): number | undefined {
|
|
1512
|
-
if (this.isPackV2(this.pack)) {
|
|
1513
|
-
return this.pack.execution?.default_timeout;
|
|
1514
|
-
}
|
|
1515
|
-
return this.pack.execution?.timeout;
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
/**
|
|
1519
|
-
* Get execution retries (v1 or v2 format)
|
|
1520
|
-
*/
|
|
1521
|
-
private getExecutionRetries(): number | undefined {
|
|
1522
|
-
if (this.isPackV2(this.pack)) {
|
|
1523
|
-
return this.pack.execution?.default_retries;
|
|
1524
|
-
}
|
|
1525
|
-
return this.pack.execution?.max_retries;
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
/**
|
|
1529
|
-
* Ensure output directory exists
|
|
1530
|
-
*/
|
|
1531
|
-
private ensureOutputDir(): void {
|
|
1532
|
-
if (!existsSync(this.outputDir)) {
|
|
1533
|
-
mkdirSync(this.outputDir, { recursive: true });
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
}
|