From ced1f7687e97f17f09d9e9807d2f98d395835403 Mon Sep 17 00:00:00 2001 From: CTO Hermes Date: Thu, 4 Jun 2026 11:38:38 +0700 Subject: [PATCH 1/2] feat: release branch setup + install.sh checksum + release sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SHA256 checksum verification to install.sh (uses checksums-sha256.txt from releases) - Add sync-main job to release workflow (pushes develop → main on every tag) - Update release notes template to prioritize install.sh over manual download - Fix changelog link to point to main branch - Add CORA_VERSION pinning example in README - Simplify CI manual install to use install.sh Closes #151 --- .github/workflows/release.yml | 25 +++++++++++++++++++------ README.md | 12 ++++++++---- install.sh | 23 ++++++++++++++++++++++- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b48bd0b2..57916eb3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,21 @@ env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: + sync-main: + name: Sync main branch + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: develop + + - name: Push to main + run: | + git push origin HEAD:main --force + echo "✅ main synced to develop at ${{ github.sha }}" + build-release: name: Build ${{ matrix.target }} runs-on: ${{ matrix.os }} @@ -152,18 +167,16 @@ jobs: printf '| Windows (x86_64) | `cora-x86_64-pc-windows-msvc-%s.zip` |\n\n' "${{ steps.version.outputs.TAG }}" printf '### 🚀 Quick Start\n\n' printf '```bash\n' - printf '# Install via cargo\n' + printf '# Quick install (Linux / macOS)\n' + printf 'curl -fsSL https://raw.githubusercontent.com/codecoradev/cora-cli/main/install.sh | sh\n\n' + printf '# Or via cargo\n' printf 'cargo install cora\n\n' - printf '# Or download binary (extracts as '\''cora'\'')\n' - printf 'curl -fsSL https://github.com/codecoradev/cora-cli/releases/latest/download/cora-x86_64-unknown-linux-gnu-%s.tar.gz | tar xz\n' "${{ steps.version.outputs.TAG }}" - printf 'chmod +x cora\n' - printf 'sudo mv cora /usr/local/bin/\n\n' printf '# Init project\n' printf 'cora init\n\n' printf '# Review staged changes\n' printf 'CORA_API_KEY=your-key cora review --staged\n' printf '```\n\n' - printf '**Full changelog:** https://github.com/codecoradev/cora-cli/blob/develop/CHANGELOG.md\n' + printf '**Full changelog:** https://github.com/codecoradev/cora-cli/blob/main/CHANGELOG.md\n' } > release-notes.md - name: Create GitHub Release diff --git a/README.md b/README.md index 9afba1fc..da1b49a5 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,12 @@ Installs to `~/.local/bin`. Add to PATH if needed: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc ``` +Pin a specific version with `CORA_VERSION`: + +```bash +CORA_VERSION=v0.4.0 curl -fsSL https://raw.githubusercontent.com/codecoradev/cora-cli/main/install.sh | sh +``` + ### Pre-built Binaries Download from [GitHub Releases](https://github.com/codecoradev/cora-cli/releases): @@ -358,11 +364,9 @@ jobs: Or install manually: ```yaml -# Manual install in CI +# Manual install in CI (using install script) - name: Install cora-cli - run: | - curl -fsSL https://github.com/codecoradev/cora-cli/releases/latest/download/cora-x86_64-unknown-linux-gnu.tar.gz | tar xz - sudo mv cora /usr/local/bin/ + run: curl -fsSL https://raw.githubusercontent.com/codecoradev/cora-cli/main/install.sh | sh ``` ### GitLab CI diff --git a/install.sh b/install.sh index d0f53d17..63f95a83 100755 --- a/install.sh +++ b/install.sh @@ -100,14 +100,35 @@ install() { TEMP_DIR=$(mktemp -d) ARCHIVE="${TEMP_DIR}/${ARCHIVE_NAME}" + CHECKSUMS_URL="https://github.com/${REPO}/releases/download/${VERSION}/checksums-sha256.txt" + CHECKSUM_FILE="${TEMP_DIR}/checksums-sha256.txt" + info "Downloading from: $DOWNLOAD_URL" if ! curl -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then error "Failed to download ${ARCHIVE_NAME}" fi + # Verify SHA256 checksum (prevents MITM / corrupted download). + info "Downloading checksums..." + if curl -fsSL "$CHECKSUMS_URL" -o "$CHECKSUM_FILE"; then + info "Verifying SHA256 checksum..." + EXPECTED=$(grep -F "$ARCHIVE_NAME" "$CHECKSUM_FILE" | awk '{print $1}') + if [ -n "$EXPECTED" ]; then + ACTUAL=$(sha256sum "$ARCHIVE" | awk '{print $1}') + if [ "$ACTUAL" != "$EXPECTED" ]; then + error "Checksum mismatch! Expected: ${EXPECTED}, got: ${ACTUAL}" + fi + info "Checksum verified: $EXPECTED" + else + warn "Checksum for ${ARCHIVE_NAME} not found in checksums file — skipping verification" + fi + else + warn "Failed to download checksums — skipping verification" + fi + # Verify archive contents before extraction (CWE-22 path traversal). # Reject any entry with an absolute path or a ".." component. - info "Verifying archive..." + info "Verifying archive integrity..." if tar -tzf "$ARCHIVE" | grep -qE '^/|(^|/)\.\.(/|$)'; then error "Archive contains unsafe paths (absolute or directory traversal) — refusing to extract" fi From abcc0f9cc47b7f6be96897d96ca8b4905ef120f5 Mon Sep 17 00:00:00 2001 From: CTO Hermes Date: Thu, 4 Jun 2026 11:41:12 +0700 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20address=20CodeCora=20review=20?= =?UTF-8?q?=E2=80=94=20gate=20sync-main,=20add=20needs,=20document=20force?= =?UTF-8?q?-push=20rationale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add explicit if guard: startsWith(github.ref, 'refs/tags/v') - build-release now needs: sync-main (sequential, not parallel) - Document why force-push is safe: main is release-only mirror --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 57916eb3..a52ad3ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,10 @@ jobs: sync-main: name: Sync main branch runs-on: ubuntu-latest + # Only runs on v* tag pushes (release trigger). Uses force-push because main + # is a release-only mirror of develop — any commits on main not in develop + # are stale snapshots that should be overwritten by the current release. + if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write steps: @@ -26,6 +30,7 @@ jobs: echo "✅ main synced to develop at ${{ github.sha }}" build-release: + needs: sync-main name: Build ${{ matrix.target }} runs-on: ${{ matrix.os }} strategy: