Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4f8daef
fix: create workspace_entities/workspace_documents and provision Work…
claude Sep 1, 2026
31b400c
fix(data): serialize workspace provisioning
seonghobae Sep 1, 2026
37bcd6e
fix(data): bind documents to organization scope
seonghobae Sep 1, 2026
bfe347e
test: cover the workspace/organization collision in the quality surface
claude Sep 1, 2026
317c721
fix: guard 0016 against a genuinely missing workspace_documents table
claude Sep 1, 2026
e05f1b3
test(data): reproduce legacy document organization scope regression
seonghobae Sep 1, 2026
5054a8e
fix: trust legacy NULL-organization documents only for the owning org
claude Sep 1, 2026
6fe1de1
fix: reconcile emails/email_records fix with PR #1502
claude Sep 1, 2026
053c066
fix: guard 0011_email_read_state on column, not just table, existence
claude Sep 1, 2026
d3020ca
fix: make 0011_email_read_state's downgrade non-destructive
claude Sep 1, 2026
da2d7fe
fix: add forward migration repairing already-stamped is_read gap
claude Sep 1, 2026
2beaf0e
fix: preserve document scope migration data
seonghobae Sep 1, 2026
9c4e5ed
fix: create legacy index through SQLAlchemy
seonghobae Sep 1, 2026
9c18513
fix: explain intentional best-effort DB teardown swallow
claude Sep 1, 2026
b4cb934
ci: validate stacked pull request bases
seonghobae Sep 4, 2026
804b5e7
docs(governance): define stacked validation gate
seonghobae Sep 4, 2026
1ac1f82
fix(actions): activate locked pnpm before cache
seonghobae Sep 4, 2026
f209170
merge(stack): build trigger repair on governance owner
seonghobae Sep 4, 2026
9990a99
fix(test): install Starlette TestClient dependency
seonghobae Sep 4, 2026
3a4ec58
test(deps): verify Starlette client pin hashes
seonghobae Sep 4, 2026
948f1e3
test(actions): preserve Bandit rerun isolation in successor
seonghobae Sep 4, 2026
bfc87a3
fix(actions): preserve Bandit rerun isolation in stacked-base repair
seonghobae Sep 4, 2026
ac46035
test(actions): compose stacked-base and rerun concurrency contracts
seonghobae Sep 4, 2026
bc91b36
fix(actions): compose stacked-base and rerun concurrency identities
seonghobae Sep 4, 2026
52dfc86
test(deps): verify Starlette httpx2 runtime
seonghobae Sep 5, 2026
19d5860
fix(migrations): inherit locked TestClient prerequisite
seonghobae Sep 5, 2026
ef85817
fix: run migrated PostgreSQL evidence in Application CI
seonghobae Sep 6, 2026
e30aa0d
fix(deps): integrate patched js-yaml prerequisite
seonghobae Sep 6, 2026
4d2e4ab
Merge branch 'codex/js-yaml-4-3-1' of https://github.com/ContextualWi…
seonghobae Sep 6, 2026
30d8476
fix(ci): preserve isolation in migration subprocesses
seonghobae Sep 6, 2026
b2e98a5
fix(ci): separate signal probe startup observation
seonghobae Sep 6, 2026
1f538b1
fix(ci): retain cancellation during process registration
seonghobae Sep 6, 2026
b0d1bb6
merge: inherit multiline governance owner repair
seonghobae Sep 6, 2026
0648eac
fix(ci): inherit complete stale-notice governance repair
seonghobae Sep 6, 2026
938d4b1
merge: inherit complete review publisher and warning repair
seonghobae Sep 6, 2026
0ec1cf9
merge(ci): inherit clean-summary governance repair
seonghobae Sep 6, 2026
cdef603
merge(ci): inherit complete security prerequisite stack
seonghobae Sep 6, 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
6 changes: 4 additions & 2 deletions .github/workflows/app-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ permissions:
contents: read

concurrency:
group: application-ci-${{ github.event.pull_request.number || github.ref }}
group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
Expand Down Expand Up @@ -87,7 +87,9 @@ jobs:
persist-credentials: false

- name: Install pnpm
run: corepack enable pnpm
run: |
corepack enable pnpm
corepack install --global pnpm@11.5.3

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/bandit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name == 'pull_request' && github.run_attempt == 1 && github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' && github.run_attempt == 1 }}

jobs:
security:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Comment on lines +13 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Isolate non-supersedable Docker workflow runs

When a maintainer reruns this workflow from an older PR head while current-head image validation is running, both attempts share this PR-only group and the stale rerun cancels the required current-head run. Tag runs for the same ref also share one group, so cancel-in-progress: false still permits GitHub concurrency to replace an older pending publication, contrary to the documented non-cancellation contract. Mirror Bandit's first-attempt PR cancellation plus run_id isolation and cover Docker in backend/tests/test_workflow_concurrency.py.

AGENTS.md reference: AGENTS.md:L192-L192

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current head 1f538b1: the finding is valid, but copying Bandit's run_id suffix is not a complete repair.

  • docker-publish.yml:13-14 admits stale reruns to the same PR group before any live-head validation.
  • cancel-in-progress:false alone still replaces older pending work. Native queue:max now retains up to100 pending entries, but over-capacity runs are cancelled; it is not unbounded durable delivery.
  • docker-publish.yml:304-307 publishes a shared latest tag for every version. A per-ref or per-run group does not serialize different version publications to that shared target; a slower old release can overwrite the newer latest tag.
  • Application CI has the same pre-admission PR group boundary; Bandit's isolated reruns do not enforce the requested workflow-repository-PR ownership contract.

Repair must separate trusted current-head admission and PR validation cancellation from a shared-target release/deployment lock, exact-revision/idempotency checks and retained/recoverable release intent. Matrix components must not cancel sibling validations. Reuse the canonical .github owner contract rather than copying a local scheduler or appending arbitrary group suffixes. Do not waive this finding based on prior backend tests.

Reference: GitHub. (n.d.). Control the concurrency of workflows and jobs. https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency (accessed2026-09-06). No workflow, release, ruleset or PR-state mutation made by this diagnosis.


env:
REGISTRY: ghcr.io
# Keep the explicit opt-in as belt-and-suspenders. The real warning removal
Expand Down
35 changes: 35 additions & 0 deletions backend/tests/test_release_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,35 @@ def test_app_ci_runs_backend_and_frontend_checks_without_duplicate_release_pushe
assert "branches-ignore:" not in pull_request_block


@pytest.mark.parametrize(
"workflow_path",
[
".github/workflows/app-ci.yml",
".github/workflows/bandit.yml",
".github/workflows/docker-publish.yml",
],
)
def test_pr_validation_workflows_run_for_stacked_base_branches(
workflow_path: str,
) -> None:
workflow_text = read_repo_text(workflow_path)
workflow = yaml.load(workflow_text, Loader=yaml.BaseLoader)

assert workflow["on"]["pull_request"] in (None, "")
Comment thread
seonghobae marked this conversation as resolved.
assert (
"group: ${{ github.workflow }}-${{ github.repository }}-"
"${{ github.event.pull_request.number || github.ref }}"
) in workflow_text


def test_merge_gate_policy_documents_stacked_base_validation() -> None:
policy = read_repo_text("docs/development/merge-gate-policy.md")

assert "run on every pull\n request base, including stacked branches" in policy
assert "direct push checks for `develop` and `master`" in policy
assert "tag publication is never cancelled" in policy


def test_docker_publish_validates_pr_images_and_publishes_semver_images_only_on_tags() -> (
None
):
Expand All @@ -681,6 +710,7 @@ def test_docker_publish_validates_pr_images_and_publishes_semver_images_only_on_
assert "pull_request:" in workflow
assert "push:" in workflow
assert "FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true" in workflow
assert "cancel-in-progress: ${{ github.event_name == 'pull_request' }}" in workflow
assert (
workflow.count(
"docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0"
Expand Down Expand Up @@ -750,8 +780,13 @@ def test_frontend_dockerfile_builds_and_starts_production_artifact() -> None:
docker_publish_workflow = read_repo_text(".github/workflows/docker-publish.yml")
frontend_deployment = read_repo_text("k8s/frontend-deployment.yaml")
package_json = read_repo_text("frontend/package.json")
app_ci_workflow = read_repo_text(".github/workflows/app-ci.yml")

assert '"packageManager": "pnpm@11.5.3"' in package_json
assert "corepack install --global pnpm@11.5.3" in app_ci_workflow
assert app_ci_workflow.index("corepack install --global pnpm@11.5.3") < (
app_ci_workflow.index("cache: pnpm")
)
assert "NEXT_PUBLIC_API_URL" not in root_dockerfile
assert "NEXT_PUBLIC_API_URL" not in dockerfile
assert "NEXT_PUBLIC_API_URL" not in docker_publish_workflow
Expand Down
31 changes: 31 additions & 0 deletions backend/tests/test_workflow_concurrency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Regression tests for GitHub Actions concurrency boundaries."""

from __future__ import annotations

from pathlib import Path

import yaml


REPO_ROOT = Path(__file__).resolve().parents[2]


def _load_workflow(workflow_name: str) -> dict[str, object]:
path = REPO_ROOT / ".github" / "workflows" / workflow_name
assert path.exists(), f"workflow is missing: {workflow_name}"
parsed = yaml.safe_load(path.read_text(encoding="utf-8"))
assert isinstance(parsed, dict), (
f"workflow must parse as a mapping: {workflow_name}"
)
return parsed


def test_bandit_cancels_only_superseded_pull_request_runs() -> None:
"""Keep manual, push, and rerun scans independent while deduplicating first PR scans."""
concurrency = _load_workflow("bandit.yml").get("concurrency")

assert isinstance(concurrency, dict)
assert concurrency == {
"group": "${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name == 'pull_request' && github.run_attempt == 1 && github.event.pull_request.number || github.run_id }}",
"cancel-in-progress": "${{ github.event_name == 'pull_request' && github.run_attempt == 1 }}",
}
9 changes: 5 additions & 4 deletions docs/development/merge-gate-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ awaited by default.
## Required gate contract

- Required status checks must pass on the current head SHA.
- Application CI must run backend pytest and frontend test/lint/build checks on
every pull request, including one stacked on another open PR's branch, not
just `develop`/`master`/`release/**` — required checks must not exclude a PR
base; push checks are scoped to `develop` and `master`.
- Application CI, Bandit, and pull-request image validation run on every pull
request base, including stacked branches. Application CI and Bandit retain
direct push checks for `develop` and `master`; image publication remains
tag-only for `v*`. Validation concurrency is scoped by workflow, repository,
and PR, while tag publication is never cancelled by a newer run.
- The robot-review gate prefers CodeRabbit evidence. When the current head has
CodeRabbit check-run evidence, it satisfies the gate only when current-head
blocking findings, warnings, and failures are fixed, rebutted with evidence,
Expand Down
Loading