claude-aws-mfa 1.1.0-rc.1 → 1.1.0

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.
@@ -0,0 +1,139 @@
1
+ name: Release from Changelog
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ detect-release:
10
+ runs-on: ubuntu-latest
11
+ outputs:
12
+ version: ${{ steps.parse.outputs.version }}
13
+ prerelease: ${{ steps.parse.outputs.prerelease }}
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-tags: true
18
+
19
+ - name: Parse latest changelog version
20
+ id: parse
21
+ run: |
22
+ # Extract the first heading that matches: ## [vX.Y.Z...] - YYYY-MM-DD
23
+ # The date is required — headings without a date are treated as drafts.
24
+ HEADING=$(grep -P '^## \[v[^\]]+\]\s+-\s+\d{4}-\d{2}-\d{2}' CHANGELOG.md | head -1)
25
+
26
+ if [ -z "$HEADING" ]; then
27
+ echo "No dated release heading found — nothing to release."
28
+ echo "version=" >> "$GITHUB_OUTPUT"
29
+ exit 0
30
+ fi
31
+
32
+ VERSION=$(echo "$HEADING" | grep -oP '(?<=\[)[^\]]+')
33
+
34
+ # Must be valid semver with v prefix
35
+ if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]]; then
36
+ echo "::error::First changelog heading '$VERSION' is not valid semver with v prefix"
37
+ exit 1
38
+ fi
39
+
40
+ # Verify the date is today (UTC +/- 12h to accommodate any timezone)
41
+ ENTRY_DATE=$(echo "$HEADING" | grep -oP '\d{4}-\d{2}-\d{2}')
42
+ YESTERDAY=$(date -u -d '-12 hours' +%Y-%m-%d)
43
+ TODAY=$(date -u +%Y-%m-%d)
44
+ TOMORROW=$(date -u -d '+12 hours' +%Y-%m-%d)
45
+ if [[ "$ENTRY_DATE" != "$YESTERDAY" && "$ENTRY_DATE" != "$TODAY" && "$ENTRY_DATE" != "$TOMORROW" ]]; then
46
+ echo "::error::Changelog date $ENTRY_DATE does not match today — expected $YESTERDAY, $TODAY, or $TOMORROW"
47
+ exit 1
48
+ fi
49
+
50
+ # Check if this tag already exists on the remote
51
+ if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then
52
+ echo "Tag $VERSION already exists — skipping release."
53
+ echo "version=" >> "$GITHUB_OUTPUT"
54
+ exit 0
55
+ fi
56
+
57
+ # Check if a GitHub release already exists
58
+ if gh release view "$VERSION" >/dev/null 2>&1; then
59
+ echo "::error::GitHub release $VERSION already exists but tag does not — manual cleanup needed"
60
+ exit 1
61
+ fi
62
+
63
+ PRERELEASE="false"
64
+ SEMVER="${VERSION#v}"
65
+ if [[ "$SEMVER" =~ - ]]; then
66
+ PRERELEASE="true"
67
+ fi
68
+
69
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
70
+ echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
71
+ echo "Detected version=$VERSION prerelease=$PRERELEASE"
72
+
73
+ release:
74
+ needs: detect-release
75
+ if: needs.detect-release.outputs.version != ''
76
+ runs-on: ubuntu-latest
77
+ permissions:
78
+ contents: read
79
+ id-token: write
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+ with:
83
+ token: ${{ secrets.RELEASE_PAT }}
84
+
85
+ - uses: oven-sh/setup-bun@v2
86
+ with:
87
+ bun-version: latest
88
+
89
+ - run: bun install --frozen-lockfile
90
+
91
+ - run: bun test
92
+
93
+ - name: Set package version
94
+ run: |
95
+ VERSION="${{ needs.detect-release.outputs.version }}"
96
+ npm version "${VERSION#v}" --no-git-tag-version
97
+
98
+ - name: Extract changelog entry
99
+ id: changelog
100
+ run: |
101
+ VERSION="${{ needs.detect-release.outputs.version }}"
102
+ # Extract the body of the first changelog section (between first ## and second ##)
103
+ BODY=$(awk '/^## \[/{if(found) exit; found=1; next} found' CHANGELOG.md)
104
+ # Write to file for the release body
105
+ echo "$BODY" > /tmp/release-body.md
106
+
107
+ - name: Create Git tag
108
+ run: |
109
+ VERSION="${{ needs.detect-release.outputs.version }}"
110
+ git tag "$VERSION"
111
+ git push origin "$VERSION"
112
+
113
+ - name: Create GitHub Release
114
+ env:
115
+ GH_TOKEN: ${{ secrets.RELEASE_PAT }}
116
+ run: |
117
+ VERSION="${{ needs.detect-release.outputs.version }}"
118
+ PRERELEASE="${{ needs.detect-release.outputs.prerelease }}"
119
+ FLAGS=""
120
+ if [ "$PRERELEASE" = "true" ]; then
121
+ FLAGS="--prerelease"
122
+ fi
123
+ gh release create "$VERSION" \
124
+ --title "$VERSION" \
125
+ --notes-file /tmp/release-body.md \
126
+ $FLAGS
127
+
128
+ - uses: actions/setup-node@v4
129
+ with:
130
+ node-version: 24
131
+ registry-url: https://registry.npmjs.org
132
+
133
+ - name: Publish to npm
134
+ run: |
135
+ TAG="latest"
136
+ if [ "${{ needs.detect-release.outputs.prerelease }}" = "true" ]; then
137
+ TAG="next"
138
+ fi
139
+ npm publish --access public --tag "$TAG"
package/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ### Releasing
9
+
10
+ Releases are automated via CI. To create a new release:
11
+
12
+ 1. Add a new entry at the top of this file with heading `## [vX.Y.Z]` (without a
13
+ date). This is a draft — it can be merged to `main` without triggering a
14
+ release.
15
+ 2. When ready to publish, update the heading to `## [vX.Y.Z] - YYYY-MM-DD` and
16
+ merge to `main`. The date signals "ready to release".
17
+ 3. The workflow will run tests, create a Git tag, GitHub Release, and npm publish.
18
+ 4. If the tag already exists, the workflow skips (safe to re-merge).
19
+ 5. If tests fail, no tag/release is created. The release will be re-attempted on
20
+ each subsequent push to `main`, or can be manually retried from the Actions UI.
21
+
22
+ Stable versions (e.g. `v1.2.0`) publish to npm `@latest`. Pre-release versions
23
+ (e.g. `v1.2.0-rc.1`) publish to npm `@next` and create a GitHub pre-release.
24
+
25
+ ## [v1.1.0] - 2026-06-04
26
+
27
+ ### Added
28
+ - **Session caching** (`--cache-session`): Cache STS session credentials in the config file and reuse them until they expire, avoiding repeated MFA prompts.
29
+ - **Auto-MFA** (`--auto-mfa`): Automatically run the configured MFA command to obtain credentials without showing the dialog. Falls back to the dialog if the command fails.
30
+ - **Single-instance lock** (`--single-instance-lock`): Prevent multiple concurrent instances from showing overlapping dialogs. Subsequent invocations wait for the first to finish and reuse its cached session.
31
+ - New CLI flags with `--no-` negation support for all new options.
32
+ - New config file options: `cacheSession`, `autoMfa`, `singleInstanceLock`.
33
+ - Tests for session caching, lock mechanism, and CLI flag parsing.
34
+ - CHANGELOG.md to track project changes.
35
+ - Updated README with documentation for new CLI flags and features.
36
+
37
+ ### Changed
38
+ - Automated release pipeline: releases are now triggered by changelog entries pushed to `main`, replacing the previous manual GitHub Release workflow.
39
+
40
+ ### Fixed
41
+ - Release workflow: use `RELEASE_PAT` via `actions/checkout` token so git credential helper authenticates with the PAT instead of the default `GITHUB_TOKEN` (which cannot bypass tag rulesets).
42
+
43
+ ## [v1.0.0] - 2026-03-28
44
+
45
+ ### Added
46
+ - Initial stable release.
47
+ - Native GUI dialog for AWS credential and MFA code entry.
48
+ - MFA Command mode: provide a shell command (e.g. `op item get --otp …`) to fetch TOTP codes automatically.
49
+ - Automatic STS session duration negotiation (12h → 6h → 2h → 1h).
50
+ - Guided setup wizard (`--setup`) for Claude Code Bedrock configuration.
51
+ - Configuration persistence in `~/.config/claude-aws-mfa.json` (mode 0600).
52
+ - Credential masking in error output.
53
+ - Cross-platform support (macOS, Linux, Windows).
54
+ - CI test workflows (unit + GUI screenshot tests).
55
+ - npm publish workflow triggered by GitHub Releases.
package/README.md CHANGED
@@ -32,6 +32,17 @@ Add this (plus any addtitional config you prefer) to your Claude Code settings (
32
32
  }
33
33
  ```
34
34
 
35
+ ## CLI Flags
36
+
37
+ All flags can be negated with a `--no-` prefix (e.g. `--no-cache-session`). CLI flags override values saved in the config file.
38
+
39
+ | Flag | Description |
40
+ |------|-------------|
41
+ | `--setup` | Launch the guided setup wizard |
42
+ | `--cache-session` | Cache STS session credentials and reuse them until they expire |
43
+ | `--auto-mfa` | Automatically run the configured MFA command and obtain credentials without showing the dialog (requires MFA Command mode) |
44
+ | `--single-instance-lock` | Prevent multiple concurrent instances from showing overlapping dialogs; subsequent invocations wait for the first to finish and reuse its cached session |
45
+
35
46
  ## How it works
36
47
 
37
48
  1. On first run, seeds the dialog with credentials from your existing AWS config (`~/.aws/credentials`, environment variables, SSO, etc.)
@@ -44,6 +55,18 @@ Add this (plus any addtitional config you prefer) to your Claude Code settings (
44
55
 
45
56
  On subsequent runs, all fields are pre-populated from the saved config — just enter a fresh MFA code and hit OK. If you use the command mode, the TOTP code is fetched automatically so no manual entry is needed at all.
46
57
 
58
+ ### Session caching
59
+
60
+ With `--cache-session` (or `"cacheSession": true` in the config file), temporary credentials are saved to the config file and reused on subsequent runs until they expire. This avoids prompting for MFA on every invocation.
61
+
62
+ ### Auto-MFA
63
+
64
+ With `--auto-mfa` (or `"autoMfa": true` in the config file), when a MFA command is configured, credentials are obtained automatically without showing the dialog at all. If the command fails or isn't configured, the dialog is shown as a fallback.
65
+
66
+ ### Single-instance lock
67
+
68
+ With `--single-instance-lock` (or `"singleInstanceLock": true` in the config file), only one instance of the tool will show a dialog at a time. Additional invocations will wait for the first to finish and then reuse its cached session (when session caching is also enabled). The lock file is stored at `~/.config/claude-aws-mfa.lock` and is automatically cleaned up after 2 minutes if the holding process crashes.
69
+
47
70
  ## System requirements
48
71
 
49
72
  The GUI dialog uses [webview-bun](https://github.com/tr1ckydev/webview-bun), which requires:
@@ -60,6 +83,10 @@ bun run src/index.ts # run locally
60
83
  bun test # run tests
61
84
  ```
62
85
 
86
+ ## Releasing
87
+
88
+ See the [Releasing section of CHANGELOG.md](CHANGELOG.md#releasing) for how to publish new versions.
89
+
63
90
  ## License
64
91
 
65
92
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-aws-mfa",
3
- "version": "1.1.0-rc.1",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "repository": "https://github.com/p120ph37/claude-aws-mfa",
6
6
  "bin": {
@@ -1,76 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- jobs:
8
- publish:
9
- runs-on: ubuntu-latest
10
- permissions:
11
- contents: read
12
- id-token: write
13
-
14
- steps:
15
- - uses: actions/checkout@v4
16
-
17
- - name: Validate release tag
18
- run: |
19
- TAG="${GITHUB_REF_NAME}"
20
- IS_PRERELEASE="${{ github.event.release.prerelease }}"
21
-
22
- # Must start with "v"
23
- if [[ "$TAG" != v* ]]; then
24
- echo "::error::Tag must start with 'v' (got '$TAG')"
25
- exit 1
26
- fi
27
-
28
- VERSION="${TAG#v}"
29
-
30
- # Must be valid semver (X.Y.Z or X.Y.Z-prerelease)
31
- if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]]; then
32
- echo "::error::Tag must be a valid semver with a 'v' prefix (got '$TAG')"
33
- exit 1
34
- fi
35
-
36
- HAS_PRERELEASE_SUFFIX="false"
37
- if [[ "$VERSION" =~ - ]]; then
38
- HAS_PRERELEASE_SUFFIX="true"
39
- fi
40
-
41
- # Prerelease checkbox must match tag format
42
- if [ "$IS_PRERELEASE" = "true" ] && [ "$HAS_PRERELEASE_SUFFIX" = "false" ]; then
43
- echo "::error::Release is marked as prerelease but tag '$TAG' has no prerelease suffix (e.g. v1.0.0-beta.1)"
44
- exit 1
45
- fi
46
-
47
- if [ "$IS_PRERELEASE" = "false" ] && [ "$HAS_PRERELEASE_SUFFIX" = "true" ]; then
48
- echo "::error::Tag '$TAG' has a prerelease suffix but release is not marked as prerelease"
49
- exit 1
50
- fi
51
-
52
- echo "VERSION=$VERSION" >> "$GITHUB_ENV"
53
-
54
- - uses: oven-sh/setup-bun@v2
55
- with:
56
- bun-version: latest
57
-
58
- - run: bun install --frozen-lockfile
59
-
60
- - run: bun test
61
-
62
- - name: Set package version from release tag
63
- run: npm version "$VERSION" --no-git-tag-version
64
-
65
- - uses: actions/setup-node@v4
66
- with:
67
- node-version: 24
68
- registry-url: https://registry.npmjs.org
69
-
70
- - name: Publish to npm
71
- run: |
72
- TAG="latest"
73
- if [ "${{ github.event.release.prerelease }}" = "true" ]; then
74
- TAG="next"
75
- fi
76
- npm publish --access public --tag "$TAG"