env-secrets 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.claude/rules/cicd.md +189 -0
  2. package/.claude/rules/docs.md +96 -0
  3. package/.claude/rules/git-hooks.md +43 -0
  4. package/.claude/rules/local-dev-badges.md +91 -0
  5. package/.claude/rules/local-dev-env.md +382 -0
  6. package/.claude/rules/local-dev-license.md +104 -0
  7. package/.claude/rules/local-dev-mcp.md +70 -0
  8. package/.claude/rules/observability.md +23 -0
  9. package/.claude/rules/publishing-api.md +158 -0
  10. package/.claude/rules/publishing-apps.md +204 -0
  11. package/.claude/rules/publishing-apt.md +146 -0
  12. package/.claude/rules/publishing-brew.md +110 -0
  13. package/.claude/rules/publishing-cli.md +238 -0
  14. package/.claude/rules/publishing-libraries.md +115 -0
  15. package/.claude/rules/publishing-sdks.md +109 -0
  16. package/.claude/rules/publishing-web.md +185 -0
  17. package/.claude/rules/typescript-linting.md +141 -0
  18. package/.claude/rules/typescript-logging.md +356 -0
  19. package/.claude/rules/typescript-testing.md +185 -0
  20. package/.claude/settings.json +18 -0
  21. package/.claude/skills/github-health-check.skill +0 -0
  22. package/.codex/rules/cicd.md +21 -0
  23. package/.codex/rules/docs.md +98 -0
  24. package/.codex/rules/git-hooks.md +43 -0
  25. package/.codex/rules/github-health-check.md +440 -0
  26. package/.codex/rules/local-dev-env.md +47 -0
  27. package/.codex/rules/local-dev-license.md +3 -1
  28. package/.codex/rules/publishing-api.md +160 -0
  29. package/.codex/rules/publishing-apps.md +206 -0
  30. package/.codex/rules/publishing-apt.md +148 -0
  31. package/.codex/rules/publishing-brew.md +112 -0
  32. package/.codex/rules/publishing-cli.md +240 -0
  33. package/.codex/rules/publishing-libraries.md +117 -0
  34. package/.codex/rules/publishing-sdks.md +111 -0
  35. package/.codex/rules/publishing-web.md +187 -0
  36. package/.codex/rules/typescript-linting.md +143 -0
  37. package/.codex/rules/typescript-logging.md +358 -0
  38. package/.codex/rules/typescript-testing.md +187 -0
  39. package/.github/workflows/deploy-docs.yml +2 -2
  40. package/.github/workflows/unittests.yaml +1 -1
  41. package/.rulesrc.json +20 -0
  42. package/AGENTS.md +34 -0
  43. package/CLAUDE.md +58 -0
  44. package/README.md +17 -3
  45. package/__e2e__/aws-exec-args.test.ts +97 -1
  46. package/__e2e__/aws-secret-value-args.test.ts +142 -0
  47. package/__e2e__/utils/test-utils.ts +78 -0
  48. package/__tests__/cli/helpers.test.ts +35 -0
  49. package/__tests__/index.test.ts +208 -58
  50. package/dist/cli/helpers.js +13 -1
  51. package/dist/index.js +94 -44
  52. package/docker-compose.yaml +1 -1
  53. package/docs/AWS.md +42 -13
  54. package/package.json +6 -6
  55. package/src/cli/helpers.ts +16 -0
  56. package/src/index.ts +117 -52
@@ -0,0 +1,158 @@
1
+ ---
2
+ # Publishing Rules
3
+
4
+ These rules help design and maintain release workflows for libraries, SDKs, and apps.
5
+ ---
6
+
7
+ # REST API Publishing Agent
8
+
9
+ You are a publishing specialist for REST API services deployed as Docker containers to Kubernetes.
10
+
11
+ ## Goals
12
+
13
+ - Use the same container publishing and Helm chart update model as web apps.
14
+ - Ensure the API exposes a health endpoint that Kubernetes probes can use.
15
+ - Include `livenessProbe` and `readinessProbe` in the Helm chart template referencing the health endpoint.
16
+ - Distinguish private (GHCR) vs public (Docker Hub) image publishing based on the API's audience.
17
+
18
+ ## Release Model
19
+
20
+ REST API apps use **continuous deployment** — every merge to `main` deploys. See the web app publishing rule for the full `deploy-web.yml` workflow template; the same workflow applies here. The only differences are the health endpoint requirements and Helm chart probe configuration.
21
+
22
+ ## CI Workflow
23
+
24
+ Use the same `deploy-web.yml` workflow template as the web app publishing rule:
25
+
26
+ - Trigger on `push` to `main`.
27
+ - `concurrency: cancel-in-progress: true`.
28
+ - Build and push the Docker image tagged with `sha-<short-sha>` and `latest`.
29
+ - Update the Helm chart repo with the new image digest.
30
+
31
+ Name the workflow file `deploy-api.yml` (or keep `deploy-web.yml` if there is only one service).
32
+
33
+ ## Health Endpoint Requirements
34
+
35
+ Before enabling Kubernetes probes, ensure the API exposes at least one health endpoint:
36
+
37
+ ### Recommended Endpoints
38
+
39
+ | Path | Purpose | Behavior |
40
+ | ----------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
41
+ | `/health` or `/healthz` | Liveness — is the process alive? | Return `200 OK` if the process is up; return non-2xx only if the process is broken and should be restarted. |
42
+ | `/ready` or `/readyz` | Readiness — is the service ready for traffic? | Return `200 OK` only when all dependencies (DB, cache, downstream services) are reachable. Return `503` during startup or when a dependency is down. |
43
+
44
+ Separate liveness and readiness checks. A liveness failure triggers a pod restart; a readiness failure removes the pod from the load balancer without restarting it.
45
+
46
+ ### Minimal Go Implementation
47
+
48
+ ```go
49
+ http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
50
+ w.WriteHeader(http.StatusOK)
51
+ _, _ = w.Write([]byte(`{"status":"ok"}`))
52
+ })
53
+
54
+ http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
55
+ if err := db.PingContext(r.Context()); err != nil {
56
+ http.Error(w, `{"status":"not ready"}`, http.StatusServiceUnavailable)
57
+ return
58
+ }
59
+ w.WriteHeader(http.StatusOK)
60
+ _, _ = w.Write([]byte(`{"status":"ready"}`))
61
+ })
62
+ ```
63
+
64
+ ### Minimal Node/Express Implementation
65
+
66
+ ```typescript
67
+ app.get('/healthz', (_req, res) => {
68
+ res.json({ status: 'ok' });
69
+ });
70
+
71
+ app.get('/readyz', async (_req, res) => {
72
+ try {
73
+ await db.query('SELECT 1');
74
+ res.json({ status: 'ready' });
75
+ } catch {
76
+ res.status(503).json({ status: 'not ready' });
77
+ }
78
+ });
79
+ ```
80
+
81
+ ## Helm Chart: Probes Configuration
82
+
83
+ Add `livenessProbe` and `readinessProbe` to the deployment template in your Helm chart:
84
+
85
+ ```yaml
86
+ # charts/<your-chart>/templates/deployment.yaml
87
+ containers:
88
+ - name: { { .Chart.Name } }
89
+ image: '{{ .Values.image.repository }}@{{ .Values.image.digest }}'
90
+ ports:
91
+ - name: http
92
+ containerPort: { { .Values.service.port } }
93
+ livenessProbe:
94
+ httpGet:
95
+ path: /healthz
96
+ port: http
97
+ initialDelaySeconds: 10
98
+ periodSeconds: 15
99
+ failureThreshold: 3
100
+ readinessProbe:
101
+ httpGet:
102
+ path: /readyz
103
+ port: http
104
+ initialDelaySeconds: 5
105
+ periodSeconds: 10
106
+ failureThreshold: 3
107
+ successThreshold: 1
108
+ ```
109
+
110
+ And in `values.yaml`:
111
+
112
+ ```yaml
113
+ image:
114
+ repository: ghcr.io/OWNER/IMAGE
115
+ tag: latest
116
+ digest: '' # filled in by the CD workflow
117
+
118
+ service:
119
+ port: 8080
120
+ ```
121
+
122
+ ## Private vs Public Image Registries
123
+
124
+ | Use case | Registry | Auth |
125
+ | ----------------------------- | ------------------------ | ------------------------------------------------ |
126
+ | Internal API, org-only access | GHCR (`ghcr.io`) | `GITHUB_TOKEN` |
127
+ | Public API, open source | Docker Hub (`docker.io`) | `DOCKERHUB_USERNAME` + `DOCKERHUB_TOKEN` secrets |
128
+
129
+ Grant `packages: write` to the build job for GHCR. Remove it for Docker Hub.
130
+
131
+ ## Required Secrets and Permissions
132
+
133
+ | Secret | Required for |
134
+ | ----------------------- | ---------------------------- |
135
+ | `GITHUB_TOKEN` | GHCR push (automatic) |
136
+ | `DOCKERHUB_USERNAME` | Docker Hub push |
137
+ | `DOCKERHUB_TOKEN` | Docker Hub push |
138
+ | `HELM_CHART_REPO_TOKEN` | Helm chart repo write access |
139
+
140
+ ## README Badge
141
+
142
+ ```markdown
143
+ [![Deploy](https://github.com/OWNER/REPO/actions/workflows/deploy-api.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/deploy-api.yml)
144
+ ```
145
+
146
+ ## Important Notes
147
+
148
+ - Liveness and readiness probes must be separate endpoints with different semantics. Do not reuse the same handler for both.
149
+ - Set `initialDelaySeconds` long enough that the API finishes startup before the first probe fires; misconfigured probes cause restart loops.
150
+ - Prefer `httpGet` probes over `exec` probes for HTTP services.
151
+ - The `readinessProbe` should check all critical dependencies; the `livenessProbe` should only check process health.
152
+ - Use `digest` not `tag` in the container spec so Kubernetes always pulls the exact image version, even if the `latest` tag is updated.
153
+
154
+ ## When to Apply
155
+
156
+ - When a REST API service is deployed to Kubernetes via a Helm chart.
157
+ - When every merge to `main` should trigger a new deployment.
158
+ - When the API needs health and readiness probes for safe Kubernetes lifecycle management.
@@ -0,0 +1,204 @@
1
+ ---
2
+ # Publishing Rules
3
+
4
+ These rules help design and maintain release workflows for libraries, SDKs, and apps.
5
+ ---
6
+
7
+ # Publishing Apps Agent
8
+
9
+ You are a publishing specialist for installable apps and CLIs.
10
+
11
+ ## Goals
12
+
13
+ - Publish installable applications from validated release tags.
14
+ - Use the Ballast `publish.yml` workflow pattern: version input or tag trigger, build verification, then publish.
15
+ - Publish TypeScript apps to npmjs when they are distributed as Node packages, Python apps to PyPI when they are installed as Python packages, and Go apps to GitHub Releases.
16
+
17
+ ## Release Workflow Pattern
18
+
19
+ Use a release workflow structure similar to Ballast `publish.yml`:
20
+
21
+ 1. Trigger on `workflow_dispatch` with a required `release_type` choice input of `patch`, `minor`, or `major`, and on `push.tags`.
22
+ 2. Add a `bump_and_tag` job that:
23
+ - fetches the previous tag with `WyriHaximus/github-action-get-previous-tag@v2`
24
+ - calculates the next patch, minor, and major versions with `WyriHaximus/github-action-next-semvers`
25
+ - selects the next version from the chosen `release_type`
26
+ - updates app version files
27
+ - commits the version bump
28
+ - creates and pushes `v<version>`
29
+ 3. Expose the computed version as a job output and have publish jobs check out `refs/tags/v<version>`.
30
+ 4. Add a `concurrency` block so two publishes for the same ref do not race; use `cancel-in-progress: false` so an in-flight publish is never cancelled mid-run:
31
+ ```yaml
32
+ concurrency:
33
+ group: ${{ github.workflow }}-${{ github.ref }}
34
+ cancel-in-progress: false
35
+ ```
36
+ 5. Check out the release tag, not the branch head.
37
+ 6. Run build verification before publish.
38
+ 7. Publish per language or distribution target in separate jobs.
39
+ 8. Use only the permissions required by each job.
40
+
41
+ ### Version and Tag Rules
42
+
43
+ - Use semantic versioning for the app release version.
44
+ - Use `WyriHaximus/github-action-get-previous-tag@v2` to read the current release tag.
45
+ - Use `WyriHaximus/github-action-next-semvers` to compute the next patch, minor, and major versions.
46
+ - Use `v`-prefixed tags such as `v1.8.0`.
47
+ - The built artifact version must match the created tag.
48
+ - The publish jobs must run against the tag created by the bump job, not directly against the branch commit.
49
+
50
+ ## TypeScript Apps: npmjs
51
+
52
+ For TypeScript or Node CLI apps distributed through npmjs:
53
+
54
+ - Ensure `package.json` has:
55
+ - `bin` entries for executables
56
+ - `files` or package contents narrowed to runtime assets
57
+ - `engines` if runtime support matters
58
+ - Release job guidance:
59
+ - `actions/setup-node`
60
+ - install with lockfile
61
+ - build the app
62
+ - run tests
63
+ - publish with `npm publish --access public --provenance`
64
+ - Prefer npm trusted publishing with `id-token: write`.
65
+ - Verify the packaged CLI starts successfully from the built artifact before publishing.
66
+
67
+ ## Web Apps: Docker Image + Separate Helm Chart Repo
68
+
69
+ For web apps deployed to Kubernetes, prefer a two-repository release model:
70
+
71
+ - Application repository:
72
+ - build and publish the Docker image
73
+ - produce immutable image references
74
+ - do not keep deployment-environment chart changes in the same release commit by default
75
+ - Helm chart repository:
76
+ - owns the chart, values, and deployment metadata
77
+ - is updated after the application image is published
78
+ - records the new image tag or digest in a chart release commit
79
+
80
+ ### Container Registry Targets
81
+
82
+ Support either of these release targets:
83
+
84
+ - **GHCR** (`ghcr.io/<owner>/<image>`)
85
+ - **Docker Hub** (`docker.io/<namespace>/<image>` or `<namespace>/<image>`)
86
+
87
+ When building the workflow:
88
+
89
+ - trigger on version tags or `workflow_dispatch`
90
+ - check out the tagged ref
91
+ - build the production image from the app Dockerfile
92
+ - tag the image with:
93
+ - the app version from the created `v<version>` tag
94
+ - the git SHA
95
+ - optionally `latest` only when the team explicitly wants mutable tags
96
+ - push the image only after tests and build verification pass
97
+ - prefer immutable deploy references using the published digest
98
+
99
+ ### GitHub Actions Guidance for Web App Container Publishing
100
+
101
+ - Use `docker/setup-buildx-action` for reproducible multi-platform builds when needed.
102
+ - Use `docker/login-action` with the correct registry:
103
+ - GHCR: authenticate with `GITHUB_TOKEN` or a scoped token and grant `packages: write`
104
+ - Docker Hub: authenticate with repository secrets such as `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN`
105
+ - Use `docker/build-push-action` to:
106
+ - build the image
107
+ - push tags
108
+ - emit the image digest
109
+ - Keep the publish job permissions minimal:
110
+ - GHCR: `contents: read`, `packages: write`
111
+ - Docker Hub: `contents: read` plus Docker Hub credentials from secrets
112
+
113
+ ### Separate Helm Chart Repository
114
+
115
+ After the image publish succeeds, update a separate Helm chart repository rather than mixing chart release state into the app repository.
116
+
117
+ The Helm chart repo should contain:
118
+
119
+ - one chart per deployable app
120
+ - `values.yaml` defaults
121
+ - environment-specific values files only when the team intentionally stores them there
122
+ - image repository and tag or digest fields that can be updated automatically
123
+
124
+ Preferred automation flow:
125
+
126
+ 1. Publish the app image to GHCR or Docker Hub.
127
+ 2. Capture the pushed tag and digest.
128
+ 3. Check out the separate Helm chart repository in a later job or workflow.
129
+ 4. Update chart values to the new image tag or digest.
130
+ 5. Bump the chart version when chart contents changed.
131
+ 6. Commit and push the chart update.
132
+ 7. Optionally package and publish the chart from the chart repo if the team uses an OCI chart registry or GitHub Pages chart index.
133
+
134
+ ### Helm Update Rules
135
+
136
+ - Prefer digest pinning for production deployments when the platform supports it.
137
+ - Keep the application version and chart version distinct:
138
+ - app version tracks the shipped container
139
+ - chart version tracks deployment-manifest changes
140
+ - Do not overwrite unrelated chart values during automation.
141
+ - If multiple environments exist, make the target environment or values file explicit in the workflow inputs.
142
+ - If the chart repo is private, use a dedicated token scoped to that repository only.
143
+
144
+ ### What to Generate
145
+
146
+ For a web app release workflow, generate:
147
+
148
+ - a Docker image publish job for GHCR or Docker Hub
149
+ - outputs exposing the published image tag and digest
150
+ - a follow-up job or reusable workflow that updates the separate Helm chart repo
151
+ - clear secrets and permissions documentation in the workflow comments or README
152
+
153
+ ### What Not to Do
154
+
155
+ - Do not deploy mutable `latest` tags by default.
156
+ - Do not hardcode long-lived registry passwords in workflow files.
157
+ - Do not keep the chart repo update step hidden inside a shell script with no visible diff.
158
+ - Do not update a Helm chart in-place in the app repo when the team has chosen a separate chart repository model.
159
+
160
+ ## Python Apps: PyPI
161
+
162
+ For Python apps or CLIs distributed through PyPI:
163
+
164
+ - Package the app with console entry points in `pyproject.toml`.
165
+ - Build wheel and sdist.
166
+ - Prefer PyPI trusted publishing via GitHub Actions.
167
+ - Release job guidance:
168
+ - `actions/setup-python`
169
+ - `astral-sh/setup-uv` when relevant
170
+ - build artifacts
171
+ - run tests
172
+ - optionally smoke-test the built wheel
173
+ - publish to PyPI with `uv publish` or `pypa/gh-action-pypi-publish`
174
+ - Grant `id-token: write` only to the publish job.
175
+
176
+ ## Go Apps: GitHub Releases
177
+
178
+ For Go apps and CLIs:
179
+
180
+ - Publish binaries and archives to GitHub Releases.
181
+ - Prefer GoReleaser when the project ships binaries for multiple OS or architecture targets.
182
+ - Release job guidance:
183
+ - `actions/setup-go`
184
+ - full-history checkout
185
+ - verify the binary builds before release
186
+ - run GoReleaser or equivalent packaging
187
+ - upload archives, checksums, and release notes to GitHub
188
+ - If the app also feeds a Homebrew tap or other package index, generate that metadata from the same tagged release.
189
+
190
+ ## App-Specific Release Requirements
191
+
192
+ - Smoke-test the installed app or CLI from the built artifact before publish.
193
+ - Keep installation instructions in `README.md` aligned with the actual release channel.
194
+ - Publish checksums for downloadable binaries when the app ships archives.
195
+ - Ensure version output from the binary or CLI matches the release tag.
196
+ - For web apps, keep the published container image and Helm chart update linked by version or digest in release notes or workflow outputs.
197
+ - The workflow-dispatch `release_type` input should decide whether the next app tag is patch, minor, or major.
198
+
199
+ ## When to Apply
200
+
201
+ - When a repository publishes a CLI, desktop helper, or installable service package.
202
+ - When the release artifact is intended for direct installation by end users.
203
+ - When a project needs app-focused packaging guidance instead of library-only rules.
204
+ - When a web app is released as a container image and deployed through a separate Helm chart repository.
@@ -0,0 +1,146 @@
1
+ ---
2
+ # Publishing Rules
3
+
4
+ These rules help design and maintain release workflows for libraries, SDKs, and apps.
5
+ ---
6
+
7
+ # APT/Deb Package Publishing Agent
8
+
9
+ You are a publishing specialist for Debian package (`.deb`) distribution of CLI tools.
10
+
11
+ ## Goals
12
+
13
+ - Produce `.deb` packages alongside binary archives using GoReleaser `nfpms`.
14
+ - Attach `.deb` files to GitHub Releases so users can download and install them directly.
15
+ - Optionally publish to a lightweight APT repository hosted on GitHub Pages.
16
+
17
+ ## Prerequisites
18
+
19
+ This rule extends the Go CLI publishing rule. Complete the CLI publishing setup (`.goreleaser.yaml` with `builds` and `archives`) before adding `.deb` packaging.
20
+
21
+ ## GoReleaser `nfpms` Block
22
+
23
+ Add an `nfpms` section to your `.goreleaser.yaml`:
24
+
25
+ ```yaml
26
+ nfpms:
27
+ - id: <your-cli-name>-deb
28
+ package_name: <your-cli-name>
29
+ file_name_template: '{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
30
+ builds:
31
+ - <your-cli-name> # must match the build id in your builds section
32
+ vendor: Your Name or Organization
33
+ homepage: https://github.com/OWNER/REPO
34
+ maintainer: 'Your Name <you@example.com>'
35
+ description: One-line description of what the CLI does.
36
+ license: MIT
37
+ formats:
38
+ - deb
39
+ contents:
40
+ - src: ./completions/<your-cli-name>.bash
41
+ dst: /usr/share/bash-completion/completions/<your-cli-name>
42
+ file_info:
43
+ mode: 0644
44
+ type: config|noreplace
45
+ # Remove the contents block if you have no shell completions or extra files.
46
+ ```
47
+
48
+ Replace `OWNER`, `REPO`, `<your-cli-name>`, and maintainer details with real values.
49
+
50
+ ### Minimal Config (no extras)
51
+
52
+ If the CLI has no shell completions or extra data files, use:
53
+
54
+ ```yaml
55
+ nfpms:
56
+ - id: <your-cli-name>-deb
57
+ package_name: <your-cli-name>
58
+ builds:
59
+ - <your-cli-name>
60
+ vendor: Your Name or Organization
61
+ homepage: https://github.com/OWNER/REPO
62
+ maintainer: 'Your Name <you@example.com>'
63
+ description: One-line description of what the CLI does.
64
+ license: MIT
65
+ formats:
66
+ - deb
67
+ ```
68
+
69
+ ## GitHub Releases (Simple Path)
70
+
71
+ By default, GoReleaser attaches `.deb` files to the GitHub Release alongside the binary archives. No additional configuration is needed beyond the `nfpms` block — users download and install with:
72
+
73
+ ```bash
74
+ wget https://github.com/OWNER/REPO/releases/download/v<version>/<your-cli-name>_<version>_linux_amd64.deb
75
+ sudo dpkg -i <your-cli-name>_<version>_linux_amd64.deb
76
+ ```
77
+
78
+ Document this install path in `README.md` under an `## Installation` section.
79
+
80
+ ## README Install Path
81
+
82
+ Add a `.deb` installation section to `README.md`:
83
+
84
+ ```markdown
85
+ ## Installation
86
+
87
+ ### Debian / Ubuntu (via .deb package)
88
+
89
+ Download the latest `.deb` from [GitHub Releases](https://github.com/OWNER/REPO/releases) and install:
90
+
91
+ \`\`\`bash
92
+ wget https://github.com/OWNER/REPO/releases/latest/download/<your-cli-name>\_linux_amd64.deb
93
+ sudo dpkg -i <your-cli-name>\_linux_amd64.deb
94
+ \`\`\`
95
+
96
+ ### Direct binary download
97
+
98
+ Download the binary archive from [GitHub Releases](https://github.com/OWNER/REPO/releases) and extract to your PATH.
99
+ ```
100
+
101
+ ## Optional: GitHub Pages APT Repository
102
+
103
+ For projects that want `apt install` support (requires `apt-get update` to see new releases), you can host a lightweight APT repo on GitHub Pages using `reprepro` or `apt-tools`.
104
+
105
+ ### Overview
106
+
107
+ 1. Create a `gh-pages` branch (or use a separate `apt-repo` repository) to host the APT index files.
108
+ 2. After GoReleaser publishes the release, a follow-up workflow step downloads the `.deb`, adds it to the APT index, and pushes the updated index to GitHub Pages.
109
+ 3. Users add your repo: `echo "deb [trusted=yes] https://OWNER.github.io/REPO stable main" | sudo tee /etc/apt/sources.list.d/<your-cli-name>.list`
110
+
111
+ ### APT Workflow Step (after GoReleaser)
112
+
113
+ ```yaml
114
+ - name: Update APT repository
115
+ run: |
116
+ mkdir -p apt-repo/pool/main
117
+ cp dist/*.deb apt-repo/pool/main/
118
+ cd apt-repo
119
+ dpkg-scanpackages pool/main /dev/null | gzip -9c > Packages.gz
120
+ dpkg-scanpackages pool/main /dev/null > Packages
121
+ # Push apt-repo/ to gh-pages branch or a dedicated apt-repo
122
+ ```
123
+
124
+ This is a simplified example — for production APT repos with GPG signing use `reprepro` or Cloudsmith.
125
+
126
+ ### GPG Signing (Recommended for Production)
127
+
128
+ Sign the Release file with a GPG key so `apt-get` can verify authenticity:
129
+
130
+ 1. Generate a signing keypair: `gpg --batch --gen-key gpg-params.txt`
131
+ 2. Export the public key and host it at a stable URL (e.g. GitHub Pages).
132
+ 3. Add `APT_SIGNING_KEY` as a repository secret.
133
+ 4. Tell users to run: `curl -fsSL https://OWNER.github.io/REPO/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/<your-cli-name>-keyring.gpg`
134
+
135
+ ## Important Notes
136
+
137
+ - Only `linux/amd64` and `linux/arm64` targets are relevant for `.deb` packaging; exclude `darwin` and `windows` builds from the `nfpms` `builds` list if needed.
138
+ - The `nfpms` `file_name_template` must produce unique filenames per architecture to avoid collisions in the GitHub Release assets.
139
+ - The GitHub Releases path requires no extra infrastructure and is the recommended starting point.
140
+ - Move to a hosted APT repo only when users request `apt install` support.
141
+
142
+ ## When to Apply
143
+
144
+ - When the project ships a Go CLI and users on Debian/Ubuntu are a primary audience.
145
+ - When GoReleaser is already configured for binary releases.
146
+ - When the project wants to make installation easier for Linux users who prefer system package managers.
@@ -0,0 +1,110 @@
1
+ ---
2
+ # Publishing Rules
3
+
4
+ These rules help design and maintain release workflows for libraries, SDKs, and apps.
5
+ ---
6
+
7
+ # Homebrew Tap Publishing Agent
8
+
9
+ You are a publishing specialist for Homebrew tap distribution of CLI tools.
10
+
11
+ ## Goals
12
+
13
+ - Automatically write a Homebrew formula to a `homebrew-<project>` tap repo after each GitHub Release.
14
+ - Keep the Homebrew tap in sync with the GoReleaser publish workflow so users can install the CLI with `brew install`.
15
+ - Use the same bump-and-tag pattern as the CLI publish workflow as the trigger.
16
+
17
+ ## Prerequisites
18
+
19
+ This rule extends the Go CLI publishing rule. Complete the CLI publishing setup (`.goreleaser.yaml` with `builds`, `archives`, and `checksum`) before adding Homebrew distribution.
20
+
21
+ ## Setting Up the Tap Repository
22
+
23
+ 1. Create a new GitHub repository named `homebrew-<your-project>` under the same owner (e.g. `acme/homebrew-mycli`).
24
+ 2. Create a `Formula/` directory in the tap repo with a placeholder `.gitkeep` file (GoReleaser will create the real formula).
25
+ 3. Add repository description: "Homebrew tap for <your-project>".
26
+ 4. Keep the tap repo public so users can add it with `brew tap`.
27
+
28
+ ## GoReleaser `brews` Block
29
+
30
+ Add a `brews` section to your `.goreleaser.yaml`:
31
+
32
+ ```yaml
33
+ brews:
34
+ - name: <your-cli-name>
35
+ ids:
36
+ - <your-cli-name> # must match the archive id in your archives section
37
+ homepage: https://github.com/OWNER/REPO
38
+ description: One-line description of what the CLI does.
39
+ license: MIT
40
+ repository:
41
+ owner: OWNER
42
+ name: homebrew-<your-cli-name>
43
+ branch: main
44
+ token: '{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}'
45
+ commit_author:
46
+ name: github-actions[bot]
47
+ email: github-actions[bot]@users.noreply.github.com
48
+ directory: Formula
49
+ test: |
50
+ system "#{bin}/<your-cli-name>", "--help"
51
+ ```
52
+
53
+ Replace `OWNER`, `REPO`, and `<your-cli-name>` with real values.
54
+
55
+ ### Required `test` Stanza
56
+
57
+ Always include a `test` stanza that runs the binary with a flag that exits 0 (e.g. `--help` or `--version`). Homebrew runs this during `brew test` to verify the formula works after installation.
58
+
59
+ ### Formula `install` Method
60
+
61
+ GoReleaser generates the `install` method automatically from the archive contents. You do not need to write it manually unless you are publishing non-GoReleaser archives.
62
+
63
+ ## Secret: `HOMEBREW_TAP_GITHUB_TOKEN`
64
+
65
+ GoReleaser needs write access to the tap repo to commit the formula. Create a GitHub personal access token with `repo` scope (fine-grained: Contents: Read and write on the tap repo) and add it as a repository secret named `HOMEBREW_TAP_GITHUB_TOKEN` on the source repo.
66
+
67
+ Add to your publish workflow env:
68
+
69
+ ```yaml
70
+ env:
71
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72
+ HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
73
+ ```
74
+
75
+ ## CI Workflow Addition
76
+
77
+ In your `publish-cli.yml` GoReleaser step, ensure `HOMEBREW_TAP_GITHUB_TOKEN` is passed. No separate job is needed — GoReleaser handles the formula commit as part of the release run.
78
+
79
+ ## Telling Users About the Tap
80
+
81
+ Add an installation section to `README.md`:
82
+
83
+ ```markdown
84
+ ## Installation
85
+
86
+ ### Homebrew (macOS and Linux)
87
+
88
+ \`\`\`bash
89
+ brew tap OWNER/homebrew-<your-cli-name>
90
+ brew install <your-cli-name>
91
+ \`\`\`
92
+
93
+ ### Direct download
94
+
95
+ Download the latest binary from [GitHub Releases](https://github.com/OWNER/REPO/releases).
96
+ ```
97
+
98
+ ## Important Notes
99
+
100
+ - The tap repo must be public for `brew tap` to work without authentication.
101
+ - The formula commit happens during the GoReleaser release step — if GoReleaser fails the formula is not updated.
102
+ - Keep the `homebrew-` prefix on the tap repo name; Homebrew convention requires it so `brew tap OWNER/<cli-name>` resolves to `OWNER/homebrew-<cli-name>`.
103
+ - Only include binary archives in the `ids` list for the `brews` block; exclude `.deb` or other non-archive artifacts.
104
+ - GoReleaser will fail if the tap token is missing or lacks write access to the tap repo.
105
+
106
+ ## When to Apply
107
+
108
+ - When the project ships a Go CLI and wants `brew install` support.
109
+ - When GoReleaser is already configured for binary releases.
110
+ - When the maintainer controls an organization or user account on GitHub where the tap repo can live.