-
Notifications
You must be signed in to change notification settings - Fork 955
[WRONG BRANCH] test: add regression test for upstream timeout branch #3030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ce883a5
bd21269
c2778ca
73eb88b
df8b388
a85e9f5
dcdceab
6c360de
0290d29
c7c94cf
3d1a28f
a95be90
ad8ba04
ab60fd5
6cb770d
90b8972
b273950
8d1c99c
6b9f15c
11aeea5
751adf1
0df7a89
5eaf591
c9a4569
f5a625c
6f75616
1031b6f
870a2ad
0ea4396
5f2986f
719d5e1
23d5f02
e60e8cb
007d74c
38df9ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| name: Dev version bump | ||
|
|
||
| # When a release publishes, open a pull request that moves `dev` past the published | ||
| # version. Without this, `dev` keeps carrying a version that is at or behind a released | ||
| # one, and `tests/release-version-line.test.ts` fails on `dev` and on every pull request | ||
| # opened against it - inherited red a contributor cannot fix from their own diff. | ||
| # | ||
| # That has been repaired by hand four times: 32529c2b2, e4a85d134, 076ad3036, befcac3e1. | ||
| # The second of those ADDED the detector and two more repairs followed it, so more | ||
| # visibility was never the missing piece; a prepared change was. | ||
| # | ||
| # WHAT THIS DOES NOT DO. It does not push to `dev`. It opens a pull request and a human | ||
| # merges it, because ruleset `Protect dev` requires an approving review and code-owner | ||
| # sign-off that a bot cannot supply. Until that merge the red persists. This converts a | ||
| # forgotten chore into a queued, reviewable change - not into an automatic repair. | ||
| # | ||
| # A `release` event resolves this workflow file from the repository DEFAULT branch | ||
| # (`main`), not from `dev` - the same trap documented in cleanup-closed-pr-branches.yml. | ||
| # So merging this file to `dev` installs it but arms nothing; it first fires after an | ||
| # ordinary dev -> main promotion carries it there. | ||
| # | ||
| # There is deliberately no `workflow_dispatch`: a branch-selected manual run executes | ||
| # THAT branch body with `contents: write`. Re-drive a missed run by running | ||
| # `bun scripts/bump-dev-version.ts <released> package.json` locally and opening the pull | ||
| # request normally. | ||
| on: | ||
| release: | ||
| types: [published] | ||
|
|
||
| permissions: {} | ||
|
|
||
| concurrency: | ||
| group: dev-version-bump | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| open-bump-pr: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| # Push the new codex/dev-version-* branch. Ruleset `Protect dev` covers only | ||
| # refs/heads/dev, so the bump branch is unprotected and this token cannot | ||
| # bypass dev review. It is the ruleset that keeps this job off dev, not the | ||
| # permission name. | ||
| contents: write | ||
| # Open the pull request. | ||
| pull-requests: write | ||
| steps: | ||
| - name: Checkout dev | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||
| with: | ||
| ref: dev | ||
| # Tags are load-bearing, not decoration: the freeness gate below is a bun | ||
| # test that reads the local tag set, and release-version-line.test.ts | ||
| # returns EARLY on an empty set. A shallow checkout would make that gate | ||
| # silently vacuous instead of failing loudly. | ||
| fetch-depth: 0 | ||
| # Do NOT set persist-credentials: false here as the read-only workflows do. | ||
| # This job has to push its bump branch. | ||
|
|
||
| # The repository-owned composite action, not a hand-pinned setup-bun SHA: it | ||
| # resolves the Bun version from package.json so the runtime SOT stays in one | ||
| # place. An independently pinned action here would drift from every other job. | ||
| - name: Setup project Bun | ||
| uses: ./.github/actions/setup-project-bun | ||
|
|
||
| - name: Install dependencies | ||
| run: bun install --frozen-lockfile | ||
|
|
||
| - name: Decide the version dev should carry | ||
| id: decide | ||
| env: | ||
| RELEASED_VERSION: ${{ github.event.release.tag_name }} | ||
| run: | | ||
| set -euo pipefail | ||
| bun scripts/bump-dev-version.ts "${RELEASED_VERSION}" package.json | ||
|
|
||
| - name: Prove the chosen version is unused | ||
| if: ${{ steps.decide.outputs.changed == 'true' }} | ||
| # The script decides the candidate from the released version SHAPE, which is all | ||
| # a pure function can see. Whether that candidate is actually FREE is a property | ||
| # of the tag set, so it is settled here by the detector that already owns the | ||
| # question. If this fails, no pull request is opened and the job goes red asking | ||
| # for a human decision - which is the correct outcome, not a fallback. | ||
| run: bun test tests/release-version-line.test.ts | ||
|
|
||
| - name: Open the bump pull request | ||
| if: ${{ steps.decide.outputs.changed == 'true' }} | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| NEXT_VERSION: ${{ steps.decide.outputs.version }} | ||
| RELEASED_VERSION: ${{ github.event.release.tag_name }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| branch="codex/dev-version-${NEXT_VERSION}" | ||
|
|
||
| # Idempotent: a second publish, a re-run, or a manual repair must not turn a | ||
| # successful release into a red job. | ||
| # | ||
| # Check the PULL REQUEST as well as the branch, not just the branch. A security | ||
| # review caught that: an open bump pull request whose head branch was deleted | ||
| # leaves the branch check passing, so the job would recreate the branch and then | ||
| # fail on `gh pr create` with "already exists" — turning a successful release red | ||
| # for a repair that was already queued. | ||
| open_prs="$(gh pr list --base dev --head "${branch}" --state open --json number --jq 'length')" | ||
| if [ "${open_prs}" != "0" ]; then | ||
| echo "::notice::a bump pull request for ${branch} is already open; nothing to do" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # An existing branch is NOT terminal. If a previous run pushed the branch and then | ||
| # failed at `gh pr create`, exiting here would leave the repair permanently unqueued | ||
| # while every rerun reports success - the exact failure mode a reviewer caught. So | ||
| # reuse the branch and fall through to pull-request creation instead. | ||
| if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then | ||
| echo "::notice::${branch} exists without an open pull request; validating it" | ||
| git fetch origin "${branch}" | ||
|
|
||
| # Fail closed on unexpected content. The branch carries the bot's own one-line | ||
| # bump, so anything else on it means a human or another job is using that name and | ||
| # this job must not push to it or open a pull request from it. | ||
| changed_files="$(git diff --name-only "origin/dev...origin/${branch}")" | ||
| if [ "${changed_files}" != "package.json" ]; then | ||
| echo "::error::${branch} touches unexpected files: ${changed_files:-<none>}" | ||
| exit 1 | ||
| fi | ||
| branch_version="$(git show "origin/${branch}:package.json" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).version")" | ||
| if [ "${branch_version}" != "${NEXT_VERSION}" ]; then | ||
| echo "::error::${branch} carries ${branch_version}, expected ${NEXT_VERSION}" | ||
| exit 1 | ||
| fi | ||
| git checkout -B "${branch}" "origin/${branch}" | ||
| else | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git checkout -b "${branch}" | ||
| git add package.json | ||
| git commit -m "fix(release): move dev to ${NEXT_VERSION} after ${RELEASED_VERSION}" | ||
| git push origin "${branch}" | ||
| fi | ||
|
|
||
| gh pr create \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
# In a test release, verify that the generated bump PR has all required checks.
set -euo pipefail
pr_number="${1:?pass the generated bump PR number}"
gh pr checks "$pr_number" --requiredRepository: lidge-jun/opencodex Length of output: 208 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- repository guidance ---'
find /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732 -maxdepth 2 -type f -name '*.md' -print \
-exec sh -c 'echo "--- $1"; head -120 "$1"' sh {} \;
printf '%s\n' '--- workflow ---'
cat -n .github/workflows/dev-version-bump.yml
printf '%s\n' '--- workflow triggers and CI references ---'
rg -n -i '^(on:| pull_request| push:| workflow_dispatch:|name:| required|check|dev-version|version-bump)|pull_request|workflow_dispatch|branches:.*dev' .github/workflows .github 2>/dev/null || true
printf '%s\n' '--- maintainer policy ---'
if [ -f MAINTAINERS.md ]; then cat -n MAINTAINERS.md; fiRepository: lidge-jun/opencodex Length of output: 50377 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- MAINTAINERS.md ---'
cat -n MAINTAINERS.md
printf '%s\n' '--- CI trigger, jobs, and dispatch inputs ---'
sed -n '1,115p' .github/workflows/ci.yml
rg -n '^( [A-Za-z0-9_-]+:| [A-Za-z0-9_-]+:)|name:|required|workflow_run|workflow_dispatch|pull_request|push:' .github/workflows/ci.yml
printf '%s\n' '--- policy workflow trigger and check-producing sections ---'
sed -n '1,210p' .github/workflows/enforce-pr-target.yml
rg -n 'setOutput|createCheck|check-runs|status|pull_request|push:|workflow_run|name:' .github/workflows/enforce-pr-target.yml
printf '%s\n' '--- other PR-triggered workflows and job names ---'
for f in .github/workflows/*.yml; do
if rg -q 'pull_request' "$f"; then
echo "--- $f"
sed -n '1,45p' "$f"
fi
doneRepository: lidge-jun/opencodex Length of output: 50375 🌐 Web query:
💡 Result: GitHub Actions is designed to prevent infinite recursive loops by restricting the ability of the default GITHUB_TOKEN to trigger new workflow runs [1][2]. When a workflow uses the default GITHUB_TOKEN to create or update a pull request, the resulting pull_request event (if it uses the opened, synchronize, or reopened activity types) does not trigger new workflows automatically [1][3][2]. Instead, these runs are created in an approval-required state, and a user with write access to the repository must manually approve them from the pull request page [1][2]. Other pull request activity types (such as labeled, edited, or closed) do not create workflow runs at all [1][2]. To bypass this restriction and have workflows trigger automatically when a pull request is created or updated by automation, you must use a more privileged credential instead of the default GITHUB_TOKEN [1][2]. The recommended alternatives are: 1. Personal Access Token (PAT): You can create a PAT (fine-grained or classic) with the appropriate repository permissions, store it as a repository secret, and configure your action (e.g., create-pull-request) to use this secret instead of the default token [4][5]. 2. GitHub App Installation Access Token: Using a GitHub App installation token is also an effective way to trigger workflows automatically, as these tokens are treated as distinct from the repository's automatic GITHUB_TOKEN [1][2]. Using these alternatives allows the resulting pull request events to trigger workflows immediately without requiring manual approval [1][2]. Citations:
Ensure the generated pull request receives required CI checks. Because 🤖 Prompt for AI AgentsSource: Path instructions |
||
| --base dev \ | ||
| --head "${branch}" \ | ||
| --title "fix(release): move dev to ${NEXT_VERSION} after ${RELEASED_VERSION}" \ | ||
| --body "$(cat <<BODY | ||
| ## Summary | ||
|
|
||
| \`${RELEASED_VERSION}\` published, so \`dev\` would otherwise keep a version at or | ||
| behind a released one and \`tests/release-version-line.test.ts\` would fail on | ||
| \`dev\` and on every pull request opened against it. This moves \`dev\` to | ||
| \`${NEXT_VERSION}\`. | ||
|
|
||
| Opened automatically by \`.github/workflows/dev-version-bump.yml\`. The same | ||
| repair was previously done by hand in 32529c2b2, e4a85d134, 076ad3036, and | ||
| befcac3e1. | ||
|
|
||
| ## Verification | ||
|
|
||
| \`bun test tests/release-version-line.test.ts\` ran against this exact tree | ||
| before the pull request was opened; the workflow refuses to open one if the | ||
| chosen version collides with a published release. | ||
|
|
||
| ## Checklist | ||
|
|
||
| - [x] Scope stays focused and avoids unrelated cleanup. | ||
| - [x] Docs or release notes were updated when needed. | ||
| - [x] Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. | ||
| BODY | ||
| )" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| @echo off | ||
| setlocal | ||
|
|
||
| powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0Start-OpenCodex.ps1" %* | ||
| set "launcher_exit=%ERRORLEVEL%" | ||
|
|
||
| if not "%launcher_exit%"=="0" ( | ||
| echo. | ||
| echo OpenCodex could not be started. Review the error above. | ||
| pause | ||
| ) | ||
|
|
||
| exit /b %launcher_exit% |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||||||
| [CmdletBinding()] | ||||||||
| param( | ||||||||
| [ValidateRange(1, 65535)] | ||||||||
| [int]$Port = 10100, | ||||||||
|
|
||||||||
| [ValidateRange(1, 120)] | ||||||||
| [int]$StartupTimeoutSeconds = 30, | ||||||||
|
|
||||||||
| [switch]$NoBrowser | ||||||||
| ) | ||||||||
|
|
||||||||
| $ErrorActionPreference = "Stop" | ||||||||
| $repoRoot = $PSScriptRoot | ||||||||
| $dashboardUrl = "http://127.0.0.1:$Port/" | ||||||||
| $healthUrl = "${dashboardUrl}healthz" | ||||||||
| $logDirectory = Join-Path $repoRoot ".tmp" | ||||||||
| $stdoutLog = Join-Path $logDirectory "launcher.out.log" | ||||||||
| $stderrLog = Join-Path $logDirectory "launcher.err.log" | ||||||||
|
|
||||||||
| function Get-OpenCodexHealth { | ||||||||
| try { | ||||||||
| $response = Invoke-RestMethod -Uri $healthUrl -Method Get -TimeoutSec 2 | ||||||||
| if ($response.service -eq "opencodex" -and $response.status -eq "ok") { | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Accept the canonical OpenCodex health response shapes.
Mirror the canonical identity predicate. Keep PID validation separate because the canonical predicate also permits an absent PID. 🤖 Prompt for AI Agents |
||||||||
| return $response | ||||||||
| } | ||||||||
| } | ||||||||
| catch { | ||||||||
| return $null | ||||||||
| } | ||||||||
|
|
||||||||
| return $null | ||||||||
| } | ||||||||
|
|
||||||||
| function Open-Dashboard { | ||||||||
| if (-not $NoBrowser) { | ||||||||
| Start-Process $dashboardUrl | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| function Test-IsLocalCheckoutProcess { | ||||||||
| param([Parameter(Mandatory = $true)][int]$ProcessId) | ||||||||
|
|
||||||||
| try { | ||||||||
| $runningProcess = Get-CimInstance Win32_Process -Filter "ProcessId=$ProcessId" | ||||||||
| if ($null -eq $runningProcess) { | ||||||||
| return $false | ||||||||
| } | ||||||||
|
|
||||||||
| if (-not [string]::IsNullOrWhiteSpace($runningProcess.ExecutablePath) -and | ||||||||
| $runningProcess.ExecutablePath.StartsWith($repoRoot, [StringComparison]::OrdinalIgnoreCase)) { | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Check a checkout path at a directory boundary.
Normalize the root and require a trailing path separator before the comparison. Proposed fix+ $checkoutPrefix = $repoRoot.TrimEnd('\', '/') + '\'
if (-not [string]::IsNullOrWhiteSpace($runningProcess.ExecutablePath) -and
- $runningProcess.ExecutablePath.StartsWith($repoRoot, [StringComparison]::OrdinalIgnoreCase)) {
+ $runningProcess.ExecutablePath.StartsWith($checkoutPrefix, [StringComparison]::OrdinalIgnoreCase)) {
return $true
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| return $true | ||||||||
| } | ||||||||
|
|
||||||||
| if ([string]::IsNullOrWhiteSpace($runningProcess.CommandLine)) { | ||||||||
| return $false | ||||||||
| } | ||||||||
|
|
||||||||
| $expectedEntryPoint = Join-Path $repoRoot "src\cli\index.ts" | ||||||||
| return $runningProcess.CommandLine.IndexOf($expectedEntryPoint, [StringComparison]::OrdinalIgnoreCase) -ge 0 | ||||||||
| } | ||||||||
| catch { | ||||||||
| return $false | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| $localBunExecutable = Join-Path $repoRoot "node_modules\bun\bin\bun.exe" | ||||||||
| $bunApplication = Get-Command bun.exe -CommandType Application -ErrorAction SilentlyContinue | ||||||||
| if (Test-Path -LiteralPath $localBunExecutable) { | ||||||||
| $bunExecutable = $localBunExecutable | ||||||||
| } | ||||||||
| elseif ($null -ne $bunApplication) { | ||||||||
| $bunExecutable = $bunApplication.Source | ||||||||
| } | ||||||||
| else { | ||||||||
| throw "Bun was not found. Install Bun from https://bun.sh, then run this launcher again." | ||||||||
| } | ||||||||
|
|
||||||||
| if (-not (Test-Path -LiteralPath (Join-Path $repoRoot "node_modules"))) { | ||||||||
| throw "Dependencies are missing. Open PowerShell in '$repoRoot', run 'bun install', then try again." | ||||||||
| } | ||||||||
|
|
||||||||
| $existingHealth = Get-OpenCodexHealth | ||||||||
| if ($null -ne $existingHealth) { | ||||||||
| if (Test-IsLocalCheckoutProcess -ProcessId $existingHealth.pid) { | ||||||||
| Write-Host "This OpenCodex checkout is already running on port $Port (PID $($existingHealth.pid))." | ||||||||
| Open-Dashboard | ||||||||
| exit 0 | ||||||||
| } | ||||||||
|
|
||||||||
| Write-Host "A different OpenCodex installation is using port $Port (PID $($existingHealth.pid))." | ||||||||
| Write-Host "Stopping it before starting this checkout..." | ||||||||
| & $bunExecutable run src/cli/index.ts stop | ||||||||
| if ($LASTEXITCODE -ne 0) { | ||||||||
| throw "The existing OpenCodex instance could not be stopped safely." | ||||||||
| } | ||||||||
|
|
||||||||
| $stopDeadline = (Get-Date).AddSeconds(15) | ||||||||
| do { | ||||||||
| Start-Sleep -Milliseconds 250 | ||||||||
| $existingHealth = Get-OpenCodexHealth | ||||||||
| } while ($null -ne $existingHealth -and (Get-Date) -lt $stopDeadline) | ||||||||
|
|
||||||||
| if ($null -ne $existingHealth) { | ||||||||
| throw "The previous OpenCodex instance is still using port $Port." | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null | ||||||||
|
|
||||||||
| Write-Host "Starting OpenCodex on port $Port..." | ||||||||
| $process = Start-Process ` | ||||||||
| -FilePath $bunExecutable ` | ||||||||
| -ArgumentList @("run", "src/cli/index.ts", "start", "--port", "$Port") ` | ||||||||
| -WorkingDirectory $repoRoot ` | ||||||||
| -WindowStyle Hidden ` | ||||||||
| -RedirectStandardOutput $stdoutLog ` | ||||||||
| -RedirectStandardError $stderrLog ` | ||||||||
| -PassThru | ||||||||
|
|
||||||||
| $deadline = (Get-Date).AddSeconds($StartupTimeoutSeconds) | ||||||||
| do { | ||||||||
| Start-Sleep -Milliseconds 250 | ||||||||
| $process.Refresh() | ||||||||
|
|
||||||||
| $health = Get-OpenCodexHealth | ||||||||
| if ($null -ne $health) { | ||||||||
| if (-not (Test-IsLocalCheckoutProcess -ProcessId $health.pid)) { | ||||||||
| throw "Port $Port became healthy, but it belongs to a different OpenCodex installation." | ||||||||
| } | ||||||||
| Write-Host "OpenCodex is ready at $dashboardUrl (PID $($health.pid))." | ||||||||
| Open-Dashboard | ||||||||
| exit 0 | ||||||||
| } | ||||||||
|
|
||||||||
| if ($process.HasExited) { | ||||||||
| throw "OpenCodex stopped during startup (exit code $($process.ExitCode)). See '$stderrLog'." | ||||||||
| } | ||||||||
| } while ((Get-Date) -lt $deadline) | ||||||||
|
|
||||||||
| throw "OpenCodex did not become ready within $StartupTimeoutSeconds seconds. See '$stderrLog'." | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 232
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 5468
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 7182
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 5732
Security Misconfiguration (CWE-269): Improper Privilege Management
Reachability: Internal · Exploitability: Difficult
Isolate the write token from code checked out from
dev.The workflow checks out
devwith persistent credentials, then runs repository-controlled code and tests. A compromised change merged intodevcould read the checkout credential and use the job'scontents: writepermission before the workflow opens the bump pull request.Set
persist-credentials: falseat.github/workflows/dev-version-bump.yml#L57-L58. Provide a narrowly scoped credential only to thegit pushandgh pr createoperations. TheProtect devrule prevents bot merging, but it does not isolate credentials from code executed before the pull request is opened.🧰 Tools
🪛 zizmor (1.29.0)
[warning] 48-62: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
📍 Affects 2 files
.github/workflows/dev-version-bump.yml#L57-L58(this comment)MAINTAINERS.md#L83-L85🤖 Prompt for AI Agents
Sources: Coding guidelines, Path instructions, Linters/SAST tools