@metasession.co/devaudit-cli 0.3.4 → 0.3.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/dist/index.js +92 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ function emitJsonResult(payload) {
|
|
|
56
56
|
|
|
57
57
|
// package.json
|
|
58
58
|
var package_default = {
|
|
59
|
-
version: "0.3.
|
|
59
|
+
version: "0.3.6"};
|
|
60
60
|
|
|
61
61
|
// src/lib/version.ts
|
|
62
62
|
var CLI_VERSION = package_default.version;
|
|
@@ -1234,11 +1234,12 @@ var GitHubProvider = class {
|
|
|
1234
1234
|
}
|
|
1235
1235
|
if (!res.ok) throw new Error(`GitHub REST variable create failed: HTTP ${res.status}`);
|
|
1236
1236
|
}
|
|
1237
|
-
async applyBranchProtection(cwd, branch, requiredChecks) {
|
|
1237
|
+
async applyBranchProtection(cwd, branch, requiredChecks, options) {
|
|
1238
|
+
const reviewCount = options?.requiredReviewCount ?? 0;
|
|
1238
1239
|
const body = {
|
|
1239
1240
|
required_status_checks: { strict: false, contexts: requiredChecks },
|
|
1240
|
-
enforce_admins:
|
|
1241
|
-
required_pull_request_reviews: { dismiss_stale_reviews: true, required_approving_review_count:
|
|
1241
|
+
enforce_admins: true,
|
|
1242
|
+
required_pull_request_reviews: { dismiss_stale_reviews: true, required_approving_review_count: reviewCount },
|
|
1242
1243
|
restrictions: null
|
|
1243
1244
|
};
|
|
1244
1245
|
if (this.preferGhCli && await ghAvailable()) {
|
|
@@ -1731,13 +1732,21 @@ async function bootstrapNode(ctx) {
|
|
|
1731
1732
|
await execa("npx", ["husky", "init"], { cwd: ctx.projectPath, stdio: "inherit" });
|
|
1732
1733
|
return { step: "8/11 Bootstrap hook framework", status: "ok", message: ".husky/ bootstrapped" };
|
|
1733
1734
|
}
|
|
1734
|
-
|
|
1735
|
-
// src/install/branch-protection.ts
|
|
1736
1735
|
var REQUIRED_CHECKS = [
|
|
1737
|
-
"
|
|
1738
|
-
"
|
|
1739
|
-
"Quality Gates"
|
|
1736
|
+
"Quality Gates",
|
|
1737
|
+
"CI Status Fallback"
|
|
1740
1738
|
];
|
|
1739
|
+
var MAIN_REVIEW_COUNT = 1;
|
|
1740
|
+
var DEVELOP_REVIEW_COUNT = 0;
|
|
1741
|
+
async function resolveIntegrationBranch(projectPath) {
|
|
1742
|
+
try {
|
|
1743
|
+
const raw = await promises.readFile(join(projectPath, "sdlc-config.json"), "utf-8");
|
|
1744
|
+
const config = JSON.parse(raw);
|
|
1745
|
+
return config.integration_branch ?? "develop";
|
|
1746
|
+
} catch {
|
|
1747
|
+
return "develop";
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1741
1750
|
async function configureBranchProtection(ctx, provider) {
|
|
1742
1751
|
if (ctx.installMode === "developer") {
|
|
1743
1752
|
return {
|
|
@@ -1757,25 +1766,34 @@ async function configureBranchProtection(ctx, provider) {
|
|
|
1757
1766
|
};
|
|
1758
1767
|
}
|
|
1759
1768
|
const repo = `${meta.owner}/${meta.name}`;
|
|
1769
|
+
const integrationBranch = await resolveIntegrationBranch(ctx.projectPath);
|
|
1760
1770
|
if (ctx.dryRun) {
|
|
1761
1771
|
return {
|
|
1762
1772
|
step: "9/11 Configure branch protection",
|
|
1763
1773
|
status: "planned",
|
|
1764
|
-
message: `would apply branch protection on ${repo}:${meta.defaultBranch} with checks=${JSON.stringify(REQUIRED_CHECKS)}`
|
|
1774
|
+
message: `would apply branch protection on ${repo}:${meta.defaultBranch} (1 review) + ${integrationBranch} (0 reviews) with checks=${JSON.stringify(REQUIRED_CHECKS)}`
|
|
1765
1775
|
};
|
|
1766
1776
|
}
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
};
|
|
1777
|
+
const results = [];
|
|
1778
|
+
const mainResult = await provider.applyBranchProtection(ctx.projectPath, meta.defaultBranch, REQUIRED_CHECKS, { requiredReviewCount: MAIN_REVIEW_COUNT });
|
|
1779
|
+
if (mainResult.applied) {
|
|
1780
|
+
results.push(`${meta.defaultBranch}: ok (${MAIN_REVIEW_COUNT} review)`);
|
|
1781
|
+
} else {
|
|
1782
|
+
results.push(`${meta.defaultBranch}: FAILED \u2014 ${mainResult.message ?? "unknown"}`);
|
|
1774
1783
|
}
|
|
1784
|
+
if (integrationBranch !== meta.defaultBranch) {
|
|
1785
|
+
const devResult = await provider.applyBranchProtection(ctx.projectPath, integrationBranch, REQUIRED_CHECKS, { requiredReviewCount: DEVELOP_REVIEW_COUNT });
|
|
1786
|
+
if (devResult.applied) {
|
|
1787
|
+
results.push(`${integrationBranch}: ok (${DEVELOP_REVIEW_COUNT} reviews)`);
|
|
1788
|
+
} else {
|
|
1789
|
+
results.push(`${integrationBranch}: FAILED \u2014 ${devResult.message ?? "unknown"}`);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
const allOk = results.every((r) => r.includes(": ok"));
|
|
1775
1793
|
return {
|
|
1776
1794
|
step: "9/11 Configure branch protection",
|
|
1777
|
-
status: "warn",
|
|
1778
|
-
message:
|
|
1795
|
+
status: allOk ? "ok" : "warn",
|
|
1796
|
+
message: allOk ? results.join(" | ") : `${results.join(" | ")} \u2014 configure manually`
|
|
1779
1797
|
};
|
|
1780
1798
|
}
|
|
1781
1799
|
var ajv = new Ajv({ allErrors: true, strict: false });
|
|
@@ -2496,6 +2514,59 @@ async function syncWorkflows(ctx) {
|
|
|
2496
2514
|
message: files.length > 0 ? `synced to .devin/workflows/` : "no workflow files found"
|
|
2497
2515
|
};
|
|
2498
2516
|
}
|
|
2517
|
+
var REQUIRED_CHECKS2 = [
|
|
2518
|
+
"Quality Gates",
|
|
2519
|
+
"CI Status Fallback"
|
|
2520
|
+
];
|
|
2521
|
+
var MAIN_REVIEW_COUNT2 = 1;
|
|
2522
|
+
var DEVELOP_REVIEW_COUNT2 = 0;
|
|
2523
|
+
async function verifyBranchProtection(ctx) {
|
|
2524
|
+
const config = await readSdlcConfig(ctx.projectPath);
|
|
2525
|
+
const integrationBranch = config?.integration_branch ?? "develop";
|
|
2526
|
+
config?.release_branch ?? "main";
|
|
2527
|
+
let provider;
|
|
2528
|
+
try {
|
|
2529
|
+
provider = await getGitProvider(ctx.projectPath);
|
|
2530
|
+
} catch (err) {
|
|
2531
|
+
return {
|
|
2532
|
+
name: "Branch protection",
|
|
2533
|
+
filesSynced: 0,
|
|
2534
|
+
warning: `git provider unavailable (${err.message}) \u2014 verify manually`
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2537
|
+
let meta;
|
|
2538
|
+
try {
|
|
2539
|
+
meta = await provider.getRepoMeta(ctx.projectPath);
|
|
2540
|
+
} catch (err) {
|
|
2541
|
+
return {
|
|
2542
|
+
name: "Branch protection",
|
|
2543
|
+
filesSynced: 0,
|
|
2544
|
+
warning: `could not resolve repo (${err.message}) \u2014 verify manually`
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
const results = [];
|
|
2548
|
+
const mainResult = await provider.applyBranchProtection(ctx.projectPath, meta.defaultBranch, REQUIRED_CHECKS2, { requiredReviewCount: MAIN_REVIEW_COUNT2 });
|
|
2549
|
+
if (mainResult.applied) {
|
|
2550
|
+
results.push(`${meta.defaultBranch}: ok`);
|
|
2551
|
+
} else {
|
|
2552
|
+
results.push(`${meta.defaultBranch}: failed \u2014 ${mainResult.message ?? "unknown"}`);
|
|
2553
|
+
}
|
|
2554
|
+
if (integrationBranch !== meta.defaultBranch) {
|
|
2555
|
+
const devResult = await provider.applyBranchProtection(ctx.projectPath, integrationBranch, REQUIRED_CHECKS2, { requiredReviewCount: DEVELOP_REVIEW_COUNT2 });
|
|
2556
|
+
if (devResult.applied) {
|
|
2557
|
+
results.push(`${integrationBranch}: ok`);
|
|
2558
|
+
} else {
|
|
2559
|
+
results.push(`${integrationBranch}: failed \u2014 ${devResult.message ?? "unknown"}`);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
const allOk = results.every((r) => r.endsWith(": ok"));
|
|
2563
|
+
return {
|
|
2564
|
+
name: "Branch protection",
|
|
2565
|
+
filesSynced: 0,
|
|
2566
|
+
message: results.join(" | "),
|
|
2567
|
+
warning: allOk ? void 0 : "some branches failed \u2014 verify manually"
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2499
2570
|
var TIER_1_DOCS = ["Test_Policy.md", "Test_Strategy.md", "Test_Architecture.md"];
|
|
2500
2571
|
async function runValidation(projectPath) {
|
|
2501
2572
|
const warnings = [];
|
|
@@ -2543,7 +2614,8 @@ var SECTION_RUNNERS = [
|
|
|
2543
2614
|
{ key: "2f", run: syncCiTemplates },
|
|
2544
2615
|
{ key: "2g", run: syncGitignore },
|
|
2545
2616
|
{ key: "2h", run: syncSdlcEngine },
|
|
2546
|
-
{ key: "2i", run: syncWorkflows }
|
|
2617
|
+
{ key: "2i", run: syncWorkflows },
|
|
2618
|
+
{ key: "2j", run: verifyBranchProtection }
|
|
2547
2619
|
];
|
|
2548
2620
|
async function syncProject(projectPath) {
|
|
2549
2621
|
const absPath = resolve(projectPath);
|