Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
aac99bb
fix(security): update pip audit lock past pysec-2026-3721
seonghobae Aug 21, 2026
84ee91b
feat: route autofix through contextual orchestrator
seonghobae Aug 21, 2026
d195ef4
chore(security): restore pip-audit lock owner scope
seonghobae Aug 21, 2026
b9cffcf
chore: schedule contextual-orchestrator hourly review repair (#1178)
seonghobae Aug 21, 2026
0e9d24c
Revert "chore: schedule contextual-orchestrator hourly review repair …
seonghobae Aug 21, 2026
08c92c4
Reapply "chore: schedule contextual-orchestrator hourly review repair…
seonghobae Aug 21, 2026
94a2804
fix(security): use osv scanner output-file flag
seonghobae Aug 21, 2026
859d3b7
fix(test): track osv scanner output-file option
seonghobae Aug 21, 2026
90ea841
fix(security): keep reporter output contract
seonghobae Aug 21, 2026
592deef
docs: complete fixture initializer docstring coverage
seonghobae Aug 21, 2026
4ed00ac
fix(codeql): bind merge analysis to merge commit SHA (#1206)
seonghobae Aug 21, 2026
94e2b28
fix(codeql): keep merge upload ref in documented form
seonghobae Aug 21, 2026
4d3d24a
fix(actions): deduplicate workflow-run scheduler scans (#1203)
seonghobae Aug 21, 2026
3016543
fix(review): fail closed when required check is not a verdict (#1002)
seonghobae Aug 21, 2026
4c659d2
Merge protected main into pip-audit scheduler root
seonghobae Aug 21, 2026
3b91220
fix(review): reject external heads in privileged paths
seonghobae Aug 21, 2026
dbb3c8a
fix(codeql): verify merge preview identity
seonghobae Aug 21, 2026
33cdcad
fix(codeql): authenticate merge preview fetch
seonghobae Aug 21, 2026
801c2f1
fix(codeql): bind analysis to exact current merge tree
seonghobae Aug 21, 2026
61ecd32
Merge protected main into exact merge-preview repair
seonghobae Aug 21, 2026
e5a7ac8
test: refresh review dispatch blob pin after restack
seonghobae Aug 21, 2026
1ff33c9
fix(codeql): fetch merge ancestry before preview
seonghobae Aug 23, 2026
997e4f1
Merge protected main into CodeQL review repair
seonghobae Aug 23, 2026
bee244e
merge(main): refresh CodeQL review owner
seonghobae Aug 24, 2026
069bfa6
merge(main): refresh CodeQL review owner
seonghobae Aug 24, 2026
dafcf87
fix(review): validate exact VCS dependency licenses
seonghobae Aug 24, 2026
88579ae
test(review): keep VCS license fixtures whitespace-clean
seonghobae Aug 24, 2026
863c343
test(review): prove VCS license gate coverage
seonghobae Aug 24, 2026
98af23e
fix(review): reject VCS license metadata redirects
seonghobae Aug 24, 2026
09c2489
Merge protected main into review verdict owner
seonghobae Aug 25, 2026
0b5dbd1
fix(review): reject dot-only VCS repository names
seonghobae Aug 25, 2026
59fdd8c
Merge protected main and clarify the MPL-2.0 policy exception
seonghobae Aug 25, 2026
234bbd6
Merge protected main into review-verdict owner
seonghobae Aug 25, 2026
b69d9c8
fix(ci): normalize merged scheduler files at EOF
seonghobae Aug 25, 2026
748e881
merge: converge review-verdict owner with protected main
seonghobae Aug 26, 2026
27a8bd5
fix(codeql): resolve fork heads through exact PR ref
seonghobae Aug 26, 2026
2d00301
Merge branch 'main' into fix/pip-audit-pip-2621
opencode-agent[bot] Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 85 additions & 2 deletions .github/workflows/codeql-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,90 @@ jobs:
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
ref: ${{ format('refs/pull/{0}/merge', github.event.pull_request.number) }}
# GitHub can omit the synthetic merge ref for stacked/non-default-base PRs;
# materialize the exact merge-result SHA locally while retaining the
# documented pull-request ref shape for CodeQL result publication.
ref: ${{ github.event.pull_request.merge_commit_sha }}
Comment thread
seonghobae marked this conversation as resolved.
Comment thread
seonghobae marked this conversation as resolved.
Comment thread
seonghobae marked this conversation as resolved.
# merge-tree requires the real base/head merge base; an explicit-SHA
# depth-1 checkout leaves every fetched commit as a shallow root.
fetch-depth: 0

- name: Verify merge preview identity
id: verify-merge-preview
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0=http.extraheader
export GIT_CONFIG_VALUE_0="AUTHORIZATION: bearer $GITHUB_TOKEN"
git fetch --no-tags origin "$BASE_SHA" "$MERGE_SHA"
head_fetch_succeeded=0
if git cat-file -e "$HEAD_SHA^{commit}"; then
head_fetch_succeeded=1
elif git fetch --no-tags origin "$HEAD_SHA" &&
git cat-file -e "$HEAD_SHA^{commit}"; then
head_fetch_succeeded=1
else
echo "Direct CodeQL head-SHA fetch was unavailable; resolving the exact head through the target pull request ref."
fi
if [ "$head_fetch_succeeded" -ne 1 ]; then
for pr_head_fetch_attempt in 1 2 3 4 5 6; do
if git fetch --no-tags --prune origin \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr-${PR_NUMBER}-head"; then
fetched_head_sha="$(git rev-parse "refs/remotes/origin/pr-${PR_NUMBER}-head")"
if [ "$fetched_head_sha" = "$HEAD_SHA" ]; then
head_fetch_succeeded=1
break
fi
if [ "$pr_head_fetch_attempt" -lt 6 ]; then
echo "Fetched PR head $fetched_head_sha, expected $HEAD_SHA; retrying after propagation delay."
sleep 10
fi
elif [ "$pr_head_fetch_attempt" -lt 6 ]; then
echo "PR head ref fetch failed on attempt $pr_head_fetch_attempt; retrying after propagation delay."
sleep 10
fi
done
fi
if [ "$head_fetch_succeeded" -ne 1 ] ||
! git cat-file -e "$HEAD_SHA^{commit}"; then
echo "::error::CodeQL merge preview could not resolve exact head SHA $HEAD_SHA from origin or refs/pull/$PR_NUMBER/head."
exit 1
fi
unset GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0
provided_tree="$(git rev-parse "$MERGE_SHA^{tree}")"
read -r actual_merge parent_one parent_two extra <<EOF
$(git rev-list --parents -n 1 "$MERGE_SHA")
EOF
expected_tree="$(git merge-tree --write-tree "$BASE_SHA" "$HEAD_SHA")"
local_merge_sha="$MERGE_SHA"
if [ "$actual_merge" != "$MERGE_SHA" ] ||
[ "$parent_one" != "$BASE_SHA" ] ||
[ "$parent_two" != "$HEAD_SHA" ] ||
[ -n "${extra:-}" ] ||
[ "$provided_tree" != "$expected_tree" ]; then
echo "::notice::GitHub merge preview metadata is stale or structurally different; materializing the exact base/head merge tree locally."
local_merge_sha="$(
printf 'CWL CodeQL exact merge preview\n\nbase=%s\nhead=%s\n' "$BASE_SHA" "$HEAD_SHA" |
env GIT_AUTHOR_NAME='CWL CodeQL verifier' \
GIT_AUTHOR_EMAIL='cwl-codeql-verifier@localhost' \
GIT_COMMITTER_NAME='CWL CodeQL verifier' \
GIT_COMMITTER_EMAIL='cwl-codeql-verifier@localhost' \
git commit-tree "$expected_tree" -p "$BASE_SHA" -p "$HEAD_SHA"
)"
fi
git reset --hard "$local_merge_sha"
test "$(git rev-parse "$local_merge_sha^{tree}")" = "$expected_tree"
{
echo "merge_sha=$local_merge_sha"
echo "merge_tree=$expected_tree"
} >> "$GITHUB_OUTPUT"
Comment thread
seonghobae marked this conversation as resolved.
echo "Verified merge preview: base=$BASE_SHA head=$HEAD_SHA provided_merge=$MERGE_SHA analyzed_merge=$local_merge_sha tree=$expected_tree"

- name: Initialize CodeQL
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
Expand All @@ -209,7 +292,7 @@ jobs:
upload: false
output: codeql-results-merge
ref: ${{ format('refs/pull/{0}/merge', github.event.pull_request.number) }}
sha: ${{ github.event.pull_request.merge_commit_sha }}
sha: ${{ steps.verify-merge-preview.outputs.merge_sha }}

- name: Enforce CodeQL Medium+ SARIF gate
shell: python3 {0}
Expand Down
105 changes: 101 additions & 4 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ jobs:
! [[ "$live_is_private" =~ ^(true|false)$ ]] ||
[ -z "$live_base_ref" ] ||
[ -z "$live_head_ref" ]; then
printf '::error::PR metadata validation rejected closed, missing, or malformed live metadata. target=%s#%s state=%s base_repo=%s head_repo=%s base=%s head=%s\n' "$TARGET_REPOSITORY" "$PR_NUMBER" "${live_state:-<missing>}" "${live_base_repository:-<missing>}" "${live_head_repository:-<missing>}" "${live_base_sha:-<missing>}" "${live_head_sha:-<missing>}"
printf '::error::PR metadata validation rejected closed, missing, malformed, or base-repository-mismatched live metadata. target=%s#%s state=%s base_repo=%s head_repo=%s base=%s head=%s\n' "$TARGET_REPOSITORY" "$PR_NUMBER" "${live_state:-<missing>}" "${live_base_repository:-<missing>}" "${live_head_repository:-<missing>}" "${live_base_sha:-<missing>}" "${live_head_sha:-<missing>}"
exit 1
fi

Expand Down Expand Up @@ -333,8 +333,44 @@ jobs:
git -C "$fetch_dir" remote add origin "${GITHUB_SERVER_URL}/${TARGET_REPOSITORY}.git"
if ! git -C "$fetch_dir" \
-c http.extraheader="AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules origin "$PR_BASE_SHA" "$PR_HEAD_SHA"; then
echo "::error::Coverage fetch could not authenticate to ${TARGET_REPOSITORY} or read base/head SHAs ${PR_BASE_SHA}/${PR_HEAD_SHA}; check token permissions, target repository access, and SHA visibility."
fetch --no-tags --prune --no-recurse-submodules origin "$PR_BASE_SHA"; then
echo "::error::Coverage fetch could not authenticate to ${TARGET_REPOSITORY} or read base SHA ${PR_BASE_SHA}; check token permissions, target repository access, and SHA visibility."
exit 1
fi
head_fetch_succeeded=0
if git -C "$fetch_dir" \
-c http.extraheader="AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules origin "$PR_HEAD_SHA"; then
head_fetch_succeeded=1
else
echo "Direct head-SHA coverage fetch was unavailable; resolving the exact head through the target pull request ref."
fi
if [ "$head_fetch_succeeded" -ne 1 ]; then
for pr_head_fetch_attempt in 1 2 3 4 5 6; do
if git -C "$fetch_dir" \
-c http.extraheader="AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules origin \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr-${PR_NUMBER}-head"; then
fetched_head_sha="$(git -C "$fetch_dir" rev-parse "refs/remotes/origin/pr-${PR_NUMBER}-head")"
if [ "$fetched_head_sha" = "$PR_HEAD_SHA" ]; then
head_fetch_succeeded=1
break
fi
if [ "$pr_head_fetch_attempt" -lt 6 ]; then
echo "Fetched PR head $fetched_head_sha, expected $PR_HEAD_SHA; retrying after propagation delay."
sleep 10
else
echo "Fetched PR head $fetched_head_sha, expected $PR_HEAD_SHA; no retries remain."
fi
elif [ "$pr_head_fetch_attempt" -lt 6 ]; then
echo "PR head ref fetch failed on attempt $pr_head_fetch_attempt; retrying after propagation delay."
sleep 10
fi
done
fi
if [ "$head_fetch_succeeded" -ne 1 ] ||
! git -C "$fetch_dir" cat-file -e "${PR_HEAD_SHA}^{commit}"; then
echo "::error::Coverage fetch could not resolve exact head SHA ${PR_HEAD_SHA} from ${TARGET_REPOSITORY} or refs/pull/${PR_NUMBER}/head; check token permissions, target repository access, PR state, and SHA propagation."
exit 1
fi
git -C "$fetch_dir" checkout --detach "$PR_BASE_SHA"
Expand Down Expand Up @@ -609,6 +645,7 @@ jobs:
coverage_build_dir="${RUNNER_TEMP}/opencode-coverage-tool-build"
trusted_ci_requirements="${GITHUB_WORKSPACE}/requirements-opencode-review-ci-hashes.txt"
trusted_base_python_installer="${GITHUB_WORKSPACE}/scripts/ci/install_base_python_locks.py"
trusted_vcs_license_validator="${GITHUB_WORKSPACE}/scripts/ci/validate_vcs_dependency_license.py"
if [ ! -f "$trusted_ci_requirements" ] || [ -L "$trusted_ci_requirements" ]; then
echo "::error::Trusted coverage requirements must be a regular non-symlink file."
exit 1
Expand All @@ -617,13 +654,19 @@ jobs:
echo "::error::Trusted base Python lock installer must be a regular non-symlink file."
exit 1
fi
if [ ! -f "$trusted_vcs_license_validator" ] || [ -L "$trusted_vcs_license_validator" ]; then
echo "::error::Trusted VCS dependency license validator must be a regular non-symlink file."
exit 1
fi
sudo rm -rf "$coverage_build_dir"
mkdir -p "$coverage_build_dir"
chmod 0700 "$coverage_build_dir"
install -m 0644 "$trusted_ci_requirements" \
"$coverage_build_dir/requirements-opencode-review-ci-hashes.txt"
install -m 0755 "$trusted_base_python_installer" \
"$coverage_build_dir/install-base-python-locks.py"
install -m 0755 "$trusted_vcs_license_validator" \
"$coverage_build_dir/validate-vcs-dependency-license.py"
python3 -I "$GITHUB_WORKSPACE/scripts/ci/materialize_base_python_requirements.py" \
--repo-root "$COVERAGE_SOURCE_WORKDIR" \
--base-sha "$PR_BASE_SHA" \
Expand Down Expand Up @@ -720,6 +763,7 @@ jobs:
-r /tmp/requirements-opencode-review-ci-hashes.txt \
&& rm -f /tmp/requirements-opencode-review-ci-hashes.txt
COPY base-python-requirements /tmp/base-python-requirements
COPY validate-vcs-dependency-license.py /usr/local/libexec/validate-vcs-dependency-license.py
RUN set -eu; \
mkdir -p /opt/base-vcs-dependencies; \
site_packages="$(python3 -c 'import site; print(site.getsitepackages()[0])')"; \
Expand All @@ -730,6 +774,10 @@ jobs:
jq -r '.[] | [.import_name, .repository, .commit] | @tsv' \
/tmp/base-python-requirements/vcs-manifest.json >"$dependency_list"; \
while IFS="$(printf '\t')" read -r import_name repository commit; do \
license_spdx="$(python3 -I /usr/local/libexec/validate-vcs-dependency-license.py \
--repository "$repository" --commit "$commit")"; \
printf 'Validated permitted VCS dependency license: repository=%s commit=%s SPDX=%s\n' \
"$repository" "$commit" "$license_spdx"; \
destination="$(printf '/opt/base-vcs-dependencies/dependency-%03d' "$dependency_index")"; \
git init --quiet "$destination"; \
git -C "$destination" remote add origin \
Expand Down Expand Up @@ -887,6 +935,11 @@ jobs:
: >"$GITHUB_OUTPUT"
chmod 0600 "$GITHUB_OUTPUT"
unset ACTIONS_ID_TOKEN_REQUEST_TOKEN ACTIONS_ID_TOKEN_REQUEST_URL ACTIONS_RUNTIME_TOKEN GH_TOKEN GITHUB_TOKEN
# Corepack may resolve a package-manager release from package.json.
# The validated base/head identity check below makes that selection
# immutable, and this keeps execution offline even if Corepack would
# otherwise attempt a download.
export COREPACK_ENABLE_NETWORK=0
umask 077
cd "$COVERAGE_SOURCE_WORKDIR"

Expand Down Expand Up @@ -1430,6 +1483,49 @@ jobs:
writable_npm_cache_dir="$destination"
}

trusted_pnpm_package_manager_matches_base() {
local relative_dir
local relative_manifest
local base_spec
local head_spec
local worktree_spec

case "$PWD" in
"$COVERAGE_SOURCE_WORKDIR")
relative_dir=""
;;
"$COVERAGE_SOURCE_WORKDIR"/*)
relative_dir="${PWD#"$COVERAGE_SOURCE_WORKDIR"/}"
;;
*)
echo "::error::pnpm project directory escaped the validated coverage worktree." >&2
return 1
;;
esac
relative_manifest="${relative_dir:+${relative_dir}/}package.json"
if [ ! -f package.json ] || [ -L package.json ]; then
echo "::error::Current pnpm package manifest must be a regular non-symlink file." >&2
return 1
fi

base_spec="$(trusted_git show "${PR_BASE_SHA}:${relative_manifest}" | jq -er '.packageManager // empty')" || {
echo "::error::Validated base does not declare an exact pnpm packageManager in ${relative_manifest}." >&2
return 1
}
head_spec="$(trusted_git show "${PR_HEAD_SHA}:${relative_manifest}" | jq -er '.packageManager // empty')" || {
echo "::error::Validated head does not declare an exact pnpm packageManager in ${relative_manifest}." >&2
return 1
}
worktree_spec="$(jq -er '.packageManager // empty' package.json)" || {
echo "::error::Current pnpm package manifest does not declare packageManager." >&2
return 1
}
if [ "$base_spec" != "$head_spec" ] || [ "$head_spec" != "$worktree_spec" ]; then
echo "::error::Current pnpm packageManager specification differs from the validated base; refusing Corepack version resolution." >&2
return 1
fi
}

trusted_pnpm_lock_matches_base() {
local relative_dir
local relative_lock
Expand Down Expand Up @@ -1557,6 +1653,7 @@ jobs:
fi
;;
pnpm)
trusted_pnpm_package_manager_matches_base
trusted_pnpm_lock_matches_base
prepare_writable_pnpm_store
if pnpm_supports_trust_lockfile; then
Expand Down Expand Up @@ -2322,7 +2419,7 @@ jobs:
! [[ "$EXPECTED_IS_PRIVATE" =~ ^(true|false)$ ]] ||
! [[ "$live_is_private" =~ ^(true|false)$ ]] ||
[ "$live_is_private" != "$EXPECTED_IS_PRIVATE" ]; then
printf '::error::OpenCode privileged review metadata changed before OIDC, review-token, CodeGraph, or model execution. target=%s#%s state=%s base_repo=%s base=%s/%s expected_base=%s/%s head_repo=%s head=%s/%s expected_head=%s/%s private=%s expected_private=%s\n' \
printf '::error::OpenCode privileged review metadata changed before OIDC, review-token, CodeGraph, or model execution; exact base/head identity no longer matches the validated request. target=%s#%s state=%s base_repo=%s base=%s/%s expected_base=%s/%s head_repo=%s head=%s/%s expected_head=%s/%s private=%s expected_private=%s\n' \
"$GH_REPOSITORY" "$PR_NUMBER" "${live_state:-<missing>}" "${base_repository:-<missing>}" "${live_base_ref:-<missing>}" "${live_base_sha:-<missing>}" "$EXPECTED_BASE_REF" "$EXPECTED_BASE_SHA" "${head_repository:-<missing>}" "${live_head_ref:-<missing>}" "${live_head_sha:-<missing>}" "$EXPECTED_HEAD_REF" "$EXPECTED_HEAD_SHA" "${live_is_private:-<missing>}" "${EXPECTED_IS_PRIVATE:-<missing>}"
exit 1
fi
Expand Down
56 changes: 53 additions & 3 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ concurrency:

permissions:
contents: read
pull-requests: read

jobs:
required-workflow-bootstrap:
Expand Down Expand Up @@ -53,7 +54,56 @@ jobs:
name: opencode-review
needs: [coverage-evidence]
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- run: >-
echo "Review approval remains a separate current-head PR review
requirement produced by the authenticated dispatch workflow."
- name: Fail closed without a current-head OpenCode verdict
env:
GH_TOKEN: ${{ github.token }}
TARGET_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
if [ "${{ github.event.action }}" = "closed" ]; then
echo "PR closed; a current-head OpenCode verdict is not required."
exit 0
fi
if [ -z "${PR_NUMBER:-}" ] || [ -z "${HEAD_SHA:-}" ]; then
echo "::error::Missing PR number or head SHA; cannot verify a current-head OpenCode verdict."
exit 1
fi
reviews="$(gh api --paginate "repos/${TARGET_REPOSITORY}/pulls/${PR_NUMBER}/reviews")"
verdict="$(printf '%s\n' "$reviews" | jq -r -s --arg sha "$HEAD_SHA" '
(add // [])
| [
.[]
| select(
(.user.login // "" | ascii_downcase) as $user
| $user == "opencode-agent" or $user == "opencode-agent[bot]"
)
| select((.commit_id // "" | ascii_downcase) == ($sha | ascii_downcase))
]
| (last // {}) as $review
| ($review.body // "" | ascii_downcase) as $body
| if $review.state == "CHANGES_REQUESTED" then
"CHANGES_REQUESTED"
elif $review.state == "APPROVED"
and ($body | contains("deterministic current-head evidence") | not)
and ($body | contains("deterministic fallback approval") | not)
and ($body | contains("model-unavailable evidence fallback") | not)
and ($body | contains("did not emit a usable current-head control block") | not)
and ($body | contains("scope: `unsupported`") | not)
and ($body | contains("model-pool outcome: `unknown`") | not)
then
"APPROVED"
else
empty
end
')"
Comment thread
seonghobae marked this conversation as resolved.
if [ -z "$verdict" ]; then
echo "::error::No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head. This required check is not a review and must not succeed until the authenticated dispatch posts a current-head verdict."
exit 1
fi
Comment thread
seonghobae marked this conversation as resolved.
echo "Current-head OpenCode verdict: ${verdict}."
Loading
Loading