@metasession.co/devaudit-cli 0.3.4 → 0.3.5
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 +91 -17
- 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.5"};
|
|
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,22 @@ 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
1736
|
"Compliance Validation",
|
|
1738
1737
|
"DevAudit Release Approval",
|
|
1739
1738
|
"Quality Gates"
|
|
1740
1739
|
];
|
|
1740
|
+
var MAIN_REVIEW_COUNT = 1;
|
|
1741
|
+
var DEVELOP_REVIEW_COUNT = 0;
|
|
1742
|
+
async function resolveIntegrationBranch(projectPath) {
|
|
1743
|
+
try {
|
|
1744
|
+
const raw = await promises.readFile(join(projectPath, "sdlc-config.json"), "utf-8");
|
|
1745
|
+
const config = JSON.parse(raw);
|
|
1746
|
+
return config.integration_branch ?? "develop";
|
|
1747
|
+
} catch {
|
|
1748
|
+
return "develop";
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1741
1751
|
async function configureBranchProtection(ctx, provider) {
|
|
1742
1752
|
if (ctx.installMode === "developer") {
|
|
1743
1753
|
return {
|
|
@@ -1757,25 +1767,34 @@ async function configureBranchProtection(ctx, provider) {
|
|
|
1757
1767
|
};
|
|
1758
1768
|
}
|
|
1759
1769
|
const repo = `${meta.owner}/${meta.name}`;
|
|
1770
|
+
const integrationBranch = await resolveIntegrationBranch(ctx.projectPath);
|
|
1760
1771
|
if (ctx.dryRun) {
|
|
1761
1772
|
return {
|
|
1762
1773
|
step: "9/11 Configure branch protection",
|
|
1763
1774
|
status: "planned",
|
|
1764
|
-
message: `would apply branch protection on ${repo}:${meta.defaultBranch} with checks=${JSON.stringify(REQUIRED_CHECKS)}`
|
|
1775
|
+
message: `would apply branch protection on ${repo}:${meta.defaultBranch} (1 review) + ${integrationBranch} (0 reviews) with checks=${JSON.stringify(REQUIRED_CHECKS)}`
|
|
1765
1776
|
};
|
|
1766
1777
|
}
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
};
|
|
1778
|
+
const results = [];
|
|
1779
|
+
const mainResult = await provider.applyBranchProtection(ctx.projectPath, meta.defaultBranch, REQUIRED_CHECKS, { requiredReviewCount: MAIN_REVIEW_COUNT });
|
|
1780
|
+
if (mainResult.applied) {
|
|
1781
|
+
results.push(`${meta.defaultBranch}: ok (${MAIN_REVIEW_COUNT} review)`);
|
|
1782
|
+
} else {
|
|
1783
|
+
results.push(`${meta.defaultBranch}: FAILED \u2014 ${mainResult.message ?? "unknown"}`);
|
|
1774
1784
|
}
|
|
1785
|
+
if (integrationBranch !== meta.defaultBranch) {
|
|
1786
|
+
const devResult = await provider.applyBranchProtection(ctx.projectPath, integrationBranch, REQUIRED_CHECKS, { requiredReviewCount: DEVELOP_REVIEW_COUNT });
|
|
1787
|
+
if (devResult.applied) {
|
|
1788
|
+
results.push(`${integrationBranch}: ok (${DEVELOP_REVIEW_COUNT} reviews)`);
|
|
1789
|
+
} else {
|
|
1790
|
+
results.push(`${integrationBranch}: FAILED \u2014 ${devResult.message ?? "unknown"}`);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
const allOk = results.every((r) => r.includes(": ok"));
|
|
1775
1794
|
return {
|
|
1776
1795
|
step: "9/11 Configure branch protection",
|
|
1777
|
-
status: "warn",
|
|
1778
|
-
message:
|
|
1796
|
+
status: allOk ? "ok" : "warn",
|
|
1797
|
+
message: allOk ? results.join(" | ") : `${results.join(" | ")} \u2014 configure manually`
|
|
1779
1798
|
};
|
|
1780
1799
|
}
|
|
1781
1800
|
var ajv = new Ajv({ allErrors: true, strict: false });
|
|
@@ -2496,6 +2515,60 @@ async function syncWorkflows(ctx) {
|
|
|
2496
2515
|
message: files.length > 0 ? `synced to .devin/workflows/` : "no workflow files found"
|
|
2497
2516
|
};
|
|
2498
2517
|
}
|
|
2518
|
+
var REQUIRED_CHECKS2 = [
|
|
2519
|
+
"Compliance Validation",
|
|
2520
|
+
"DevAudit Release Approval",
|
|
2521
|
+
"Quality Gates"
|
|
2522
|
+
];
|
|
2523
|
+
var MAIN_REVIEW_COUNT2 = 1;
|
|
2524
|
+
var DEVELOP_REVIEW_COUNT2 = 0;
|
|
2525
|
+
async function verifyBranchProtection(ctx) {
|
|
2526
|
+
const config = await readSdlcConfig(ctx.projectPath);
|
|
2527
|
+
const integrationBranch = config?.integration_branch ?? "develop";
|
|
2528
|
+
config?.release_branch ?? "main";
|
|
2529
|
+
let provider;
|
|
2530
|
+
try {
|
|
2531
|
+
provider = await getGitProvider(ctx.projectPath);
|
|
2532
|
+
} catch (err) {
|
|
2533
|
+
return {
|
|
2534
|
+
name: "Branch protection",
|
|
2535
|
+
filesSynced: 0,
|
|
2536
|
+
warning: `git provider unavailable (${err.message}) \u2014 verify manually`
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
let meta;
|
|
2540
|
+
try {
|
|
2541
|
+
meta = await provider.getRepoMeta(ctx.projectPath);
|
|
2542
|
+
} catch (err) {
|
|
2543
|
+
return {
|
|
2544
|
+
name: "Branch protection",
|
|
2545
|
+
filesSynced: 0,
|
|
2546
|
+
warning: `could not resolve repo (${err.message}) \u2014 verify manually`
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
const results = [];
|
|
2550
|
+
const mainResult = await provider.applyBranchProtection(ctx.projectPath, meta.defaultBranch, REQUIRED_CHECKS2, { requiredReviewCount: MAIN_REVIEW_COUNT2 });
|
|
2551
|
+
if (mainResult.applied) {
|
|
2552
|
+
results.push(`${meta.defaultBranch}: ok`);
|
|
2553
|
+
} else {
|
|
2554
|
+
results.push(`${meta.defaultBranch}: failed \u2014 ${mainResult.message ?? "unknown"}`);
|
|
2555
|
+
}
|
|
2556
|
+
if (integrationBranch !== meta.defaultBranch) {
|
|
2557
|
+
const devResult = await provider.applyBranchProtection(ctx.projectPath, integrationBranch, REQUIRED_CHECKS2, { requiredReviewCount: DEVELOP_REVIEW_COUNT2 });
|
|
2558
|
+
if (devResult.applied) {
|
|
2559
|
+
results.push(`${integrationBranch}: ok`);
|
|
2560
|
+
} else {
|
|
2561
|
+
results.push(`${integrationBranch}: failed \u2014 ${devResult.message ?? "unknown"}`);
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
const allOk = results.every((r) => r.endsWith(": ok"));
|
|
2565
|
+
return {
|
|
2566
|
+
name: "Branch protection",
|
|
2567
|
+
filesSynced: 0,
|
|
2568
|
+
message: results.join(" | "),
|
|
2569
|
+
warning: allOk ? void 0 : "some branches failed \u2014 verify manually"
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2499
2572
|
var TIER_1_DOCS = ["Test_Policy.md", "Test_Strategy.md", "Test_Architecture.md"];
|
|
2500
2573
|
async function runValidation(projectPath) {
|
|
2501
2574
|
const warnings = [];
|
|
@@ -2543,7 +2616,8 @@ var SECTION_RUNNERS = [
|
|
|
2543
2616
|
{ key: "2f", run: syncCiTemplates },
|
|
2544
2617
|
{ key: "2g", run: syncGitignore },
|
|
2545
2618
|
{ key: "2h", run: syncSdlcEngine },
|
|
2546
|
-
{ key: "2i", run: syncWorkflows }
|
|
2619
|
+
{ key: "2i", run: syncWorkflows },
|
|
2620
|
+
{ key: "2j", run: verifyBranchProtection }
|
|
2547
2621
|
];
|
|
2548
2622
|
async function syncProject(projectPath) {
|
|
2549
2623
|
const absPath = resolve(projectPath);
|