Migrate from Publish to BCR app to workflow (#50)

## Summary
- Add `.github/workflows/publish.yaml` that uses the
`bazel-contrib/publish-to-bcr` reusable workflow to automate BCR
publishing after releases
- Update `release.yml` to call the new publish workflow after a
successful release and bump `release_ruleset` from v6 to v7.2.2
- Add required permissions for artifact attestations (`id-token: write`,
`attestations: write`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
new file mode 100644
index 0000000..9c7ceaf
--- /dev/null
+++ b/.github/workflows/publish.yaml
@@ -0,0 +1,36 @@
+# Publish new releases to Bazel Central Registry.
+name: Publish to BCR
+on:
+  # Run the publish workflow after a successful release
+  # Will be triggered from the release.yaml workflow
+  workflow_call:
+    inputs:
+      tag_name:
+        required: true
+        type: string
+    secrets:
+      publish_token:
+        required: true
+  # In case of problems, let release engineers retry by manually dispatching
+  # the workflow from the GitHub UI
+  workflow_dispatch:
+    inputs:
+      tag_name:
+        description: git tag being released
+        required: true
+        type: string
+jobs:
+  publish:
+    uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v1.1.0
+    with:
+      tag_name: ${{ inputs.tag_name }}
+      # GitHub repository which is a fork of the upstream where the Pull Request will be opened.
+      registry_fork: bazel-contrib/bazel-central-registry
+      draft: false
+    permissions:
+      attestations: write
+      contents: write
+      id-token: write
+    secrets:
+      # Necessary to push to the BCR fork, and to open a pull request against a registry
+      publish_token: ${{ secrets.publish_token || secrets.BCR_PUBLISH_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b5aaac3..e0a1c0c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,19 +1,24 @@
 # Cut a release whenever a new tag is pushed to the repo.
-# You should use an annotated tag, like `git tag -a v1.2.3`
-# and put the release notes into the commit message for the tag.
 name: Release
-
 on:
   push:
     tags:
       - "v*.*.*"
-
 permissions:
+  id-token: write
+  attestations: write
   contents: write
-
 jobs:
   release:
-    uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v6
+    uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v7.2.2
     with:
-      prerelease: false
       release_files: rules_shell-*.tar.gz
+      prerelease: false
+      tag_name: ${{ inputs.tag_name || github.ref_name }}
+  publish:
+    needs: release
+    uses: ./.github/workflows/publish.yaml
+    with:
+      tag_name: ${{ inputs.tag_name || github.ref_name }}
+    secrets:
+      publish_token: ${{ secrets.publish_token || secrets.BCR_PUBLISH_TOKEN }}