@@ -487,6 +487,7 @@ function diffRepos(desired, live, opts, out) {
487487 }
488488 diffBranchProtection(name, dr.branchProtection, lr.branchProtection ?? [], opts, out);
489489 diffRulesets(`${name}/`, "repo-ruleset", dr.rulesets, lr.rulesets ?? [], opts, out);
490+ diffRepoSecurity(name, dr.security, lr.security, out);
490491 }
491492 for (const name of Object.keys(live)) {
492493 if (!Object.prototype.hasOwnProperty.call(desired, name)) {
@@ -584,6 +585,24 @@ function diffRulesets(keyPrefix, resourceType, desired, live, opts, out) {
584585 }
585586 }
586587}
588+ function diffRepoSecurity(repoName, desired, live, out) {
589+ if (desired === void 0) return;
590+ if (live === void 0) {
591+ out.push({ kind: "create", resourceType: "repo-security", key: repoName, after: desired });
592+ return;
593+ }
594+ const fields = diffObject(desired, live);
595+ if (fields.length > 0) {
596+ out.push({
597+ kind: "update",
598+ resourceType: "repo-security",
599+ key: repoName,
600+ before: live,
601+ after: desired,
602+ fields
603+ });
604+ }
605+ }
587606function diffObject(desired, live) {
588607 const fields = [];
589608 for (const key of Object.keys(desired)) {
@@ -659,6 +678,7 @@ var init_diff = __esm({
659678 "team-repo",
660679 "member",
661680 "repo",
681+ "repo-security",
662682 "branch-protection",
663683 "repo-ruleset"
664684 ];
@@ -229948,14 +229968,129 @@ var rulesetsCycle = {
229948229968 }
229949229969};
229950229970
229971+ // src/cycles/security-features.ts
229972+ function hasManagedSecurity(repo) {
229973+ return repo.security !== void 0;
229974+ }
229975+ function statusToBool(s) {
229976+ if (s == null || s.status == null) return void 0;
229977+ return s.status === "enabled";
229978+ }
229979+ async function fetchRepoSecurity(client, org, repo, budget) {
229980+ const live = {};
229981+ budget.use(1);
229982+ const repoData = await client.request("GET", `/repos/${org}/${repo}`);
229983+ const saa = repoData.security_and_analysis ?? {};
229984+ const adv = statusToBool(saa.advanced_security);
229985+ const ss = statusToBool(saa.secret_scanning);
229986+ const ssp = statusToBool(saa.secret_scanning_push_protection);
229987+ if (adv !== void 0) live.advancedSecurity = adv;
229988+ if (ss !== void 0) live.secretScanning = ss;
229989+ if (ssp !== void 0) live.secretScanningPushProtection = ssp;
229990+ if (!budget.exhausted) {
229991+ budget.use(1);
229992+ try {
229993+ await client.request("GET", `/repos/${org}/${repo}/vulnerability-alerts`);
229994+ live.vulnerabilityAlerts = true;
229995+ } catch (err) {
229996+ if (err instanceof Error && err.message.includes("404")) {
229997+ live.vulnerabilityAlerts = false;
229998+ } else {
229999+ throw err;
230000+ }
230001+ }
230002+ }
230003+ if (!budget.exhausted) {
230004+ budget.use(1);
230005+ try {
230006+ const fixes = await client.request(
230007+ "GET",
230008+ `/repos/${org}/${repo}/automated-security-fixes`
230009+ );
230010+ live.dependabotSecurityUpdates = fixes.enabled === true;
230011+ } catch (err) {
230012+ if (err instanceof Error && err.message.includes("404")) {
230013+ live.dependabotSecurityUpdates = false;
230014+ } else {
230015+ throw err;
230016+ }
230017+ }
230018+ }
230019+ return live;
230020+ }
230021+ function buildSecurityAnalysisBody(desired) {
230022+ const saa = {};
230023+ if (desired.advancedSecurity !== void 0) {
230024+ saa.advanced_security = { status: desired.advancedSecurity ? "enabled" : "disabled" };
230025+ }
230026+ if (desired.secretScanning !== void 0) {
230027+ saa.secret_scanning = { status: desired.secretScanning ? "enabled" : "disabled" };
230028+ }
230029+ if (desired.secretScanningPushProtection !== void 0) {
230030+ saa.secret_scanning_push_protection = {
230031+ status: desired.secretScanningPushProtection ? "enabled" : "disabled"
230032+ };
230033+ }
230034+ return saa;
230035+ }
230036+ var securityFeaturesCycle = {
230037+ name: "security-features",
230038+ // ── Part 2: fetchLive ──────────────────────────────────────────────────────
230039+ async fetchLive(client, orgLogin, scope, budget) {
230040+ if (budget.exhausted) {
230041+ const { BudgetExhaustedError: BudgetExhaustedError2 } = await Promise.resolve().then(() => (init_runner(), runner_exports));
230042+ throw new BudgetExhaustedError2();
230043+ }
230044+ const repos = {};
230045+ for (const [name, repoConfig] of Object.entries(scope?.repos ?? {})) {
230046+ if (!hasManagedSecurity(repoConfig)) continue;
230047+ if (budget.exhausted) break;
230048+ repos[name] = { security: await fetchRepoSecurity(client, orgLogin, name, budget) };
230049+ }
230050+ return { repos };
230051+ },
230052+ // ── Part 3: buildDesired ───────────────────────────────────────────────────
230053+ buildDesired(orgConfig, _orgLogin, _scope) {
230054+ if (!orgConfig.repos) return {};
230055+ const repos = {};
230056+ for (const [name, repoConfig] of Object.entries(orgConfig.repos)) {
230057+ if (hasManagedSecurity(repoConfig)) repos[name] = { security: repoConfig.security };
230058+ }
230059+ return { repos };
230060+ },
230061+ // ── Part 4: apply ──────────────────────────────────────────────────────────
230062+ async apply(client, entry, orgLogin, _scope, budget) {
230063+ if (entry.resourceType !== "repo-security") return;
230064+ if (entry.kind === "delete") return;
230065+ const repo = entry.key;
230066+ const desired = entry.after;
230067+ const saa = buildSecurityAnalysisBody(desired);
230068+ if (Object.keys(saa).length > 0) {
230069+ budget.use(1);
230070+ await client.request("PATCH", `/repos/${orgLogin}/${repo}`, { security_and_analysis: saa });
230071+ }
230072+ if (desired.vulnerabilityAlerts !== void 0) {
230073+ budget.use(1);
230074+ const method = desired.vulnerabilityAlerts ? "PUT" : "DELETE";
230075+ await client.request(method, `/repos/${orgLogin}/${repo}/vulnerability-alerts`);
230076+ }
230077+ if (desired.dependabotSecurityUpdates !== void 0) {
230078+ budget.use(1);
230079+ const method = desired.dependabotSecurityUpdates ? "PUT" : "DELETE";
230080+ await client.request(method, `/repos/${orgLogin}/${repo}/automated-security-fixes`);
230081+ }
230082+ }
230083+ };
230084+
229951230085// src/cli/registry.ts
229952230086var CYCLE_REGISTRY = {
229953230087 [branchProtectionCycle.name]: branchProtectionCycle,
229954230088 [orgSettingsCycle.name]: orgSettingsCycle,
229955230089 [repoSettingsCycle.name]: repoSettingsCycle,
229956230090 [membershipCycle.name]: membershipCycle,
229957230091 [teamsCycle.name]: teamsCycle,
229958- [rulesetsCycle.name]: rulesetsCycle
230092+ [rulesetsCycle.name]: rulesetsCycle,
230093+ [securityFeaturesCycle.name]: securityFeaturesCycle
229959230094};
229960230095
229961230096// node_modules/@intentius/chant/src/audit/fetch.ts
0 commit comments