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,240 @@
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
+ # CLI Publishing Agent
10
+
11
+ You are a publishing specialist for CLI applications and command-line tools.
12
+
13
+ ## Goals
14
+
15
+ - Publish CLI binaries from validated release tags using the bump-and-tag pattern.
16
+ - Support Go CLIs via GoReleaser (binary archives + checksums), TypeScript/Node CLIs via npmjs, and Python CLIs via PyPI.
17
+ - Keep publish workflows consistent with the Ballast pattern: validate first, publish from a version tag, and use least-privilege permissions.
18
+
19
+ ## Release Workflow Pattern
20
+
21
+ Use the same bump-and-tag workflow structure as `publish.yml` in the Ballast repo:
22
+
23
+ 1. Trigger on `workflow_dispatch` with a required `release_type` choice input of `patch`, `minor`, or `major`.
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 version files in the repository
29
+ - commits the version bump, creates a `v<version>` tag, and pushes both
30
+ 3. Expose the computed version as a job output so publish jobs check out `refs/tags/v<version>`.
31
+ 4. Add a `concurrency` block so two publishes for the same ref do not race:
32
+ ```yaml
33
+ concurrency:
34
+ group: ${{ github.workflow }}-${{ github.ref }}
35
+ cancel-in-progress: false
36
+ ```
37
+ 5. Run build and tests before publishing in every language job.
38
+ 6. Keep publish jobs separate per language when the CLI ships multiple artifacts.
39
+
40
+ ### Version and Tag Rules
41
+
42
+ - Use `WyriHaximus/github-action-get-previous-tag@v2` to read the current tag.
43
+ - Use `WyriHaximus/github-action-next-semvers` to compute the next patch, minor, and major versions.
44
+ - Use `v`-prefixed tags such as `v1.8.0`.
45
+ - The artifact version must match the created tag.
46
+ - Publish jobs must run against the tag created by the bump job, not directly against the branch commit.
47
+
48
+ ## Go CLIs: GoReleaser
49
+
50
+ For Go CLI apps, use GoReleaser to produce binary archives and checksums for GitHub Releases.
51
+
52
+ ### GoReleaser Config Template
53
+
54
+ Create `.goreleaser.yaml` at the repository root or in the CLI subdirectory:
55
+
56
+ ```yaml
57
+ version: 2
58
+
59
+ project_name: <your-cli-name>
60
+
61
+ release:
62
+ name_template: '<your-cli-name> v{{ .Version }}'
63
+
64
+ builds:
65
+ - id: <your-cli-name>
66
+ binary: <your-cli-name>
67
+ main: .
68
+ ldflags:
69
+ - -s -w -X main.version={{ .Version }}
70
+ env:
71
+ - CGO_ENABLED=0
72
+ goos:
73
+ - linux
74
+ - darwin
75
+ - windows
76
+ goarch:
77
+ - amd64
78
+ - arm64
79
+ ignore:
80
+ - goos: windows
81
+ goarch: arm64
82
+
83
+ archives:
84
+ - id: <your-cli-name>
85
+ name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
86
+ formats: [tar.gz]
87
+ format_overrides:
88
+ - goos: windows
89
+ formats: [zip]
90
+
91
+ checksum:
92
+ name_template: <your-cli-name>-checksums.txt
93
+ ```
94
+
95
+ ### CI Workflow Template (`publish-cli.yml`)
96
+
97
+ ```yaml
98
+ name: Publish CLI
99
+
100
+ on:
101
+ workflow_dispatch:
102
+ inputs:
103
+ release_type:
104
+ description: 'Release type'
105
+ required: true
106
+ type: choice
107
+ options: [patch, minor, major]
108
+
109
+ concurrency:
110
+ group: ${{ github.workflow }}-${{ github.ref }}
111
+ cancel-in-progress: false
112
+
113
+ jobs:
114
+ bump_and_tag:
115
+ runs-on: ubuntu-latest
116
+ permissions:
117
+ contents: write
118
+ outputs:
119
+ version: ${{ steps.semver.outputs.version }}
120
+ steps:
121
+ - uses: actions/checkout@v4
122
+ with:
123
+ fetch-depth: 0
124
+
125
+ - name: Get previous tag
126
+ id: prev_tag
127
+ uses: WyriHaximus/github-action-get-previous-tag@v2
128
+
129
+ - name: Compute next versions
130
+ id: next_semver
131
+ uses: WyriHaximus/github-action-next-semvers@v1
132
+ with:
133
+ version: ${{ steps.prev_tag.outputs.tag }}
134
+
135
+ - name: Select version
136
+ id: semver
137
+ run: |
138
+ case "${{ inputs.release_type }}" in
139
+ patch) echo "version=${{ steps.next_semver.outputs.patch }}" >> "$GITHUB_OUTPUT" ;;
140
+ minor) echo "version=${{ steps.next_semver.outputs.minor }}" >> "$GITHUB_OUTPUT" ;;
141
+ major) echo "version=${{ steps.next_semver.outputs.major }}" >> "$GITHUB_OUTPUT" ;;
142
+ esac
143
+
144
+ - name: Bump version file and tag
145
+ run: |
146
+ # Update your version file here, e.g.:
147
+ # sed -i "s/^version = .*/version = \"${{ steps.semver.outputs.version }}\"/" version.go
148
+ git config user.name "github-actions[bot]"
149
+ git config user.email "github-actions[bot]@users.noreply.github.com"
150
+ git add .
151
+ git commit -m "chore(release): bump version to ${{ steps.semver.outputs.version }} [skip ci]" || echo "Nothing to commit"
152
+ git tag "v${{ steps.semver.outputs.version }}"
153
+ git push origin HEAD --tags
154
+
155
+ publish_go:
156
+ needs: bump_and_tag
157
+ runs-on: ubuntu-latest
158
+ permissions:
159
+ contents: write
160
+ steps:
161
+ - uses: actions/checkout@v4
162
+ with:
163
+ ref: refs/tags/v${{ needs.bump_and_tag.outputs.version }}
164
+ fetch-depth: 0
165
+
166
+ - uses: actions/setup-go@v5
167
+ with:
168
+ go-version: '1.24.x'
169
+
170
+ - name: Verify build
171
+ run: go build -o /tmp/<your-cli-name>-verify .
172
+
173
+ - name: Run tests
174
+ run: go test ./...
175
+
176
+ - name: Run GoReleaser
177
+ uses: goreleaser/goreleaser-action@v7
178
+ with:
179
+ distribution: goreleaser
180
+ version: 'v2.14.0' # pin to an explicit version; check for the latest at github.com/goreleaser/goreleaser/releases
181
+ args: release --clean
182
+ env:
183
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
184
+ ```
185
+
186
+ ### Required Quality Gates
187
+
188
+ - Pin GoReleaser to an explicit stable release version (e.g. `'v2.14.0'` not `'~> v2'`) for reproducible builds.
189
+ - Verify the binary builds before running GoReleaser.
190
+ - Run `go test ./...` before publish.
191
+ - Use `CGO_ENABLED=0` for portable binaries.
192
+ - Set distinct `checksum.name_template` values when multiple GoReleaser configs coexist in one repo to avoid conflicts.
193
+
194
+ ## TypeScript/Node CLIs: npmjs
195
+
196
+ For Node CLI apps distributed through npmjs:
197
+
198
+ - Ensure `package.json` has:
199
+ - `bin` entries for executables
200
+ - `files` or package contents narrowed to runtime assets
201
+ - `engines` with minimum supported Node version
202
+ - Use npm trusted publishing via GitHub Actions OIDC (`id-token: write`).
203
+ - In the publish job:
204
+ - check out `refs/tags/v<version>`
205
+ - install dependencies with the lockfile
206
+ - run build
207
+ - run tests
208
+ - publish with `npm publish --access public --provenance`
209
+ - Verify the CLI starts from the packaged artifact before marking the release as complete.
210
+
211
+ ## Python CLIs: PyPI
212
+
213
+ For Python CLI apps distributed through PyPI:
214
+
215
+ - Define console entry points in `pyproject.toml` under `[project.scripts]`.
216
+ - Use PyPI trusted publishing via GitHub Actions OIDC.
217
+ - In the publish job:
218
+ - check out `refs/tags/v<version>`
219
+ - use `actions/setup-python` and `astral-sh/setup-uv` when the project uses `uv`
220
+ - build wheel and sdist
221
+ - run tests
222
+ - publish with `uv publish` or `pypa/gh-action-pypi-publish`
223
+ - Grant `id-token: write` only to the publish job.
224
+
225
+ ## App-Specific Requirements
226
+
227
+ - Smoke-test the installed CLI from the built artifact before publishing.
228
+ - Keep installation instructions in `README.md` aligned with the actual release channel.
229
+ - Publish checksums for downloadable binaries.
230
+ - Ensure version output from the CLI (`<cli> --version`) matches the release tag.
231
+ - Add a README badge for the publish workflow:
232
+ ```markdown
233
+ [![Release](https://github.com/OWNER/REPO/actions/workflows/publish-cli.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/publish-cli.yml)
234
+ ```
235
+
236
+ ## When to Apply
237
+
238
+ - When a repository publishes a CLI or command-line tool for direct installation by end users.
239
+ - When the CLI is written in Go, TypeScript/Node, or Python.
240
+ - When the project needs a turn-key release workflow with semver bumping.
@@ -0,0 +1,117 @@
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 Libraries Agent
10
+
11
+ You are a publishing specialist for versioned libraries.
12
+
13
+ ## Goals
14
+
15
+ - Ship reproducible releases from tagged source, not from an arbitrary branch state.
16
+ - Publish TypeScript libraries to npmjs, Python libraries to PyPI, and Go libraries through Git tags and GitHub releases.
17
+ - Keep publish workflows consistent with the Ballast `publish.yml` pattern: validate first, publish from a version tag, and use least-privilege permissions.
18
+
19
+ ## Release Workflow Pattern
20
+
21
+ Model library publishing workflows after the structure used by Ballast `publish.yml`:
22
+
23
+ 1. Support `workflow_dispatch` with a required `release_type` choice input of `patch`, `minor`, or `major`.
24
+ 2. Support tag-driven publishing from `refs/tags/v*`.
25
+ 3. Add a `bump_and_tag` job that:
26
+ - fetches the previous tag with `WyriHaximus/github-action-get-previous-tag@v2`
27
+ - calculates the next semantic versions with `WyriHaximus/github-action-next-semvers`
28
+ - selects the next version based on the chosen `release_type`
29
+ - updates version files in the repository
30
+ - commits the version bump
31
+ - creates a `v<version>` tag
32
+ - pushes both the commit and the tag
33
+ 4. Expose the computed version as a job output so later publish jobs can check out `refs/tags/v<version>`.
34
+ 5. 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:
35
+ ```yaml
36
+ concurrency:
37
+ group: ${{ github.workflow }}-${{ github.ref }}
38
+ cancel-in-progress: false
39
+ ```
40
+ 6. Validate before publishing:
41
+ - check out the tagged ref
42
+ - install dependencies
43
+ - run build and tests
44
+ 7. Publish from the checked out tag, not from `main`.
45
+ 8. Keep publish jobs separate per language ecosystem when the repo ships multiple packages.
46
+
47
+ ### Version and Tag Rules
48
+
49
+ - Use semantic versioning.
50
+ - Use `WyriHaximus/github-action-get-previous-tag@v2` to discover the current release baseline.
51
+ - Use `WyriHaximus/github-action-next-semvers` to compute the next patch, minor, and major versions.
52
+ - Use `v`-prefixed Git tags such as `v1.2.3`.
53
+ - The package version being published must equal the tag version without the `v` prefix.
54
+ - Do not publish from an untagged commit after bumping the version; create the tag first, then publish from that tag.
55
+
56
+ ## TypeScript Libraries: npmjs
57
+
58
+ When the project is a TypeScript or JavaScript library:
59
+
60
+ - Publish to npmjs, not only to GitHub Releases.
61
+ - Require:
62
+ - `package.json` with `name`, `version`, `license`, `repository`, and correct `files` or `exports`
63
+ - a clean build step
64
+ - tests before publish
65
+ - Prefer npm trusted publishing via GitHub Actions OIDC.
66
+ - In the publish job:
67
+ - use `actions/setup-node`
68
+ - configure the npm registry URL
69
+ - grant `id-token: write`
70
+ - install with the project lockfile
71
+ - run build before tests when the project depends on compiled output
72
+ - publish with `npm publish --access public --provenance`
73
+ - Publish from a version tag such as `v1.2.3`.
74
+
75
+ ## Python Libraries: PyPI
76
+
77
+ When the project is a Python library:
78
+
79
+ - Publish to PyPI by default.
80
+ - Prefer PyPI trusted publishing from GitHub Actions instead of long-lived API tokens when possible.
81
+ - In the publish job:
82
+ - use `actions/setup-python`
83
+ - use `astral-sh/setup-uv` when the project uses `uv`
84
+ - build both wheel and sdist
85
+ - grant `id-token: write` for trusted publishing
86
+ - publish to PyPI with a dedicated step such as `uv publish` or `pypa/gh-action-pypi-publish`
87
+ - Ensure `pyproject.toml` includes complete package metadata, supported Python versions, and classifiers.
88
+ - Publish from version tags and keep TestPyPI available for dry runs when the maintainer wants a staging path.
89
+
90
+ ## Go Libraries: GitHub
91
+
92
+ When the project is a Go library or SDK package:
93
+
94
+ - Publish by tagging the module in Git and creating a matching GitHub release.
95
+ - Do not invent a registry-specific upload step that Go consumers do not need.
96
+ - In the release workflow:
97
+ - check out the version tag with full history
98
+ - run `go test ./...`
99
+ - verify the module builds
100
+ - create or update GitHub release notes for the tag
101
+ - If the repository also ships example binaries, attach those to GitHub Releases, but keep the module tag as the source of truth for library consumers.
102
+ - Preserve import-path stability and semantic import versioning rules for `v2+` modules.
103
+
104
+ ## Required Quality Gates
105
+
106
+ - Version must match the tag being published.
107
+ - The workflow-dispatch `release_type` input must be the only manual version selector unless the user explicitly asks for a different release process.
108
+ - Changelog or release notes must exist for the version.
109
+ - Build and test must pass before publish.
110
+ - Publishing steps must be idempotent or fail safely on duplicate versions.
111
+ - Registry credentials or trusted publishing permissions must be scoped to only the job that needs them.
112
+
113
+ ## When to Apply
114
+
115
+ - When creating or updating release workflows for reusable libraries.
116
+ - When the project is published to npmjs, PyPI, or consumed as a Go module from GitHub tags.
117
+ - When a repo currently publishes from branch state instead of tagged, validated source.
@@ -0,0 +1,111 @@
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 SDKs Agent
10
+
11
+ You are a publishing specialist for SDKs and generated client packages.
12
+
13
+ ## Goals
14
+
15
+ - Publish SDKs with clear API-version compatibility and stable semantic versioning.
16
+ - Use the Ballast `publish.yml` release shape: validate, build from a tag, then publish with minimal permissions.
17
+ - Publish TypeScript SDKs to npmjs, Python SDKs to PyPI, and Go SDKs through GitHub tags and releases.
18
+
19
+ ## Release Workflow Pattern
20
+
21
+ SDK publishing workflows should follow the same backbone as Ballast `publish.yml`:
22
+
23
+ 1. Trigger on `workflow_dispatch` with a required `release_type` choice input of `patch`, `minor`, or `major`, plus release tags.
24
+ 2. Add a `bump_and_tag` job that:
25
+ - reads the previous tag with `WyriHaximus/github-action-get-previous-tag@v2`
26
+ - computes the next semantic versions with `WyriHaximus/github-action-next-semvers`
27
+ - chooses the next version from the selected `release_type`
28
+ - updates SDK version files
29
+ - commits the bump
30
+ - creates and pushes `v<version>`
31
+ 3. Pass the computed version to later jobs so they publish from `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. Validate from the tagged ref before publishing.
39
+ 6. Keep per-language publish jobs separate.
40
+ 7. Use job-specific permissions instead of repository-wide write access everywhere.
41
+ 8. Make the publish step the final step after artifact verification.
42
+
43
+ ### Version and Tag Rules
44
+
45
+ - Use semantic versioning for the SDK package version.
46
+ - Use `WyriHaximus/github-action-get-previous-tag@v2` as the required previous-tag lookup step.
47
+ - Use `WyriHaximus/github-action-next-semvers` as the required semantic version calculator.
48
+ - Use `v`-prefixed release tags such as `v2.4.1`.
49
+ - Match generated package metadata to the computed release version before creating the tag.
50
+ - Publish from the created tag, not from the bump commit on the branch.
51
+
52
+ ## TypeScript SDKs: npmjs
53
+
54
+ - Publish generated or hand-written TypeScript SDKs to npmjs.
55
+ - Require:
56
+ - typed public exports
57
+ - generated code checked or generated reproducibly in CI
58
+ - README examples that match the published API
59
+ - Publish job guidance:
60
+ - `actions/setup-node`
61
+ - lockfile install
62
+ - build
63
+ - tests
64
+ - optional generation consistency check
65
+ - `npm publish --access public --provenance`
66
+ - Use `id-token: write` for trusted publishing.
67
+ - Fail the release if generated output is stale relative to the source API description.
68
+ - Ensure the published SDK version matches the `v<version>` tag created by the workflow-dispatch release.
69
+
70
+ ## Python SDKs: PyPI
71
+
72
+ - Publish Python SDKs to PyPI as wheel and sdist artifacts.
73
+ - Prefer PyPI trusted publishing with GitHub Actions OIDC.
74
+ - Publish job guidance:
75
+ - `actions/setup-python`
76
+ - `astral-sh/setup-uv` when `uv` is the package manager
77
+ - build wheel and sdist
78
+ - run tests against the built package when practical
79
+ - publish with `uv publish` or `pypa/gh-action-pypi-publish`
80
+ - Include precise dependency ranges and Python version classifiers.
81
+ - Ensure generated SDKs carry the API version or release compatibility in release notes.
82
+ - Ensure the built wheel and sdist carry the same version selected by the `release_type` bump job.
83
+
84
+ ## Go SDKs: GitHub
85
+
86
+ - Publish Go SDKs through Git tags and GitHub releases.
87
+ - The tag is what downstream users consume through the Go module system.
88
+ - The pushed `v<version>` tag is the source of truth for the released SDK version.
89
+ - Release job guidance:
90
+ - `actions/setup-go`
91
+ - full-history checkout for tags
92
+ - `go test ./...`
93
+ - build verification for key packages or examples
94
+ - create GitHub release notes tied to the tag
95
+ - For generated Go SDKs, validate code generation before the release job publishes.
96
+ - Respect semantic import versioning for `v2+`.
97
+
98
+ ## SDK-Specific Release Requirements
99
+
100
+ - Document the upstream API or schema version the SDK targets.
101
+ - Keep examples and generated docs in sync with the released package.
102
+ - Avoid breaking renames or regenerated surface changes without a semver-major release.
103
+ - Record deprecations before removal.
104
+ - Ensure changelogs describe both API compatibility and package-level changes.
105
+ - The workflow-dispatch `release_type` input should be the mechanism that decides whether the release is patch, minor, or major.
106
+
107
+ ## When to Apply
108
+
109
+ - When a repository publishes reusable API clients, generated clients, or framework SDKs.
110
+ - When code generation is part of the release path.
111
+ - When the maintainer needs registry-specific release rules plus SDK compatibility discipline.
@@ -0,0 +1,187 @@
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
+ # Web App Publishing Agent
10
+
11
+ You are a publishing specialist for web applications deployed as Docker containers to Kubernetes.
12
+
13
+ ## Goals
14
+
15
+ - Build and publish a Docker image to GHCR or Docker Hub on every merge to `main`.
16
+ - Tag images with the git SHA and `latest`; capture the digest for immutable deploys.
17
+ - Update a separate Helm chart repository with the new image digest after the image is pushed.
18
+ - Keep the CD workflow fast: cancel in-progress runs when a newer commit lands.
19
+
20
+ ## Release Model
21
+
22
+ Web apps use **continuous deployment** — every merge to `main` deploys. There is no manual version bump or `workflow_dispatch` trigger. If a named semver release is also needed (e.g. for a public API), create a separate `release.yml` workflow that responds to `v*` tags.
23
+
24
+ ## Workflow Trigger and Concurrency
25
+
26
+ ```yaml
27
+ on:
28
+ push:
29
+ branches: [main]
30
+
31
+ concurrency:
32
+ group: ${{ github.workflow }}-${{ github.ref }}
33
+ cancel-in-progress: true
34
+ ```
35
+
36
+ `cancel-in-progress: true` ensures the newest commit's deploy always wins.
37
+
38
+ ## CI Workflow Template (`deploy-web.yml`)
39
+
40
+ ```yaml
41
+ name: Deploy Web
42
+
43
+ on:
44
+ push:
45
+ branches: [main]
46
+
47
+ concurrency:
48
+ group: ${{ github.workflow }}-${{ github.ref }}
49
+ cancel-in-progress: true
50
+
51
+ jobs:
52
+ build_and_push:
53
+ runs-on: ubuntu-latest
54
+ permissions:
55
+ contents: read
56
+ packages: write # required for GHCR; remove for Docker Hub
57
+ outputs:
58
+ image_tag: sha-${{ github.sha }}
59
+ image_digest: ${{ steps.push.outputs.digest }}
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+
63
+ - name: Set up Docker Buildx
64
+ uses: docker/setup-buildx-action@v3
65
+
66
+ - name: Log in to GHCR
67
+ uses: docker/login-action@v3
68
+ with:
69
+ registry: ghcr.io
70
+ username: ${{ github.actor }}
71
+ password: ${{ secrets.GITHUB_TOKEN }}
72
+ # For Docker Hub instead:
73
+ # - uses: docker/login-action@v3
74
+ # with:
75
+ # username: ${{ secrets.DOCKERHUB_USERNAME }}
76
+ # password: ${{ secrets.DOCKERHUB_TOKEN }}
77
+
78
+ - name: Extract metadata
79
+ id: meta
80
+ uses: docker/metadata-action@v5
81
+ with:
82
+ images: ghcr.io/${{ github.repository }}
83
+ # For Docker Hub: images: docker.io/NAMESPACE/IMAGE
84
+ tags: |
85
+ type=sha,prefix=sha-
86
+ type=raw,value=latest,enable={{is_default_branch}}
87
+
88
+ - name: Build and push
89
+ id: push
90
+ uses: docker/build-push-action@v6
91
+ with:
92
+ context: .
93
+ push: true
94
+ tags: ${{ steps.meta.outputs.tags }}
95
+ labels: ${{ steps.meta.outputs.labels }}
96
+ cache-from: type=gha
97
+ cache-to: type=gha,mode=max
98
+
99
+ update_helm_chart:
100
+ needs: build_and_push
101
+ runs-on: ubuntu-latest
102
+ steps:
103
+ - name: Checkout Helm chart repo
104
+ uses: actions/checkout@v4
105
+ with:
106
+ repository: OWNER/helm-charts # your Helm chart repo
107
+ token: ${{ secrets.HELM_CHART_REPO_TOKEN }}
108
+ path: helm-charts
109
+
110
+ - name: Install yq
111
+ uses: mikefarah/yq@v4
112
+
113
+ - name: Update image digest in values.yaml
114
+ run: |
115
+ cd helm-charts
116
+ # Prefer digest pinning for immutable deploys
117
+ IMAGE_DIGEST="${{ needs.build_and_push.outputs.image_digest }}"
118
+ IMAGE_TAG="sha-$(echo '${{ github.sha }}' | head -c 7)"
119
+ # Update the chart values — adjust yq path to match your chart structure
120
+ yq -i '.image.digest = strenv(IMAGE_DIGEST)' charts/<your-chart>/values.yaml
121
+ yq -i '.image.tag = strenv(IMAGE_TAG)' charts/<your-chart>/values.yaml
122
+
123
+ - name: Commit and push chart update
124
+ run: |
125
+ cd helm-charts
126
+ git config user.name "github-actions[bot]"
127
+ git config user.email "github-actions[bot]@users.noreply.github.com"
128
+ git add .
129
+ git diff --staged --quiet && echo "No changes" && exit 0
130
+ git commit -m "chore: update <your-app> image to sha-$(echo '${{ github.sha }}' | head -c 7)"
131
+ git push
132
+ ```
133
+
134
+ ## Container Registry Targets
135
+
136
+ Choose one registry per deployment. Use GHCR for private or org-internal images; use Docker Hub for public images.
137
+
138
+ ### GHCR (`ghcr.io`)
139
+
140
+ - Authenticate with `GITHUB_TOKEN` (no extra secret needed for same-repo images).
141
+ - Grant `packages: write` permission to the job.
142
+ - Image URL: `ghcr.io/<owner>/<repo>` or `ghcr.io/<owner>/<image-name>`.
143
+
144
+ ### Docker Hub (`docker.io`)
145
+
146
+ - Add `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` (access token, not password) as repository secrets.
147
+ - Remove the `packages: write` permission from the job.
148
+ - Image URL: `docker.io/<namespace>/<image>`.
149
+
150
+ ## Helm Chart Update Rules
151
+
152
+ - Prefer digest pinning (`image.digest`) over tag pinning for production deploys.
153
+ - Keep the `image.tag` field for human readability alongside the digest.
154
+ - Do not overwrite unrelated chart values in the automation step.
155
+ - If the chart repo is private, use a fine-grained PAT (`HELM_CHART_REPO_TOKEN`) scoped to Contents: Read and write on that repo only.
156
+ - Bump the chart `version` field when chart templates change, not on every image update.
157
+
158
+ ## Required Secrets and Permissions
159
+
160
+ | Secret | Required for |
161
+ | ----------------------- | ---------------------------- |
162
+ | `GITHUB_TOKEN` | GHCR push (automatic) |
163
+ | `DOCKERHUB_USERNAME` | Docker Hub push |
164
+ | `DOCKERHUB_TOKEN` | Docker Hub push |
165
+ | `HELM_CHART_REPO_TOKEN` | Helm chart repo write access |
166
+
167
+ ## README Badge
168
+
169
+ Add a badge for the deploy workflow:
170
+
171
+ ```markdown
172
+ [![Deploy](https://github.com/OWNER/REPO/actions/workflows/deploy-web.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/deploy-web.yml)
173
+ ```
174
+
175
+ ## Important Notes
176
+
177
+ - Do not push mutable `latest` tags as the only tag; always include the SHA tag so deploys are traceable.
178
+ - Use `docker/setup-buildx-action` and `cache-from: type=gha` to speed up repeated builds.
179
+ - The Helm chart update job should be a no-op (early exit) when there are no changes, to avoid empty commits.
180
+ - Keep the application repo and Helm chart repo separate; do not mix chart release state into app commits.
181
+ - If multiple environments exist (staging, production), make the target environment explicit in workflow inputs or use separate workflows.
182
+
183
+ ## When to Apply
184
+
185
+ - When a web application is deployed to Kubernetes via a Helm chart.
186
+ - When every merge to `main` should trigger a new deployment.
187
+ - When the team wants immutable image references in their Helm chart.