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