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.
- package/.github/CONTRIBUTING.md +27 -33
- package/.github/SECURITY.md +1 -2
- package/.github/actions/setup/action.yml +2 -1
- package/.github/code-foundry.yml +1 -3
- package/.github/workflows/ci.yml +8 -8
- package/.github/workflows/cloudflare-deploy.yml +33 -0
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/draft-control_self-ci.yml +44 -0
- package/.github/workflows/opencode-security_self-ci.yml +6 -14
- package/.github/workflows/release.yml +8 -4
- package/.github/workflows/release_self-ci.yml +0 -1
- package/.github/workflows/security.yml +12 -9
- package/.github/workflows/test.yml +10 -10
- package/.github/workflows/validation.yml +7 -6
- package/.github/workflows/validation_self-ci.yml +4 -9
- package/AGENTS.md +3 -3
- package/CHANGELOG.md +15 -0
- package/README.md +6 -4
- package/docs/CONFIGURATION.md +13 -11
- package/docs/RELEASES.md +2 -2
- package/docs/WORKFLOWS.md +23 -21
- package/package.json +1 -1
- package/src/commands/doctor.mjs +29 -8
- package/src/commands/sync.mjs +76 -27
- package/src/lib/github-doctor.mjs +50 -10
- package/src/lib/validation-policy.mjs +7 -9
|
@@ -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
|
-
|
|
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
|
-
|
|
149
|
+
String(opencodeSecurityVariable?.value ?? 'false').toLowerCase() === 'true' &&
|
|
107
150
|
!credentialChecks.opencodeApiKeyPresent
|
|
108
151
|
)
|
|
109
152
|
warnings.push(
|
|
110
|
-
'
|
|
153
|
+
'OPENCODE_SECURITY is true but OPENCODE_API_KEY is not configured; the optional scan will be skipped.'
|
|
111
154
|
)
|
|
112
|
-
|
|
113
|
-
|
|
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.
|
|
23
|
-
* suite
|
|
24
|
-
*
|
|
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
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
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
|
/**
|