create-qa-architect 5.0.0 → 5.0.6
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/.github/RELEASE_CHECKLIST.md +2 -4
- package/.github/workflows/daily-deploy-check.yml +136 -0
- package/.github/workflows/nightly-gitleaks-verification.yml +1 -1
- package/.github/workflows/quality.yml +3 -0
- package/.github/workflows/release.yml +12 -10
- package/.github/workflows/weekly-audit.yml +173 -0
- package/LICENSE +66 -0
- package/README.md +44 -30
- package/config/defaults.js +22 -1
- package/config/quality-config.schema.json +1 -1
- package/create-saas-monetization.js +75 -27
- package/docs/ARCHITECTURE.md +53 -0
- package/docs/DEPLOYMENT.md +62 -0
- package/docs/PREFLIGHT_REPORT.md +108 -0
- package/docs/SLA_GATES.md +28 -0
- package/docs/TESTING.md +61 -0
- package/docs/security/SOC2_STARTER.md +29 -0
- package/lib/config-validator.js +8 -2
- package/lib/dependency-monitoring-basic.js +73 -26
- package/lib/dependency-monitoring-premium.js +21 -19
- package/lib/github-api.js +249 -0
- package/lib/interactive/questions.js +4 -0
- package/lib/license-validator.js +1 -1
- package/lib/licensing.js +11 -10
- package/lib/package-utils.js +224 -8
- package/lib/project-maturity.js +1 -1
- package/lib/setup-enhancements.js +33 -0
- package/lib/template-loader.js +2 -0
- package/lib/ui-helpers.js +2 -1
- package/lib/validation/base-validator.js +5 -1
- package/lib/validation/cache-manager.js +1 -0
- package/lib/validation/config-security.js +5 -4
- package/lib/validation/validation-factory.js +1 -1
- package/lib/yaml-utils.js +15 -10
- package/package.json +18 -13
- package/scripts/check-docs.sh +63 -0
- package/scripts/smart-test-strategy.sh +98 -0
- package/scripts/test-e2e-package.sh +283 -0
- package/scripts/validate-command-patterns.js +112 -0
- package/setup.js +161 -44
- package/templates/QUALITY_TROUBLESHOOTING.md +403 -0
- package/templates/ci/circleci-config.yml +35 -0
- package/templates/ci/gitlab-ci.yml +47 -0
- package/templates/integration-tests/api-service.test.js +244 -0
- package/templates/integration-tests/frontend-app.test.js +267 -0
- package/templates/scripts/smart-test-strategy.sh +109 -0
- package/templates/test-stubs/e2e.smoke.test.js +12 -0
- package/templates/test-stubs/unit.test.js +7 -0
- package/legal/README.md +0 -106
- package/legal/copyright.md +0 -76
- package/legal/disclaimer.md +0 -146
- package/legal/privacy-policy.html +0 -324
- package/legal/privacy-policy.md +0 -196
- package/legal/terms-of-service.md +0 -224
- package/marketing/beta-user-email-campaign.md +0 -372
- package/marketing/landing-page.html +0 -721
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
* - Conversion landing page
|
|
14
14
|
* - Beta user email campaigns
|
|
15
15
|
* - Upgrade prompts and messaging
|
|
16
|
+
*
|
|
17
|
+
* Roadmap / Future Ideas:
|
|
18
|
+
* - Extract licensing to shared npm package (@vibebuildlab/licensing)
|
|
19
|
+
* - Single source of truth across all Vibe Lab products
|
|
20
|
+
* - Central license server with one API for all products
|
|
21
|
+
* - Device/activation limits (optional enforcement)
|
|
22
|
+
* - License revocation for chargebacks
|
|
23
|
+
* - Team/seat-based licensing with org management
|
|
24
|
+
* - SSO/SAML integration for Enterprise tier
|
|
25
|
+
* - Usage-based billing option (metered pricing)
|
|
16
26
|
*/
|
|
17
27
|
|
|
18
28
|
'use strict'
|
|
@@ -29,7 +39,7 @@ const FOUNDER_ENTERPRISE_PRICE = '74.50'
|
|
|
29
39
|
|
|
30
40
|
class SaaSMonetizationBootstrap {
|
|
31
41
|
constructor() {
|
|
32
|
-
this.projectRoot = process.cwd()
|
|
42
|
+
this.projectRoot = path.resolve(process.cwd())
|
|
33
43
|
this.config = {}
|
|
34
44
|
this.templates = {
|
|
35
45
|
stripe: this.getStripeTemplate(),
|
|
@@ -40,6 +50,56 @@ class SaaSMonetizationBootstrap {
|
|
|
40
50
|
}
|
|
41
51
|
}
|
|
42
52
|
|
|
53
|
+
resolveProjectPath(relativePath) {
|
|
54
|
+
const normalizedRoot = this.projectRoot.endsWith(path.sep)
|
|
55
|
+
? this.projectRoot
|
|
56
|
+
: `${this.projectRoot}${path.sep}`
|
|
57
|
+
const resolvedPath = path.resolve(this.projectRoot, relativePath)
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
resolvedPath !== this.projectRoot &&
|
|
61
|
+
!resolvedPath.startsWith(normalizedRoot)
|
|
62
|
+
) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Refusing to access path outside project root: ${relativePath}`
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return resolvedPath
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ensureDir(relativePath) {
|
|
72
|
+
const target = this.resolveProjectPath(relativePath)
|
|
73
|
+
// Path is constrained to the project root before touching the filesystem
|
|
74
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
75
|
+
if (!fs.existsSync(target)) {
|
|
76
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
77
|
+
fs.mkdirSync(target, { recursive: true })
|
|
78
|
+
}
|
|
79
|
+
return target
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
writeProjectFile(relativePath, content) {
|
|
83
|
+
const target = this.resolveProjectPath(relativePath)
|
|
84
|
+
// Path is constrained to the project root before touching the filesystem
|
|
85
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
86
|
+
fs.writeFileSync(target, content)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
readProjectFile(relativePath) {
|
|
90
|
+
const target = this.resolveProjectPath(relativePath)
|
|
91
|
+
// Path is constrained to the project root before touching the filesystem
|
|
92
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
93
|
+
return fs.readFileSync(target, 'utf8')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
projectFileExists(relativePath) {
|
|
97
|
+
const target = this.resolveProjectPath(relativePath)
|
|
98
|
+
// Path is constrained to the project root before touching the filesystem
|
|
99
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
100
|
+
return fs.existsSync(target)
|
|
101
|
+
}
|
|
102
|
+
|
|
43
103
|
async run() {
|
|
44
104
|
console.log('🚀 Create SaaS Monetization')
|
|
45
105
|
console.log('═══════════════════════════════════')
|
|
@@ -149,10 +209,7 @@ class SaaSMonetizationBootstrap {
|
|
|
149
209
|
const dirs = ['lib/monetization', 'legal', 'marketing', 'billing']
|
|
150
210
|
|
|
151
211
|
dirs.forEach(dir => {
|
|
152
|
-
|
|
153
|
-
if (!fs.existsSync(fullPath)) {
|
|
154
|
-
fs.mkdirSync(fullPath, { recursive: true })
|
|
155
|
-
}
|
|
212
|
+
this.ensureDir(dir)
|
|
156
213
|
})
|
|
157
214
|
}
|
|
158
215
|
|
|
@@ -162,8 +219,8 @@ class SaaSMonetizationBootstrap {
|
|
|
162
219
|
.replace(/{{PRO_PRICE}}/g, this.config.proPrice)
|
|
163
220
|
.replace(/{{ENTERPRISE_PRICE}}/g, this.config.enterprisePrice)
|
|
164
221
|
|
|
165
|
-
|
|
166
|
-
path.join(
|
|
222
|
+
this.writeProjectFile(
|
|
223
|
+
path.join('lib/monetization', 'stripe-integration.js'),
|
|
167
224
|
stripeCode
|
|
168
225
|
)
|
|
169
226
|
}
|
|
@@ -178,8 +235,8 @@ class SaaSMonetizationBootstrap {
|
|
|
178
235
|
.replace(/{{FOUNDER_PRO_PRICE}}/g, this.config.founderProPrice)
|
|
179
236
|
.replace(/{{DOMAIN}}/g, this.config.domain)
|
|
180
237
|
|
|
181
|
-
|
|
182
|
-
path.join(
|
|
238
|
+
this.writeProjectFile(
|
|
239
|
+
path.join('lib/monetization', 'licensing.js'),
|
|
183
240
|
licensingCode
|
|
184
241
|
)
|
|
185
242
|
}
|
|
@@ -194,7 +251,7 @@ class SaaSMonetizationBootstrap {
|
|
|
194
251
|
.replace(/{{DESCRIPTION}}/g, this.config.description)
|
|
195
252
|
.replace(/{{DATE}}/g, new Date().toISOString().split('T')[0])
|
|
196
253
|
|
|
197
|
-
|
|
254
|
+
this.writeProjectFile(path.join('legal', filename), content)
|
|
198
255
|
}
|
|
199
256
|
}
|
|
200
257
|
|
|
@@ -223,10 +280,7 @@ class SaaSMonetizationBootstrap {
|
|
|
223
280
|
)
|
|
224
281
|
.replace(/{{SUPPORT_EMAIL}}/g, this.config.supportEmail)
|
|
225
282
|
|
|
226
|
-
|
|
227
|
-
path.join(this.projectRoot, 'marketing', filename),
|
|
228
|
-
content
|
|
229
|
-
)
|
|
283
|
+
this.writeProjectFile(path.join('marketing', filename), content)
|
|
230
284
|
}
|
|
231
285
|
}
|
|
232
286
|
|
|
@@ -242,17 +296,14 @@ class SaaSMonetizationBootstrap {
|
|
|
242
296
|
)
|
|
243
297
|
.replace(/{{PREMIUM_FEATURES}}/g, this.config.premiumFeatures)
|
|
244
298
|
|
|
245
|
-
|
|
246
|
-
path.join(this.projectRoot, 'billing/dashboard.html'),
|
|
247
|
-
billingCode
|
|
248
|
-
)
|
|
299
|
+
this.writeProjectFile(path.join('billing', 'dashboard.html'), billingCode)
|
|
249
300
|
}
|
|
250
301
|
|
|
251
302
|
async updatePackageJson() {
|
|
252
|
-
const packagePath =
|
|
303
|
+
const packagePath = 'package.json'
|
|
253
304
|
|
|
254
|
-
if (
|
|
255
|
-
const pkg = JSON.parse(
|
|
305
|
+
if (this.projectFileExists(packagePath)) {
|
|
306
|
+
const pkg = JSON.parse(this.readProjectFile(packagePath))
|
|
256
307
|
|
|
257
308
|
// Add monetization scripts
|
|
258
309
|
pkg.scripts = pkg.scripts || {}
|
|
@@ -266,7 +317,7 @@ class SaaSMonetizationBootstrap {
|
|
|
266
317
|
pkg.dependencies.stripe = '^14.15.0'
|
|
267
318
|
pkg.dependencies.crypto = '^1.0.1'
|
|
268
319
|
|
|
269
|
-
|
|
320
|
+
this.writeProjectFile(packagePath, JSON.stringify(pkg, null, 2))
|
|
270
321
|
}
|
|
271
322
|
}
|
|
272
323
|
|
|
@@ -297,7 +348,7 @@ COMPANY_NAME=${this.config.companyName}
|
|
|
297
348
|
# STRIPE_PUBLISHABLE_KEY=pk_live_your_live_key_here
|
|
298
349
|
`
|
|
299
350
|
|
|
300
|
-
|
|
351
|
+
this.writeProjectFile('.env.template', envTemplate)
|
|
301
352
|
}
|
|
302
353
|
|
|
303
354
|
async generateDeploymentGuide() {
|
|
@@ -473,10 +524,7 @@ For implementation questions:
|
|
|
473
524
|
**Revenue Potential**: $1,500-5,000/month recurring
|
|
474
525
|
`
|
|
475
526
|
|
|
476
|
-
|
|
477
|
-
path.join(this.projectRoot, 'MONETIZATION_GUIDE.md'),
|
|
478
|
-
guide
|
|
479
|
-
)
|
|
527
|
+
this.writeProjectFile('MONETIZATION_GUIDE.md', guide)
|
|
480
528
|
}
|
|
481
529
|
|
|
482
530
|
// Template methods (condensed versions of our implementations)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
QA Architect is a CLI tool that bootstraps quality automation in JavaScript/TypeScript and Python projects.
|
|
6
|
+
|
|
7
|
+
## Core Components
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
create-qa-architect/
|
|
11
|
+
├── setup.js # Main CLI entry point
|
|
12
|
+
├── lib/
|
|
13
|
+
│ ├── smart-strategy-generator.js # Smart test strategy (Pro)
|
|
14
|
+
│ ├── dependency-monitoring-*.js # Dependency monitoring
|
|
15
|
+
│ └── validation/ # Validation utilities
|
|
16
|
+
├── templates/ # Project templates
|
|
17
|
+
│ ├── eslint.config.cjs
|
|
18
|
+
│ ├── .prettierrc
|
|
19
|
+
│ ├── .husky/
|
|
20
|
+
│ └── scripts/
|
|
21
|
+
└── config/ # Language-specific configs
|
|
22
|
+
├── pyproject.toml
|
|
23
|
+
└── quality-python.yml
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Data Flow
|
|
27
|
+
|
|
28
|
+
1. **Detection Phase**: Detect project type (JS/TS/Python/mixed)
|
|
29
|
+
2. **Configuration Phase**: Generate appropriate configs
|
|
30
|
+
3. **Installation Phase**: Copy templates, update package.json
|
|
31
|
+
4. **Validation Phase**: Verify setup is complete
|
|
32
|
+
|
|
33
|
+
## Extension Points
|
|
34
|
+
|
|
35
|
+
- Custom templates via `--template` flag
|
|
36
|
+
- Language detection can be extended in `setup.js`
|
|
37
|
+
- New quality checks via template files
|
|
38
|
+
|
|
39
|
+
## Smart Test Strategy (Pro)
|
|
40
|
+
|
|
41
|
+
Risk-based pre-push validation that adapts to change context:
|
|
42
|
+
|
|
43
|
+
1. Calculate risk score (0-10) based on files changed
|
|
44
|
+
2. Select appropriate test tier (minimal → comprehensive)
|
|
45
|
+
3. Run tests with appropriate depth
|
|
46
|
+
|
|
47
|
+
## CLI Flags
|
|
48
|
+
|
|
49
|
+
- `--update` - Update existing setup
|
|
50
|
+
- `--deps` - Dependency monitoring only
|
|
51
|
+
- `--security-config` - Security validation
|
|
52
|
+
- `--check-maturity` - Project maturity report
|
|
53
|
+
- `--comprehensive` - Full validation suite
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
QA Architect is published to npm as `create-qa-architect`.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 20+
|
|
10
|
+
- npm account with publish access
|
|
11
|
+
- Git repository access
|
|
12
|
+
|
|
13
|
+
## Release Process
|
|
14
|
+
|
|
15
|
+
### 1. Pre-Release Validation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run prerelease # Run all tests and validations
|
|
19
|
+
npm run test:coverage # Verify coverage thresholds
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Version Bump
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run release:patch # Bug fixes (1.0.x)
|
|
26
|
+
npm run release:minor # New features (1.x.0)
|
|
27
|
+
npm run release:major # Breaking changes (x.0.0)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 3. Publish
|
|
31
|
+
|
|
32
|
+
GitHub Actions automatically publishes on tagged releases.
|
|
33
|
+
|
|
34
|
+
For manual publish:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm publish
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Verification
|
|
41
|
+
|
|
42
|
+
After release, verify:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx create-qa-architect@latest --version
|
|
46
|
+
npx create-qa-architect@latest --help
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rollback
|
|
50
|
+
|
|
51
|
+
If issues are discovered:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm unpublish create-qa-architect@VERSION
|
|
55
|
+
# or
|
|
56
|
+
npm deprecate create-qa-architect@VERSION "Critical bug, use VERSION instead"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## npm Registry
|
|
60
|
+
|
|
61
|
+
- Package: https://www.npmjs.com/package/create-qa-architect
|
|
62
|
+
- Documentation: https://github.com/vibebuildlab/qa-architect
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Preflight Review: QA Architect (create-qa-architect)
|
|
2
|
+
|
|
3
|
+
**Depth**: standard
|
|
4
|
+
**Date**: 2025-12-09
|
|
5
|
+
**Version**: 5.0.2
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overall Status: ✅ PASS
|
|
10
|
+
|
|
11
|
+
All critical launch blockers pass. Minor issues documented below are acceptable for npm package release.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Critical Issues (P0) - Must Fix
|
|
16
|
+
|
|
17
|
+
| Issue | Category | Location | Fix |
|
|
18
|
+
| ----- | -------- | -------- | --- |
|
|
19
|
+
| None | - | - | - |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Important Issues (P1) - Should Fix
|
|
24
|
+
|
|
25
|
+
| Issue | Category | Location | Recommendation |
|
|
26
|
+
| ------------------------ | -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
27
|
+
| Gitleaks false positives | Security | tests/\*.test.js | Test fixtures use fake API key patterns (QAA-XXXX format); not real secrets. Consider adding `.gitleaksignore` for test files. |
|
|
28
|
+
| npm version mismatch | Release | package.json | Local 5.0.2, npm shows 5.0.1. Publish pending or recently published. |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## P0 Functional Checks
|
|
33
|
+
|
|
34
|
+
| Check | Status | Notes |
|
|
35
|
+
| ----------------- | ------ | ---------------------- |
|
|
36
|
+
| All tests passing | ✅ | Full test suite passes |
|
|
37
|
+
| npm audit | ✅ | 0 vulnerabilities |
|
|
38
|
+
| ESLint | ✅ | No errors |
|
|
39
|
+
| Build/validation | ✅ | Core validation passes |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## P0 Security Checks
|
|
44
|
+
|
|
45
|
+
| Check | Status | Notes |
|
|
46
|
+
| ------------------------- | ------ | -------------------------------------------------------------------- |
|
|
47
|
+
| npm audit (high/critical) | ✅ | 0 vulnerabilities found |
|
|
48
|
+
| Hardcoded secrets scan | ⚠️ | 4 findings - all in test files with fake keys (QAA-1234-XXXX format) |
|
|
49
|
+
| No production secrets | ✅ | No `.env` files, no real API keys |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Product Packaging
|
|
54
|
+
|
|
55
|
+
| Item | Status | Notes |
|
|
56
|
+
| ------------ | ------ | ----------------------- |
|
|
57
|
+
| CHANGELOG.md | ✅ | Present |
|
|
58
|
+
| LICENSE | ✅ | Present |
|
|
59
|
+
| README.md | ✅ | Present |
|
|
60
|
+
| .env.example | N/A | Not needed for CLI tool |
|
|
61
|
+
| Version tags | ✅ | v4.3.0 - v5.0.2 |
|
|
62
|
+
| Git status | ✅ | Clean working tree |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quality Violations
|
|
67
|
+
|
|
68
|
+
| Type | Count | Assessment |
|
|
69
|
+
| ----------------------- | ----- | ------------------------------------------------------------ |
|
|
70
|
+
| eslint-disable comments | 24 | All have security justification comments explaining why safe |
|
|
71
|
+
| any types | 0 | JavaScript project, N/A |
|
|
72
|
+
|
|
73
|
+
**Note**: The `eslint-disable` comments are all for security-related ESLint rules (detect-unsafe-regex, detect-non-literal-fs-filename, detect-object-injection) and each includes a detailed safety justification explaining why the pattern is safe in context.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Silent Killer Check (N/A for npm package)
|
|
78
|
+
|
|
79
|
+
| Integration | Status | Notes |
|
|
80
|
+
| --------------- | ------ | --------------------- |
|
|
81
|
+
| Stripe webhooks | N/A | CLI tool, no webhooks |
|
|
82
|
+
| OAuth redirects | N/A | CLI tool |
|
|
83
|
+
| API keys | N/A | CLI tool |
|
|
84
|
+
| CORS config | N/A | CLI tool |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Next Steps
|
|
89
|
+
|
|
90
|
+
1. **Optional**: Add `.gitleaksignore` to exclude test files with fake license keys
|
|
91
|
+
2. **Verify**: Confirm npm publish completed for 5.0.2 (may be propagating)
|
|
92
|
+
3. **Ready**: Proceed with launch/release announcement
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Recommendation
|
|
97
|
+
|
|
98
|
+
**✅ CLEARED FOR LAUNCH**
|
|
99
|
+
|
|
100
|
+
This is an npm CLI package, not a web application. All critical checks pass:
|
|
101
|
+
|
|
102
|
+
- Tests passing
|
|
103
|
+
- No security vulnerabilities
|
|
104
|
+
- No real secrets
|
|
105
|
+
- Clean git state
|
|
106
|
+
- Proper versioning and packaging
|
|
107
|
+
|
|
108
|
+
The gitleaks findings are false positives on intentional test fixtures using fake license key formats.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Quality Gates & Merge Readiness (Default Recommendations)
|
|
2
|
+
|
|
3
|
+
These defaults are meant to give teams a simple, enforceable bar. They are intentionally conservative so most repos can adopt them on day one without re-architecting.
|
|
4
|
+
|
|
5
|
+
## Targets
|
|
6
|
+
|
|
7
|
+
- Coverage: **80%** (line) for critical paths; **70%** repo-wide minimum.
|
|
8
|
+
- Lint: **0** blocking ESLint/Stylelint errors; warnings allowed but surface in PR comment/summary.
|
|
9
|
+
- Secrets: **0** leaked secrets (gitleaks hard fail).
|
|
10
|
+
- Dependency vulns: No **high/critical** advisories (npm/yarn/pnpm audit). Medium allowed with justification.
|
|
11
|
+
- Performance budgets (CI): installs < 2m; test suite < 5m (already enforced in workflow).
|
|
12
|
+
|
|
13
|
+
## How to enforce
|
|
14
|
+
|
|
15
|
+
- GitHub Actions: quality.yml is wired to fail on lint/scan/test failures. Set env `MIN_COVERAGE=80` to gate on coverage (add a coverage reporter such as `c8` or `vitest --coverage`).
|
|
16
|
+
- Branch protection: require the “Quality Checks” workflow to pass; enable dismiss stale approvals on push.
|
|
17
|
+
- PR comments: run setup with `--pr-comments` to surface gate status in the PR thread.
|
|
18
|
+
- Alerts: run setup with `--alerts-slack` to post failures to Slack.
|
|
19
|
+
|
|
20
|
+
## Exceptions
|
|
21
|
+
|
|
22
|
+
- Allow temporary waivers via labels (e.g., `risk-accepted`) and document in the PR body.
|
|
23
|
+
- Lower coverage floors for greenfield proofs-of-concept (set `MIN_COVERAGE=60`) but time-box the exemption.
|
|
24
|
+
|
|
25
|
+
## Next steps
|
|
26
|
+
|
|
27
|
+
- Add repo-specific risk areas to `.qualityrc.json` under `riskAreas`.
|
|
28
|
+
- Track SLA drift in reports (future: audit log + team dashboard hooks).
|
package/docs/TESTING.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Testing Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
QA Architect uses Jest for testing with a focus on integration tests that validate real CLI workflows.
|
|
6
|
+
|
|
7
|
+
## Running Tests
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm test # Run all tests
|
|
11
|
+
npm run test:coverage # Run with coverage report
|
|
12
|
+
npm run test:watch # Watch mode for development
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Test Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
tests/
|
|
19
|
+
├── setup.test.js # Main CLI integration tests
|
|
20
|
+
├── cli-deps-integration.test.js # Dependency CLI tests
|
|
21
|
+
├── real-world-packages.test.js # Real package validation
|
|
22
|
+
└── premium-dependency-monitoring.test.js # Pro feature tests
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Coverage Requirements
|
|
26
|
+
|
|
27
|
+
- **Overall**: 75%+ lines, statements, functions, branches
|
|
28
|
+
- **New files**: 75%+ coverage before merging
|
|
29
|
+
- **Critical files**: `setup.js` requires 80%+
|
|
30
|
+
|
|
31
|
+
## Testing Patterns
|
|
32
|
+
|
|
33
|
+
### Integration Tests
|
|
34
|
+
|
|
35
|
+
Test real CLI workflows with temp directories:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const testDir = createTempGitRepo()
|
|
39
|
+
const result = execSync('node setup.js --deps', { cwd: testDir })
|
|
40
|
+
assert(fs.existsSync(path.join(testDir, '.github/dependabot.yml')))
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Real-World Data
|
|
44
|
+
|
|
45
|
+
Use real packages from the ecosystem, not toy examples:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const TOP_PYTHON_PACKAGES = [
|
|
49
|
+
'django-cors-headers',
|
|
50
|
+
'scikit-learn',
|
|
51
|
+
'pytest-cov',
|
|
52
|
+
]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Pre-Release Validation
|
|
56
|
+
|
|
57
|
+
Always run before release:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run prerelease # Runs docs:check + all tests
|
|
61
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SOC 2 Starter (Preflight Checklist)
|
|
2
|
+
|
|
3
|
+
This starter doc is a lightweight preflight for teams using QA Architect. It is not a substitute for a real SOC 2 program, but it maps common CI/quality controls to SOC 2 CC/PII areas.
|
|
4
|
+
|
|
5
|
+
## Controls to Wire First
|
|
6
|
+
|
|
7
|
+
- **Change Management (CC8.1):** Require PR review + Quality Checks workflow pass; enable branch protection on main.
|
|
8
|
+
- **Secure SDLC (CC6.1):** Keep ESLint security, gitleaks, dependency audit steps enabled; document exceptions in PRs.
|
|
9
|
+
- **Logging & Alerts (CC7.2):** Turn on Slack alerts via `--alerts-slack` and keep CI logs for 90 days.
|
|
10
|
+
- **Backup of Config (CC9.2):** Check in `.qualityrc.json`, `quality.yml`, and Dependabot configs; avoid secrets in repo.
|
|
11
|
+
- **Access (CC6.2):** Use least-privilege GitHub tokens; rotate `GITLEAKS_TOKEN`/`SEMGREP_APP_TOKEN` every 90 days.
|
|
12
|
+
|
|
13
|
+
## Evidence You Can Collect Today
|
|
14
|
+
|
|
15
|
+
- CI run artifacts showing lint/test/security passes.
|
|
16
|
+
- Dependency audit reports (npm audit logs) and gitleaks scan results.
|
|
17
|
+
- Coverage reports (c8/Vitest/Jest) stored in artifacts.
|
|
18
|
+
- PR comments from quality workflow (when `--pr-comments` is enabled).
|
|
19
|
+
|
|
20
|
+
## Gaps to plan for
|
|
21
|
+
|
|
22
|
+
- **SSO/SAML & RBAC:** Roadmap item (Enterprise); track in issue tracker.
|
|
23
|
+
- **Audit logging:** Add a central log sink (e.g., S3/CloudWatch) for CI events.
|
|
24
|
+
- **Vendor risk:** Document third-party actions; pin SHAs (already pinned in quality.yml) and review quarterly.
|
|
25
|
+
|
|
26
|
+
## How to use this file
|
|
27
|
+
|
|
28
|
+
- Keep it checked in; edit per repo to note exceptions and waivers.
|
|
29
|
+
- Link it in onboarding docs so new contributors know the expected bar.
|
package/lib/config-validator.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const AjvImport = require('ajv')
|
|
4
|
+
const addFormatsImport = require('ajv-formats')
|
|
5
5
|
const fs = require('fs')
|
|
6
6
|
const path = require('path')
|
|
7
7
|
|
|
8
|
+
// Handle CJS/ESM interop for Ajv and ajv-formats in JS type-checking
|
|
9
|
+
const Ajv = /** @type {any} */ (AjvImport.default || AjvImport)
|
|
10
|
+
const addFormats = /** @type {(ajv: any) => void} */ (
|
|
11
|
+
addFormatsImport.default || addFormatsImport
|
|
12
|
+
)
|
|
13
|
+
|
|
8
14
|
function validateQualityConfig(configPath) {
|
|
9
15
|
const result = {
|
|
10
16
|
valid: false,
|
|
@@ -17,6 +17,7 @@ function hasNpmProject(projectPath) {
|
|
|
17
17
|
/**
|
|
18
18
|
* Generate basic Dependabot configuration (Free Tier)
|
|
19
19
|
* Limited to npm only, no framework detection, basic settings
|
|
20
|
+
* Supports monorepo per-package directories
|
|
20
21
|
*/
|
|
21
22
|
function generateBasicDependabotConfig(options = {}) {
|
|
22
23
|
const {
|
|
@@ -24,49 +25,95 @@ function generateBasicDependabotConfig(options = {}) {
|
|
|
24
25
|
schedule = 'weekly',
|
|
25
26
|
day = 'monday',
|
|
26
27
|
time = '09:00',
|
|
28
|
+
monorepoInfo = null, // Optional monorepo detection result
|
|
27
29
|
} = options
|
|
28
30
|
|
|
29
31
|
if (!hasNpmProject(projectPath)) {
|
|
30
32
|
return null // Only npm projects supported in free tier
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
const updates = []
|
|
36
|
+
|
|
37
|
+
// If monorepo with resolved packages, create per-package entries
|
|
38
|
+
if (
|
|
39
|
+
monorepoInfo &&
|
|
40
|
+
monorepoInfo.isMonorepo &&
|
|
41
|
+
monorepoInfo.resolvedPackages &&
|
|
42
|
+
monorepoInfo.resolvedPackages.length > 0
|
|
43
|
+
) {
|
|
44
|
+
// Root package
|
|
45
|
+
updates.push({
|
|
46
|
+
'package-ecosystem': 'npm',
|
|
47
|
+
directory: '/',
|
|
48
|
+
schedule: {
|
|
49
|
+
interval: schedule,
|
|
50
|
+
day: day,
|
|
51
|
+
time: time,
|
|
52
|
+
},
|
|
53
|
+
'open-pull-requests-limit': 5,
|
|
54
|
+
labels: ['dependencies', 'root'],
|
|
55
|
+
'commit-message': {
|
|
56
|
+
prefix: 'deps(root)',
|
|
57
|
+
include: 'scope',
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Per-package entries
|
|
62
|
+
for (const pkg of monorepoInfo.resolvedPackages) {
|
|
63
|
+
const dir = '/' + pkg.relativePath.replace(/\\/g, '/')
|
|
64
|
+
updates.push({
|
|
37
65
|
'package-ecosystem': 'npm',
|
|
38
|
-
directory:
|
|
66
|
+
directory: dir,
|
|
39
67
|
schedule: {
|
|
40
68
|
interval: schedule,
|
|
41
69
|
day: day,
|
|
42
70
|
time: time,
|
|
43
71
|
},
|
|
44
|
-
'open-pull-requests-limit':
|
|
45
|
-
labels: ['dependencies'],
|
|
72
|
+
'open-pull-requests-limit': 3,
|
|
73
|
+
labels: ['dependencies', pkg.name],
|
|
46
74
|
'commit-message': {
|
|
47
|
-
prefix:
|
|
75
|
+
prefix: `deps(${pkg.name})`,
|
|
48
76
|
include: 'scope',
|
|
49
77
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
// Single package (non-monorepo)
|
|
82
|
+
updates.push({
|
|
83
|
+
'package-ecosystem': 'npm',
|
|
84
|
+
directory: '/',
|
|
85
|
+
schedule: {
|
|
86
|
+
interval: schedule,
|
|
87
|
+
day: day,
|
|
88
|
+
time: time,
|
|
54
89
|
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
interval: schedule,
|
|
61
|
-
day: day,
|
|
62
|
-
time: time,
|
|
63
|
-
},
|
|
64
|
-
labels: ['dependencies', 'github-actions'],
|
|
65
|
-
'commit-message': {
|
|
66
|
-
prefix: 'deps(actions)',
|
|
67
|
-
},
|
|
90
|
+
'open-pull-requests-limit': 5,
|
|
91
|
+
labels: ['dependencies'],
|
|
92
|
+
'commit-message': {
|
|
93
|
+
prefix: 'deps',
|
|
94
|
+
include: 'scope',
|
|
68
95
|
},
|
|
69
|
-
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// GitHub Actions monitoring (free tier includes this)
|
|
100
|
+
updates.push({
|
|
101
|
+
'package-ecosystem': 'github-actions',
|
|
102
|
+
directory: '/',
|
|
103
|
+
schedule: {
|
|
104
|
+
interval: schedule,
|
|
105
|
+
day: day,
|
|
106
|
+
time: time,
|
|
107
|
+
},
|
|
108
|
+
labels: ['dependencies', 'github-actions'],
|
|
109
|
+
'commit-message': {
|
|
110
|
+
prefix: 'deps(actions)',
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const config = {
|
|
115
|
+
version: 2,
|
|
116
|
+
updates: updates,
|
|
70
117
|
}
|
|
71
118
|
|
|
72
119
|
return config
|