From 8d2fda3af901b2c762d66f13c1d6724244660a2f Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Thu, 28 Aug 2025 15:03:20 -0700 Subject: [PATCH] ci: harden release pipeline; gate to upstream, migrate tokens, remove docker-on-tag CHANGES - Gate release and version workflows to upstream owner only. - Switch tagging and releases to built-in GITHUB_TOKEN. - Replace environment passing with step outputs across workflows. - Remove docker-publish-on-tag workflow to reduce duplication and complexity. - Add OCI description label to Docker image. - Document GHCR multi-arch annotations for accurate package descriptions. - Update README with new ARM binary release announcement. - Simplify GoReleaser config by removing comments and extras. --- .github/pull_request_template.md | 3 + .github/workflows/docker-publish-on-tag.yml | 150 ------------------ .github/workflows/release.yml | 4 +- .../update-version-and-create-tag.yml | 26 +-- .goreleaser.yaml | 42 +---- .vscode/settings.json | 4 + README.md | 1 + cmd/generate_changelog/incoming/1736.txt | 8 + scripts/docker/Dockerfile | 2 + scripts/docker/README.md | 12 ++ 10 files changed, 49 insertions(+), 203 deletions(-) delete mode 100644 .github/workflows/docker-publish-on-tag.yml create mode 100644 cmd/generate_changelog/incoming/1736.txt diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 90e8adc8..984b3c42 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,12 @@ ## What this Pull Request (PR) does + Please briefly describe what this PR does. ## Related issues + Please reference any open issues this PR relates to in here. If it closes an issue, type `closes #[ISSUE_NUMBER]`. ## Screenshots + Provide any screenshots you may find relevant to facilitate us understanding your PR. diff --git a/.github/workflows/docker-publish-on-tag.yml b/.github/workflows/docker-publish-on-tag.yml deleted file mode 100644 index fdd49070..00000000 --- a/.github/workflows/docker-publish-on-tag.yml +++ /dev/null @@ -1,150 +0,0 @@ -name: Release Docker image on tag (GHCR + Docker Hub) - -on: - push: - tags: ["v*"] # e.g., v1.4.300 - -permissions: - contents: read - packages: write # needed for GHCR with GITHUB_TOKEN - -jobs: - build-and-push: - # Optional safety: only run from your fork - if: ${{ github.repository_owner == 'ksylvan' }} - runs-on: ubuntu-latest - - outputs: - is_latest: ${{ steps.latest.outputs.is_latest }} - owner_lc: ${{ steps.vars.outputs.owner_lc }} - repo_lc: ${{ steps.vars.outputs.repo_lc }} - dockerhub_user_lc: ${{ steps.dh.outputs.user_lc }} - - steps: - - name: Checkout - uses: actions/checkout@v5 - with: - fetch-depth: 0 # full history for tag comparisons - - - name: Fetch all tags - run: git fetch --tags --force - - # More reliable cross-builds - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - # Compute lowercase owner/repo for registry image names - - name: Compute image names - id: vars - run: | - OWNER="${GITHUB_REPOSITORY_OWNER}" - REPO="${GITHUB_REPOSITORY#*/}" - echo "owner_lc=${OWNER,,}" >> "$GITHUB_OUTPUT" - echo "repo_lc=${REPO,,}" >> "$GITHUB_OUTPUT" - - # Lowercase Docker Hub username (belt & suspenders) - - name: Lowercase Docker Hub username - id: dh - run: echo "user_lc=${DOCKERHUB_USERNAME,,}" >> "$GITHUB_OUTPUT" - env: - DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }} - - # Determine if the current tag is the highest vX.Y.Z (no pre-releases) - - name: Is this the latest semver tag? - id: latest - shell: bash - run: | - CTAG="${GITHUB_REF_NAME}" - LATEST="$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1)" - echo "current_tag=$CTAG" >> "$GITHUB_OUTPUT" - echo "latest_tag=$LATEST" >> "$GITHUB_OUTPUT" - if [[ "$CTAG" == "$LATEST" ]]; then - echo "is_latest=true" >> "$GITHUB_OUTPUT" - else - echo "is_latest=false" >> "$GITHUB_OUTPUT" - fi - - # Login to GHCR (uses built-in GITHUB_TOKEN) - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Login to Docker Hub - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ steps.dh.outputs.user_lc }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - # Generate versioned tags/labels for BOTH registries (no :latest here) - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ steps.vars.outputs.repo_lc }} - docker.io/${{ steps.dh.outputs.user_lc }}/${{ steps.vars.outputs.repo_lc }} - tags: | - type=ref,event=tag # v1.4.300 - type=semver,pattern={{version}} # 1.4.300 (optional) - type=semver,pattern={{major}}.{{minor}} # 1.4 (optional) - labels: | - org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - - - name: Build and push (multi-arch) - uses: docker/build-push-action@v6 - with: - context: . - file: ./scripts/docker/Dockerfile - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Separate job to (re)point :latest — serialized to avoid races - move-latest: - needs: build-and-push - if: ${{ needs.build-and-push.outputs.is_latest == 'true' }} - runs-on: ubuntu-latest - - # Only one "latest" move at a time; newer runs cancel older in-progress ones - concurrency: - group: latest-${{ github.repository }} - cancel-in-progress: true - - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Tag :latest on GHCR - run: | - SRC="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}" - DST="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest" - docker buildx imagetools create -t "$DST" "$SRC" - - - name: Tag :latest on Docker Hub - run: | - SRC="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}" - DST="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest" - docker buildx imagetools create -t "$DST" "$SRC" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 422586e3..4092a7e3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,8 @@ jobs: run: go test -v ./... build: + # only run in main upstream repo + if: ${{ github.repository_owner == 'danielmiessler' }} name: Build & Release with Goreleaser needs: [test] runs-on: ubuntu-latest @@ -48,4 +50,4 @@ jobs: distribution: goreleaser args: release --clean env: - GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-version-and-create-tag.yml b/.github/workflows/update-version-and-create-tag.yml index 01f079c5..13b7328e 100644 --- a/.github/workflows/update-version-and-create-tag.yml +++ b/.github/workflows/update-version-and-create-tag.yml @@ -21,9 +21,10 @@ concurrency: jobs: update-version: - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: > + ${{ github.repository_owner == 'danielmiessler' }} && + github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest - steps: - name: Checkout repository uses: actions/checkout@v5 @@ -48,12 +49,13 @@ jobs: run: | latest_tag=$(git tag --sort=-creatordate | head -n 1) echo "Latest tag is: $latest_tag" + echo "tag=$latest_tag" >> $GITHUB_OUTPUT echo "tag=$latest_tag" >> $GITHUB_ENV # Save the latest tag to environment file - name: Increment patch version id: increment_version run: | - latest_tag=${{ env.tag }} + latest_tag=${{ steps.get_latest_tag.outputs.tag }} major=$(echo "$latest_tag" | cut -d. -f1 | sed 's/v//') minor=$(echo "$latest_tag" | cut -d. -f2) patch=$(echo "$latest_tag" | cut -d. -f3) @@ -61,19 +63,21 @@ jobs: new_version="${major}.${minor}.${new_patch}" new_tag="v${new_version}" echo "New version is: $new_version" + echo "new_version=$new_version" >> $GITHUB_OUTPUT echo "new_version=$new_version" >> $GITHUB_ENV # Save the new version to environment file echo "New tag is: $new_tag" + echo "new_tag=$new_tag" >> $GITHUB_OUTPUT echo "new_tag=$new_tag" >> $GITHUB_ENV # Save the new tag to environment file - name: Update version.go file run: | echo "package main" > cmd/fabric/version.go echo "" >> cmd/fabric/version.go - echo "var version = \"${{ env.new_tag }}\"" >> cmd/fabric/version.go + echo "var version = \"${{ steps.increment_version.outputs.new_tag }}\"" >> cmd/fabric/version.go - name: Update version.nix file run: | - echo "\"${{ env.new_version }}\"" > nix/pkgs/fabric/version.nix + echo "\"${{ steps.increment_version.outputs.new_version }}\"" > nix/pkgs/fabric/version.nix - name: Format source code run: | @@ -87,7 +91,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - go run ./cmd/generate_changelog --process-prs ${{ env.new_tag }} + go run ./cmd/generate_changelog --process-prs ${{ steps.increment_version.outputs.new_tag }} go run ./cmd/generate_changelog --sync-db - name: Commit changes run: | @@ -100,7 +104,7 @@ jobs: # and removing the incoming/ directory. if ! git diff --staged --quiet; then - git commit -m "chore(release): Update version to ${{ env.new_tag }}" + git commit -m "chore(release): Update version to ${{ steps.increment_version.outputs.new_tag }}" else echo "No changes to commit." fi @@ -113,10 +117,10 @@ jobs: - name: Create a new tag env: - GITHUB_TOKEN: ${{ secrets.TAG_PAT }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git tag ${{ env.new_tag }} - git push origin ${{ env.new_tag }} # Push the new tag + git tag ${{ steps.increment_version.outputs.new_tag }} + git push origin ${{ steps.increment_version.outputs.new_tag }} # Push the new tag - name: Dispatch event to trigger release workflow env: @@ -126,4 +130,4 @@ jobs: -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/${{ github.repository }}/dispatches \ - -d '{"event_type": "tag_created", "client_payload": {"tag": "${{ env.new_tag }}"}}' + -d '{"event_type": "tag_created", "client_payload": {"tag": "${{ steps.increment_version.outputs.new_tag }}"}}' diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 0719c91f..4ce28d78 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,10 +1,4 @@ -# This is an example .goreleaser.yml file with some sensible defaults. -# Make sure to check the documentation at https://goreleaser.com - -# The lines below are called `modelines`. See `:help modeline` -# Feel free to remove those if you don't want/need to use them. -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json -# vim: set ts=2 sw=2 tw=0 fo=cnqoj +# Read the documentation at https://goreleaser.com version: 2 @@ -26,7 +20,6 @@ builds: main: ./cmd/fabric binary: fabric - archives: - formats: [tar.gz] # this name template makes the OS and Arch compatible with the results of `uname`. @@ -41,36 +34,3 @@ archives: format_overrides: - goos: windows formats: [zip] - -winget: - - name: Fabric - publisher: danielmiessler - license: MIT - homepage: https://github.com/danielmiessler/fabric - copyright: Daniel Miessler - short_description: open-source AI framework for augmenting - repository: - owner: danielmiessler - name: winget-pkgs - branch: "danielmiessler.Fabric-{{.Version}}" - pull_request: - enabled: true - draft: true - base: - owner: microsoft - name: winget-pkgs - branch: master - -changelog: - sort: asc - filters: - exclude: - - "^docs:" - - "^test:" - -release: - footer: >- - - --- - - Released by [GoReleaser](https://github.com/goreleaser/goreleaser). diff --git a/.vscode/settings.json b/.vscode/settings.json index 143845b5..aeab1bf9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "goopenai", "GOPATH", "gopkg", + "Goreleaser", "GOROOT", "Graphviz", "grokai", @@ -105,6 +106,8 @@ "mbed", "metacharacters", "Miessler", + "modeline", + "modelines", "mpga", "nometa", "numpy", @@ -162,6 +165,7 @@ "videoid", "webp", "WEBVTT", + "winget", "wipecontext", "wipesession", "wireframes", diff --git a/README.md b/README.md index af6329e9..32ae1094 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Below are the **new features and capabilities** we've added (newest first): ### Recent Major Features +- [v1.4.303](https://github.com/danielmiessler/fabric/releases/tag/v1.4.303) (Aug 29, 2025) — **New Binary Releases**: Linux ARM and Windows ARM targets. You can run Fabric on the Raspberry PI and on your Windows Surface! - [v1.4.294](https://github.com/danielmiessler/fabric/releases/tag/v1.4.294) (Aug 20, 2025) — **Venice AI Support**: Added the Venice AI provider. Venice is a Privacy-First, Open-Source AI provider. See their ["About Venice"](https://docs.venice.ai/overview/about-venice) page for details. - [v1.4.291](https://github.com/danielmiessler/fabric/releases/tag/v1.4.291) (Aug 18, 2025) — **Speech To Text**: Add OpenAI speech-to-text support with `--transcribe-file`, `--transcribe-model`, and `--split-media-file` flags. - [v1.4.287](https://github.com/danielmiessler/fabric/releases/tag/v1.4.287) (Aug 16, 2025) — **AI Reasoning**: Add Thinking to Gemini models and introduce `readme_updates` python script diff --git a/cmd/generate_changelog/incoming/1736.txt b/cmd/generate_changelog/incoming/1736.txt new file mode 100644 index 00000000..1ebc231a --- /dev/null +++ b/cmd/generate_changelog/incoming/1736.txt @@ -0,0 +1,8 @@ +### PR [#1736](https://github.com/danielmiessler/Fabric/pull/1736) by [tonymet](https://github.com/tonymet): Winget Publishing and GoReleaser + +- Added GoReleaser support for improved package distribution +- Winget and Docker publishing moved to ksylvan/fabric-packager GitHub repo +- Hardened release pipeline by gating workflows to upstream owner only +- Migrated from custom tokens to built-in GITHUB_TOKEN for enhanced security +- Removed docker-publish-on-tag workflow to reduce duplication and complexity +- Added ARM binary release support with updated documentation diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile index 25147c8d..a6231b8c 100644 --- a/scripts/docker/Dockerfile +++ b/scripts/docker/Dockerfile @@ -16,6 +16,8 @@ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /fabric ./cmd/fabric FROM alpine:latest +LABEL org.opencontainers.image.description="A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details." + RUN apk add --no-cache ca-certificates \ && mkdir -p /root/.config/fabric diff --git a/scripts/docker/README.md b/scripts/docker/README.md index 95a03e5c..a21f1f4b 100644 --- a/scripts/docker/README.md +++ b/scripts/docker/README.md @@ -46,3 +46,15 @@ docker run --rm -it -p 8080:8080 -v $HOME/.fabric-config:/root/.config/fabric fa ``` The API will be available at `http://localhost:8080`. + +## Multi-arch builds and GHCR packages + +For multi-arch Docker builds (such as those used for GitHub Container Registry packages), the description should be set via annotations in the manifest instead of the Dockerfile LABEL. When building multi-arch images, ensure the build configuration includes: + +```json +"annotations": { + "org.opencontainers.image.description": "A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details." +} +``` + +This ensures that GHCR packages display the proper description.