code-foundry 1.9.5 → 1.9.7

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.
@@ -71,7 +71,42 @@ export function doctorGithub(root) {
71
71
  )
72
72
  }
73
73
 
74
- const config = readConfig(root)
74
+ const config = readConfig(join(root, '.github/code-foundry.yml'))
75
+ const repositorySettings = ghJson(['api', `repos/${repository}`]) ?? {}
76
+ const configuredWorkflow = config.git_workflow ?? 'direct'
77
+ details.mergeMethods = {
78
+ squash: repositorySettings.allow_squash_merge,
79
+ rebase: repositorySettings.allow_rebase_merge,
80
+ merge: repositorySettings.allow_merge_commit,
81
+ autoMerge: repositorySettings.allow_auto_merge,
82
+ }
83
+ if (configuredWorkflow === 'direct') {
84
+ if (repositorySettings.allow_squash_merge !== true)
85
+ errors.push('direct topology requires squash merging to be enabled.')
86
+ if (
87
+ repositorySettings.allow_rebase_merge === true ||
88
+ repositorySettings.allow_merge_commit === true
89
+ )
90
+ errors.push('direct topology must disable rebase and merge-commit methods.')
91
+ if (config.release_type !== 'none' && repositorySettings.allow_auto_merge !== true)
92
+ errors.push('automated releases require repository auto-merge to be enabled.')
93
+ details.stagingBranchExists = Boolean(
94
+ ghJson(['api', `repos/${repository}/branches/staging`])?.name
95
+ )
96
+ if (details.stagingBranchExists)
97
+ errors.push('direct topology still has a staging branch; remove the obsolete branch.')
98
+ for (const ruleset of mainRulesets) {
99
+ for (const rule of ruleset.rules ?? []) {
100
+ if (rule?.type !== 'pull_request') continue
101
+ const methods = rule.parameters?.allowed_merge_methods ?? []
102
+ if (methods.length !== 1 || methods[0] !== 'squash') {
103
+ errors.push(
104
+ `main ruleset ${ruleset.name ?? ruleset.id} must allow only squash merges; got ${methods.join(', ') || '(none)'}.`
105
+ )
106
+ }
107
+ }
108
+ }
109
+ }
75
110
  if (
76
111
  ['workflow-dispatch', 'dispatch'].includes(config.post_release_mode) &&
77
112
  config.post_release !== 'false' &&
@@ -80,11 +115,19 @@ export function doctorGithub(root) {
80
115
  ) {
81
116
  errors.push('post-release workflow-dispatch mode requires CODE_FOUNDRY_TOKEN to be present.')
82
117
  }
118
+ const repositoryVariables =
119
+ ghJson(['variable', 'list', '--repo', repository, '--json', 'name,value']) ?? []
120
+ const opencodeSecurityVariable = Array.isArray(repositoryVariables)
121
+ ? repositoryVariables.find(
122
+ /** @param {{ name?: string }} variable */ (variable) =>
123
+ variable.name === 'OPENCODE_SECURITY'
124
+ )
125
+ : undefined
83
126
  const credentialChecks = {
84
127
  npmTokenPresent: secretNames.includes('NPM_TOKEN'),
85
128
  turboTokenPresent: secretNames.includes('TURBO_TOKEN'),
86
129
  turboTeamPresent: Boolean(
87
- ghJson(['variable', 'list', '--repo', repository, '--json', 'name'])?.some(
130
+ repositoryVariables.some(
88
131
  /** @param {{ name?: string }} variable */ (variable) => variable.name === 'TURBO_TEAM'
89
132
  )
90
133
  ),
@@ -103,18 +146,15 @@ export function doctorGithub(root) {
103
146
  'turbo_remote is enabled but TURBO_TOKEN and/or TURBO_TEAM is not configured; remote caching will be skipped.'
104
147
  )
105
148
  if (
106
- ['true', 'auto'].includes(config.opencode_security ?? 'false') &&
149
+ String(opencodeSecurityVariable?.value ?? 'false').toLowerCase() === 'true' &&
107
150
  !credentialChecks.opencodeApiKeyPresent
108
151
  )
109
152
  warnings.push(
110
- 'opencode_security is enabled but OPENCODE_API_KEY is not configured; the optional scan will be skipped.'
153
+ 'OPENCODE_SECURITY is true but OPENCODE_API_KEY is not configured; the optional scan will be skipped.'
111
154
  )
112
- if (['true', 'auto'].includes(config.opencode_security ?? 'false'))
113
- details.credentials.opencodeSecurityConfigured = true
114
- details.credentials.opencodeSecurityVariable =
115
- ghJson(['variable', 'list', '--repo', repository, '--json', 'name'])?.some(
116
- /** @param {{ name?: string }} variable */ (variable) => variable.name === 'OPENCODE_SECURITY'
117
- ) ?? false
155
+ details.credentials.opencodeSecurityEnabled =
156
+ String(opencodeSecurityVariable?.value ?? 'false').toLowerCase() === 'true'
157
+ details.credentials.opencodeSecurityVariable = Boolean(opencodeSecurityVariable)
118
158
 
119
159
  const prs = ghJson([
120
160
  'pr',
@@ -19,9 +19,9 @@ export const RELEASE_PLEASE_PREFIX = 'release-please--branches--main'
19
19
 
20
20
  /** Stable aggregate check name emitted by the validation orchestrator's gate job. */
21
21
  export const AGGREGATE_CHECK_NAME = 'Validation / Gate'
22
- /** Job ids owned by the validation orchestrator. The release tier runs no
23
- * suite jobs: its policy executes as a conditional step inside the gate, so
24
- * no release-policy job id exists. */
22
+ /** Job ids owned by the validation orchestrator. Release runs the full audit
23
+ * suite and validates its generated diff inside the gate, so no separate
24
+ * release-policy job id exists. */
25
25
  export const VALIDATION_JOBS = ['ci', 'test', 'security', 'codeql']
26
26
 
27
27
  /** Events that may trigger canonical validation. */
@@ -82,12 +82,10 @@ export function classifyValidationMode(input) {
82
82
  const REQUIRED_JOBS_BY_MODE = {
83
83
  fast: ['ci', 'test'],
84
84
  audit: ['ci', 'test', 'security', 'codeql'],
85
- // The release tier skips the CI/test/security suites (the generated release
86
- // diff check runs as a conditional step inside the gate itself) but still
87
- // runs CodeQL: repository rulesets that require code scanning results need
88
- // a CodeQL analysis of the release pull request's commit, and Release
89
- // Please pull requests must not deadlock against that requirement.
90
- release: ['codeql'],
85
+ // Release Please pull requests run the full audit suite so every registered
86
+ // validation check succeeds rather than appearing as an expected skip. The
87
+ // gate additionally validates the generated release diff.
88
+ release: ['ci', 'test', 'security', 'codeql'],
91
89
  }
92
90
 
93
91
  /**