From 01acf89d3e7d4b3d4227b308ab5af336f2174f49 Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 20:53:21 -0400 Subject: [PATCH 1/7] fix(workflows): replace relative reusable paths with full org/repo refs GitHub Actions does not support the ./ relative path syntax for reusable workflows in subdirectories. Replaced all uses of ./.github/workflows/reusable/*.yml with the full YiAgent/OpenCI/.github/workflows/reusable/*.yml@SHA format, which supports subdirectory paths and is valid per GitHub docs. This fixes the broken workflow names (showing file paths instead of name: field values) and the workflow dispatch failures. --- .github/workflows/agent.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/dependencies.yml | 2 +- .github/workflows/deploy.yml | 4 ++-- .github/workflows/docs.yml | 2 +- .github/workflows/issue-ops.yml | 8 ++++---- .github/workflows/observability.yml | 6 +++--- .github/workflows/on-maintenance.yml | 2 +- .github/workflows/pull-request.yml | 2 +- .github/workflows/release.yml | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index b016fba..f64eb7d 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -40,7 +40,7 @@ concurrency: jobs: agent: - uses: ./.github/workflows/reusable/agent.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/agent.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: task: ${{ inputs.task }} prompt: ${{ inputs.prompt }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cec423a..86cd14b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ concurrency: jobs: ci: - uses: ./.github/workflows/reusable/ci.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/ci.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ github.sha }} registry: ghcr.io diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 6fe5c6e..57dd8b1 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -15,6 +15,6 @@ concurrency: jobs: deps: - uses: ./.github/workflows/reusable/deps.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/deps.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a9062a3..614560c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: && github.event.workflow_run.name == 'ci' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'stg') - uses: ./.github/workflows/reusable/stg.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/stg.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} @@ -54,7 +54,7 @@ jobs: && github.event.workflow_run.name == 'release' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'prd') - uses: ./.github/workflows/reusable/prd.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/prd.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 73f16cd..a5d70a0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,7 +22,7 @@ concurrency: jobs: docs: - uses: ./.github/workflows/reusable/docs.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/docs.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: build-cmd: ${{ vars.DOCS_BUILD_CMD || '' }} docs-path: ${{ vars.DOCS_DIR || 'docs' }} diff --git a/.github/workflows/issue-ops.yml b/.github/workflows/issue-ops.yml index 9d12156..94eaab5 100644 --- a/.github/workflows/issue-ops.yml +++ b/.github/workflows/issue-ops.yml @@ -32,7 +32,7 @@ concurrency: jobs: lifecycle: if: github.event_name == 'issues' || github.event_name == 'issue_comment' - uses: ./.github/workflows/reusable/issue.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: lifecycle runner: blacksmith-32vcpu-ubuntu-2404 @@ -46,7 +46,7 @@ jobs: ingest: if: github.event_name == 'repository_dispatch' - uses: ./.github/workflows/reusable/issue.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ingest runner: blacksmith-32vcpu-ubuntu-2404 @@ -60,7 +60,7 @@ jobs: maintenance: if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'maintenance') - uses: ./.github/workflows/reusable/issue.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: maintenance runner: blacksmith-32vcpu-ubuntu-2404 @@ -74,7 +74,7 @@ jobs: manual: if: github.event_name == 'workflow_dispatch' && inputs.mode != 'maintenance' - uses: ./.github/workflows/reusable/issue.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ inputs.mode }} runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/observability.yml b/.github/workflows/observability.yml index c3b987f..8b61485 100644 --- a/.github/workflows/observability.yml +++ b/.github/workflows/observability.yml @@ -30,7 +30,7 @@ concurrency: jobs: observe-canary: if: ${{ github.event_name == 'schedule' && github.event.schedule == '*/15 * * * *' }} - uses: ./.github/workflows/reusable/observability.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: canary-watch runner: blacksmith-32vcpu-ubuntu-2404 @@ -38,7 +38,7 @@ jobs: observe-drift: if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 4 * * *' }} - uses: ./.github/workflows/reusable/observability.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: terraform-drift infra-dir: ${{ vars.INFRA_DIR || 'infrastructure' }} @@ -50,7 +50,7 @@ jobs: (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || github.event_name == 'repository_dispatch' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'verify-fix') - uses: ./.github/workflows/reusable/observability.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: verify-fix runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/on-maintenance.yml b/.github/workflows/on-maintenance.yml index fed01ff..76a3e8d 100644 --- a/.github/workflows/on-maintenance.yml +++ b/.github/workflows/on-maintenance.yml @@ -115,7 +115,7 @@ jobs: if: | !contains(fromJSON('["pr-review","flag-audit"]'), needs.resolve-mode.outputs.mode) - uses: ./.github/workflows/reusable/maintenance.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/maintenance.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ needs.resolve-mode.outputs.mode }} openci-ref: ${{ needs.resolve-mode.outputs.openci-ref }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index e6d26d4..ea2004e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -28,7 +28,7 @@ concurrency: jobs: checks: - uses: ./.github/workflows/reusable/pr.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/pr.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: enable-ai-review: true enable-eval: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 75bc1b9..1986939 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ concurrency: jobs: release: - uses: ./.github/workflows/reusable/release.yml + uses: YiAgent/OpenCI/.github/workflows/reusable/release.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ inputs.mode || 'both' }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} From 8b21871c00c8a0094b671d9eda74dc1be8a3154c Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 20:56:05 -0400 Subject: [PATCH 2/7] fix(workflows): use manifest SHA and update routing tests Switch from HEAD SHA to manifest-pinned SHA d280a64 for all YiAgent/OpenCI reusable workflow references, matching the verify-sha hook requirement. Also update two BATS tests that asserted the old ./ relative path pattern, and suppress a SC2016 false positive where $ is intentional grep BRE syntax. --- .github/workflows/agent.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/dependencies.yml | 2 +- .github/workflows/deploy.yml | 4 ++-- .github/workflows/docs.yml | 2 +- .github/workflows/issue-ops.yml | 8 ++++---- .github/workflows/observability.yml | 6 +++--- .github/workflows/on-maintenance.yml | 2 +- .github/workflows/pull-request.yml | 2 +- .github/workflows/release.yml | 2 +- tests/actions/on-issue-routing.bats | 3 ++- tests/actions/on-pr-routing.bats | 2 +- 12 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index f64eb7d..723c0e7 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -40,7 +40,7 @@ concurrency: jobs: agent: - uses: YiAgent/OpenCI/.github/workflows/reusable/agent.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/agent.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: task: ${{ inputs.task }} prompt: ${{ inputs.prompt }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86cd14b..1462a3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ concurrency: jobs: ci: - uses: YiAgent/OpenCI/.github/workflows/reusable/ci.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/ci.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: openci-ref: ${{ github.sha }} registry: ghcr.io diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 57dd8b1..482fe6b 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -15,6 +15,6 @@ concurrency: jobs: deps: - uses: YiAgent/OpenCI/.github/workflows/reusable/deps.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/deps.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 614560c..5e59260 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: && github.event.workflow_run.name == 'ci' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'stg') - uses: YiAgent/OpenCI/.github/workflows/reusable/stg.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/stg.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} @@ -54,7 +54,7 @@ jobs: && github.event.workflow_run.name == 'release' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'prd') - uses: YiAgent/OpenCI/.github/workflows/reusable/prd.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/prd.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a5d70a0..72e859c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,7 +22,7 @@ concurrency: jobs: docs: - uses: YiAgent/OpenCI/.github/workflows/reusable/docs.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/docs.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: build-cmd: ${{ vars.DOCS_BUILD_CMD || '' }} docs-path: ${{ vars.DOCS_DIR || 'docs' }} diff --git a/.github/workflows/issue-ops.yml b/.github/workflows/issue-ops.yml index 94eaab5..66e448d 100644 --- a/.github/workflows/issue-ops.yml +++ b/.github/workflows/issue-ops.yml @@ -32,7 +32,7 @@ concurrency: jobs: lifecycle: if: github.event_name == 'issues' || github.event_name == 'issue_comment' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: lifecycle runner: blacksmith-32vcpu-ubuntu-2404 @@ -46,7 +46,7 @@ jobs: ingest: if: github.event_name == 'repository_dispatch' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: ingest runner: blacksmith-32vcpu-ubuntu-2404 @@ -60,7 +60,7 @@ jobs: maintenance: if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'maintenance') - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: maintenance runner: blacksmith-32vcpu-ubuntu-2404 @@ -74,7 +74,7 @@ jobs: manual: if: github.event_name == 'workflow_dispatch' && inputs.mode != 'maintenance' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: ${{ inputs.mode }} runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/observability.yml b/.github/workflows/observability.yml index 8b61485..2e6dc0b 100644 --- a/.github/workflows/observability.yml +++ b/.github/workflows/observability.yml @@ -30,7 +30,7 @@ concurrency: jobs: observe-canary: if: ${{ github.event_name == 'schedule' && github.event.schedule == '*/15 * * * *' }} - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: canary-watch runner: blacksmith-32vcpu-ubuntu-2404 @@ -38,7 +38,7 @@ jobs: observe-drift: if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 4 * * *' }} - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: terraform-drift infra-dir: ${{ vars.INFRA_DIR || 'infrastructure' }} @@ -50,7 +50,7 @@ jobs: (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || github.event_name == 'repository_dispatch' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'verify-fix') - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: verify-fix runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/on-maintenance.yml b/.github/workflows/on-maintenance.yml index 76a3e8d..d363da2 100644 --- a/.github/workflows/on-maintenance.yml +++ b/.github/workflows/on-maintenance.yml @@ -115,7 +115,7 @@ jobs: if: | !contains(fromJSON('["pr-review","flag-audit"]'), needs.resolve-mode.outputs.mode) - uses: YiAgent/OpenCI/.github/workflows/reusable/maintenance.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/maintenance.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: ${{ needs.resolve-mode.outputs.mode }} openci-ref: ${{ needs.resolve-mode.outputs.openci-ref }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index ea2004e..90fc0ab 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -28,7 +28,7 @@ concurrency: jobs: checks: - uses: YiAgent/OpenCI/.github/workflows/reusable/pr.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/pr.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: enable-ai-review: true enable-eval: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1986939..5be3dab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ concurrency: jobs: release: - uses: YiAgent/OpenCI/.github/workflows/reusable/release.yml@ebe8fca3260dce68d34d51b74703169e776bc72d + uses: YiAgent/OpenCI/.github/workflows/reusable/release.yml@d280a64a392b7f1a3e906246286ca983e610f920 with: mode: ${{ inputs.mode || 'both' }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} diff --git a/tests/actions/on-issue-routing.bats b/tests/actions/on-issue-routing.bats index b6e5b1a..bb0c145 100644 --- a/tests/actions/on-issue-routing.bats +++ b/tests/actions/on-issue-routing.bats @@ -88,6 +88,7 @@ setup() { } @test "manual job passes the dispatch input mode dynamically" { + # shellcheck disable=SC2016 # \$ is for grep BRE, not shell expansion grep -q 'mode: \${{ inputs.mode }}' "$ENTRY" } @@ -97,7 +98,7 @@ setup() { @test "all four jobs call the same reusable workflow reusable/issue.yml" { local count - count=$(grep -c 'uses: \.\/\.github\/workflows\/reusable\/issue\.yml' "$ENTRY") + count=$(grep -c 'uses: YiAgent/OpenCI/.github/workflows/reusable/issue\.yml' "$ENTRY") [ "$count" -eq 4 ] } diff --git a/tests/actions/on-pr-routing.bats b/tests/actions/on-pr-routing.bats index 8454a74..3e77222 100644 --- a/tests/actions/on-pr-routing.bats +++ b/tests/actions/on-pr-routing.bats @@ -41,7 +41,7 @@ setup() { # --------------------------------------------------------------------------- @test "single checks job calls reusable pr.yml workflow" { - grep -q 'uses: \.\/\.github\/workflows\/reusable\/pr\.yml' "$ENTRY" + grep -q 'uses: YiAgent/OpenCI/.github/workflows/reusable/pr\.yml' "$ENTRY" } @test "checks job enables AI review" { From 7794e59d20255904c0bb265bb67f3be9828a10e8 Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 22:30:44 -0400 Subject: [PATCH 3/7] fix(workflows): update pinned SHA to commit with reusable/ directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SHA d280a64 predates the reusable/ subdirectory reorganization — at that commit the directory does not exist, causing GitHub Actions to fail with "workflow file issue" before any job starts. Updated all 24 references and manifest.yml to ebe8fca which is the first main-branch commit confirmed to contain .github/workflows/reusable/*.yml. --- .github/workflows/agent.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/dependencies.yml | 2 +- .github/workflows/deploy.yml | 4 ++-- .github/workflows/docs.yml | 2 +- .github/workflows/issue-ops.yml | 8 ++++---- .github/workflows/observability.yml | 6 +++--- .github/workflows/on-maintenance.yml | 2 +- .github/workflows/pull-request.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/reusable/ci.yml | 16 ++++++++-------- manifest.yml | 2 +- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index 723c0e7..f64eb7d 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -40,7 +40,7 @@ concurrency: jobs: agent: - uses: YiAgent/OpenCI/.github/workflows/reusable/agent.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/agent.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: task: ${{ inputs.task }} prompt: ${{ inputs.prompt }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1462a3a..86cd14b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ concurrency: jobs: ci: - uses: YiAgent/OpenCI/.github/workflows/reusable/ci.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/ci.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ github.sha }} registry: ghcr.io diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 482fe6b..57dd8b1 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -15,6 +15,6 @@ concurrency: jobs: deps: - uses: YiAgent/OpenCI/.github/workflows/reusable/deps.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/deps.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5e59260..614560c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: && github.event.workflow_run.name == 'ci' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'stg') - uses: YiAgent/OpenCI/.github/workflows/reusable/stg.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/stg.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} @@ -54,7 +54,7 @@ jobs: && github.event.workflow_run.name == 'release' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'prd') - uses: YiAgent/OpenCI/.github/workflows/reusable/prd.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/prd.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: app-name: ${{ vars.APP_NAME || github.event.repository.name }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 72e859c..a5d70a0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,7 +22,7 @@ concurrency: jobs: docs: - uses: YiAgent/OpenCI/.github/workflows/reusable/docs.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/docs.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: build-cmd: ${{ vars.DOCS_BUILD_CMD || '' }} docs-path: ${{ vars.DOCS_DIR || 'docs' }} diff --git a/.github/workflows/issue-ops.yml b/.github/workflows/issue-ops.yml index 66e448d..94eaab5 100644 --- a/.github/workflows/issue-ops.yml +++ b/.github/workflows/issue-ops.yml @@ -32,7 +32,7 @@ concurrency: jobs: lifecycle: if: github.event_name == 'issues' || github.event_name == 'issue_comment' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: lifecycle runner: blacksmith-32vcpu-ubuntu-2404 @@ -46,7 +46,7 @@ jobs: ingest: if: github.event_name == 'repository_dispatch' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ingest runner: blacksmith-32vcpu-ubuntu-2404 @@ -60,7 +60,7 @@ jobs: maintenance: if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'maintenance') - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: maintenance runner: blacksmith-32vcpu-ubuntu-2404 @@ -74,7 +74,7 @@ jobs: manual: if: github.event_name == 'workflow_dispatch' && inputs.mode != 'maintenance' - uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/issue.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ inputs.mode }} runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/observability.yml b/.github/workflows/observability.yml index 2e6dc0b..8b61485 100644 --- a/.github/workflows/observability.yml +++ b/.github/workflows/observability.yml @@ -30,7 +30,7 @@ concurrency: jobs: observe-canary: if: ${{ github.event_name == 'schedule' && github.event.schedule == '*/15 * * * *' }} - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: canary-watch runner: blacksmith-32vcpu-ubuntu-2404 @@ -38,7 +38,7 @@ jobs: observe-drift: if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 4 * * *' }} - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: terraform-drift infra-dir: ${{ vars.INFRA_DIR || 'infrastructure' }} @@ -50,7 +50,7 @@ jobs: (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || github.event_name == 'repository_dispatch' || (github.event_name == 'workflow_dispatch' && inputs.mode == 'verify-fix') - uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/observability.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: verify-fix runner: blacksmith-32vcpu-ubuntu-2404 diff --git a/.github/workflows/on-maintenance.yml b/.github/workflows/on-maintenance.yml index d363da2..76a3e8d 100644 --- a/.github/workflows/on-maintenance.yml +++ b/.github/workflows/on-maintenance.yml @@ -115,7 +115,7 @@ jobs: if: | !contains(fromJSON('["pr-review","flag-audit"]'), needs.resolve-mode.outputs.mode) - uses: YiAgent/OpenCI/.github/workflows/reusable/maintenance.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/maintenance.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ needs.resolve-mode.outputs.mode }} openci-ref: ${{ needs.resolve-mode.outputs.openci-ref }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 90fc0ab..ea2004e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -28,7 +28,7 @@ concurrency: jobs: checks: - uses: YiAgent/OpenCI/.github/workflows/reusable/pr.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/pr.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: enable-ai-review: true enable-eval: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5be3dab..1986939 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ concurrency: jobs: release: - uses: YiAgent/OpenCI/.github/workflows/reusable/release.yml@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/.github/workflows/reusable/release.yml@ebe8fca3260dce68d34d51b74703169e776bc72d with: mode: ${{ inputs.mode || 'both' }} image-name: ${{ vars.IMAGE_NAME || github.event.repository.name }} diff --git a/.github/workflows/reusable/ci.yml b/.github/workflows/reusable/ci.yml index e4456e5..e19d51f 100644 --- a/.github/workflows/reusable/ci.yml +++ b/.github/workflows/reusable/ci.yml @@ -127,7 +127,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - name: Probe secrets @@ -155,7 +155,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - id: detect @@ -183,7 +183,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - id: build @@ -212,7 +212,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - id: scan @@ -235,7 +235,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 @@ -282,7 +282,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - uses: ./.openci/actions/ci/check-migration @@ -305,7 +305,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - uses: ./.openci/actions/ci/eval-smoke @@ -485,7 +485,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: { persist-credentials: false } - name: Resolve OpenCI ref and checkout - uses: YiAgent/OpenCI/actions/_common/resolve-openci@d280a64a392b7f1a3e906246286ca983e610f920 + uses: YiAgent/OpenCI/actions/_common/resolve-openci@ebe8fca3260dce68d34d51b74703169e776bc72d with: openci-ref: ${{ inputs.openci-ref }} - name: Download ci-context artifact diff --git a/manifest.yml b/manifest.yml index 0bb9831..4282d10 100644 --- a/manifest.yml +++ b/manifest.yml @@ -101,7 +101,7 @@ deps: softprops/action-gh-release: "b4309332981a82ec1c5618f44dd2e27cc8bfbfda" # v3.0.0 # ── Self (OpenCI vendoring itself via remote action reference) ────────── - YiAgent/OpenCI: "d280a64a392b7f1a3e906246286ca983e610f920" # resolve-openci bootstrap + YiAgent/OpenCI: "ebe8fca3260dce68d34d51b74703169e776bc72d" # resolve-openci bootstrap # ───────────────────────────────────────────────────────────────────────────── # Reusable workflow catalog (consumed via `uses: YiAgent/OpenCI/.github/workflows/.yml@`) From c3418e4b24e681092ac4200e309788f5b95aa78b Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 22:38:45 -0400 Subject: [PATCH 4/7] feat(tooling): add structural SHA validation and bump-self-sha script Two changes to prevent the "SHA predates reusable/ directory" class of failures from reaching CI: 1. verify-sha-consistency.sh: after the existing consistency check, verify that any self-referencing entry (currently YiAgent/OpenCI) actually has the required directory (.github/workflows/reusable/) at the pinned SHA. Error message explicitly points to bump-self-sha.sh. 2. scripts/bump-self-sha.sh: automates the SHA update workflow. Fetches the latest main-branch HEAD, walks back until a commit with reusable/ is found, then atomically updates manifest.yml and all workflow files. Supports --dry-run for preview. Usage: bash scripts/bump-self-sha.sh --- .github/scripts/verify-sha-consistency.sh | 23 +++++ scripts/bump-self-sha.sh | 115 ++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100755 scripts/bump-self-sha.sh diff --git a/.github/scripts/verify-sha-consistency.sh b/.github/scripts/verify-sha-consistency.sh index 87a436d..4c9e4f2 100755 --- a/.github/scripts/verify-sha-consistency.sh +++ b/.github/scripts/verify-sha-consistency.sh @@ -28,6 +28,11 @@ REPO_ROOT="${REPO_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}" MANIFEST="${MANIFEST:-$REPO_ROOT/manifest.yml}" PENDING="${PENDING:-$REPO_ROOT/manifest-pending.yml}" +# Self-referencing entries that need structural validation beyond SHA consistency. +# Each entry maps to the required path that must exist at the pinned SHA. +declare -A SELF_REFS +SELF_REFS["YiAgent/OpenCI"]=".github/workflows/reusable" + # SPEC Appendix B.2 — deprecated actions. Keep in sync with docs/SPEC.md. DEPRECATED_ACTIONS=( "semgrep/semgrep-action" @@ -205,6 +210,24 @@ main() { fi done < <(collect_uses) + # ── Structural validation for self-referencing entries ────────────────────── + # Checks that the pinned SHA actually contains the required directory. + # Catches the "SHA predates reusable/ reorganization" class of failures + # before they reach CI (where they manifest as silent "workflow file issue"). + local self_name self_required_path self_sha tree_output + for self_name in "${!SELF_REFS[@]}"; do + self_required_path="${SELF_REFS[$self_name]}" + self_sha="$(echo "$manifest_map" | awk -F'\t' -v key="$self_name" '$1 == key { print $2; exit }')" + [ -z "$self_sha" ] && continue + + # git ls-tree returns non-empty output when the path exists at that SHA. + tree_output="$(git ls-tree "$self_sha" "$self_required_path/" 2>/dev/null || true)" + if [ -z "$tree_output" ]; then + emit_error "SHA Missing Structure" \ + "manifest.yml: $self_name SHA $self_sha has no '$self_required_path/' directory. Run scripts/bump-self-sha.sh to update to a valid commit." + fi + done + emit_notice "verify-sha-consistency" "Checked $checked uses, $errors error(s)." if [ "$errors" -gt 0 ]; then diff --git a/scripts/bump-self-sha.sh b/scripts/bump-self-sha.sh new file mode 100755 index 0000000..f869d35 --- /dev/null +++ b/scripts/bump-self-sha.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# ───────────────────────────────────────────────────────────────────────────── +# bump-self-sha.sh — Update the YiAgent/OpenCI self-reference SHA. +# ───────────────────────────────────────────────────────────────────────────── +# Finds the latest commit on the main branch that contains +# .github/workflows/reusable/, then writes it to manifest.yml and all +# workflow files that reference YiAgent/OpenCI. +# +# Usage: +# bash scripts/bump-self-sha.sh # update in-place +# bash scripts/bump-self-sha.sh --dry-run # print new SHA, make no changes +# +# Requirements: git (fetch access to origin), yq, sed +# ───────────────────────────────────────────────────────────────────────────── +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +MANIFEST="$REPO_ROOT/manifest.yml" +REQUIRED_PATH=".github/workflows/reusable" +REMOTE="${REMOTE:-origin}" +BASE_BRANCH="${BASE_BRANCH:-main}" +DRY_RUN=false + +for arg in "$@"; do + [ "$arg" = "--dry-run" ] && DRY_RUN=true +done + +die() { echo "::error::$*" >&2; exit 1; } +info() { echo " $*"; } + +# ── 1. Resolve the latest remote SHA for BASE_BRANCH ───────────────────────── + +info "Fetching $REMOTE/$BASE_BRANCH ..." +git fetch --quiet "$REMOTE" "$BASE_BRANCH" 2>/dev/null || \ + die "Cannot fetch $REMOTE/$BASE_BRANCH. Check your remote and network access." + +remote_sha="$(git rev-parse "refs/remotes/$REMOTE/$BASE_BRANCH" 2>/dev/null)" || \ + die "Could not resolve $REMOTE/$BASE_BRANCH after fetch." + +info "Remote HEAD: $remote_sha" + +# ── 2. Walk back until we find a commit that has the required directory ─────── + +candidate="$remote_sha" +max_walk=20 +walked=0 + +while true; do + tree_output="$(git ls-tree "$candidate" "$REQUIRED_PATH/" 2>/dev/null || true)" + if [ -n "$tree_output" ]; then + break + fi + walked=$((walked + 1)) + if [ "$walked" -ge "$max_walk" ]; then + die "Walked $max_walk commits back from $remote_sha without finding '$REQUIRED_PATH/'. Is the path correct?" + fi + # Step to parent. + candidate="$(git rev-parse "${candidate}^" 2>/dev/null)" || \ + die "Ran out of history before finding '$REQUIRED_PATH/'." +done + +if [ "$walked" -gt 0 ]; then + echo "::warning::Remote HEAD ($remote_sha) is missing '$REQUIRED_PATH/'. Using ancestor $candidate instead (walked $walked commits back)." +fi + +new_sha="$candidate" + +# ── 3. Read current SHA from manifest.yml ──────────────────────────────────── + +if ! command -v yq >/dev/null 2>&1; then + die "yq is required (brew install yq / apt install yq)" +fi + +old_sha="$(yq -r '.deps["YiAgent/OpenCI"] // ""' "$MANIFEST")" + +if [ "$old_sha" = "$new_sha" ]; then + echo "manifest.yml already at $new_sha — nothing to do." + exit 0 +fi + +echo "" +echo " old SHA: ${old_sha:-}" +echo " new SHA: $new_sha" +echo "" + +if [ "$DRY_RUN" = true ]; then + echo "[dry-run] Would update manifest.yml and all workflow files." + echo "[dry-run] Run without --dry-run to apply." + exit 0 +fi + +# ── 4. Update manifest.yml ──────────────────────────────────────────────────── + +if [ -z "$old_sha" ]; then + die "YiAgent/OpenCI not found in manifest.yml .deps — add it manually first." +fi + +sed -i'' -e "s|${old_sha}|${new_sha}|g" "$MANIFEST" +info "Updated manifest.yml" + +# ── 5. Update all workflow files that reference the old SHA ────────────────── + +updated=0 +while IFS= read -r -d '' f; do + if grep -q "$old_sha" "$f" 2>/dev/null; then + sed -i'' -e "s|${old_sha}|${new_sha}|g" "$f" + info "Updated $f" + updated=$((updated + 1)) + fi +done < <(find "$REPO_ROOT/.github/workflows" "$REPO_ROOT/actions" \ + -name "*.yml" -o -name "*.yaml" 2>/dev/null | tr '\n' '\0') + +echo "" +echo "Done. Updated manifest.yml + $updated workflow file(s) to $new_sha" +echo "Stage and commit: git add manifest.yml .github/workflows && git commit -m 'chore(manifest): bump YiAgent/OpenCI SHA to $new_sha'" From 743933524ecdb54b262b97eb78e62968e2267f67 Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 22:48:02 -0400 Subject: [PATCH 5/7] feat(ci): add SHA validation to PR gate and auto-bump post-merge Two additions to prevent the "SHA predates reusable/ directory" class of failures from ever reaching main: 1. reusable/pr.yml: new verify-sha job (needs: preflight) that runs verify-sha-consistency.sh on every PR. The enrich/Stage-2 gate now depends on it, so a bad SHA blocks the merge button. 2. on-main-bump-sha.yml: post-merge workflow that fires on every push to main. Checks whether the YiAgent/OpenCI SHA in manifest.yml is current and structurally valid; if not, runs bump-self-sha.sh and opens an auto-PR so the manifest never drifts out of sync without human action. --- .github/workflows/on-main-bump-sha.yml | 98 ++++++++++++++++++++++++++ .github/workflows/reusable/pr.yml | 28 +++++++- 2 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/on-main-bump-sha.yml diff --git a/.github/workflows/on-main-bump-sha.yml b/.github/workflows/on-main-bump-sha.yml new file mode 100644 index 0000000..354be72 --- /dev/null +++ b/.github/workflows/on-main-bump-sha.yml @@ -0,0 +1,98 @@ +# on-main-bump-sha.yml — Auto-bump the YiAgent/OpenCI self-reference SHA after +# every merge to main. Opens a follow-up PR when the SHA needs updating so the +# manifest never drifts out of sync. +# +# Why: the pinned SHA must point to a commit that contains +# .github/workflows/reusable/. After structural reorganizations (or simply +# as main moves forward) the SHA can become stale. This workflow detects +# that condition and creates a one-commit PR to fix it automatically. +name: Auto-bump self SHA + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + bump: + name: Bump YiAgent/OpenCI SHA if stale + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 + with: { egress-policy: audit } + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + fetch-depth: 0 + persist-credentials: true + + - name: Install yq + run: | + sudo wget -qO /usr/local/bin/yq \ + https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + + - name: Check if SHA needs bumping + id: check + run: | + current_sha="$(yq -r '.deps["YiAgent/OpenCI"] // ""' manifest.yml)" + head_sha="$(git rev-parse HEAD)" + + if [ -z "$current_sha" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "::notice::YiAgent/OpenCI not in manifest.yml — skipping" + exit 0 + fi + + tree_out="$(git ls-tree "$current_sha" .github/workflows/reusable/ 2>/dev/null || true)" + if [ -n "$tree_out" ] && [ "$current_sha" = "$head_sha" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "::notice::SHA $current_sha is current and valid — nothing to do" + exit 0 + fi + + { + echo "skip=false" + echo "current_sha=$current_sha" + echo "new_sha=$head_sha" + } >> "$GITHUB_OUTPUT" + + - name: Run bump-self-sha.sh + if: steps.check.outputs.skip != 'true' + run: bash scripts/bump-self-sha.sh + + - name: Commit and open PR + if: steps.check.outputs.skip != 'true' + env: + GH_TOKEN: ${{ github.token }} + NEW_SHA: ${{ steps.check.outputs.new_sha }} + OLD_SHA: ${{ steps.check.outputs.current_sha }} + run: | + branch="chore/bump-self-sha-${NEW_SHA:0:8}" + short_old="${OLD_SHA:0:8}" + short_new="${NEW_SHA:0:8}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$branch" + git add manifest.yml .github/workflows/ + git commit -m "chore(manifest): bump YiAgent/OpenCI SHA to ${short_new}" \ + -m "Automated update from on-main-bump-sha workflow. old=${OLD_SHA} new=${NEW_SHA}" + + git push origin "$branch" + + # shellcheck disable=SC2016 + printf 'Automated SHA bump: `%s` to `%s`\n\nThe YiAgent/OpenCI self-reference SHA in manifest.yml was stale. Updated to the latest main HEAD so all reusable workflow calls resolve correctly.\n\n> Generated by the on-main-bump-sha workflow.' \ + "$short_old" "$short_new" > /tmp/pr-body.md + + gh pr create \ + --title "chore(manifest): bump YiAgent/OpenCI SHA to ${short_new}" \ + --body-file /tmp/pr-body.md \ + --base main \ + --head "$branch" \ + --label "chore" 2>/dev/null || true diff --git a/.github/workflows/reusable/pr.yml b/.github/workflows/reusable/pr.yml index c45af03..b9d7044 100644 --- a/.github/workflows/reusable/pr.yml +++ b/.github/workflows/reusable/pr.yml @@ -348,10 +348,33 @@ jobs: with: sonar-token: ${{ secrets.sonar-token }} + verify-sha: + name: Verify SHA Consistency + needs: preflight + runs-on: ${{ inputs.runner }} + timeout-minutes: 5 + permissions: + contents: read + steps: + - uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 + with: { egress-policy: audit } + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: { persist-credentials: false } + - name: Install yq + run: | + if ! command -v yq >/dev/null 2>&1; then + sudo wget -qO /usr/local/bin/yq \ + https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + fi + - name: Run verify-sha-consistency.sh + run: bash .github/scripts/verify-sha-consistency.sh + lint: name: Lint needs: detect-language runs-on: ${{ inputs.runner }} + timeout-minutes: 10 permissions: contents: read @@ -672,14 +695,15 @@ jobs: # ─────────────────────────────────────────────────────────────────────────── enrich: name: Stage 2 · Enrich - needs: [lint, test, validate-pr-title, scan-deps, scan-secrets] + needs: [lint, test, validate-pr-title, scan-deps, scan-secrets, verify-sha] if: >- always() && github.event.pull_request != null && needs.lint.result == 'success' && needs.test.result == 'success' && needs.validate-pr-title.result == 'success' && - needs.scan-deps.result == 'success' + needs.scan-deps.result == 'success' && + needs.verify-sha.result == 'success' runs-on: ${{ inputs.runner }} timeout-minutes: 5 permissions: From 98535780db1e6e0636cfaa5c9e8553881f755633 Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 23:01:05 -0400 Subject: [PATCH 6/7] chore(lint): exclude worktrees from yamllint scan --- .yamllint | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.yamllint b/.yamllint index ee45cee..eba451e 100644 --- a/.yamllint +++ b/.yamllint @@ -5,6 +5,9 @@ # 2. Aligned multi-line `with:` blocks for readability extends: default +ignore: | + .claude/worktrees/ + rules: line-length: disable document-start: disable # --- header is optional in this project From 58fdfb339bc7f7198de31ef18526253ac575e364 Mon Sep 17 00:00:00 2001 From: YiWang24 Date: Sun, 3 May 2026 23:04:14 -0400 Subject: [PATCH 7/7] fix(tests): replace grep -P with grep -E for macOS compatibility --- tests/actions/self-test-routing.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/actions/self-test-routing.bats b/tests/actions/self-test-routing.bats index 1110ffd..3026a01 100644 --- a/tests/actions/self-test-routing.bats +++ b/tests/actions/self-test-routing.bats @@ -227,7 +227,7 @@ setup() { @test "issue-ops.yml calls reusable issue.yml" { local issue_entry="${PROJECT_ROOT}/.github/workflows/issue-ops.yml" - grep -qP 'uses:\s+YiAgent/OpenCI/\.github/workflows/reusable/issue\.yml@[0-9a-f]{40}' "$issue_entry" + grep -qE 'uses:[[:space:]]+YiAgent/OpenCI/\.github/workflows/reusable/issue\.yml@[0-9a-f]{40}' "$issue_entry" } @test "issue-ops.yml has lifecycle job" {