From 0820eb8f77d8a491fef873858a29a2561aef40ca Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:43:02 -0700 Subject: [PATCH 1/8] chore: add GitHub code owners --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..8aeb61e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +.github/workflows/* @djchen +.github/dependabot.yml @djchen From 56e56b050d90c9ca47b019daa2408c154f8a6cf0 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:43:13 -0700 Subject: [PATCH 2/8] chore: reduce updater workflow permissions --- .github/workflows/update-opencode-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/update-opencode-release.yml b/.github/workflows/update-opencode-release.yml index 0de2b40..2b0f345 100644 --- a/.github/workflows/update-opencode-release.yml +++ b/.github/workflows/update-opencode-release.yml @@ -11,8 +11,7 @@ on: - cron: "17 0 * * *" permissions: - contents: write - pull-requests: write + contents: read concurrency: group: update-opencode-release From f1b2e2efd53491444ab2eb05a26392bc2e191d16 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:43:33 -0700 Subject: [PATCH 3/8] chore: disable checkout credential persistence --- .github/workflows/ci.yml | 6 ++++++ .github/workflows/docker-publish.yml | 1 + .github/workflows/update-opencode-release.yml | 1 + 3 files changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09bbc1e..035092b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,7 @@ jobs: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false submodules: recursive - name: Build Docker image for regression checks @@ -41,6 +42,7 @@ jobs: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false submodules: recursive - name: Setup Bun @@ -70,6 +72,8 @@ jobs: steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Run actionlint uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 @@ -80,6 +84,8 @@ jobs: steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Install ShellCheck run: sudo apt-get update && sudo apt-get install -y shellcheck diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index ccbee88..e8be15d 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -36,6 +36,7 @@ jobs: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false ref: ${{ github.event.workflow_run.head_sha || github.sha }} submodules: recursive diff --git a/.github/workflows/update-opencode-release.yml b/.github/workflows/update-opencode-release.yml index 2b0f345..1aad897 100644 --- a/.github/workflows/update-opencode-release.yml +++ b/.github/workflows/update-opencode-release.yml @@ -26,6 +26,7 @@ jobs: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false fetch-depth: 0 submodules: recursive From 1fae3464e2514984421bc2c820b5af553b3017a6 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:43:47 -0700 Subject: [PATCH 4/8] chore: remove Docker Actions cache --- .github/workflows/docker-publish.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e8be15d..6568d7e 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -72,8 +72,6 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max build-args: | VERSION=${{ steps.meta.outputs.version }} REVISION=${{ github.event.workflow_run.head_sha || github.sha }} From 71875b9a7889ccf4b4fc966e5cb9caeca898ef60 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:44:14 -0700 Subject: [PATCH 5/8] chore: validate upstream release tags --- .github/workflows/update-opencode-release.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-opencode-release.yml b/.github/workflows/update-opencode-release.yml index 1aad897..d757649 100644 --- a/.github/workflows/update-opencode-release.yml +++ b/.github/workflows/update-opencode-release.yml @@ -36,13 +36,21 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} INPUT_RELEASE_TAG: ${{ inputs.release_tag }} run: | + validate_release_tag() { + if ! printf '%s\n' "$1" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)*(-[0-9A-Za-z][0-9A-Za-z.-]*)?$'; then + printf 'Invalid release tag: %s\n' "$1" >&2 + exit 1 + fi + } + if [ -n "$INPUT_RELEASE_TAG" ]; then tag="$INPUT_RELEASE_TAG" else tag="$(gh release view --repo anomalyco/opencode --json tagName --jq .tagName)" fi - echo "tag=$tag" >> "$GITHUB_OUTPUT" + validate_release_tag "$tag" + printf 'tag=%s\n' "$tag" >> "$GITHUB_OUTPUT" - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 From 0b8b54f3486ac3445957fed263ea12d490937146 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:55:27 -0700 Subject: [PATCH 6/8] chore: add zizmor workflow security scan --- .github/workflows/ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 035092b..813fcf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,6 +78,25 @@ jobs: - name: Run actionlint uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 + zizmor: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + with: + advanced-security: false + inputs: .github/workflows + min-severity: medium + min-confidence: medium + shellcheck: runs-on: ubuntu-latest From 72d41c468179f22c8c9cce0a4e0ca37e2287a6fb Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 20:59:17 -0700 Subject: [PATCH 7/8] chore: protect code owners file --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8aeb61e..8e66913 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,3 @@ +.github/CODEOWNERS @djchen .github/workflows/* @djchen .github/dependabot.yml @djchen From 4ed34240f84ae0074f8983a0c72ec64bbb98c545 Mon Sep 17 00:00:00 2001 From: Dan Chen Date: Thu, 14 May 2026 21:19:13 -0700 Subject: [PATCH 8/8] chore: replace workflow_run publish trigger --- .github/workflows/ci.yml | 110 +------------------------ .github/workflows/docker-publish.yml | 40 ++++----- .github/workflows/validate.yml | 117 +++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 131 deletions(-) create mode 100644 .github/workflows/validate.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 813fcf3..10c2424 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,119 +4,13 @@ on: pull_request: branches: - main - push: - branches: - - main workflow_dispatch: permissions: contents: read jobs: - runtime-config-regression: - runs-on: ubuntu-latest - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - submodules: recursive - - - name: Build Docker image for regression checks - run: docker build -t opencode-web-docker . - - - name: Setup Bun - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - - - name: Install dependencies - run: bun install --frozen-lockfile - - - name: Run runtime-config regression checks - run: bun run test:runtime-config - - build-compat-tests: - runs-on: ubuntu-latest - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - submodules: recursive - - - name: Setup Bun - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - - - name: Install dependencies - run: bun install --frozen-lockfile - - - name: Run build-compat unit tests - run: bun test - - - name: Run upstream compatibility check - run: bun run test:compat - - - name: Run TypeScript typecheck - run: bun run typecheck - - - name: Run Biome lint - run: bun run lint - - - name: Check formatting - run: bun run format:check - - actionlint: - runs-on: ubuntu-latest - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Run actionlint - uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 - - zizmor: - runs-on: ubuntu-latest + validate: + uses: ./.github/workflows/validate.yml permissions: contents: read - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Run zizmor - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 - with: - advanced-security: false - inputs: .github/workflows - min-severity: medium - min-confidence: medium - - shellcheck: - runs-on: ubuntu-latest - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Install ShellCheck - run: sudo apt-get update && sudo apt-get install -y shellcheck - - - name: Run ShellCheck on root scripts - shell: bash - run: | - mapfile -t files < <(git ls-files '*.sh' | grep -v '^opencode/' || true) - - if [ "${#files[@]}" -eq 0 ]; then - echo "No repository-owned shell scripts found." - exit 0 - fi - - shellcheck --severity=warning "${files[@]}" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6568d7e..f51c68c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,43 +1,38 @@ name: Docker Publish on: - workflow_run: - workflows: - - CI - types: - - completed push: + branches: + - main tags: - "v*" workflow_dispatch: -permissions: - contents: read - packages: write +permissions: {} concurrency: - group: docker-publish-${{ github.event.workflow_run.head_branch || github.ref }} + group: docker-publish-${{ github.ref }} cancel-in-progress: true jobs: + validate: + uses: ./.github/workflows/validate.yml + permissions: + contents: read + docker: - if: | - github.event_name == 'workflow_dispatch' || - startsWith(github.ref, 'refs/tags/v') || - ( - github.event_name == 'workflow_run' && - github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.event == 'push' && - github.event.workflow_run.head_branch == 'main' - ) + needs: validate + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - ref: ${{ github.event.workflow_run.head_sha || github.sha }} submodules: recursive - name: Set up QEMU @@ -60,9 +55,8 @@ jobs: images: ghcr.io/${{ github.repository }} tags: | type=ref,event=tag - type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=main,enable=${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'main' || github.event_name == 'workflow_dispatch' && github.ref_name == 'main' }} - type=raw,value=latest,enable=${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'main' || github.event_name == 'workflow_dispatch' && github.ref_name == 'main' }} + type=ref,event=branch + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - name: Build and push image uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7 @@ -74,5 +68,5 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ steps.meta.outputs.version }} - REVISION=${{ github.event.workflow_run.head_sha || github.sha }} + REVISION=${{ github.sha }} SOURCE_URL=https://github.com/${{ github.repository }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..df035c6 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,117 @@ +name: Validate + +on: + workflow_call: + +permissions: + contents: read + +jobs: + runtime-config-regression: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + submodules: recursive + + - name: Build Docker image for regression checks + run: docker build -t opencode-web-docker . + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run runtime-config regression checks + run: bun run test:runtime-config + + build-compat-tests: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + submodules: recursive + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run build-compat unit tests + run: bun test + + - name: Run upstream compatibility check + run: bun run test:compat + + - name: Run TypeScript typecheck + run: bun run typecheck + + - name: Run Biome lint + run: bun run lint + + - name: Check formatting + run: bun run format:check + + actionlint: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run actionlint + uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 + + zizmor: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + with: + advanced-security: false + inputs: .github/workflows + min-severity: medium + min-confidence: medium + version: v1.24.1 + + shellcheck: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install ShellCheck + run: sudo apt-get update && sudo apt-get install -y shellcheck + + - name: Run ShellCheck on root scripts + shell: bash + run: | + mapfile -t files < <(git ls-files '*.sh' | grep -v '^opencode/' || true) + + if [ "${#files[@]}" -eq 0 ]; then + echo "No repository-owned shell scripts found." + exit 0 + fi + + shellcheck --severity=warning "${files[@]}"